diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/.cproject b/applications/user-crypto/miv-rv32-aes-cryptography/.cproject new file mode 100644 index 0000000..a4390e1 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/.cproject @@ -0,0 +1,333 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/.gitignore b/applications/user-crypto/miv-rv32-aes-cryptography/.gitignore new file mode 100644 index 0000000..f1b6b72 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/.gitignore @@ -0,0 +1,3 @@ +/.settings/ +/*miv-rv32-imc-debug*/ +/*miv-rv32-imc-release*/ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/.project b/applications/user-crypto/miv-rv32-aes-cryptography/.project new file mode 100644 index 0000000..711a87e --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/.project @@ -0,0 +1,26 @@ + + + miv-rv32-aes-cryptography + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/README.md b/applications/user-crypto/miv-rv32-aes-cryptography/README.md new file mode 100644 index 0000000..323fd24 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/README.md @@ -0,0 +1,158 @@ +PolarFire User Crypto AES Cryptography Services example +================================================================================ +This example project demonstrate the use of symmetric key encryption and +decryption services. The following PolarFire User Crypto service functions are used + + - CALSymEncrypt() + - CALSymEncryptDMA() + - CALSymDecrypt() + - CALSymDecryptDMA() + +There are two different build configurations provided with this project which +configure this SoftConsole project for RISC-V IMC instruction extension. +The following configurations are provided with the example: + + - miv-rv32-imc-debug + - miv-rv32-imc-release + +Mi-V Soft Processor +-------------------------------------------------------------------------------- +This example uses Mi-V SoftProcessor MiV_RV32.The design is built for debugging +MiV_RV32 through the PolarFire FPGA programming JTAG port using a FlashPro5. +To achieve this the CoreJTAGDebug IP is used to connect to the JTAG port of the +MiV_RV32. + +All the platform/design specific definitions such as peripheral base addresses, +system clock frequency etc. are included in fpga_design_config.h. The +fpga_design_config.h is located at the root folder of this project. + +The Mi-V Soft Processor MiV_RV32 firmware projects needs the miv_rv32_hal and +the hal firmware(RISC-V HAL). + +The RISC-V HAL is available at GitHub [Mi-V-Soft-RISC-V](https://mi-v-ecosystem.github.io/redirects/platform). + +How to use this example +-------------------------------------------------------------------------------- +This example project is targeted at a MIV_RV32 design running on a PolarFire-Eval-Kit +connected via a USB-UART serial cable to a host PC running a terminal emulator +such as TeraTerm or Putty configured as follows: + + - 115200 baud + - 8 data bits + - 1 stop bit + - no parity + - no flow control. + +Run the example project using a debugger. A greeting message will appear over the +UART terminal followed by a menu system and instructions. + +This program displays the return data from User Crypto processor for encryption +and decryption services. + +fpga_design_config (formerly known as hw_config.h) +-------------------------------------------------------------------------------- +The SoftConsole project targeted for Mi-V processors now use an improved +directory structure. The fpga_design_config.h must be stored as shown below + +` + /boards//fpga_design_config/fpga_design_config.h +` + +Currently, this file must be hand crafted when using the Mi-V Soft Processor. +In future, all the design and soft IP configurations will be automatically +generated from the Libero design description data. + +You can use the sample file provided with MIV_RV32 HAL as an example. Rename it +from sample_fpga_design_config.h to fpga_design_config.h and then customize it +per your hardware design such as SYS_CLK_FREQ, peripheral BASE addresses, +interrupt numbers, definition of MSCC_STDIO_UART_BASE_ADDR if you want a +CoreUARTapb mapped to STDIO, etc. + +### Data Encryption + +Select option '1' for data encryption using AES-256 algorithm based on electronic +code book encryption (ECB) mode and key. This example project reads the plain +text and an encryption key from URAT terminal and calls **CALSymEncrypt()** or +**CALSymEncryptDMA()** function. The **CALSymEncrypt()** and **CALSymEncryptDMA()** +functions encrypt the message based on electronic code book encryption (ECB) +mode and symmetric encryption key and generate the cipher text. This cipher +text is also displayed on UART terminal. + +### Data Decryption + +Select option '2' for data decryption using AES-256 algorithm based on electronic +code book (ECB) mode and key. This example project reads a cipher text and a +decryption key from URAT terminal and calls **CALSymDecrypt()** or **CALSymDecrypt()** +function. The **CALSymDecrypt()** and **CALSymDecryptDMA()** functions decrypt the +cipher text based on ECB mode and symmetric encryption key, and generate the +plain text. The generated plain text is also displayed on UART terminal. You +have to provide same key to decrypt the cipher text, which is used for encryption. + +**NOTE:** + If you try to enter data values other than 0 - 9, a - f, A - F, an error + message will be displayed on the serial port terminal. + +### Configurations + +The CAL library needs a config_user.h containing the configuration data. +This application provides following settings as per CAL requirement + 1. A variable which provides the base address of the User Crypto hardware block + is defined in main.c + + `uint32_t g_user_crypto_base_addr = 0x62000000UL;` + + 2. A symbol INC_STDINT_H is defined in project preprocessor setting. + For more detail, please refer to caltypes.h file present in CAL folder. + +### Test script + +A test script is provided with this example which automatically enters the NIST +vectors and associated data to verify the functionality. You can use +RV32_AES_Cryptography.ttl Tera Term Macro script present in project directory for +testing AES Cryptography example project. + +**NOTE:** +1. Tera Term Macros don’t work with Windows 10 build 14393.0. You should update + to Windows 10 build 14393.0.105 or [later.](https://osdn.net/ticket/browse.php?group_id=1412&tid=36526) +2. Before running Tera Term Macro script, set language as English + (Setup->General->Language). Also setup transmit delay in (Setup->Serial port) + to 5msec/char and 5msec/line. +3. By default, Tera Term log will be stored in Tera Term installation Directory. + +## Target hardware + +This project was tested on PolarFire-Eval-Kit with CFG4 configuration of the +MIV_RV32 design available [here](https://github.com/Mi-V-Soft-RISC-V/PolarFire-Eval-Kit/tree/main/Libero_Projects) + +All the design specific definitions such as peripheral base addresses, system +clock frequency etc. are included in fpga_design_config.h. + +The firmware projects needs the HAL and the MIV_RV32 HAL firmware components. + +This example project can be used with another design using a different hardware +configurations. This can be achieved by overwriting the content of this example +project's "fpga_design_config.h" file with the correct data per your Libero design. + +### Booting the system + +Currently the example project is configured to use FlashPro debugger to execute +from LSRAM in both Debug and Release mode. + +In the release mode build configuration, following setting is used +`--change-section-lma *-0x80000000` under +Tool Settings > Cross RISCV GNU Create Flash Image > General > Other flags. + +This will allow you to attach the release mode executable as the memory +initialization client in Libero when you want to execute it from non-volatile memory. + +## Silicon revision dependencies + +This example is tested on PolarFire MPF300TS device. + +### CAL library src + +To obtain the CAL source code and a SoftConsole project to generate the CAL +library archive file (*.a) refer [SoftConsole Documentation](https://mi-v-ecosystem.github.io/SoftConsole-Documentation/SoftConsole-v2021.3/using_softconsole/other.html#crypto-application-library). +The CAL source code is bound by license agreement and it will be available as +part of the SoftConsole installation if the CAL specific license was agreed +while installing it. \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/RV32_AES_Cryptography.ttl b/applications/user-crypto/miv-rv32-aes-cryptography/RV32_AES_Cryptography.ttl new file mode 100644 index 0000000..f175060 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/RV32_AES_Cryptography.ttl @@ -0,0 +1,246 @@ +; Tera Term Setting: +; 1. Before running Tera Term Macro script, you should set language as English +; and transmit delay in Serial port setup to 5msec/char and 5msec/line. +; 2. By default, Tera Term log will be stored in Tera Term installation Directory. + +changedir '.' +logopen "AES_Cryptography.log" 0 0 0 1 + +settitle 'PolarFire User Crypto AES-128' + +setsync 1 + +;Clear screen +clearscreen 0 + +; Set baud rate to 115200 +setbaud 115200 + +; local echo off +setecho 0 + +;; Send Dummy +send $0 + +; --------------------------------------------------------------------------------------------------------------- +; AES-128 Encryption +; --------------------------------------------------------------------------------------------------------------- +;Test Case 1 - using DMA +; INPUT +; COUNT = 0 +; KEY = c47b0294dbbbee0fec4757f22ffeee3587ca4730c3d33b691df38bab076bc558 +; PLAINTEXT = 00000000000000000000000000000000 +; OUTPUT +; CIPHERTEXT = 46f2fb342d6f0ab477476fc501242c5f +; --------------------------------------------------------------------------------------------------------------- +send '1' +pause 1 + +;key +send 'c47b0294dbbbee0fec4757f22ffeee3587ca4730c3d33b691df38bab076bc558' +pause 1 + +;IV +send '00000000000000000000000000000000' +pause 1 + +;PLAINTEXT +send '00000000000000000000000000000000' +send 13 +pause 1 + +;DMA enabled +send '1' +pause 4 + +;Press any key +send $0 + +; --------------------------------------------------------------------------------------------------------------- +;Test Case 2 - non DMA +; INPUT +; COUNT = 0 +; KEY = c47b0294dbbbee0fec4757f22ffeee3587ca4730c3d33b691df38bab076bc558 +; PLAINTEXT = 00000000000000000000000000000000 +; OUTPUT +; CIPHERTEXT = 46f2fb342d6f0ab477476fc501242c5f +; --------------------------------------------------------------------------------------------------------------- +send '1' +pause 1 + +;key +send 'c47b0294dbbbee0fec4757f22ffeee3587ca4730c3d33b691df38bab076bc558' +pause 1 + +;IV +send '00000000000000000000000000000000' +pause 1 + +;PLAINTEXT +send '00000000000000000000000000000000' +send 13 +pause 1 + +;DMA disabled +send '0' +pause 4 + +;Press any key +send $0 + +; --------------------------------------------------------------------------------------------------------------- +; Test Case 3 - DMA enabled +; INPUT +; KEY = 0000000000000000000000000000000000000000000000000000000000000000 +; PLAINTEXT = 91fbef2d15a97816060bee1feaa49afe +; OUTPUT +; CIPHERTEXT = 1bc704f1bce135ceb810341b216d7abe +; --------------------------------------------------------------------------------------------------------------- +send '1' +pause 1 + +;key +send '0000000000000000000000000000000000000000000000000000000000000000' +pause 1 + +;IV +send '00000000000000000000000000000000' +pause 1 + +;PLAINTEXT +send '91fbef2d15a97816060bee1feaa49afe' +send 13 +pause 1 + +;DMA Enabled +send '1' +pause 4 + +;Press any key +send $0 + +; --------------------------------------------------------------------------------------------------------------- +; Test Case 4 - DMA disabled +; INPUT +; KEY = 0000000000000000000000000000000000000000000000000000000000000000 +; PLAINTEXT = 91fbef2d15a97816060bee1feaa49afe +; OUTPUT +; CIPHERTEXT = 1bc704f1bce135ceb810341b216d7abe +; --------------------------------------------------------------------------------------------------------------- +send '1' +pause 1 + +;key +send '0000000000000000000000000000000000000000000000000000000000000000' +pause 1 + +;IV +send '00000000000000000000000000000000' +pause 1 + +;PLAINTEXT +send '91fbef2d15a97816060bee1feaa49afe' +send 13 +pause 1 + +;DMA Disabled +send '0' +pause 4 + +;Press any key +send $0 + + +; --------------------------------------------------------------------------------------------------------------- +; Test Case 5 - DMA Enabled +; INPUT +; KEY = 1d85a181b54cde51f0e098095b2962fdc93b51fe9b88602b3f54130bf76a5bd9 +; PLAINTEXT = 00000000000000000000000000000000 +; OUTPUT +; CIPHERTEXT = 531c2c38344578b84d50b3c917bbb6e1 +; --------------------------------------------------------------------------------------------------------------- +send '1' +pause 1 + +;key +send '1d85a181b54cde51f0e098095b2962fdc93b51fe9b88602b3f54130bf76a5bd9' +pause 1 + +;IV +send '00000000000000000000000000000000' +pause 1 + +;PLAINTEXT +send '00000000000000000000000000000000' +send 13 +pause 1 + +;DMA Enabled +send '1' +pause 4 + +;Press any key +send $0 + +; --------------------------------------------------------------------------------------------------------------- +; AES-128 Decryption +; --------------------------------------------------------------------------------------------------------------- +; --------------------------------------------------------------------------------------------------------------- +; Test Case 6 - non DMA +; INPUT +; KEY = 28d46cffa158533194214a91e712fc2b45b518076675affd910edeca5f41ac64 +; CIPHERTEXT = 4bf3b0a69aeb6657794f2901b1440ad4 +; OUTPUT +; PLAINTEXT = 00000000000000000000000000000000 +; --------------------------------------------------------------------------------------------------------------- +send '2' +pause 1 + +;key +send '28d46cffa158533194214a91e712fc2b45b518076675affd910edeca5f41ac64' +pause 1 + +;IV +send '00000000000000000000000000000000' +pause 1 + +;CIPHERTEXT +send '4bf3b0a69aeb6657794f2901b1440ad4' +pause 1 + +;DMA disabed +send '0' +pause 4 + +;Press any key +send $0 + + +; --------------------------------------------------------------------------------------------------------------- +; Test Case 7 - DMA +; INPUT +; KEY = 28d46cffa158533194214a91e712fc2b45b518076675affd910edeca5f41ac64 +; CIPHERTEXT = 4bf3b0a69aeb6657794f2901b1440ad4 +; OUTPUT +; PLAINTEXT = 00000000000000000000000000000000 +; --------------------------------------------------------------------------------------------------------------- +send '2' +pause 1 + +;key +send '28d46cffa158533194214a91e712fc2b45b518076675affd910edeca5f41ac64' +pause 1 + +;IV +send '00000000000000000000000000000000' +pause 1 + +;CIPHERTEXT +send '4bf3b0a69aeb6657794f2901b1440ad4' +pause 1 + +;DMA enabed +send '1' + +pause 5 +logclose \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/miv-rv32-aes-cryptography hw Debug.launch b/applications/user-crypto/miv-rv32-aes-cryptography/miv-rv32-aes-cryptography hw Debug.launch new file mode 100644 index 0000000..c681675 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/miv-rv32-aes-cryptography hw Debug.launch @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/miv-rv32-aes-cryptography hw attach.launch b/applications/user-crypto/miv-rv32-aes-cryptography/miv-rv32-aes-cryptography hw attach.launch new file mode 100644 index 0000000..199daf6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/miv-rv32-aes-cryptography hw attach.launch @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/application/helper.c b/applications/user-crypto/miv-rv32-aes-cryptography/src/application/helper.c new file mode 100644 index 0000000..4a78569 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/application/helper.c @@ -0,0 +1,312 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file helper.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Helper function for PolarFire User Crypto- Cryptography service example. + * + */ +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" +#include "helper.h" + +extern UART_instance_t g_uart; + +static const uint8_t g_separator[] = +"\r\n\ +------------------------------------------------------------------------------"; + + +/*============================================================================== + Function to clear local variable and array. + */ +static void clear_variable(uint8_t *p_var, uint16_t size) +{ + uint16_t inc; + + for(inc = 0; inc < size; inc++) + { + *p_var = 0x00; + p_var++; + } +} + +/*============================================================================== + Function to get the input data from user. + */ +uint16_t get_input_data +( + uint8_t* location, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +) +{ + uint16_t count = 0u; + + /* Clear the memory location. */ + clear_variable(location, size); + + /* Read data from UART terminal. */ + count = get_data_from_uart(location, size, msg, msg_size); + + return count; +} + +/*============================================================================== + Function to get the key from user. + */ +void get_key +( + uint8_t key_type, + uint8_t* location, + uint8_t size, + const uint8_t* msg, + uint8_t msg_size +) +{ + uint8_t status = 0u; + const uint8_t invalid_ms[] = "\r\n Invalid key type. "; + + if(status == VALID) + { + /* Read the 16 bytes of input data from UART terminal. */ + get_input_data(location, size, msg, msg_size); + } + else + { + UART_send(&g_uart, invalid_ms, sizeof( invalid_ms)); + } +} + +/*============================================================================== + Convert ASCII value to hex value. + */ +uint8_t convert_ascii_to_hex(uint8_t* dest, const uint8_t* src) +{ + uint8_t error_flag = 0u; + + if((*src >= '0') && (*src <= '9')) + { + *dest = (*src - '0'); + } + else if((*src >= 'a') && (*src <= 'f')) + { + *dest = (*src - 'a') + 10u; + } + else if((*src >= 'A') && (*src <= 'F')) + { + *dest = (*src - 'A') + 10u; + } + else if(*src != 0x00u) + { + UART_send(&g_uart, (const uint8_t *)"\r\n Invalid data.", sizeof("\r\n Invalid data.")); + error_flag = 1u; + } + return error_flag; +} + +/*============================================================================== + Validate the input hex value . + */ +uint8_t validate_input(uint8_t ascii_input) +{ + uint8_t valid_key = 0u; + + if(((ascii_input >= 'A') && (ascii_input <= 'F')) || \ + ((ascii_input >= 'a') && (ascii_input <= 'f')) || \ + ((ascii_input >= '0') && (ascii_input <= '9'))) + { + valid_key = 1u; + } + else + { + valid_key = 0u; + } + return valid_key; +} + +const uint8_t hex_chars[16] = { '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + +/*============================================================================== + Display content of buffer passed as parameter as hex values. + */ +void display_output +( + uint8_t* in_buffer, + uint32_t byte_length +) +{ + uint32_t inc; + uint8_t byte = 0; + + UART_send(&g_uart, (const uint8_t*)" ", sizeof(" ")); + for(inc = 0; inc < byte_length; ++inc) + { + if((inc > 1u) &&(0u == (inc % 16u))) + { + UART_send(&g_uart, (const uint8_t*)"\r\n ", sizeof("\r\n ")); + } + + byte = in_buffer[inc]; + UART_send(&g_uart, &hex_chars[((byte & 0xF0) >> 4) ], 1); + UART_send(&g_uart, &hex_chars[(byte & 0x0F)], 1); + } + +} + +/*============================================================================== + Function to read data from UART terminal and stored it. + */ +uint16_t get_data_from_uart +( + uint8_t* src_ptr, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +) +{ + uint8_t complete = 0u; + uint8_t rx_buff[1]; + uint8_t rx_size = 0u; + uint16_t count = 0u; + uint16_t ret_size = 0u; + uint8_t first = 0u; + uint16_t src_ind = 0u; + uint8_t prev = 0; + uint8_t curr = 0; + uint8_t temp = 0; + uint8_t next_byte = 0; + uint16_t read_data_size = 0; + + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, msg, msg_size); + + if(size != 1) + { + read_data_size = size * 2; + } + else + { + read_data_size = size; + } + + /* Read the key size sent by user and store it. */ + count = 0u; + while(!complete) + { + rx_size = UART_get_rx(&g_uart, rx_buff, sizeof(rx_buff)); + if(rx_size > 0u) + { + /* Is it to terminate from the loop */ + if(ENTER == rx_buff[0]) + { + complete = 1u; + } + /* Is entered key valid */ + else if(validate_input(rx_buff[0]) != 1u) + { + UART_send(&g_uart, rx_buff, sizeof(rx_buff)); + UART_send(&g_uart, (const uint8_t *)"\r\n Invalid input.", + sizeof("\r\n Invalid input.")); + UART_send(&g_uart, msg, msg_size); + complete = 0u; + count = 0u; + first = 0u; + clear_variable(src_ptr, 4); + } + else + { + if(next_byte == 0) + { + convert_ascii_to_hex(&src_ptr[src_ind], &rx_buff[0]); + prev = src_ptr[src_ind]; + next_byte = 1; + } + else + { + convert_ascii_to_hex(&curr, &rx_buff[0]); + temp = ((prev << 4) & 0xF0); + src_ptr[src_ind] = (temp | curr); + next_byte = 0; + src_ind++; + } + + + /* Switching to next line after every 8 bytes */ + if(((count % 32u) == 0x00u) && (count > 0x00u) && (complete != 0x01u)) + { + UART_send(&g_uart, (const uint8_t *)"\n\r", sizeof("\n\r")); + first = 0u; + } + + if(first == 0u) + { + UART_send(&g_uart, (const uint8_t *)" ", sizeof(" ")); + first++; + } + UART_send(&g_uart, rx_buff, sizeof(rx_buff)); + count++; + if(read_data_size == count) + { + complete = 1u; + } + } + } + } + + if((count%2) == 0) + { + ret_size = count/2; + } + else + { + if(size!=1) + { + temp = src_ptr[src_ind]; + src_ptr[src_ind] = ((temp << 4) & 0xF0); + + ret_size = (count/2)+1; + } + else + { + ret_size = 1; + } + } + + return ret_size; +} + +/*============================================================================== + Function to get the key from user. + */ +uint8_t enable_dma +( + const uint8_t* msg, + uint8_t msg_size +) +{ + volatile uint8_t invalid_ip = 1u; + uint8_t dma_enable = 0; + + const uint8_t invalid_ms[] = "\r\n Invalid input. "; + + while(invalid_ip != 0) + { + /* Read the 16 bytes of input data from UART terminal. */ + get_input_data(&dma_enable, 1, msg, msg_size); + + if(dma_enable >= 2) + { + UART_send(&g_uart, invalid_ms, sizeof( invalid_ms)); + } + else + { + invalid_ip = 0; + } + } + + return dma_enable; +} diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/application/helper.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/application/helper.h new file mode 100644 index 0000000..7f21b6e --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/application/helper.h @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file helper.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Helper function public API. + * + */ +#ifndef __HELPER_H_ +#define __HELPER_H_ 1 + +/****************************************************************************** + * Maximum buffer size. + *****************************************************************************/ +#define MAX_RX_DATA_SIZE 256 +#define MASTER_TX_BUFFER 10 + +/*============================================================================== + Macro + */ +#define VALID 0U +#define INVALID 1U +#define ENTER 13u + +/****************************************************************************** + * CoreUARTapb instance data. + *****************************************************************************/ + +uint16_t get_input_data +( + uint8_t* location, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +); +void get_key +( + uint8_t key_type, + uint8_t* location, + uint8_t size, + const uint8_t* msg, + uint8_t msg_size +); +uint16_t get_data_from_uart +( + uint8_t* src_ptr, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +); +uint8_t enable_dma +( + const uint8_t* msg, + uint8_t msg_size +); +void display_output +( + uint8_t* in_buffer, + uint32_t byte_length +); +#endif /* __HELPER_H_ */ diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/application/main.c b/applications/user-crypto/miv-rv32-aes-cryptography/src/application/main.c new file mode 100644 index 0000000..30427c6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/application/main.c @@ -0,0 +1,320 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file main.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief This Example Project demonstrates the usage of PolarFire User Crypto + * services for message encryption and decryption using AES algorithm. + * + */ +#include +#include +#include +#include "stdint.h" +#include "helper.h" +#include "hal/hal.h" +#include "fpga_design_config/fpga_design_config.h" +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" + +#include "cal/calpolicy.h" +#include "cal/pk.h" +#include "cal/pkx.h" +#include "cal/pkxlib.h" +#include "cal/calini.h" +#include "cal/utils.h" +#include "cal/hash.h" +#include "cal/drbgf5200.h" +#include "cal/drbg.h" +#include "cal/nrbg.h" +#include "cal/sym.h" +#include "cal/shaf5200.h" +#include "cal/calenum.h" + +#define KEY_SIZE 32 + +/****************************************************************************** + * CoreUARTapb instance data. + *****************************************************************************/ +UART_instance_t g_uart; + +uint32_t g_user_crypto_base_addr = 0x62000000UL; +/*============================================================================== + Messages displayed over the UART. + */ +const uint8_t g_greeting_msg[] = +"\r\n\r\n\ +******************************************************************************\r\n\ +********* PolarFire User Crypto AES Cryptography Service Example Project *********\r\n\ +******************************************************************************\r\n\ + This example project demonstrates the use of the PolarFire User Crypto \r\n\ + Cryptography Services. The following User Athena services are demonstrated:\r\n\ + 1 - AES-256 encryption.\r\n\ + 2 - AES-256 decryption.\r\n"; + +const uint8_t g_select_operation_msg[] = +"\r\n\ +------------------------------------------------------------------------------\r\n\ + Select the Cryptographic operation to perform:\r\n\ + Press key '1' to perform AES-256 encryption \r\n\ + Press key '2' to perform AES-256 decryption \r\n\ +------------------------------------------------------------------------------\r\n"; +static const uint8_t aes_encrypt_select_msg[] = +"\r\n Selected AES-256 encryption service. \r\n"; +static const uint8_t aes_decrypt_select_msg[] = +"\r\n Selected AES-256 decryption service. \r\n"; +static const uint8_t g_separator[] = +"\r\n\ +------------------------------------------------------------------------------"; +static const uint8_t read_key_msg[] = +"\r\n Enter the 256-bit/32-byte key: \r\n"; +static const uint8_t read_data_msg[] = +"\r\n Enter the 16 bytes of input data to encrypt:\r\n"; +static const uint8_t read_iv_msg[] = +"\r\n Enter the 16 bytes initialization vector(IV):\r\n"; +static const uint8_t read_dma_enable_ip[] = +"\r\n Enter 1 to perform Symmetric encryption with DMA or \r\n\ + 0 to perform Symmetric encryption without DMA: \r\n"; +static const uint8_t read_encrypted_data_msg[] = +"\r\n Enter the 16 bytes of cipher text to decrypt: \r\n"; + +/*============================================================================== + Global Variables. + */ +static uint8_t __attribute__ ((section (".crypto_data"))) g_cipher_text[KEY_SIZE/2] = {0x00}; +static uint8_t __attribute__ ((section (".crypto_data"))) g_key_256bit[KEY_SIZE] = {0x00}; +static uint8_t __attribute__ ((section (".crypto_data"))) g_iv[KEY_SIZE/2] = {0x00}; +static uint8_t __attribute__ ((section (".crypto_data"))) g_plain_text[KEY_SIZE] = {0x00}; + +/*============================================================================== + Clear AES global variable. + */ +static void clear_aes_var(void) +{ + uint16_t var = 0; + + for(var = 0; var < sizeof(g_key_256bit); var++) + { + g_key_256bit[var] = 0; + } + for(var = 0; var < sizeof(g_iv); var++) + { + g_iv[var] = 0; + } + for(var = 0; var < sizeof(g_plain_text); var++) + { + g_plain_text[var] = 0; + } + for(var = 0; var < sizeof(g_cipher_text); var++) + { + g_cipher_text[var] = 0; + } +} + +/*============================================================================== + AES-256 encryption. + */ +static void aes256_encryption(void) +{ + uint8_t status = 0u; + uint8_t use_dma = 0; + uint16_t msg_len = 0; + + /* Clear input and output variables */ + clear_aes_var(); + + /* Get key. */ + get_input_data(&g_key_256bit[0], sizeof(g_key_256bit), read_key_msg, + sizeof(read_key_msg)); + + /* Get Initialization Vector value */ + get_input_data(&g_iv[0], sizeof(g_iv), read_iv_msg, sizeof(read_iv_msg)); + + /* Read input data to be encrypt. */ + msg_len = get_input_data(&g_plain_text[0], sizeof(g_plain_text), + read_data_msg, sizeof(read_data_msg)); + + /* Use dma or not */ + use_dma = enable_dma(read_dma_enable_ip, sizeof(read_dma_enable_ip)); + + if(use_dma != 1) + { + /* Without DMA */ + status = CALSymEncrypt(SATSYMTYPE_AES256, (uint32_t *)&g_key_256bit[0], + SATSYMMODE_ECB, g_iv, SAT_TRUE, g_plain_text, + g_cipher_text , msg_len); + } + else + { + /* With DMA */ + status = CALSymEncryptDMA(SATSYMTYPE_AES256, (uint32_t *)&g_key_256bit[0], + SATSYMMODE_ECB, g_iv, SAT_TRUE, + g_plain_text, g_cipher_text , msg_len, + X52CCR_DEFAULT); + } + + /* Display the encrypted data. i.e. Cipher text*/ + if(SATR_SUCCESS == status) + { + CALPKTrfRes(SAT_TRUE); + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, (const uint8_t *)"\r\n Encrypted data:\r\n", + sizeof("\r\n Encrypted data:\r\n")); + display_output(g_cipher_text, sizeof(g_cipher_text)); + } + else + { + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, (const uint8_t *)"\r\n Error\r\n", + sizeof("\r\n Error\r\n")); + } +} + +/*============================================================================== + AES-256 decryption. + */ +static void aes256_decryption(void) +{ + uint8_t status = 0u; + uint8_t use_dma = 0; + uint16_t cipher_len = 0; + + + /* Clear input and output variables. */ + clear_aes_var(); + + /* Get Key from the user to perform Decryption. Note this key should be + * same as that used for message encryption. */ + get_input_data(&g_key_256bit[0], sizeof(g_key_256bit), read_key_msg, + sizeof(read_key_msg)); + + /* Get Initialization Vector value */ + get_input_data(&g_iv[0], sizeof(g_iv), read_iv_msg, sizeof(read_iv_msg)); + + /* Read encrypted data i.e 16 bytes of cipher text to be decrypt. */ + cipher_len = get_input_data(&g_cipher_text[0], sizeof(g_cipher_text), + read_encrypted_data_msg, sizeof(read_encrypted_data_msg)); + + /* Use dma or not */ + use_dma = enable_dma(read_dma_enable_ip, sizeof(read_dma_enable_ip)); + + if(use_dma != 1) + { + status = CALSymDecrypt(SATSYMTYPE_AES256, (uint32_t*)&g_key_256bit[0], + SATSYMMODE_ECB, g_iv, SAT_TRUE, g_cipher_text, + g_plain_text, cipher_len); + } + else + { + status = CALSymDecryptDMA(SATSYMTYPE_AES256, (uint32_t*)&g_key_256bit[0], + SATSYMMODE_ECB, g_iv, SAT_TRUE, g_cipher_text, + g_plain_text, cipher_len, + X52CCR_DEFAULT); + } + + /* Display the Decrypted data i.e. Plain text. */ + if(SATR_SUCCESS == status) + { + CALPKTrfRes(SAT_TRUE); + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, (const uint8_t *)"\r\n Decrypted data:\r\n", + sizeof("\r\n Decrypted data:\r\n")); + display_output(g_plain_text, sizeof(g_plain_text)); + } + else + { + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, (const uint8_t *)"\r\n Error\r\n", + sizeof("\r\n Error\r\n")); + } +} + +/*============================================================================== + Display greeting message when application is started. + */ +static void display_greeting(void) +{ + UART_send(&g_uart, g_greeting_msg,sizeof(g_greeting_msg)); +} + +/*============================================================================== + Display the choice of cryptographic operation to perform. + */ +static void display_operation_choices(void) +{ + UART_send(&g_uart, g_select_operation_msg, sizeof(g_select_operation_msg)); +} + +/*============================================================================== + Display the Option to continue. + */ +static void display_option(void) +{ + uint8_t rx_size; + uint8_t rx_buff[1]; + + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, (const uint8_t*)"\r\n Press any key to continue.\r\n", + sizeof("\r\n Press any key to continue.\r\n")); + do + { + rx_size = UART_get_rx(&g_uart, rx_buff, sizeof(rx_buff)); + } while(0u == rx_size); +} + +/****************************************************************************** + * main function. + *****************************************************************************/ +int main( void ) +{ + uint8_t rx_buff[1]; + size_t rx_size = 0; + + + /* Initialize CoreUARTapb with its base address, baud value, and line + configuration. */ + UART_init(&g_uart, COREUARTAPB0_BASE_ADDR, BAUD_VALUE_115200, + (DATA_8_BITS | NO_PARITY)); + + /* Initializes the Athena Processor. */ + CALIni(); + + /* Display greeting message. */ + display_greeting(); + + /* Select cryptographic operation */ + display_operation_choices(); + + for(;;) + { + /* Read inputs from UART terminal. */ + rx_size = UART_get_rx(&g_uart, rx_buff, sizeof(rx_buff)); + if(rx_size > 0) + { + switch(rx_buff[0]) + { + case '1': + /* Perform encryption using AES-256 */ + UART_send(&g_uart, aes_encrypt_select_msg, + sizeof(aes_encrypt_select_msg)); + aes256_encryption(); + display_option(); + display_operation_choices(); + break; + + case '2': + /* Perform decryption using AES-256 */ + UART_send(&g_uart, aes_decrypt_select_msg, + sizeof(aes_decrypt_select_msg)); + aes256_decryption(); + display_option(); + display_operation_choices(); + break; + + default: + break; + } + } + } +} \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h new file mode 100644 index 0000000..3fd1438 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h @@ -0,0 +1,156 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file fpga_design_config.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Sample design configuration settings. + * + */ + /*========================================================================*//** + @mainpage + Example file detailing how the fpga_design_config.h should be constructed + for the SoftConsole project targeted for Mi-V processors. + + @section intro_sec Introduction + The SoftConsole project targeted for Mi-V processors now have an improved + folder structure. Detailed description of the folder structure is available + at https://github.com/Mi-V-Soft-RISC-V/miv-rv32-documentation. + + The fpga_design_config.h must be stored as shown below + /boards//fpga_design_config.h + + Currently this file must be hand crafted when using the Mi-V Soft Processor. + In future, all the design and soft IP configurations will be automatically + generated from the Libero design description data. + + You can use this sample file as an example. + Rename this file from sample_fpga_design_config.h to fpga_design_config.h + and then customize it per your hardware design. + + @section Project configuration Instructions + 1. Change SYS_CLK_FREQ define to frequency of Mi-V Soft processor clock + 2 Add all the soft IP core BASE addresses + 3. Add the peripheral Core Interrupts to Mi-V Soft processor IRQ number + mappings + 4. Define MSCC_STDIO_UART_BASE_ADDR if you want a CoreUARTapb mapped to + STDIO + + **NOTE** + In the legacy folder structures, the file hw_config.h as was used at the + root of the project folder. This file is now depricated. + +*//*=========================================================================*/ + +#ifndef FPGA_DESIGN_CONFIG_H_ +#define FPGA_DESIGN_CONFIG_H_ + +/***************************************************************************//** + * Soft-processor clock definition + * This is the only clock brought over from the Mi-V Libero design. + */ +#ifndef SYS_CLK_FREQ +#define SYS_CLK_FREQ 83000000UL +#endif + +/***************************************************************************//** + * Peripheral base addresses. + * Format of define is: + * __BASE_ADDR + * The field is optional if there is only one instance of the core + * in the design + * MIV_ESS is an extended peripheral subsystem IP core with peripherals + * connections as defined below. + * The system can be further extended by attaching APB peripherals to the + * empty APB slots. + */ +#define COREUARTAPB0_BASE_ADDR 0x70000000UL +#define COREGPIO_OUT_BASE_ADDR 0x70001000UL +#define CORESPI_BASE_ADDR 0x70002000UL +#define CORESYS_SERV_BASE_ADDR 0x70003000UL + +/***************************************************************************//** + * Peripheral Interrupts are mapped to the corresponding Mi-V Soft processor + * interrupt in the Libero design. + * + * On the legacy RV32 cores, there can be up to 31 external interrupts (IRQ[30:0] + * pins). The legacy RV32 Soft processor external interrupts are defined in the + miv_rv32_plic.h + * + * These are of the form + * typedef enum +{ + NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + . + . + . + External_31_IRQn = 31 +} IRQn_Type; + + On the legacy RV32 processors, the PLIC identifies the interrupt and passes it + on to the processor core. The interrupt 0 is not used. The pin IRQ[0] should + map to External_1_IRQn likewise IRQ[30] should map to External_31_IRQn + +e.g + +#define TIMER0_IRQn External_30_IRQn +#define TIMER1_IRQn External_31_IRQn + + The MIV_RV32 soft processor has up to six optional system interrupts, MSYS_EI[n] + in addition to one EXT_IRQ. + The MIV_RV32 does not have an inbuilt PLIC and all the interrupts are directly + delivered to the processor core, hence unlike legacy RV32 cores, no interrupt + number mapping is necessary on MIV_RV32 core. + */ + +/**************************************************************************** + * Baud value to achieve a 115200 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ +#define BAUD_VALUE_115200 ((SYS_CLK_FREQ / (16 * 115200)) - 1) + +/****************************************************************************** + * Baud value to achieve a 57600 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + #define BAUD_VALUE_57600 ((SYS_CLK_FREQ / (16 * 57600)) - 1) + +/***************************************************************************//** + * Define MSCC_STDIO_THRU_CORE_UART_APB in the project settings if you want the + * standard IOs to be redirected to a terminal via UART. + */ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +/* + * A base address mapping for the STDIO printf/scanf mapping to CortUARTapb + * must be provided if it is being used + * + * e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR + */ +#define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB0_BASE_ADDR + +#ifndef MSCC_STDIO_UART_BASE_ADDR +#error MSCC_STDIO_UART_BASE_ADDR not defined- e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR +#endif + +#ifndef MSCC_STDIO_BAUD_VALUE +/* + * The MSCC_STDIO_BAUD_VALUE define should be set in your project's settings to + * specify the baud value used by the standard output CoreUARTapb instance for + * generating the UART's baud rate if you want a different baud rate from the + * default of 115200 baud + */ +#define MSCC_STDIO_BAUD_VALUE 115200 +#endif /*MSCC_STDIO_BAUD_VALUE*/ + +#endif /* end of MSCC_STDIO_THRU_CORE_UART_APB */ +/******************************************************************************* + * End of user edit section + */ +#endif /* FPGA_DESIGN_CONFIG_H_ */ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld b/applications/user-crypto/miv-rv32-aes-cryptography/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld new file mode 100644 index 0000000..8541db6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld @@ -0,0 +1,160 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-ram.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * debug image executing in SRAM. + * + * This linker script assumes that a RAM is connected at on Mi-V soft processor + * memory space pointed by the reset vector address. + * + * NOTE : Modify the memory section address and the size according to your + * Libero design. + * For example: + * 1) If you want to download and step debug at a different RAM memory address in + * your design (For example TCM base address) than the one provided in this file. + * 2) The MIV_RV32, when used with MIV_ESS IP, provides ways to copy the executable + * HEX file from external Non-Volatile memory into the TCM at reset. In this + * case your executable must be linked to the TCM address. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +MEMORY +{ + ram (rwx) : ORIGIN = 0x80000000, LENGTH = 64k + crypto_ram (rw) : ORIGIN = 0x61000000, LENGTH = 32k +} + +RAM_START_ADDRESS = 0x80000000; /* Must be the same value MEMORY region ram ORIGIN above. */ +RAM_SIZE = 64k; /* Must be the same value MEMORY region ram LENGTH above. */ +STACK_SIZE = 2k; /* needs to be calculated for your application */ +HEAP_SIZE = 0k; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > ram + + .text : ALIGN(0x10) + { + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } > ram + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } > ram + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } > ram + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram + + . = 0x61000000; + .crypto_data : ALIGN(0x10) + { + . = ALIGN(0x10); + *(.crypto_data) + } > crypto_ram +} + diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/aesf5200.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/aesf5200.h new file mode 100644 index 0000000..889dddd --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/aesf5200.h @@ -0,0 +1,104 @@ +/* ------------------------------------------------------------------- + $Rev: 1293 $ $Date: 2017-07-27 14:09:14 -0400 (Thu, 27 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for F5200 AES function hardware implementation for + CAL. + ------------------------------------------------------------------- */ + +#ifndef AESF5200_H +#define AESF5200_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef AESF5200_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATR aesf5200aes (SATSYMTYPE eSymType, SATSYMMODE eMode, + void *pIV, SATBOOL bLoadIV, const void *pSrc, void *pDest, SATUINT32_t uiLen, + SATBOOL bDecrypt); + +extern SATR aesf5200aesk (SATSYMTYPE eSymType, const SATUINT32_t *puiKey); + +extern SATR aesf5200gcm (SATSYMTYPE eSymType, SATSYMMODE eMode, void *pIV, + const void *pSrc, void *pDest, SATUINT32_t uiEncLen, + const void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, SATUINT32_t uiMACLen, + SATBOOL bDecrypt); + +extern SATR aesf5200gcmdma(SATSYMTYPE eSymType, SATSYMMODE eMode, void *pIV, + const void *pSrc, void *pDest, SATUINT32_t uiEncLen, const void *pAuth, + SATUINT32_t uiAuthLen, void *pMAC, SATUINT32_t uiMACLen, SATBOOL bDecrypt, + SATUINT32_t uiDMAChConfig); + +extern SATR aesf5200kw(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR aesf5200kwp(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR aesf5200kr(SATSYMTYPE eSymType, SATSYMMODE eMode, + const SATUINT32_t *puiKey, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKrf, SATBOOL bDecrypt); + +extern SATR aesf5200dma(SATSYMTYPE eSymType, SATSYMMODE eMode, void *pIV, + SATBOOL bLoadIV, const void *pExtSrc, void *pExtDest, SATUINT32_t uiLen, + SATUINT32_t uiDMAChConfig, SATBOOL bDecrypt); + +extern SATR aesf5200krdma(SATSYMTYPE eSymType, SATSYMMODE eMode, + const SATUINT32_t *puiKey, void *pIV, SATBOOL bLoadIV, const void *pExtSrc, + void *pExtDest, SATUINT32_t uiLen, SATUINT32_t uiKrf, + SATUINT32_t uiDMAChConfig, SATBOOL bDecrypt); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/calcontext.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/calcontext.h new file mode 100644 index 0000000..fc408c2 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/calcontext.h @@ -0,0 +1,88 @@ +/* ------------------------------------------------------------------- + $Rev: 1298 $ $Date: 2017-08-04 13:04:19 -0400 (Fri, 04 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL context management functions. + ------------------------------------------------------------------- */ + +#ifndef CALCONTEXT_H +#define CALCONTEXT_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* Function resource handle. */ +/* ----- ------ ------- ---- */ +#define SATRES_DEFAULT (SATRESHANDLE)0U +#define SATRES_CALSW (SATRESHANDLE)1U + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ +typedef struct{ + SATUINT32_t uiBase; + SATRESCONTEXTPTR pContext; + }SATRESHANDLESTRUCT; + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALCONTEXT_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATRESCONTEXTPTR CALContextCurrent(const SATRESHANDLE hResource); + +extern SATR CALContextLoad(const SATRESHANDLE hResource, + const SATRESCONTEXTPTR pContext); + +extern SATR CALContextRemove(const SATRESHANDLE hResource); + +extern SATR CALContextUnload(const SATRESHANDLE hResource); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern void init_reshandles(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/calenum.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/calenum.h new file mode 100644 index 0000000..6281f3f --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/calenum.h @@ -0,0 +1,289 @@ +/* ------------------------------------------------------------------- + $Rev: 1566 $ $Date: 2018-09-14 11:04:30 -0400 (Fri, 14 Sep 2018) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + This file defines common types in the CAL. + + Most CAL types and constants are defined with the "SAT" prefix to + reduce the chance of name space collisions with other users. + ------------------------------------------------------------------- */ + +#ifndef CALENUM_H +#define CALENUM_H + +/* -------- */ +/* Includes */ +/* -------- */ + +/* CAL base types. */ +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ +/* NULL definitions. */ +#define SAT_NULL 0 + +/* Boolean definitions. */ +#define SAT_TRUE ((SATBOOL)1) +#define SAT_FALSE ((SATBOOL)0) + + +/* Major cipher key/SSP type. */ +/* ----- ------ ------- ----- */ +#define SATSSPTYPE_NULL (SATSSPTYPE)0 +#define SATSSPTYPE_SYMKEY (SATSSPTYPE)1 +#define SATSSPTYPE_ASYMKEY (SATSSPTYPE)2 +/* Special marker for end of list. */ +#define SATSSPTYPE_LAST (SATSSPTYPE)3 + + +/* Asymmetric Ciphers */ +/* ---------- ------- */ +#define SATASYMTYPE_NULL (SATASYMTYPE)0U +#define SATASYMTYPE_DSA_SIGN (SATASYMTYPE)1U +#define SATASYMTYPE_DSA_VERIFY (SATASYMTYPE)2U +#define SATASYMTYPE_RSA_ENCRYPT (SATASYMTYPE)3U +#define SATASYMTYPE_RSA_DECRYPT (SATASYMTYPE)4U +#define SATASYMTYPE_DH (SATASYMTYPE)5U +#define SATASYMTYPE_ECDSA_SIGN (SATASYMTYPE)6U +#define SATASYMTYPE_ECDSA_VERIFY (SATASYMTYPE)7U +#define SATASYMTYPE_ECDH (SATASYMTYPE)8U +#define SATASYMTYPE_RSA_SIGN (SATASYMTYPE)9U +#define SATASYMTYPE_RSA_VERIFY (SATASYMTYPE)10U +/* Special marker for end of list. */ +#define SATASYMTYPE_LAST (SATASYMTYPE)11U + + +/* Encoding Types */ +/* -------- ----- */ +#define SATRSAENCTYPE_NULL (SATRSAENCTYPE)0U +#define SATRSAENCTYPE_PKCS (SATRSAENCTYPE)1U +#define SATRSAENCTYPE_ANSI (SATRSAENCTYPE)2U +#define SATRSAENCTYPE_PSS (SATRSAENCTYPE)3U +/* Special marker for end of list. */ +#define SATRSAENCTYPE_LAST (SATRSAENCTYPE)4U + + +/* Symmetric Ciphers */ +/* --------- ------- */ + +/* Cipher Type. */ +#define SATSYMTYPE_NULL (SATSYMTYPE)0U +#define SATSYMTYPE_AES128 (SATSYMTYPE)1U +#define SATSYMTYPE_AES192 (SATSYMTYPE)2U +#define SATSYMTYPE_AES256 (SATSYMTYPE)3U +#define SATSYMTYPE_AESKS128 (SATSYMTYPE)4U +#define SATSYMTYPE_AESKS192 (SATSYMTYPE)5U +#define SATSYMTYPE_AESKS256 (SATSYMTYPE)6U +/* Special marker for end of list. */ +#define SATSYMTYPE_LAST (SATSYMTYPE)7U + +/* Names for common cipher key lengths, in bits. */ +#define SATSYMKEYSIZE_AES128 (SATSYMKEYSIZE)128U +#define SATSYMKEYSIZE_AES192 (SATSYMKEYSIZE)192U +#define SATSYMKEYSIZE_AES256 (SATSYMKEYSIZE)256U +#define SATSYMKEYSIZE_AESKS128 (SATSYMKEYSIZE)256U +#define SATSYMKEYSIZE_AESKS192 (SATSYMKEYSIZE)384U +#define SATSYMKEYSIZE_AESKS256 (SATSYMKEYSIZE)512U + +/* Cipher Mode. */ +#define SATSYMMODE_NULL (SATSYMMODE)0U +#define SATSYMMODE_ECB (SATSYMMODE)1U +#define SATSYMMODE_CBC (SATSYMMODE)2U +#define SATSYMMODE_CFB (SATSYMMODE)3U +#define SATSYMMODE_OFB (SATSYMMODE)4U +#define SATSYMMODE_CTR (SATSYMMODE)5U +#define SATSYMMODE_GCM (SATSYMMODE)6U +#define SATSYMMODE_GHASH (SATSYMMODE)8U +/* Special marker for end of list. */ +#define SATSYMMODE_LAST (SATSYMMODE)9U + + +/* Hashes */ +/* ------ */ +#define SATHASHTYPE_NULL (SATHASHTYPE)0U +#define SATHASHTYPE_SHA1 (SATHASHTYPE)1U +#define SATHASHTYPE_SHA224 (SATHASHTYPE)2U +#define SATHASHTYPE_SHA256 (SATHASHTYPE)3U +#define SATHASHTYPE_SHA384 (SATHASHTYPE)4U +#define SATHASHTYPE_SHA512 (SATHASHTYPE)5U +#define SATHASHTYPE_SHA512_224 (SATHASHTYPE)6U +#define SATHASHTYPE_SHA512_256 (SATHASHTYPE)7U +/* Special marker for end of list. */ +#define SATHASHTYPE_LAST (SATHASHTYPE)8U + +/* Hash sizes defined in bits */ +#define SATHASHSIZE_NULL (SATHASHSIZE)0U +#define SATHASHSIZE_SHA1 (SATHASHSIZE)160U +#define SATHASHSIZE_SHA224 (SATHASHSIZE)224U +#define SATHASHSIZE_SHA256 (SATHASHSIZE)256U +#define SATHASHSIZE_SHA384 (SATHASHSIZE)384U +#define SATHASHSIZE_SHA512 (SATHASHSIZE)512U +#define SATHASHSIZE_SHA512_224 (SATHASHSIZE)224U +#define SATHASHSIZE_SHA512_256 (SATHASHSIZE)256U + +#define SATHASHSIZE_HASH160 (SATHASHSIZE)160U +#define SATHASHSIZE_HASH192 (SATHASHSIZE)192U +#define SATHASHSIZE_HASH224 (SATHASHSIZE)224U +#define SATHASHSIZE_HASH256 (SATHASHSIZE)256U +#define SATHASHSIZE_HASH320 (SATHASHSIZE)320U +#define SATHASHSIZE_HASH384 (SATHASHSIZE)384U +#define SATHASHSIZE_HASH512 (SATHASHSIZE)512U +#define SATHASHSIZE_HASH521 (SATHASHSIZE)521U + + +/* Message Authentication Codes */ +/* ------- -------------- ----- */ + +/* Message Authentication Types */ +#define SATMACTYPE_NULL (SATMACTYPE)0U +#define SATMACTYPE_SHA1 (SATMACTYPE)1U +#define SATMACTYPE_SHA224 (SATMACTYPE)2U +#define SATMACTYPE_SHA256 (SATMACTYPE)3U +#define SATMACTYPE_SHA384 (SATMACTYPE)4U +#define SATMACTYPE_SHA512 (SATMACTYPE)5U +#define SATMACTYPE_SHA512_224 (SATMACTYPE)6U +#define SATMACTYPE_SHA512_256 (SATMACTYPE)7U +#define SATMACTYPE_AESCMAC128 (SATMACTYPE)10U +#define SATMACTYPE_AESCMAC192 (SATMACTYPE)11U +#define SATMACTYPE_AESCMAC256 (SATMACTYPE)12U +#define SATMACTYPE_AESGMAC (SATMACTYPE)13U +/* Special marker for end of list. */ +#define SATMACTYPE_LAST (SATMACTYPE)14U + + +/* Message Authentication Flags */ +#define SATMACFLAG_OP (SATMACTYPEFLAG)0U +#define SATMACFLAG_FIRSTPASS (SATMACTYPEFLAG)1U +#define SATMACFLAG_FINALPASS (SATMACTYPEFLAG)2U +#define SATMACFLAG_IKEYFINAL (SATMACTYPEFLAG)4U +#define SATMACFLAG_OKEYFINAL (SATMACTYPEFLAG)8U + + +/* Non-deterministic Random Bit Generator */ +/* ------- -------------- ----- */ + +/* NRBG register write enables */ +#define SATNRBGCONFIG_NONE 0x0 +#define SATNRBGCONFIG_RNG_CSR 0x1 +#define SATNRBGCONFIG_RNG_CNTLIM 0x2 +#define SATNRBGCONFIG_RNG_VOTIMER 0X4 +#define SATNRBGCONFIG_RNG_FMSK 0X8 + +/* RNG_CSR access defines */ +#define SATNRBGCONFIG_CSR_RODIS 0x0 +#define SATNRBGCONFIG_CSR_ROEN 0x1 +#define SATNRBGCONFIG_CSR_ROFATAL 0x2 +#define SATNRBGCONFIG_CSR_ROFATALCLR 0X4 + +/* RNG_FMSK mask values */ +#define SATNRBGCONFIG_FMSK_ROOSCF 0xFF +#define SATNRBGCONFIG_FMSK_MONOBITF 0x10000 +#define SATNRBGCONFIG_FMSK_POKERF 0x20000 +#define SATNRBGCONFIG_FMSK_RUNSF 0x40000 +#define SATNRBGCONFIG_FMSK_LRUNSF 0x80000 +#define SATNRBGCONFIG_FMSK_F1401 0xF0000 +#define SATNRBGCONFIG_FMSK_REPCNTF 0x100000 +#define SATNRBGCONFIG_FMSK_APROPF 0x200000 +#define SATNRBGCONFIG_FMSK_SP800 0x300000 + +/* RNG_ROHEALTH mask values */ +#define SATNRBGCONFIG_HLTH_ROOSCF 0x3FC0 +#define SATNRBGCONFIG_HLTH_APROPF 0x20 +#define SATNRBGCONFIG_HLTH_REPCNTF 0x10 +#define SATNRBGCONFIG_HLTH_LRUNSF 0x8 +#define SATNRBGCONFIG_HLTH_RUNSF 0x4 +#define SATNRBGCONFIG_HLTH_POKERF 0x2 +#define SATNRBGCONFIG_HLTH_MONOBITF 0x1 + + +/* Return Codes */ +/* ------ ----- */ +#define SATR_SUCCESS (SATR)0U +#define SATR_FAIL (SATR)1U +#define SATR_BADPARAM (SATR)2U +#define SATR_VERIFYFAIL (SATR)3U +#define SATR_KEYSFULL (SATR)4U +#define SATR_BUSY (SATR)5U +#define SATR_ROFATAL (SATR)6U +#define SATR_PARITYFLUSH (SATR)7U +#define SATR_SIGNFAIL (SATR)8U +#define SATR_VALIDATEFAIL (SATR)9U +#define SATR_PAF (SATR)10U +#define SATR_VALPARMX (SATR)11U +#define SATR_VALPARMY (SATR)12U +#define SATR_VALPARMB (SATR)13U +#define SATR_DCMPPARMX (SATR)14U +#define SATR_DCMPPARMB (SATR)15U +#define SATR_DCMPPARMP (SATR)16U +#define SATR_SIGNPARMD (SATR)17U +#define SATR_SIGNPARMK (SATR)18U +#define SATR_VERPARMR (SATR)19U +#define SATR_VERPARMS (SATR)20U +#define SATR_MSBICV1 (SATR)21U +#define SATR_MSBICV2 (SATR)22U +#define SATR_PADLEN (SATR)23U +#define SATR_LSB0PAD (SATR)24U +#define SATR_BADLEN (SATR)25U +#define SATR_BADHASHTYPE (SATR)26U +#define SATR_BADTYPE (SATR)27U +#define SATR_BADMODE (SATR)28U +#define SATR_BADCONTEXT (SATR)29U +#define SATR_BADHASHLEN (SATR)30U +#define SATR_BADMACTYPE (SATR)31U +#define SATR_BADMACLEN (SATR)32U +#define SATR_BADHANDLE (SATR)33U +#define SATR_FNP (SATR)34U +#define SATR_HFAULT (SATR)35U +#define SATR_NOPEND (SATR)36U +#define SATR_BADRSAENC (SATR)37U +#define SATR_BADMOD (SATR)38U +/* Special marker for end of list. */ +#define SATR_LAST (SATR)39U + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* See caltypes.h for type definitions associated with defines above. */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALENUM_C +#ifdef __cplusplus +extern "C" { +#endif + +/* NOTE: this header file does not have an associated C file. */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/calini.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/calini.h new file mode 100644 index 0000000..62461d1 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/calini.h @@ -0,0 +1,69 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL initialization + ------------------------------------------------------------------- */ + +#ifndef CALINI_H +#define CALINI_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALINI_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALIni(void); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/calpolicy.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/calpolicy.h new file mode 100644 index 0000000..2a43445 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/calpolicy.h @@ -0,0 +1,183 @@ +/* ------------------------------------------------------------------- + $Rev: 1293 $ $Date: 2017-07-27 14:09:14 -0400 (Thu, 27 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file defining CAL policy for endianess, HW/SW, etc. + ------------------------------------------------------------------- */ + +#ifndef CALPOLICY_H +#define CALPOLICY_H + +/* -------- */ +/* Includes */ +/* -------- */ + +/* The following include provides a custom configuration header file when + CALCONFIGH is defined +*/ +#ifdef CALCONFIGH +# include CALCONFIGH +#else +# error "CALCONFIGH not defined. CAL requires a custom configuration header \ +defined by CALCONFIGH. Review CAL README." +#endif + +/* ------- */ +/* Defines */ +/* ------- */ + +/* Context switching */ +#ifndef MAXRESHANDLES +# define MAXRESHANDLES 1 +#endif + +/* Little Endian (default) / Big Endian */ +#ifndef SAT_LITTLE_ENDIAN +# define SAT_LITTLE_ENDIAN 1 +#endif + +/* PK SW Point Validate Checking */ +#ifndef PKSWCHKVALPT +# define PKSWCHKVALPT 1 +#endif + +/* DMA */ +#ifndef USE_X52EXEC_DMA +# define USE_X52EXEC_DMA 0 +#endif + +/* SHA */ +#define MAXHASHLEN 512 +#define MAXHMACKEYLEN 512 + +/* RNG */ +#define NRBGSIMNUMRO 16 +#define ENTROPYMEMBLOCKS 7 +#define BUFMEMBLOCKS 3 +#ifndef RNXBLKLEN +#define RNXBLKLEN 32 +#endif +#ifndef RNXBLKOUTLEN +#define RNXBLKOUTLEN 4 +#endif + +#ifndef USENRBGSW +# define USENRBGSW 0 +#endif + +/* PK */ +#ifndef PKX0_BASE +# define PKX0_BASE 0xE0000000u +#endif + +#if USEPKSW +# ifndef MAXMODSIZE +# define MAXMODSIZE 8192 +# endif +# ifndef PKSWBUFSIZE +# define PKSWBUFSIZE 15*(MAXMODSIZE/32) +# endif +#else +# define USEPKSW 0 +#endif + +/* Set default values for X52 configuration defines. */ +#ifndef X52_CFG_OPT +# define X52_CFG_OPT 0 +#endif +#ifndef X52_LIR_LEN +# define X52_LIR_LEN 0x800 +#endif +#ifndef X52_BER_LEN +# define X52_BER_LEN 0x400 +#endif +#ifndef X52_MMR_LEN +# define X52_MMR_LEN 0x400 +#endif +#ifndef X52_TSR_LEN +# define X52_TSR_LEN 0x400 +#endif +#ifndef X52_FPR_LEN +# define X52_FPR_LEN 0x400 +#endif +#if X52_LIR_ROM_LEN>0 && X52_LIR_LEN>X52_LIR_ROM_LEN +# define PKX_OFFSET 2048 +#else +# define PKX_OFFSET 0 +#endif + +/* X52 Configuration Options */ +#define AESPKX (X52_CFG_OPT&0x00000001u) +#define AESPKXGCM (X52_CFG_OPT&0x00000008u) +#define AESPKXFASTKEY (X52_CFG_OPT&0x01000000u) +#define SHAPKXOPT1 (X52_CFG_OPT&0x00000020u) +#define SHAPKXOPT224 (X52_CFG_OPT&0x00000040u) +#define SHAPKXOPT256 (X52_CFG_OPT&0x00000080u) +#define SHAPKXOPT384 (X52_CFG_OPT&0x00000100u) +#define SHAPKXOPT512 (X52_CFG_OPT&0x00000200u) +#define SHAPKXOPT5124 (X52_CFG_OPT&0x00400000u) +#define SHAPKXOPT5126 (X52_CFG_OPT&0x00800000u) + +/* Define the maximum number of return values that may be handled using + CAL*TrfRes() function(s). +*/ +#define CAL_MAXTRFS 4 + +/* Volatile pointer operations */ +/* These access macros are designed so that they may be redefined by a + user compiling CAL. +*/ +#ifndef CALREAD32 +# define CALREAD32(ptr) ( *(ptr) ) +#endif +#ifndef CALWRITE32 +# define CALWRITE32(ptr, val) ( *(ptr)=val ) +#endif +#ifndef CALPOLL32 +# define CALPOLL32(ptr, val, mask) while ((*(ptr) & (mask)) != (val)); +#endif + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +#ifndef CALPOLICY_C +#ifdef __cplusplus +extern "C" { +#endif + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +/* NOTE: this header file does not have an associated C file. */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/caltypes.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/caltypes.h new file mode 100644 index 0000000..3b2fe0b --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/caltypes.h @@ -0,0 +1,328 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + This file defines common types in the CAL. + + Since support for the C99 stdint.h integer types is not universal, + these are defined herein and may require customization from compiler + to compiler, or use of the stdint.h header, if present (recommended). + + C99 supports 64-bit types; however, support in older compilers is + spotty. For those that do not support it, the macro NO64BITINT may be + defined by the user to prevent defintion of 64-bit types. This is + generally safe with CAL-PK and CAL-SYM; however, this is incompatible + with CAL-SW. + + Most CAL types and constants are defined with the "SAT" prefix to + reduce the chance of name space collisions with other users. + ------------------------------------------------------------------- */ + +#ifndef CALTYPES_H +#define CALTYPES_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* Base Types */ +/* ---- ----- */ + +/* The user may compile using stdint.h instead of the definitions below + by defining the macro INC_STDINT_H. */ +#ifdef INC_STDINT_H +#include +#endif + +/* Integer type abstraction layer. */ +#ifndef INC_STDINT_H + +typedef unsigned char uint8_t; +typedef signed char int8_t; + +typedef unsigned short uint16_t; +typedef signed short int16_t; + +typedef unsigned int uint32_t; +typedef int int32_t; + +/* stdint.h is a C99 feature, and C99 supports 64-bit ints, so this is + immune to the macro used to disable 64-bit int support. +*/ +typedef unsigned long long uint64_t; +typedef long long int64_t; + +typedef long uintptr_t; + +#endif + +/* Boolean type. */ +typedef uint8_t SATBOOL; + +/* Unsigned integer type */ +typedef uint8_t SATUINT8_t; +typedef uint16_t SATUINT16_t; +typedef uint32_t SATUINT32_t; +#ifdef INC_STDINT_H +typedef uint64_t SATUINT64_t; +#else +#ifndef NO64BITINT +typedef uint64_t SATUINT64_t; +#endif +#endif + +/* Integer type */ +typedef int8_t SATINT8_t; +typedef int16_t SATINT16_t; +typedef int32_t SATINT32_t; +#ifdef INC_STDINT_H +typedef int64_t SATINT64_t; +#else +#ifndef NO64BITINT +typedef int64_t SATINT64_t; +#endif +#endif + +typedef uintptr_t SATUINTPTR_t; + +/* Major cipher key/SSP type. */ +/* ----- ------ ------- ----- */ +typedef uint8_t SATSSPTYPE; +typedef SATSSPTYPE * SATSSPTYPEPTR; + + +/* Asymmetric Ciphers */ +/* ---------- ------- */ + +/* Cipher type. */ +typedef uint8_t SATASYMTYPE; +typedef SATASYMTYPE * SATASYMTYPEPTR; + +/* Cipher size type. */ +typedef uint16_t SATASYMSIZE; +typedef SATASYMSIZE * SATASYMSIZEPTR; + +/* Cipher encoding */ +typedef uint8_t SATRSAENCTYPE; +typedef SATRSAENCTYPE * SATRSAENCTYPEPTR; + +/* DSA public/private key. */ +typedef struct { + uint16_t ui16PLen; /* Length of modulus p. */ + uint16_t ui16QLen; /* Length of prime divisor q. */ + uint32_t *pui32P; /* Prime modulus p. */ + uint32_t *pui32Q; /* Prime divisor q. */ + uint32_t *pui32G; /* Generator g, length==p. */ + uint32_t *pui32X; /* Private key x, length==p. */ + uint32_t *pui32Y; /* Private key y, length==q. */ +} SATASYMDSADOMAIN; +typedef SATASYMDSADOMAIN * SATASYMDSADOMAINPTR; + + +/* Symmetric Ciphers */ +/* --------- ------- */ + +/* Cipher type. */ +typedef uint8_t SATSYMTYPE; +typedef SATSYMTYPE * SATSYMTYPEPTR; + +/* Cipher key size type (in bits). */ +typedef uint16_t SATSYMKEYSIZE; +typedef SATSYMKEYSIZE * SATSYMKEYSIZEPTR; + +/* Cipher mode type. */ +typedef uint8_t SATSYMMODE; +typedef SATSYMMODE * SATSYMMODEPTR; + +/* Cipher key object. */ +/* Other fields are only valid when sstCipher!=SATSYMTYPE_NULL. */ +typedef struct { + SATSYMTYPE sstCipher; + SATSYMKEYSIZE ssksKeyLen; + uint32_t *pui32Key; +} SATSYMKEY; +typedef SATSYMKEY * SATSYMKEYPTR; + + +/* Hashes */ +/* ------ */ + +/* Hash type. */ +typedef uint8_t SATHASHTYPE; +typedef SATHASHTYPE * SATHASHTYPEPTR; + +/* Hash size type (in bits). */ +typedef uint16_t SATHASHSIZE; +typedef SATHASHSIZE * SATHASHSIZEPTR; + + +/* Context switching. */ +/* ----- ------ ------- ----- */ + +typedef uint32_t SATRESHANDLE; +typedef SATRESHANDLE * SATRESHANDLEPTR; + +typedef struct { + SATHASHTYPE sshashtype; + uint32_t uiRunLen; + uint32_t uiHash[MAXHASHLEN/32]; /* holds intermed hash */ +} SHACTX; + +typedef struct { + SATHASHTYPE sshashtype; + uint32_t uiRunLen; + uint32_t uiKeyLen; + uint32_t uiHash[MAXHASHLEN/32]; /* holds intermed hash */ + uint32_t uiKey[MAXHMACKEYLEN/32]; /* holds intermed key */ +} SHAHMACCTX; + +typedef struct { + uint8_t uiContextType; + union{ + SHACTX ctxSHA; + SHAHMACCTX ctxMAC; + }CTXUNION; +} SATRESCONTEXT; +typedef SATRESCONTEXT * SATRESCONTEXTPTR; + + +/* Message Authentication Codes */ +/* ------- -------------- ----- */ + +/* MAC type. */ +typedef uint8_t SATMACTYPE; +typedef SATMACTYPE * SATMACTYPEPTR; +typedef uint8_t SATMACTYPEFLAG; + + +/* Random Number Generator */ +/* ------ ------ --------- */ +typedef union { + uint32_t u32[4]; + uint8_t u8[16]; +} uint128_t; + +typedef struct { + uint128_t ui128V; + uint128_t ui128K[2]; + uint32_t uiReseedCnt; + uint32_t uiReseedLim; + uint32_t uiEntropyFactor; + SATSYMKEYSIZE eStrength; + SATBOOL bTesting; + +} DRBGCTX; + +typedef DRBGCTX * DRBGCTXPTR; + + +/* Function Return Code */ +/* -------- ------ ---- */ +typedef uint16_t SATR ; +typedef SATR * SATRPTR ; + + +/* Transfer Results */ +/* -------- ------- */ +typedef struct { + SATUINT32_t uiLen; + volatile SATUINT32_t* vpuiSrc; + void* pDest; +} SATDATATRF; + +typedef struct { + SATUINT32_t uiResType; + SATUINT32_t uiNumDataTrf; + SATDATATRF dtrfArray[CAL_MAXTRFS]; +} SATRESULT; + + +/* EC Ultra Structs */ +/* -- ----- ------- */ +typedef uint32_t SATECTYPE; + +typedef struct { + SATUINT32_t uiLen; + SATUINT32_t* puiX; + SATUINT32_t* puiY; +} SATECPOINT; + +typedef struct { + SATUINT32_t uiLen; + SATUINT32_t* puiMod; + SATUINT32_t* puiMontPrecompute; + SATUINT32_t* puiRSqd; +} SATECMONTMOD; + +typedef struct { + SATUINT32_t uiCurveSize; + SATECTYPE eCurveType; + SATECPOINT* pBasePoint; + SATECMONTMOD* pModP; + SATECMONTMOD* pModN; + SATUINT32_t* puiA; + SATUINT32_t* puiB; +} SATECCURVE; + +typedef struct { + SATUINT32_t uiLen; + SATUINT32_t* puiSigR; + SATUINT32_t* puiSigS; + SATUINT32_t* puiSigX; + SATUINT32_t* puiSigY; +} SATECDSASIG; + +typedef struct { + SATHASHSIZE sHashLen; + SATUINT32_t* puiHash; +} SATHASH; + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALTYPES_C +#ifdef __cplusplus +extern "C" { +#endif + +/* NOTE: this header file does not have an associated C file. */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/config_user.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/config_user.h new file mode 100644 index 0000000..3728565 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/config_user.h @@ -0,0 +1,44 @@ +/* ------------------------------------------------------------------- + $Rev: 727 $ $Date: 2017-10-20 16:50:53 -0400 (Fri, 20 Oct 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + + User configuration file to include/exclude CAL components. + ------------------------------------------------------------------- */ + +#ifndef CALCONFIG_F5200_H +#define CALCONFIG_F5200_H + +#include "x52cfg_user.h" +#include + +extern uint32_t g_user_crypto_base_addr; + +#define SAT_LITTLE_ENDIAN 1 +#define PKX0_BASE (g_user_crypto_base_addr) +#define USEPKX 1 +#define USEAESPKX 1 +#define USESHAPKX 1 +#define USEDRBGPKX 1 +#define USENRBGPKX 1 +#define USECALCTX 1 + +#endif diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/drbg.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/drbg.h new file mode 100644 index 0000000..dba16f7 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/drbg.h @@ -0,0 +1,91 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for DRBG functions for CAL + ------------------------------------------------------------------- */ + +#ifndef DRBG_H +#define DRBG_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ +#define CALDRBGENTROPYFACTOR 2 + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef DRBG_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALDRBGInstantiate(const SATUINT32_t *puiNonce, + SATUINT32_t uiNonceLen, const SATUINT32_t *puiPzStr, + SATUINT32_t uiPzStrLen, SATSYMKEYSIZE eStrength, + SATUINT32_t uiEntropyFactor, SATUINT32_t uiReseedLim, SATBOOL bTesting); + +extern SATR CALDRBGReseed(const SATUINT32_t *puiAddIn, SATUINT32_t uiAddInLen); + +extern SATR CALDRBGGenerate(const SATUINT32_t *puiAddIn, SATUINT32_t uiAddInLen, + SATBOOL bPredResist, SATUINT32_t *puiOut, SATUINT32_t uiOutBlocks); + +extern SATR CALDRBGUninstantiate(void); + +extern SATR CALDRBGGetCtx(DRBGCTXPTR drbgCtxExt); + +extern SATR CALDRBGLoadCtx(DRBGCTXPTR drbgCtxExt); + +extern SATR CALDRBGGetbInst(void); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +extern SATR CALDrbgTrfRes(SATBOOL bBlock); + +extern void CALDrbgIni(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/drbgf5200.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/drbgf5200.h new file mode 100644 index 0000000..d7f6c4c --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/drbgf5200.h @@ -0,0 +1,120 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for F5200 DRBG function hardware implementations + in CAL. + ------------------------------------------------------------------- */ + +#ifndef DRBGF5200_H +#define DRBGF5200_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ +#define RNXEFACTOR (X52BER+2) +#define RNXIRLEN (X52BER+2) +#define RNXKEYORD (X52BER+3) +#define RNXRESPRED (X52BER+4) +#define RNXTESTSEL (X52BER+5) +#define RNXBADDIN (X52BER+6) +#define RNXPPSTR (X52BER+7) +#define RNXPCTX (X52BER+8) +#define RNXPRENT (X52BER+13) +#define RNXITMP3 (X52BER+20) +#define RNXPCTX2 (X52BER+22) +/* These use same locs as tb generator, but can change */ +#define RNXRDATA (X52BER_ENDIAN+0x24) +#define RNXAIDATAOFF 0x0062 +#define RNXAIDATA (X52BER_ENDIAN+RNXAIDATAOFF) +#define RNXCTXOFF 0x0094 +#define RNXCTX (X52FPR+RNXCTXOFF) +#define RNXCTXV (X52FPR_ENDIAN+RNXCTXOFF+6) +#define RNXCTXVMMR (X52MMR_ENDIAN+RNXCTXOFF+6) +#define RNXTESTENT (X52TSR_ENDIAN+8) + +#define RNXCTXWORDS 18 +#define RNXBLENLOC (RNXCTX+RNXCTXWORDS) +#define RNXBOUTLENLOC (RNXCTX+RNXCTXWORDS+1) + +#define RNXMAXTESTENT32 512 +#define CALDRBGMAXADDINLEN X52_BER_LEN-RNXAIDATAOFF-4 +#define CALDRBGMAXPSNONCELEN X52_BER_LEN-RNXAIDATAOFF-4 + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef DRBGF5200_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATR drbgf5200Ini(void); + +extern SATR drbgf5200TrfRes(SATBOOL bBlock); + +extern SATR drbgf5200instantiate(const SATUINT32_t *puiNonce, + SATUINT32_t uiNonceLen, const SATUINT32_t *puiPzStr, SATUINT32_t uiPzStrLen, + SATSYMKEYSIZE eStrength, SATUINT32_t uiEntropyFactor, + SATUINT32_t uiReseedLim, SATBOOL bTesting); + +extern SATR drbgf5200reseed(const SATUINT32_t *puiAddIn, + SATUINT32_t uiAddInLen); + +extern SATR drbgf5200generate(const SATUINT32_t *puiAddIn, + SATUINT32_t uiAddInLen, SATBOOL bPredResist, SATUINT32_t uiReqLen, + SATUINT32_t *puiOut); + +extern SATR drbgf5200uninstantiate(void); + +extern SATR drbgf5200getctx(DRBGCTXPTR drbgCtxExt); + +extern SATR drbgf5200loadctx(DRBGCTXPTR drbgCtxExt); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/hash.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/hash.h new file mode 100644 index 0000000..f3fd6d4 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/hash.h @@ -0,0 +1,102 @@ +/* ------------------------------------------------------------------- + $Rev: 1293 $ $Date: 2017-07-27 14:09:14 -0400 (Thu, 27 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL hash functions. + ------------------------------------------------------------------- */ + +#ifndef HASH_H +#define HASH_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ +extern const SATHASHSIZE uiHashWordLen[SATHASHTYPE_LAST]; + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef HASH_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALHash(SATHASHTYPE eHashType, const void *pMsg, + SATUINT32_t uiMsgLen, void *pHash); + +extern SATR CALHashDMA(SATHASHTYPE eHashType, const void *pMsg, + SATUINT32_t uiMsgLen, void *pHash, SATUINT32_t uiDMAChConfig); + +extern SATR CALHashCtx(const SATRESHANDLE hResource, + const SATRESCONTEXTPTR pContext, const void *pMsg, SATUINT32_t uiMsgLen, + void *pHash, const SATBOOL bFinal); + +extern SATR CALHashCtxIni(const SATRESCONTEXTPTR pContext, + const SATHASHTYPE eHashType); + +extern SATR CALHashIni(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen); + +extern SATR CALHashWrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR CALHashRead(void *pHash); + +extern SATR CALKeyTree(SATBOOL bPathSizeSel, const SATUINT32_t* puiKey, + SATUINT8_t uiOpType, const SATUINT32_t* puiPath, SATUINT32_t* puiKeyOut); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATUINT32_t iGetHashLen(SATHASHTYPE eHashType); + +extern SATUINT32_t iGetBlockLen(SATHASHTYPE eHashType); + +extern SATR CALHashCtxLoad(const SATRESHANDLE hResource, + SATRESCONTEXTPTR const pContext, SATUINT32_t uiRunLen); + +extern SATUINT32_t iGetRunLen(SATRESCONTEXTPTR const pContext); + +extern SATR CALHashTypeIni(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/mac.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/mac.h new file mode 100644 index 0000000..acdc767 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/mac.h @@ -0,0 +1,95 @@ +/* ------------------------------------------------------------------- + $Rev: 1296 $ $Date: 2017-08-01 13:54:48 -0400 (Tue, 01 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL MAC functions. + ------------------------------------------------------------------- */ + +#ifndef MAC_H +#define MAC_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef MAC_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALMAC(SATMACTYPE eMACType, const SATUINT32_t *pKey, SATUINT32_t uiKeyLen, + const void *pMsg, SATUINT32_t uiMsgLen, void *pMAC); + +extern SATR CALMACDMA(SATMACTYPE eMACType, const SATUINT32_t *pKey, + SATUINT32_t uiKeyLen, const void *pMsg, SATUINT32_t uiMsgLen, + const void *pMAC, SATUINT32_t uiDMAChConfig); + +extern SATR CALMACIni(SATMACTYPE eMACType, const SATUINT32_t *pKey, + SATUINT32_t uiKeyLen, SATUINT32_t uiMsgLen); + +extern SATR CALMACCtx(const SATRESHANDLE hResource, + const SATRESCONTEXTPTR pContext, const void *pMsg, SATUINT32_t uiMsgLen, + void *pHash, const SATUINT8_t uiFlag); + +extern SATR CALMACCtxIni(const SATRESCONTEXTPTR pContext, const SATHASHTYPE eHashType, + const SATUINT32_t *pKey, SATUINT32_t uiKeyLen); + +extern SATR CALMACWrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR CALMACRead(void *pMAC); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATUINT32_t iGetMACKeyLen(SATMACTYPE eMACType); + +extern SATR CALMACCtxLoad(const SATRESHANDLE hResource, + SATRESCONTEXTPTR const pContext, SATUINT32_t uiRunLen); + +extern SATUINT32_t iGetMACRunLen(SATRESCONTEXTPTR const pContext); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/miv-rv32i-user-crypto-lib.a b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/miv-rv32i-user-crypto-lib.a new file mode 100644 index 0000000..5fda638 Binary files /dev/null and b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/miv-rv32i-user-crypto-lib.a differ diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/miv-rv32imc-user-crypto-lib.a b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/miv-rv32imc-user-crypto-lib.a new file mode 100644 index 0000000..ee7bcf4 Binary files /dev/null and b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/miv-rv32imc-user-crypto-lib.a differ diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/nrbg.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/nrbg.h new file mode 100644 index 0000000..d517065 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/nrbg.h @@ -0,0 +1,83 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for NRBG functions for CAL. + ------------------------------------------------------------------- */ + +#ifndef NRBG_H +#define NRBG_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef NRBG_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALNRBGSetTestEntropy(SATUINT32_t * puiEntropy, + SATUINT32_t uiEntLen32); + +extern SATR CALNRBGGetEntropy(SATUINT32_t * puiEntropy, SATUINT32_t uiEntLen32, + SATBOOL bTesting); + +extern SATR CALNRBGConfig(SATUINT32_t uiWriteEn, SATUINT32_t uiCSR, + SATUINT32_t uiCntLim, SATUINT32_t uiVoTimer, SATUINT32_t uiFMsk, + SATUINT32_t* puiStatus); + +extern SATUINT32_t CALNRBGHealthStatus(void); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATUINT32_t CALNRBGGetTestEntLen(void); + +extern SATR nrbgpkxgetentropy(SATUINT32_t * puiEntropy, + SATUINT32_t uiEntLen32); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/pk.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/pk.h new file mode 100644 index 0000000..5983d9a --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/pk.h @@ -0,0 +1,302 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for for CAL PK. + ------------------------------------------------------------------- */ + +#ifndef PK_H +#define PK_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef PK_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALPKTrfRes(SATBOOL bBlock); + +extern SATR CALDSASign(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALDSASignCM(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALDSASignHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, const SATUINT32_t* puiK, + const SATUINT32_t* puiX, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, SATUINT32_t uiN, + SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALDSASignHashCM(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, const SATUINT32_t* puiK, + const SATUINT32_t* puiX, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, SATUINT32_t uiN, + SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALDSAVerify(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiY, const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, + const SATUINT32_t* puiQMu, SATUINT32_t uiN, SATUINT32_t uiL); + +extern SATR CALDSAVerifyHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, const SATUINT32_t* puiY, + const SATUINT32_t* puiR, const SATUINT32_t* puiS, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALECDHC(const SATUINT32_t* puiS, const SATUINT32_t* puiWx, + const SATUINT32_t* puiWy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t* puiK, const SATUINT32_t* puiR, + const SATUINT32_t* puiRMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiZ); + +extern SATR CALECDSASign(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALECDSASignTwist(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALECDSASignCM(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALECDSASignTwistCM(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALECDSASignHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiK, const SATUINT32_t* puiD, const SATUINT32_t* puiB, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSASignHashCM(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiK, const SATUINT32_t* puiD, const SATUINT32_t* puiB, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSASignTwistHash(const SATUINT32_t* puiMsg, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSAVerify(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS,const + SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress); + +extern SATR CALECDSAVerifyTwist(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALECDSAVerifyHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSAVerifyTwistHash(const SATUINT32_t* puiMsg, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALECMult(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECMultCM(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t* puiN, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress, SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECMultTwist(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiLen, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECMultTwistCM(const SATUINT32_t* puiMul, + const SATUINT32_t* puiPx, const SATUINT32_t* puiPy, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiMod,const SATUINT32_t* puiMu, + const SATUINT32_t* puiN, SATUINT32_t uiLen, SATUINT32_t* puiRx, + SATUINT32_t* puiRy); + +extern SATR CALECMultAdd(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiB, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen, SATUINT32_t uiPtPCompress, SATUINT32_t uiPtQCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECPtValidate(const SATUINT32_t* puiPx, const SATUINT32_t* puiPy, + const SATUINT32_t* puiB, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen); + +extern SATR CALECKeyPairGen(const SATUINT32_t* puiC, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + const SATUINT32_t* puiNM1, const SATUINT32_t* puiNM1Mu, const SATUINT32_t* puiB, + SATUINT32_t* puiD, SATUINT32_t* puiQx, SATUINT32_t* puiQy, SATUINT32_t uiLen); + +extern SATR CALExpo(const SATUINT32_t* puiBase, const SATUINT32_t* puiExpo, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALExpoCM(const SATUINT32_t* puiBase, const SATUINT32_t* puiExpo, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALMMult(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALMMultAdd(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiC, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALModRed(const SATUINT32_t* puiA, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiALen, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPreCompute(const SATUINT32_t* puiMod, SATUINT32_t* puiMu, + SATUINT32_t uiModLen); + +extern SATR CALRSACRT(const SATUINT32_t* puiCipher, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ,const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiLen, SATUINT32_t* puiPlain); + +extern SATR CALRSACRTCM(const SATUINT32_t* puiCipher, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t * puiE, const SATUINT32_t* puiP, + const SATUINT32_t* puiQ, const SATUINT32_t * puiN, + const SATUINT32_t * puiNMu, SATUINT32_t uiLen, SATUINT32_t uiELen, + SATUINT32_t* puiPlain); + +extern SATR CALRSACRTSign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + const SATUINT32_t* puiN, SATUINT32_t uiLen, SATUINT32_t* puiSig); + +extern SATR CALRSACRTSignCM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, const SATUINT32_t* puiQ, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSig); + +extern SATR CALRSACRTSignHash(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ,const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + const SATUINT32_t* puiN, SATUINT32_t uiMsgLen, SATUINT32_t uiModLen, + SATUINT32_t* puiSig, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALRSACRTSignHashCM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, const SATUINT32_t* puiQ, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, SATUINT32_t* puiSig, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALRSASign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiD, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, SATUINT32_t* puiSig); + +extern SATR CALRSASignHash(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiD, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, SATUINT32_t uiModLen, + SATUINT32_t* puiSig, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALRSAVerify(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, + const SATUINT32_t* puiSig); + +extern SATR CALRSAVerifyHash(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiE, SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, const SATUINT32_t* puiSig, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPurge52(SATBOOL bVerify); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/pkx.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/pkx.h new file mode 100644 index 0000000..c23dda4 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/pkx.h @@ -0,0 +1,409 @@ +/* ------------------------------------------------------------------- + $Rev: 1298 $ $Date: 2017-08-04 13:04:19 -0400 (Fri, 04 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for for CAL PK. + ------------------------------------------------------------------- */ + +#ifndef PKX_H +#define PKX_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* X5200 Addressing */ +#define X52BER ((volatile SATUINT32_t *) (PKX0_BASE + 0x00000000u)) +#define X52MMR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00001000u)) +#define X52TSR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00002000u)) +#define X52FPR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00003000u)) +#define X52LIR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00004000u)) +#define X52CSR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00007F80u)) +#define X52CSRMERRS ((volatile SATUINT32_t *) (PKX0_BASE + 0x00007F8Cu)) +#define X52CSRMERRT0 ((volatile SATUINT32_t *) (PKX0_BASE + 0x00007F94u)) + +#if SAT_LITTLE_ENDIAN +#define X52BER_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00008000u)) +#define X52MMR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00009000u)) +#define X52TSR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x0000A000u)) +#define X52FPR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x0000B000u)) +#define X52DMACONFIG_ENDIAN 0x8 +#else +#define X52BER_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00000000u)) +#define X52MMR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00001000u)) +#define X52TSR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00002000u)) +#define X52FPR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00003000u)) +#define X52DMACONFIG_ENDIAN 0x0 +#endif + +/* X5200 Macros */ +#define X52GO(x) (0x10 | ((x)<<8)) + +/* Counter Measures */ +#define RANDLEN 4 + +/* X5200 CSRMAIN bit field masks. */ +#define X52CSRMAINRST 1 +#define X52CSRMAINCCMPLT 2 +#define X52CSRMAINCMPLT 4 +#define X52CSRMAINBUSY 8 +#define X52CSRMAINGO 0x10 +#define X52CSRMAINPURGE 0x20 +#define X52CSRMAINECDIS 0x40 +#define X52CSRMAINALARM 0x80 +#define X52CSRMAINLIRA ((0xFFF) << 8) +#define X52CSRMERRSSEC ((0x2) << 24) +#define X52CSRMERRSA 0x1FFF + +/* Address pointers for ROM'd P-curve moduli */ +#define P192_MOD (&uiROMMods[0]) +#define P224_MOD (&uiROMMods[1]) +#define P256_MOD (&uiROMMods[2]) +#define P384_MOD (&uiROMMods[3]) +#define P521_MOD (&uiROMMods[4]) + +/* X5200 Addressing Flags */ +#define X52BYTEREVERSE_FLAG 1 +#define X52WORDREVERSE_FLAG 2 +#define X52BYTEREVERSE 0x00002000 +#define X52WORDREVERSE 0x00004000 +#define X52ADDRESSRANGE 0x2000 + +/* X5200 DMA channel configuration constants. */ +#define X52CCR_DEFAULT 0 /* BSIZE=auto, ESWP=none, PROT=user, INC=inc */ +#define X52CCR_BSIZEAUTO 0 /* BSIZE=auto */ +#define X52CCR_BSIZEBYTE 0x10 /* BSIZE=byte */ +#define X52CCR_BSIZEHWORD 0x20 /* BSIZE=half word */ +#define X52CCR_BSIZEWORD 0x30 /* BSIZE=word */ +#define X52CCR_ESWPNONE 0 /* ESWP=none */ +#define X52CCR_ESWPWORD 0x8 /* ESWP=swap bytes in word [0123]->[3210] */ +#define X52CCR_PROTUSER 0 /* PROT=user */ +#define X52CCR_PROTPRIV 0x2 /* PROT=priv */ +#define X52CCR_INCADDR 0 /* INC=inc */ +#define X52CCR_NOINCADDR 0x1 /* INC=non-inc */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef PKX_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern void CALPKXIni(void); + +extern void CALPKMem32Load(volatile SATUINT32_t * puiDst, + const SATUINT32_t * puiSrc, SATUINT32_t uiNum ); + +extern SATR CALPKXTrfRes(SATBOOL bBlock); + +extern SATR CALPKXPreCompute(const SATUINT32_t* puiMod, SATUINT32_t* puiMu, + SATUINT32_t uiModLen); + +extern SATR CALPKXExpo(const SATUINT32_t* puiBase, const SATUINT32_t* puiExpo, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALPKXExpoCM(const SATUINT32_t* puiBase, + const SATUINT32_t* puiExpo, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPKXDSASign(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXDSASignCM(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXDSASHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATUINT32_t uiDMAChConfig, const SATBOOL bCM); + +extern SATR CALPKXDSAVerify(const SATUINT32_t *puiHash, + const SATUINT32_t *puiG, const SATUINT32_t *puiY, + const SATUINT32_t *puiSigR, const SATUINT32_t *puiSigS, + const SATUINT32_t *puiP, const SATUINT32_t *puiPMu, + const SATUINT32_t *puiQ, const SATUINT32_t *puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL); + +extern SATR CALPKXDSAVHDMA(const SATUINT32_t *puiExtInput, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t *puiG, const SATUINT32_t *puiY, + const SATUINT32_t *puiSigR, const SATUINT32_t *puiSigS, + const SATUINT32_t *puiP, const SATUINT32_t *puiPMu, const SATUINT32_t *puiQ, + const SATUINT32_t *puiQMu, SATUINT32_t uiN, SATUINT32_t uiL, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXModRed(const SATUINT32_t* puiA, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiALen, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPKXMMult(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPKXMMultAdd(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiC, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALPKXECMult(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECMultTwist(const SATUINT32_t* puiMul, + const SATUINT32_t* puiPx,const SATUINT32_t* puiPy, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen, SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECMultCM(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t * puiN, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress, SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECMultTwistCM(const SATUINT32_t* puiMul, + const SATUINT32_t* puiPx, const SATUINT32_t* puiPy, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + const SATUINT32_t * puiN, SATUINT32_t uiLen, SATUINT32_t* puiRx, + SATUINT32_t* puiRy); + +extern SATR CALPKXECMultAdd(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiB, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen, SATUINT32_t uiPtPCompress, SATUINT32_t uiPtQCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECDSASign(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASignTwist(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx,const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASignCM(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASignTwistCM(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASH(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + const SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASHCM(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + const SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, SATUINT32_t uiDMAChConfig, + const SATBOOL bCM); + +extern SATR CALPKXECDSASTwistH(const SATUINT32_t* puiHash, + const SATHASHTYPE eHashType, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiK, const SATUINT32_t* puiD, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, const SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASTwistHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECDSAVerify(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVerifyTwist(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVH(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB,const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + const SATUINT32_t uiLen, const SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB,const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECDSAVTwistH(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, const SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVTwistHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECDHC(const SATUINT32_t* puiS, const SATUINT32_t* puiWx, + const SATUINT32_t* puiWy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t* puiK, const SATUINT32_t* puiR, + const SATUINT32_t* puiRMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiZ); + +extern SATR CALPKXRSACRT(const SATUINT32_t* puiCipher, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, SATUINT32_t uiLen, + SATUINT32_t* puiPlain); + +extern SATR CALPKXRSACRTCM(const SATUINT32_t* puiCipher, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiE, + const SATUINT32_t* puiP, const SATUINT32_t* puiQ, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, const SATUINT32_t uiLen, const SATUINT32_t uiELen, + SATUINT32_t* puiPlain); + +extern SATR CALPKXRSACRTSign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiCipher, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, + const SATUINT32_t* puiQMu, const SATUINT32_t* puiN, SATUINT32_t uiLen, + SATUINT32_t* puiS); + +extern SATR CALPKXRSACRTSignCM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, + const SATUINT32_t* puiP, const SATUINT32_t* puiQ, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSig); + +extern SATR CALPKXRSACRTSHDMA(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + const SATUINT32_t* puiN, SATUINT32_t uiMsgLen, SATUINT32_t uiModLen, + SATUINT32_t* puiSig, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXRSACRTSHDMACM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, + const SATUINT32_t* puiP, const SATUINT32_t* puiQ, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, SATUINT32_t uiLen, + SATUINT32_t* puiSig, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXRSASign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiD, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, SATUINT32_t* puiSig); + +extern SATR CALPKXRSASHDMA(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiD, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, SATUINT32_t* puiSig, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXRSAVerify(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, + const SATUINT32_t* puiS); + +extern SATR CALPKXRSAVHDMA(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiE,SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, const SATUINT32_t* puiS, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECPtValidate(const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiLen); + +extern SATR CALPKXECKeyPairGen(const SATUINT32_t* puiC, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + const SATUINT32_t* puiNM1, const SATUINT32_t* puiNM1Mu, const SATUINT32_t* puiB, + SATUINT32_t* puiD, SATUINT32_t* puiQx, SATUINT32_t* puiQy, SATUINT32_t uiLen); + +extern SATR CALPKXPurge52(SATBOOL bVerify); + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ +extern SATRESULT SATResults; + +/* -------- ------ --------- */ +/* External Global Constants */ +/* -------- ------ --------- */ +extern const SATUINT32_t uiROMMods[]; + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/pkxlib.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/pkxlib.h new file mode 100644 index 0000000..fb4c0fc --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/pkxlib.h @@ -0,0 +1,95 @@ +/* ------------------------------------------------------------------- + $Rev: 1434 $ $Date: 2017-10-20 16:46:16 -0400 (Fri, 20 Oct 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for PKX-5200 Library. + ------------------------------------------------------------------- */ + +#ifndef PKXLIB_H +#define PKXLIB_H + +#include "caltypes.h" +#include "calpolicy.h" + +#define PKX_JMP_NONE (0xFFFFu + PKX_OFFSET) + +/* jump table entry points: starting PC value */ +#define PKX_JMP_RECIP_PRECOMPUTE (0x0000 + PKX_OFFSET) +#define PKX_JMP_MOD_EXP (0x0002 + PKX_OFFSET) +#define PKX_JMP_RSA_CRT (0x0004 + PKX_OFFSET) +#define PKX_JMP_EC_PTMUL (0x0006 + PKX_OFFSET) +#define PKX_JMP_EC_DSA_SIGN (0x0008 + PKX_OFFSET) +#define PKX_JMP_EC_DSA_VERIFY (0x000A + PKX_OFFSET) +#define PKX_JMP_DSA_SIGN (0x000C + PKX_OFFSET) +#define PKX_JMP_DSA_VERIFY (0x000E + PKX_OFFSET) +#define PKX_JMP_MOD_MULT (0x0010 + PKX_OFFSET) +#define PKX_JMP_MOD_RED (0x0012 + PKX_OFFSET) +#define PKX_JMP_EC_PTDECOMP (0x0014 + PKX_OFFSET) +#define PKX_JMP_EC_DHC (0x0016 + PKX_OFFSET) +#define PKX_JMP_MOD_MULT_ADD (0x0018 + PKX_OFFSET) +#define PKX_JMP_EC_PTMUL_ADD (0x001A + PKX_OFFSET) +#define PKX_JMP_EC_PTVALIDATE (0x001C + PKX_OFFSET) +#define PKX_JMP_F5200_SHA (0x001E + PKX_OFFSET) +#define PKX_JMP_F5200_AES (0x0020 + PKX_OFFSET) +#define PKX_JMP_F5200_AESK (0x0022 + PKX_OFFSET) +#define PKX_JMP_F5200_GCM (0x0024 + PKX_OFFSET) +#define PKX_JMP_F5200_GHA (0x0026 + PKX_OFFSET) +#define PKX_JMP_F5200_AESKW (0x0028 + PKX_OFFSET) +#define PKX_JMP_F5200_AESKWP (0x002A + PKX_OFFSET) +#define PKX_JMP_RNG_INSTANTIATE (0x002C + PKX_OFFSET) +#define PKX_JMP_RNG_RESEED (0x002E + PKX_OFFSET) +#define PKX_JMP_RNG_GENERATE (0x0030 + PKX_OFFSET) +#define PKX_JMP_RNG_UNINSTANTIATE (0x0032 + PKX_OFFSET) +#define PKX_JMP_RNG_GETENTROPY (0x0034 + PKX_OFFSET) +#define PKX_JMP_F5200_SHA_HMAC (0x0036 + PKX_OFFSET) +#define PKX_JMP_F5200_AES_DMA (0x0038 + PKX_OFFSET) +#define PKX_JMP_RNG_CTRLSTATUS (0x003A + PKX_OFFSET) +#define PKX_JMP_F5200_SHA_DMA (0x003C + PKX_OFFSET) +#define PKX_JMP_SHX_KEYTREE (0x003E + PKX_OFFSET) +#define PKX_JMP_PKX_DSA_DMA (0x0040 + PKX_OFFSET) +#define PKX_JMP_PKX_RSACRT_SIGN (0x0042 + PKX_OFFSET) +#define PKX_JMP_PKX_RSA_SIGN (0x0044 + PKX_OFFSET) +#define PKX_JMP_PKX_RSA_VERIFY (0x0046 + PKX_OFFSET) +#define PKX_JMP_PKX_EC_DSA_DMA (0x0048 + PKX_OFFSET) +#define PKX_JMP_F5200_AES_KEYROLL (0x004A + PKX_OFFSET) +#define PKX_JMP_EXPM (0x004C + PKX_OFFSET) +#define PKX_JMP_RSACRTM (0x004E + PKX_OFFSET) +#define PKX_JMP_EC_PTMULM (0x0050 + PKX_OFFSET) +#define PKX_JMP_DSA_SIGN_M (0x0052 + PKX_OFFSET) +#define PKX_JMP_EC_DSA_SIGN_M (0x0054 + PKX_OFFSET) +#define PKX_JMP_EC_KEYPAIRGEN (0x0056 + PKX_OFFSET) +#define PKX_JMP_RSACRTCM_SIGN (0x0058 + PKX_OFFSET) +#define PKX_JMP_F5200_GCM_NEW (0x005A + PKX_OFFSET) +/* PKX PKRev 2180 */ +/* PKX SHARev 2160 */ +/* PKX AESRev 2135 */ +/* Hex Checksum: 0xd0d79866 */ + +extern const SATUINT32_t uiPKX_Flags; +extern const SATUINT32_t uiPKX_BERWords; +extern const SATUINT32_t uiPKX_LIRWords; +extern const SATUINT32_t uiPKX_Rev; +extern const SATUINT32_t uiPKX_LibSize; +extern const SATUINT32_t uiPKX_LibChksum; +extern const SATUINT32_t uiPKX_Lib[]; +extern SATBOOL bMPF300TS_ES; + +#endif diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/shaf5200.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/shaf5200.h new file mode 100644 index 0000000..da598d1 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/shaf5200.h @@ -0,0 +1,101 @@ +/* ------------------------------------------------------------------- + $Rev: 1296 $ $Date: 2017-08-01 13:54:48 -0400 (Tue, 01 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for SHA function hardware implementation for CAL. + ------------------------------------------------------------------- */ + +#ifndef SHAF5200_H +#define SHAF5200_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef SHAF5200_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATR shapkxctx(SATRESCONTEXTPTR const pContext, const void *pBuffer, + SATUINT32_t uiBufLen,void *pHash, const SATBOOL bFinal); + +extern SATR shapkxhmacctx(SATRESCONTEXTPTR const pContext, const void *pBuffer, + SATUINT32_t uiBufLen, void *pHash, const SATUINT8_t uiFlag); + +extern SATR shapkxctxload(SATRESCONTEXTPTR const pContext); + +extern void shapkxctxunload(SATRESCONTEXTPTR const pContext); + +extern SATR shapkxini(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen); + +extern SATR shapkxhmacini(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, + const void *pKey, SATUINT32_t uiKeyLen); + +extern SATR shapkxwrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR shapkxhmacwrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR shapkxread(void *pHash, SATUINT32_t uiRevFlag); + +extern SATR shapkxkeytree(SATBOOL bPathSizeSel, const SATUINT32_t* puiKey, + SATUINT8_t uiOpType, const SATUINT32_t* puiPath, SATUINT32_t* puiKeyOut); + +extern SATR shapkxdma(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, + const void *pExtSrc, const void *pExtDest, SATUINT32_t uiDMAChConfig); + +extern SATR shapkxhmacdma(SATMACTYPE eMACType, const SATUINT32_t *pKey, + SATUINT32_t uiKeyLen, const void *pMsg, SATUINT32_t uiMsgLen, + const void *pMAC, SATUINT32_t uiDMAChConfig); + +extern SATR shapkxhashtypeini(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/sym.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/sym.h new file mode 100644 index 0000000..2e07faa --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/sym.h @@ -0,0 +1,129 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for Symmetric Key Cryptography in CAL. + ------------------------------------------------------------------- */ + +#ifndef SYM_H +#define SYM_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef SYM_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALSymTrfRes(SATBOOL bBlock); + +extern SATR CALSymEncrypt(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen); + +extern SATR CALSymDecrypt(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen); + +extern SATR CALSymEncryptDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymDecryptDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymEncryptKR(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF); + +extern SATR CALSymDecryptKR(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF); + +extern SATR CALSymEncryptKRDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymDecryptKRDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymEncAuth(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen); + +extern SATR CALSymDecVerify(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen); + +extern SATR CALSymKw(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR CALSymKwp(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR CALSymEncAuthDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymDecVerifyDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen, SATUINT32_t uiDMAChConfig); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/utils.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/utils.h new file mode 100644 index 0000000..91474f0 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/utils.h @@ -0,0 +1,93 @@ +/* ------------------------------------------------------------------- + $Rev: 1300 $ $Date: 2017-08-07 11:36:02 -0400 (Mon, 07 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL utility functions. + ------------------------------------------------------------------- */ + +#ifndef UTILS_H +#define UTILS_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef UTILS_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern void CALMemCopy(void *pDst, const void *pSrc, SATUINT32_t uiNum8); + +extern void CALMemClear( void * pLoc, SATUINT32_t uiNum ); + +extern void CALMemClear32( SATUINT32_t* puiLoc, SATUINT32_t uiLen32 ); + +extern SATBOOL CALMemCmp(const void *pA, const void *pB, SATUINT32_t uiNum); + +extern void CALVol32MemLoad(volatile SATUINT32_t * puiDst, const void * pSrc, + SATUINT32_t uiNum32); + +extern void CALVol32MemRead(void * pDst, volatile SATUINT32_t * puiSrc, + SATUINT32_t uiNum32); + +extern void CALByteReverse(SATUINT32_t* puiArray, SATINT32_t iNumberBytes); + +extern void CALByteReverseWord(SATUINT32_t* puiArray, SATINT32_t iNumberWords); + +extern void CALWordReverse(SATUINT32_t *puiArray, SATINT32_t iNumberWords); + +extern void vAppendNonzero(void *puiArray, SATUINT32_t uiLen, + SATUINT32_t uiBlockSize); + +extern void vAppendZero(void *puiArray, SATUINT32_t uiLen, + SATUINT32_t uiBlockSize); + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/x52cfg_user.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/x52cfg_user.h new file mode 100644 index 0000000..c8d8648 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/middleware/cal/x52cfg_user.h @@ -0,0 +1,72 @@ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ +/* X5200 configuration */ +/* $Date: 2015-07-23 14:30:19 -0400 (Thu, 23 Jul 2015) $ $Rev: 2093 $ */ +/* ------------------------------------------------------------------- + Options: + * LIR ROM size : 4096 + * LIR RAM size : 2048 + * BER size : 1024 + * MMR size : 1024 + * TSR size : 1024 + * FPR size : 1024 + * Single error correct, dual error detect (SECDED) memory parity + * DMA enabled + * FPGA multipliers disabled + * AES enabled + - Fast key schedule generation + - GCM/GHASH enabled + - AES countermeasures enabled + * RNG enabled + * External PRNG disabled + * SHA enabled + - Fast SHA enabled + - SHA-1 enabled + - SHA-224 enabled + - SHA-256 enabled + - SHA-384 enabled + - SHA-512 enabled + - SHA-512/224 enabled + - SHA-512/256 enabled + - SHA countermeasures enabled + * P-curves populated in FCR: + - P-192 populated + - P-224 populated + - P-256 populated + - P-384 populated + - P-521 populated + * Data memory scrambling enabled + + ------------------------------------------------------------------- */ + +#ifndef X52CFG_H +#define X52CFG_H + +#define X52_CFG_MODEL 0xf5200 +#define X52_CFG_DATE 0x15072720 +#define X52_CFG_REV 0x0000082e +#define X52_CFG_OPT 0x0fd87ff9 +#define X52_CFG_OPT2 0xc0000000 +#define X52_LIR_LEN 0x1800 +#define X52_LIR_ROM_LEN 0x1000 +#define X52_LIR_RAM_LEN 0x0800 +#define X52_BER_LEN 0x400 +#define X52_MMR_LEN 0x400 +#define X52_TSR_LEN 0x400 +#define X52_FPR_LEN 0x400 + +#endif diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/README.md b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/README.md new file mode 100644 index 0000000..f7f6030 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/README.md @@ -0,0 +1,27 @@ +# Mi-V soft processor platform source code + +## Repo organization + +``` + + | + |-- drivers + | |- fpga_ip + | | | CoreGPIO + | | | CoreSysServices_PF + | | | CoreUARTapb + | | + | |- off_chip + | | | . + | | | . + | | + |-- hal + | | + |-- miv_rv32_hal + + +``` + +The drivers published here are compatible with the improved SoftConsole project folder structure being used in the latest [example projects](https://github.com/Mi-V-Soft-RISC-V/miv-rv32-bare-metal-examples). +These drivers can also be used with the legacy folder structure (projects released via Firmware Catalog) by defining the **LEGACY_DIR_STRUCTURE** macro in the SoftConsole project settings. + diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c new file mode 100644 index 0000000..1a0073f --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c @@ -0,0 +1,533 @@ +/******************************************************************************* + * (c) Copyright 2008-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file core_gpio.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreGPIO bare metal driver implementation. + * + */ +#include "coregpio_regs.h" +#include "core_gpio.h" + +/*-------------------------------------------------------------------------*//** + * + */ +#define GPIO_INT_ENABLE_MASK (uint32_t)0x00000008UL +#define OUTPUT_BUFFER_ENABLE_MASK 0x00000004UL + + +#define NB_OF_GPIO 32 + +#define CLEAR_ALL_IRQ32 (uint32_t)0xFFFFFFFF +#define CLEAR_ALL_IRQ16 (uint16_t)0xFFFF +#define CLEAR_ALL_IRQ8 (uint8_t)0xFF + +/*-------------------------------------------------------------------------*//** + * GPIO_init() + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_init +( + gpio_instance_t * this_gpio, + addr_t base_addr, + gpio_apb_width_t bus_width +) +{ + uint8_t i = 0; + addr_t cfg_reg_addr = base_addr; + + this_gpio->base_addr = base_addr; + this_gpio->apb_bus_width = bus_width; + + /* Clear configuration. */ + for( i = 0, cfg_reg_addr = base_addr; i < NB_OF_GPIO; ++i ) + { + HW_set_8bit_reg( cfg_reg_addr, 0 ); + cfg_reg_addr += 4; + } + /* Clear any pending interrupts */ + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, CLEAR_ALL_IRQ32 ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, (uint16_t)CLEAR_ALL_IRQ16 ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, (uint16_t)CLEAR_ALL_IRQ16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, (uint8_t)CLEAR_ALL_IRQ8 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_config + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_config +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint32_t config +) +{ + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + uint32_t cfg_reg_addr = this_gpio->base_addr; + cfg_reg_addr += (port_id * 4); + HW_set_32bit_reg( cfg_reg_addr, config ); + + /* + * Verify that the configuration was correctly written. Failure to read + * back the expected value may indicate that the GPIO port was configured + * as part of the hardware flow and cannot be modified through software. + * It may also indicate that the base address passed as parameter to + * GPIO_init() was incorrect. + */ + HAL_ASSERT( HW_get_32bit_reg( cfg_reg_addr ) == config ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_set_outputs + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_set_outputs +( + gpio_instance_t * this_gpio, + uint32_t value +) +{ + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, GPIO_OUT, value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, GPIO_OUT0, (uint16_t)value ); + HAL_set_16bit_reg( this_gpio->base_addr, GPIO_OUT1, (uint16_t)(value >> 16) ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT0, (uint8_t)value ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT1, (uint8_t)(value >> 8) ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT2, (uint8_t)(value >> 16) ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT3, (uint8_t)(value >> 24) ); + break; + + default: + HAL_ASSERT(0); + break; + } + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( GPIO_get_outputs( this_gpio ) == value ); +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_inputs + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_inputs +( + gpio_instance_t * this_gpio +) +{ + uint32_t gpio_in = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + gpio_in = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_IN ); + break; + + case GPIO_APB_16_BITS_BUS: + gpio_in |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_IN0 ); + gpio_in |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_IN1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + gpio_in |= HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN0 ); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN1 ) << 8); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN2 ) << 16); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return gpio_in; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_outputs + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_outputs +( + gpio_instance_t * this_gpio +) +{ + uint32_t gpio_out = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + gpio_out = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ); + break; + + case GPIO_APB_16_BITS_BUS: + gpio_out |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT0 ); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + gpio_out |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT0 ); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT1 ) << 8); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT2 ) << 16); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return gpio_out; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_set_output + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_set_output +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint8_t value +) +{ + HAL_ASSERT( port_id < NB_OF_GPIO ); + + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + { + uint32_t outputs_state; + + outputs_state = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ); + if ( 0 == value ) + { + outputs_state &= ~(1 << port_id); + } + else + { + outputs_state |= 1 << port_id; + } + HAL_set_32bit_reg( this_gpio->base_addr, GPIO_OUT, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ) == outputs_state ); + } + break; + + case GPIO_APB_16_BITS_BUS: + { + uint16_t outputs_state; + uint32_t gpio_out_reg_addr = this_gpio->base_addr + GPIO_OUT_REG_OFFSET + ((port_id >> 4) * 4); + + outputs_state = HW_get_16bit_reg( gpio_out_reg_addr ); + if ( 0 == value ) + { + outputs_state &= ~(1 << (port_id & 0x0F)); + } + else + { + outputs_state |= 1 << (port_id & 0x0F); + } + HW_set_16bit_reg( gpio_out_reg_addr, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HW_get_16bit_reg( gpio_out_reg_addr ) == outputs_state ); + } + break; + + case GPIO_APB_8_BITS_BUS: + { + uint8_t outputs_state; + uint32_t gpio_out_reg_addr = this_gpio->base_addr + GPIO_OUT_REG_OFFSET + ((port_id >> 3) * 4); + + outputs_state = HW_get_8bit_reg( gpio_out_reg_addr ); + if ( 0 == value ) + { + outputs_state &= ~(1 << (port_id & 0x07)); + } + else + { + outputs_state |= 1 << (port_id & 0x07); + } + HW_set_8bit_reg( gpio_out_reg_addr, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HW_get_8bit_reg( gpio_out_reg_addr ) == outputs_state ); + } + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_drive_inout + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_drive_inout +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + gpio_inout_state_t inout_state +) +{ + uint32_t config; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + switch( inout_state ) + { + case GPIO_DRIVE_HIGH: + /* Set output high */ + GPIO_set_output( this_gpio, port_id, 1 ); + + /* Enable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config |= OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + case GPIO_DRIVE_LOW: + /* Set output low */ + GPIO_set_output( this_gpio, port_id, 0 ); + + /* Enable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config |= OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + case GPIO_HIGH_Z: + /* Disable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config &= ~OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_enable_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_enable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t cfg_value; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + cfg_reg_addr += (port_id * 4); + cfg_value = HW_get_8bit_reg( cfg_reg_addr ); + cfg_value |= GPIO_INT_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, cfg_value ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_disable_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_disable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t cfg_value; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + cfg_reg_addr += (port_id * 4); + cfg_value = HW_get_8bit_reg( cfg_reg_addr ); + cfg_value &= ~GPIO_INT_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, cfg_value ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_clear_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_clear_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t irq_clr_value = ((uint32_t)1) << ((uint32_t)port_id); + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, irq_clr_value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, irq_clr_value >> 16 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, irq_clr_value >> 24 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_irq_sources + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_irq_sources +( + gpio_instance_t * this_gpio +) +{ + uint32_t intr_src = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + intr_src = HAL_get_32bit_reg( this_gpio->base_addr, IRQ ); + break; + + case GPIO_APB_16_BITS_BUS: + intr_src |= HAL_get_16bit_reg( this_gpio->base_addr, IRQ0 ); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + intr_src |= HAL_get_16bit_reg( this_gpio->base_addr, IRQ0 ); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ1 ) << 8); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ2 ) << 16); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return intr_src; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_clear_all_irq_sources + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_clear_all_irq_sources +( + gpio_instance_t * this_gpio, + uint32_t bitmask +) +{ + uint32_t irq_clr_value = bitmask; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, irq_clr_value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, irq_clr_value >> 16 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, irq_clr_value >> 24 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h new file mode 100644 index 0000000..88ba178 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h @@ -0,0 +1,722 @@ +/******************************************************************************* + * (c) Copyright 2008-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file core_gpio.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreGPIO bare metal driver public API. + * + */ + +/*=========================================================================*//** + @mainpage CoreGPIO Bare Metal Driver. + + @section intro_sec Introduction + The CoreGPIO hardware IP includes up to 32 general-purpose input/output GPIOs. + This driver provides a set of functions for controlling the GPIOs as part of a + bare-metal system where no operating system is available. These drivers + can be adapted for use as part of an operating system, but the implementation + of the adaptation layer between this driver and the operating system's driver + model is outside the scope of this driver. + + @section driver_configuration Driver Configuration + The individual IOs of CoreGPIO can be configured either in the hardware flow + or as part of the software application through calls to the GPIO_config() + function. GPIOs configured as part of the hardware are fixed and cannot be + modified using a call to the GPI_config() function. + + @section theory_op Theory of Operation + The CoreGPIO driver uses the Actel Hardware Abstraction Layer (HAL) to access + hardware registers. You must ensure that the Actel HAL is included as part of + your software project. The Actel HAL is available through the Actel Firmware + Catalog. + + The CoreGPIO driver functions are logically grouped into the following groups: + - Initialization + - Configuration + - Reading and writing GPIO state + - Interrupt control + + The CoreGPIO driver is initialized through a call to the GPIO_init() function. + The GPIO_init() function must be called before any other GPIO driver functions + can be called. + + Each GPIO port is individually configured through a call to the + GPIO_config() function. Configuration includes deciding if a GPIO port is + going to be used as input, output, or both. GPIO ports configured as inputs + are further configured to generate interrupts based on the state of input. + Interrupts is either level- or edge-sensitive. + Note that a CoreGPIO hardware instance is generated as part of the hardware + flow with a fixed configuration for some or all of its IOs. + Attempting to modify the configuration of such a hardware-configured IO using + the GPIO_config() function has no effect. + + The state of the GPIO ports can be read and written using the following + functions: + - GPIO_get_inputs() + - GPIO_get_outputs() + - GPIO_set_outputs() + - GPIO_drive_inout() + + Interrupts generated by GPIO ports configured as inputs are controlled using + the following functions: + - GPIO_enable_irq() + - GPIO_disable_irq() + - GPIO_clear_irq() + - GPIO_get_irq_sources() + - GPIO_clear_all_irq_sources() + + *//*=========================================================================*/ +#ifndef CORE_GPIO_H_ +#define CORE_GPIO_H_ + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + The gpio_id_t enumeration is used to identify GPIOs as part of the + parameter to functions: + - GPIO_config(), + - GPIO_drive_inout(), + - GPIO_enable_int(), + - GPIO_disable_int(), + - GPIO_clear_int() + */ +typedef enum __gpio_id_t +{ + GPIO_0 = 0, + GPIO_1 = 1, + GPIO_2 = 2, + GPIO_3 = 3, + GPIO_4 = 4, + GPIO_5 = 5, + GPIO_6 = 6, + GPIO_7 = 7, + GPIO_8 = 8, + GPIO_9 = 9, + GPIO_10 = 10, + GPIO_11 = 11, + GPIO_12 = 12, + GPIO_13 = 13, + GPIO_14 = 14, + GPIO_15 = 15, + GPIO_16 = 16, + GPIO_17 = 17, + GPIO_18 = 18, + GPIO_19 = 19, + GPIO_20 = 20, + GPIO_21 = 21, + GPIO_22 = 22, + GPIO_23 = 23, + GPIO_24 = 24, + GPIO_25 = 25, + GPIO_26 = 26, + GPIO_27 = 27, + GPIO_28 = 28, + GPIO_29 = 29, + GPIO_30 = 30, + GPIO_31 = 31 +} gpio_id_t; + +/*-------------------------------------------------------------------------*//** + Possible width of the APB bus + */ +typedef enum __gpio_apb_width_t +{ + GPIO_APB_8_BITS_BUS = 0, + GPIO_APB_16_BITS_BUS = 1, + GPIO_APB_32_BITS_BUS = 2, + GPIO_APB_UNKNOWN_BUS_WIDTH = 3 +} gpio_apb_width_t; + +/*-------------------------------------------------------------------------*//** + Structure instance holding all data regarding the CoreGPIO + */ +typedef struct __gpio_instance_t +{ + addr_t base_addr; + gpio_apb_width_t apb_bus_width; +} gpio_instance_t; + +/*-------------------------------------------------------------------------*//** + GPIO ports definitions used to identify GPIOs as part of the parameter to + function GPIO_set_outputs(). + These definitions are also be used to identity GPIO through logical operations + on the return value of function GPIO_get_inputs(). + # GPIO_0_MASK + # GPIO_1_MASK + # GPIO_2_MASK + # GPIO_3_MASK + # GPIO_4_MASK + # GPIO_5_MASK + # GPIO_6_MASK + # GPIO_7_MASK + # GPIO_8_MASK + # GPIO_9_MASK + # GPIO_10_MASK + # GPIO_11_MASK + # GPIO_12_MASK + # GPIO_13_MASK + # GPIO_14_MASK + # GPIO_15_MASK + # GPIO_16_MASK + # GPIO_17_MASK + # GPIO_18_MASK + # GPIO_19_MASK + # GPIO_20_MASK + # GPIO_21_MASK + # GPIO_22_MASK + # GPIO_23_MASK + # GPIO_24_MASK + # GPIO_25_MASK + # GPIO_26_MASK + # GPIO_27_MASK + # GPIO_28_MASK + # GPIO_29_MASK + # GPIO_30_MASK + # GPIO_31_MASK + */ +#define GPIO_0_MASK 0x00000001UL +#define GPIO_1_MASK 0x00000002UL +#define GPIO_2_MASK 0x00000004UL +#define GPIO_3_MASK 0x00000008UL +#define GPIO_4_MASK 0x00000010UL +#define GPIO_5_MASK 0x00000020UL +#define GPIO_6_MASK 0x00000040UL +#define GPIO_7_MASK 0x00000080UL +#define GPIO_8_MASK 0x00000100UL +#define GPIO_9_MASK 0x00000200UL +#define GPIO_10_MASK 0x00000400UL +#define GPIO_11_MASK 0x00000800UL +#define GPIO_12_MASK 0x00001000UL +#define GPIO_13_MASK 0x00002000UL +#define GPIO_14_MASK 0x00004000UL +#define GPIO_15_MASK 0x00008000UL +#define GPIO_16_MASK 0x00010000UL +#define GPIO_17_MASK 0x00020000UL +#define GPIO_18_MASK 0x00040000UL +#define GPIO_19_MASK 0x00080000UL +#define GPIO_20_MASK 0x00100000UL +#define GPIO_21_MASK 0x00200000UL +#define GPIO_22_MASK 0x00400000UL +#define GPIO_23_MASK 0x00800000UL +#define GPIO_24_MASK 0x01000000UL +#define GPIO_25_MASK 0x02000000UL +#define GPIO_26_MASK 0x04000000UL +#define GPIO_27_MASK 0x08000000UL +#define GPIO_28_MASK 0x10000000UL +#define GPIO_29_MASK 0x20000000UL +#define GPIO_30_MASK 0x40000000UL +#define GPIO_31_MASK 0x80000000UL + +/*-------------------------------------------------------------------------*//** + * GPIO modes + * # GPIO_INPUT_MODE + * # GPIO_OUTPUT_MODE + * # GPIO_INOUT_MODE + */ +#define GPIO_INPUT_MODE 0x0000000002UL +#define GPIO_OUTPUT_MODE 0x0000000005UL +#define GPIO_INOUT_MODE 0x0000000003UL + +/*-------------------------------------------------------------------------*//** + * Possible GPIO inputs interrupt configurations. + * # GPIO_IRQ_LEVEL_HIGH + * # GPIO_IRQ_LEVEL_LOW + * # GPIO_IRQ_EDGE_POSITIVE + * # GPIO_IRQ_EDGE_NEGATIVE + * # GPIO_IRQ_EDGE_BOTH + */ +#define GPIO_IRQ_LEVEL_HIGH 0x0000000000UL +#define GPIO_IRQ_LEVEL_LOW 0x0000000020UL +#define GPIO_IRQ_EDGE_POSITIVE 0x0000000040UL +#define GPIO_IRQ_EDGE_NEGATIVE 0x0000000060UL +#define GPIO_IRQ_EDGE_BOTH 0x0000000080UL + +/*-------------------------------------------------------------------------*//** + * Possible states for GPIO configured as INOUT + */ +typedef enum gpio_inout_state +{ + GPIO_DRIVE_LOW = 0, + GPIO_DRIVE_HIGH, + GPIO_HIGH_Z +} gpio_inout_state_t; + +/*-------------------------------------------------------------------------*//** + The GPIO_init() function initializes a CoreGPIO hardware instance and the data + structure associated with the CoreGPIO hardware instance. + Note that a CoreGPIO hardware instance is generated with a fixed configuration + for some or all of its IOs as part of the hardware flow. + Attempting to modify the configuration of such a hardware-configured IO using + the GPIO_config() function has no effect. + + @param this_gpio + Pointer to the gpio_instance_t data structure instance holding all data + regarding the CoreGPIO hardware instance being initialized. A pointer to the + same data structure is used in subsequent calls to the CoreGPIO driver + functions in order to identify the CoreGPIO instance that must perform the + operation implemented by the called driver function. + + @param base_addr + The base_addr parameter is the base address in the memory map of the + processor for the registers of the GPIO instance being initialized. + + @param bus_width + The bus_width parameter informs the driver of the APB bus width selected + during the hardware flow configuration of the CoreGPIO hardware instance. It + indicates to the driver whether the CoreGPIO hardware registers are visible + as 8, 16, or 32-bits registers. Allowed values are: + - GPIO_APB_8_BITS_BUS + - GPIO_APB_16_BITS_BUS + - GPIO_APB_32_BITS_BUS + + @return + none. + + @example + @code + #define COREGPIO_BASE_ADDR 0xC2000000 + + gpio_instance_t g_gpio; + + void system_init( void ) + { + GPIO_init( &g_gpio, COREGPIO_BASE_ADDR, GPIO_APB_32_BITS_BUS ); + } + @endcode + */ +void GPIO_init +( + gpio_instance_t * this_gpio, + addr_t base_addr, + gpio_apb_width_t bus_width +); + +/*-------------------------------------------------------------------------*//** + The GPIO_config() function is used to configure an individual GPIO port. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO port to be configured. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @param config + The config parameter specifies the configuration to be applied to the GPIO + port identified by the first parameter. It is a logical OR of GPIO mode and + interrupt mode. The interrupt mode is only relevant if the GPIO is + configured as an input. + - Possible modes are: + - GPIO_INPUT_MODE, + - GPIO_OUTPUT_MODE, + - GPIO_INOUT_MODE. + - Possible interrupt modes are: + - GPIO_IRQ_LEVEL_HIGH, + - GPIO_IRQ_LEVEL_LOW, + - GPIO_IRQ_EDGE_POSITIVE, + - GPIO_IRQ_EDGE_NEGATIVE, + - GPIO_IRQ_EDGE_BOTH + + @return + none. + + @example + For example, the following call configures GPIO 4 as an input that generates + interrupts on a low-to-high transition of the input: + @code + GPIO_config( &g_gpio, GPIO_4, GPIO_INPUT_MODE | GPIO_IRQ_EDGE_POSITIVE ); + @endcode + */ +void GPIO_config +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint32_t config +); + +/*-------------------------------------------------------------------------*//** + The GPIO_set_outputs() function is used to set the state of the GPIO ports + configured as outputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param value + The value parameter specifies the state of the GPIO ports configured as + outputs. It is a bit mask of the form (GPIO_n_MASK | GPIO_m_MASK), where n + and m are numbers identifying GPIOs. + For example, (GPIO_0_MASK | GPIO_1_MASK | GPIO_2_MASK ) specifies that the + first, second, and third GPIO must be set high and all other outputs set + low. + + @return + none. + + @example + Set GPIO 0 and 8 outputs high and all other GPIO outputs low. + @code + GPIO_set_outputs( &g_gpio, GPIO_0_MASK | GPIO_8_MASK ); + @endcode + + @example + Set GPIO 2 and 4 outputs low without affecting the other GPIO outputs. + @code + uint32_t gpio_outputs; + gpio_outputs = GPIO_get_outputs( &g_gpio ); + gpio_outputs &= ~( GPIO_2_MASK | GPIO_4_MASK ); + GPIO_set_outputs( &g_gpio, gpio_outputs ); + @endcode + + @see GPIO_get_outputs() + */ +void GPIO_set_outputs +( + gpio_instance_t * this_gpio, + uint32_t value +); + +/*-------------------------------------------------------------------------*//** + The GPIO_set_output() function is used to set the state of a single GPIO port + configured as an output. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter specifies the GPIO port that has its output set by a + call to this function. + + @param value + The value parameter specifies the desired state for the GPIO output. A value + of 0 sets the output low, and a value of 1 sets the port high. + + @return + none. + */ +void GPIO_set_output +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint8_t value +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_inputs() function is used to read the state of all GPIOs + configured as inputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @return + This function returns a 32-bit unsigned integer, where each bit represents + the state of an input. The least significant bit represents the state of + GPIO 0, and the most significant bit represents the state of GPIO 31. + */ +uint32_t GPIO_get_inputs +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_outputs() function is used to read the current state of all + GPIO outputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @return + This function returns a 32-bit unsigned integer where each bit represents + the state of an output. The least significant bit represents the state + of GPIO 0, and the most significant bit represents the state of GPIO 31. + */ +uint32_t GPIO_get_outputs +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_drive_inout() function is used to set the output state of a + GPIO configured as INOUT. An INOUT GPIO is in one of three states: + - high + - low + - high impedance + + An INOUT output is typically be used where several devices drive the state of + a signal. The high and low states are equivalent to the high and low states of + a GPIO configured as an output. The high impedance state is used to prevent + the GPIO from driving the state of the output and therefore allow reading the + state of the GPIO as an input. + Note that the GPIO port you wish to use as INOUT through this function + must be configurable through software. Therefore, the GPIO ports used as INOUT + must not have a fixed configuration selected as part of the hardware flow. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO for which this function will + change the output state. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @param inout_state + The inout_state parameter specifies the state of the I/O identified by the + first parameter. Possible states are: + - GPIO_DRIVE_HIGH, + - GPIO_DRIVE_LOW, + - GPIO_HIGH_Z (high impedance) + + @return + none. + + @example + The call to GPIO_drive_inout() below will set the GPIO 7 output to + high impedance state. + @code + GPIO_drive_inout( &g_gpio, GPIO_7, GPIO_HIGH_Z ); + @endcode + */ +void GPIO_drive_inout +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + gpio_inout_state_t inout_state +); + +/*-------------------------------------------------------------------------*//** + The GPIO_enable_irq() function is used to enable an interrupt to be + generated based on the state of the input identified as a parameter. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO input that the call to + GPIO_enable_irq() enables to generate interrupts. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + @example + The call to GPIO_enable_irq() below allows GPIO 8 to generate interrupts. + + @code + GPIO_enable_irq( &g_gpio, GPIO_8 ); + @endcode + */ +void GPIO_enable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_disable_irq() function is used to disable interrupts from being + generated based on the state of the input specified as a parameter. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO input that the call to + GPIO_disable_irq() disables from generating interrupts. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + @example + The call to GPIO_disable_irq() below prevents GPIO 8 from generating + interrupts. + @code + GPIO_disable_irq( &g_gpio, GPIO_8 ); + @endcode + */ +void GPIO_disable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_clear_irq() function is used to clear the interrupt generated by + the GPIO specified as a parameter. The GPIO_clear_irq() function must be + called as part of a GPIO interrupt service routine (ISR) in order to prevent + the same interrupt event from re-triggering a call to the GPIO ISR. + Note that interrupts may also need to be cleared in the processor's + interrupt controller. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO input for which to clear the + interrupt. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + @example + The example below demonstrates the use of the GPIO_clear_irq() function as + part of the GPIO-9 interrupt service routine. + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + GPIO_clear_irq( &g_gpio, GPIO_9 ); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +void GPIO_clear_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_irq_sources() function is used to identify the source of the + interrupt. i.e. to That is the GPIO input line, whose state change triggered + the interrupt. The GPIO_get_irq_sources() function must be called as part of + a GPIO interrupt service routine (ISR) in order to determine the interrupt + source. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @return + This function returns a 32-bit unsigned integer, where each bit represents + the pin number of a GPIO. + + @example + The example below demonstrates the use of the GPIO_get_irq_sources() + function as part of the GPIO-9 interrupt service routine. + + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + GPIO_clear_all_irq_sources(g_p_mygpio, GPIO_get_irq_sources(g_p_mygpio)); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +uint32_t GPIO_get_irq_sources +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_clear_all_irq_sources() function is used to clear all the active + interrupts generated by the GPIO specified as a parameter. The + GPIO_clear_all_irq_sources() function must be called as part of a GPIO + interrupt service routine (ISR) in order to prevent the same interrupt event + from re-triggering a call to the GPIO ISR. + Note that interrupts may also need to be cleared in the processor's + interrupt controller. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param bitmask + This bitmask parameter is a 32-bit unsigned integer where each bit + represents the GPIO pin used to clear the interrupt bit register of the + corresponding GPIO bit. The least significant bit represents the status of + GPIO 0, and the most significant bit represents the status of GPIO 31. + + @return + none. + + @example + The example below demonstrates the use of the GPIO_clear_all_irq_sources() + function as part of the GPIO-9 interrupt service routine. + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + do_interrupt_processing(); + + GPIO_clear_all_irq_sources(g_p_mygpio, GPIO_get_irq_sources(g_p_mygpio)); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +void GPIO_clear_all_irq_sources +( + gpio_instance_t * this_gpio, + uint32_t bitmask +); + +#ifdef __cplusplus +} +#endif + +#endif /* CORE_GPIO_H_ */ diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h new file mode 100644 index 0000000..41f5b7c --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h @@ -0,0 +1,45 @@ +/******************************************************************************* + * (c) Copyright 2008-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file coregpio_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreGPIO register definitions + * + */ + +#ifndef __CORE_GPIO_REGISTERS_H +#define __CORE_GPIO_REGISTERS_H 1 + +/*------------------------------------------------------------------------------ + * + */ +#define IRQ_REG_OFFSET 0x80 + +#define IRQ0_REG_OFFSET 0x80 +#define IRQ1_REG_OFFSET 0x84 +#define IRQ2_REG_OFFSET 0x88 +#define IRQ3_REG_OFFSET 0x8C + +/*------------------------------------------------------------------------------ + * + */ +#define GPIO_IN_REG_OFFSET 0x90 + +#define GPIO_IN0_REG_OFFSET 0x90 +#define GPIO_IN1_REG_OFFSET 0x94 +#define GPIO_IN2_REG_OFFSET 0x98 +#define GPIO_IN3_REG_OFFSET 0x9C + +/*------------------------------------------------------------------------------ + * + */ +#define GPIO_OUT_REG_OFFSET 0xA0 + +#define GPIO_OUT0_REG_OFFSET 0xA0 +#define GPIO_OUT1_REG_OFFSET 0xA4 +#define GPIO_OUT2_REG_OFFSET 0xA8 +#define GPIO_OUT3_REG_OFFSET 0xAC + +#endif /* __CORE_GPIO_REGISTERS_H */ diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c new file mode 100644 index 0000000..1fd3dd6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c @@ -0,0 +1,1495 @@ +/******************************************************************************* + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * CoreI2C software driver implementation. + * + */ + +#include "core_smbus_regs.h" +#include "core_i2c.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * I2C transaction direction. + */ +#define WRITE_DIR 0u +#define READ_DIR 1u + +/* -- TRANSACTIONS TYPES -- */ +#define NO_TRANSACTION 0u +#define MASTER_WRITE_TRANSACTION 1u +#define MASTER_READ_TRANSACTION 2u +#define MASTER_RANDOM_READ_TRANSACTION 3u +#define WRITE_SLAVE_TRANSACTION 4u +#define READ_SLAVE_TRANSACTION 5u + +/* -- SMBUS H/W STATES -- */ +/* -- MASTER STATES -- */ +#define ST_BUS_ERROR 0x00u /* Bus error during MST or selected slave modes */ +#define ST_I2C_IDLE 0xF8u /* No activity and no interrupt either... */ +#define ST_START 0x08u /* start condition sent */ +#define ST_RESTART 0x10u /* repeated start */ +#define ST_SLAW_ACK 0x18u /* SLA+W sent, ack received */ +#define ST_SLAW_NACK 0x20u /* SLA+W sent, nack received */ +#define ST_TX_DATA_ACK 0x28u /* Data sent, ACK'ed */ +#define ST_TX_DATA_NACK 0x30u /* Data sent, NACK'ed */ +#define ST_LOST_ARB 0x38u /* Master lost arbitration */ +#define ST_SLAR_ACK 0x40u /* SLA+R sent, ACK'ed */ +#define ST_SLAR_NACK 0x48u /* SLA+R sent, NACK'ed */ +#define ST_RX_DATA_ACK 0x50u /* Data received, ACK sent */ +#define ST_RX_DATA_NACK 0x58u /* Data received, NACK sent */ +#define ST_RESET_ACTIVATED 0xD0u /* Master reset is activated */ +#define ST_STOP_TRANSMIT 0xE0u /* Stop has been transmitted */ + +/* -- SLAVE STATES -- */ +#define ST_SLAVE_SLAW 0x60u /* SLA+W received */ +#define ST_SLAVE_SLAR_ACK 0xA8u /* SLA+R received, ACK returned */ +#define ST_SLV_LA 0x68u /* Slave lost arbitration */ +#define ST_GCA 0x70u /* GCA received */ +#define ST_GCA_LA 0x78u /* GCA lost arbitration */ +#define ST_RDATA 0x80u /* Data received */ +#define ST_SLA_NACK 0x88u /* Slave addressed, NACK returned */ +#define ST_GCA_ACK 0x90u /* Previously addresses with GCA, data ACKed */ +#define ST_GCA_NACK 0x98u /* GCA addressed, NACK returned */ +#define ST_RSTOP 0xA0u /* Stop received */ +#define ST_SLARW_LA 0xB0u /* Arbitration lost */ +#define ST_RACK 0xB8u /* Byte sent, ACK received */ +#define ST_SLAVE_RNACK 0xC0u /* Byte sent, NACK received */ +#define ST_FINAL 0xC8u /* Final byte sent, ACK received */ +#define ST_SLV_RST 0xD8u /* Slave reset state */ + + +/* I2C Channel base offset */ +#define CHANNEL_BASE_SHIFT 5u +#define CHANNEL_MASK 0x1E0u + +/* + * Maximum address offset length in slave write-read transactions. + * A maximum of two bytes will be interpreted as address offset within the slave + * tx buffer. + */ +#define MAX_OFFSET_LENGTH 2u + +/*------------------------------------------------------------------------------ + * I2C interrupts control functions implemented "i2c_interrupt.c". + * the implementation of these functions depend on the underlying hardware + * design and how the CoreI2C interrupt line is connected to the system's + * interrupt controller. + */ +void I2C_enable_irq( i2c_instance_t * this_i2c ); +void I2C_disable_irq( i2c_instance_t * this_i2c ); +static void enable_slave_if_required(i2c_instance_t * this_i2c); + +/*------------------------------------------------------------------------------ + * I2C_init() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_init +( + i2c_instance_t * this_i2c, + addr_t base_address, + uint8_t ser_address, + i2c_clock_divider_t ser_clock_speed +) +{ + psr_t saved_psr; + uint_fast16_t clock_speed = (uint_fast16_t)ser_clock_speed; + + /* + * We need to disable ints while doing this as there is no guarantee we + * have not been called already and the ISR is active. + */ + saved_psr = HAL_disable_interrupts(); + + /* + * Initialize all items of the this_i2c data structure to zero. This + * initializes all state variables to their init value. It relies on + * the fact that NO_TRANSACTION, I2C_SUCCESS and I2C_RELEASE_BUS all + * have an actual value of zero. + */ + memset(this_i2c, 0, sizeof(i2c_instance_t)); + + /* + * Set base address of I2C hardware used by this instance. + */ + this_i2c->base_address = base_address; + + /* + * Update Serial address of the device + */ + this_i2c->ser_address = ((uint_fast8_t)ser_address << 1u); + + /* + * Configure hardware. + */ + HAL_set_8bit_reg_field(this_i2c->base_address, ENS1, 0x00); /* Reset I2C hardware. */ + HAL_set_8bit_reg_field(this_i2c->base_address, ENS1, 0x01); /* set enable bit */ + HAL_set_8bit_reg_field(this_i2c->base_address, CR2, ( (clock_speed >> 2) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c->base_address, CR1, ( (clock_speed >> 1) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c->base_address, CR0, ( clock_speed & 0x01) ); + + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS, this_i2c->ser_address); + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, this_i2c->ser_address); + + /* + * Finally safe to enable interrupts. + */ + HAL_restore_interrupts( saved_psr ); +} +/*------------------------------------------------------------------------------ + * I2C_channel_init() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_channel_init +( + i2c_instance_t * this_i2c_channel, + i2c_instance_t * this_i2c, + i2c_channel_number_t channel_number, + i2c_clock_divider_t ser_clock_speed +) +{ + psr_t saved_psr; + uint_fast16_t clock_speed = (uint_fast16_t)ser_clock_speed; + + HAL_ASSERT(channel_number < I2C_MAX_CHANNELS); + HAL_ASSERT(I2C_CHANNEL_0 != channel_number); + + /* + * Cannot allow channel 0 in this function as we will trash the hardware + * base address and slave address. + */ + if ((channel_number < I2C_MAX_CHANNELS) && + (I2C_CHANNEL_0 != channel_number)) + { + /* + * We need to disable ints while doing this as the hardware should already + * be active at this stage. + */ + saved_psr = HAL_disable_interrupts(); + + /* + * Initialize channel data. + */ + memset(this_i2c_channel, 0, sizeof(i2c_instance_t)); + + this_i2c_channel->base_address = + ((this_i2c->base_address) & ~((addr_t)CHANNEL_MASK)) + | (((addr_t)channel_number) << CHANNEL_BASE_SHIFT); + + this_i2c_channel->ser_address = this_i2c->ser_address; + + HAL_set_8bit_reg_field(this_i2c_channel->base_address, ENS1, 0x00); /* Reset I2C channel hardware. */ + HAL_set_8bit_reg_field(this_i2c_channel->base_address, ENS1, 0x01); /* set enable bit */ + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR2, ( (clock_speed >> 2) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR1, ( (clock_speed >> 1) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR0, ( clock_speed & 0x01) ); + /* + * Finally safe to enable interrupts. + */ + HAL_restore_interrupts( saved_psr ); + } +} + +/*------------------------------------------------------------------------------ + * I2C_write() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_write +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * write_buffer, + uint16_t write_size, + uint8_t options +) +{ + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + saved_psr = HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_WRITE_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_WRITE_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + this_i2c->dir = WRITE_DIR; + this_i2c->master_tx_buffer = write_buffer; + this_i2c->master_tx_size = write_size; + this_i2c->master_tx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_read() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +) +{ + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + saved_psr = HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_READ_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_READ_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + + this_i2c->dir = READ_DIR; + + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_write_read() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_write_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * addr_offset, + uint16_t offset_size, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +) +{ + HAL_ASSERT(offset_size > 0u); + HAL_ASSERT(addr_offset != (uint8_t *)0); + HAL_ASSERT(read_size > 0u); + HAL_ASSERT(read_buffer != (uint8_t *)0); + + this_i2c->master_status = I2C_FAILED; + + if((read_size > 0u) && (offset_size > 0u)) + { + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + saved_psr = HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_RANDOM_READ_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_RANDOM_READ_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + + this_i2c->dir = WRITE_DIR; + + this_i2c->master_tx_buffer = addr_offset; + this_i2c->master_tx_size = offset_size; + this_i2c->master_tx_idx = 0u; + + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + + HAL_restore_interrupts( saved_psr ); + } +} + +/*------------------------------------------------------------------------------ + * I2C_get_status() + * See "core_i2c.h" for details of how to use this function. + */ +i2c_status_t I2C_get_status +( + i2c_instance_t * this_i2c +) +{ + i2c_status_t i2c_status ; + + i2c_status = this_i2c->master_status ; + + return i2c_status; +} + +/*------------------------------------------------------------------------------ + * I2C_wait_complete() + * See "core_i2c.h" for details of how to use this function. + */ +i2c_status_t I2C_wait_complete +( + i2c_instance_t * this_i2c, + uint32_t timeout_ms +) +{ + i2c_status_t i2c_status; + psr_t saved_psr; + /* + * Because we have no idea of what CPU we are supposed to be running on + * we need to guard this write to the timeout value to avoid ISR/user code + * interaction issues. Checking the status below should be fine as only a + * single byte should change in that. + */ + saved_psr = HAL_disable_interrupts(); + this_i2c->master_timeout_ms = timeout_ms; + HAL_restore_interrupts( saved_psr ); + + /* Run the loop until state returns I2C_FAILED or I2C_SUCESS*/ + do { + i2c_status = this_i2c->master_status; + } while(I2C_IN_PROGRESS == i2c_status); + return i2c_status; +} + +/*------------------------------------------------------------------------------ + * I2C_system_tick() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_system_tick +( + i2c_instance_t * this_i2c, + uint32_t ms_since_last_tick +) +{ + if(this_i2c->master_timeout_ms != I2C_NO_TIMEOUT) + { + if(this_i2c->master_timeout_ms > ms_since_last_tick) + { + this_i2c->master_timeout_ms -= ms_since_last_tick; + } + else + { + psr_t saved_psr; + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + /* + * Mark current transaction as having timed out. + */ + this_i2c->master_status = I2C_TIMED_OUT; + this_i2c->transaction = NO_TRANSACTION; + this_i2c->is_transaction_pending = 0; + + HAL_restore_interrupts( saved_psr ); + + /* + * Make sure we do not incorrectly signal a timeout for subsequent + * transactions. + */ + this_i2c->master_timeout_ms = I2C_NO_TIMEOUT; + } + } +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_tx_buffer() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_tx_buffer +( + i2c_instance_t * this_i2c, + const uint8_t * tx_buffer, + uint16_t tx_size +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + this_i2c->slave_tx_buffer = tx_buffer; + this_i2c->slave_tx_size = tx_size; + this_i2c->slave_tx_idx = 0u; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_rx_buffer() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_rx_buffer +( + i2c_instance_t * this_i2c, + uint8_t * rx_buffer, + uint16_t rx_size +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + this_i2c->slave_rx_buffer = rx_buffer; + this_i2c->slave_rx_size = rx_size; + this_i2c->slave_rx_idx = 0u; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_mem_offset_length() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_mem_offset_length +( + i2c_instance_t * this_i2c, + uint8_t offset_length +) +{ + HAL_ASSERT(offset_length <= MAX_OFFSET_LENGTH); + + /* + * Single byte update, should be interrupt safe + */ + if(offset_length > MAX_OFFSET_LENGTH) + { + this_i2c->slave_mem_offset_length = MAX_OFFSET_LENGTH; + } + else + { + this_i2c->slave_mem_offset_length = offset_length; + } +} + +/*------------------------------------------------------------------------------ + * I2C_register_write_handler() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_register_write_handler +( + i2c_instance_t * this_i2c, + i2c_slave_wr_handler_t handler +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + this_i2c->slave_write_handler = handler; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_enable_slave() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_enable_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register and slave mode flag without the I2C ISR interrupting + * us. + */ + saved_psr = HAL_disable_interrupts(); + + /* Set the Assert Acknowledge bit. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + /* Enable slave mode */ + this_i2c->is_slave_enabled = 1u; + + HAL_restore_interrupts( saved_psr ); + + /* Enable I2C IRQ*/ + I2C_enable_irq( this_i2c ); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_slave() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_disable_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + /* Reset the assert acknowledge bit. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + + /* Disable slave mode with IRQ blocked to make whole change atomic */ + this_i2c->is_slave_enabled = 0u; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * + */ +static void enable_slave_if_required +( + i2c_instance_t * this_i2c +) +{ + /* + * This function is only called from within the ISR and so does not need + * guarding on the register access. + */ + if( 0 != this_i2c->is_slave_enabled ) + { + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x01u ); + } +} +/*------------------------------------------------------------------------------ + * I2C_set_slave_second_addr() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_slave_second_addr +( + i2c_instance_t * this_i2c, + uint8_t second_slave_addr +) +{ + uint8_t second_slave_address; + + /* + This function does not support CoreI2C hardware configured with a fixed + second slave address. The current implementation of the ADDR1[0] register + bit makes it difficult for the driver to support both programmable and + fixed second slave address, so we choose to support programmable only. + With the programmable configuration, ADDR1[0] and ADDR0[0] both control + enable/disable of GCA recognition, as an effective OR of the 2 bit fields. + Therefore we set ADDR1[0] to 0 here, so that only ADDR0[0] controls GCA. + */ + second_slave_address = (uint8_t)((second_slave_addr << 1u) & (~SLAVE1_EN_MASK)); + + /* + * Single byte register write, should be interrupt safe + */ + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, second_slave_address); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_slave_second_addr() + * See "i2c.h" for details of how to use this function. + */ +void I2C_disable_slave_second_addr +( + i2c_instance_t * this_i2c +) +{ + /* + We are disabling the second slave address by setting the value of the 2nd + slave address to the primary slave address. The reason for using this method + of disabling 2nd slave address is that ADDRESS1[0] has different meaning + depending on hardware configuration. Its use would likely interfere with + the intended GCA setting. + */ + /* + * Single byte register write, should be interrupt safe + */ + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, this_i2c->ser_address); +} + +/*------------------------------------------------------------------------------ + * i2C_set_gca() + * See "i2c.h" for details of how to use this function. + */ + +void I2C_set_gca +( + i2c_instance_t * this_i2c +) +{ + /* + * This read modify write access should be interrupt safe as the address + * register is not written to in the ISR. + */ + /* accept GC addressing. */ + HAL_set_8bit_reg_field(this_i2c->base_address, GC, 0x01u); +} + +/*------------------------------------------------------------------------------ + * I2C_clear_gca() + * See "i2c.h" for details of how to use this function. + */ +void I2C_clear_gca +( + i2c_instance_t * this_i2c +) +{ + /* + * This read modify write access should be interrupt safe as the address + * register is not written to in the ISR. + */ + /* Clear GC addressing. */ + HAL_set_8bit_reg_field(this_i2c->base_address, GC, 0x00u); +} + +/*------------------------------------------------------------------------------ + * I2C_isr() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_isr +( + i2c_instance_t * this_i2c +) +{ + volatile uint8_t status; + uint8_t data; + uint8_t hold_bus; + uint8_t clear_irq = 1u; + + status = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + + switch( status ) + { + /************** MASTER TRANSMITTER / RECEIVER *******************/ + + case ST_START: /* start has been xmt'd */ + case ST_RESTART: /* repeated start has been xmt'd */ + HAL_set_8bit_reg_field( this_i2c->base_address, STA, 0x00u); + HAL_set_8bit_reg( this_i2c->base_address, DATA, this_i2c->target_addr); /* write call address */ + HAL_set_8bit_reg_field( this_i2c->base_address, DIR, this_i2c->dir); /* set direction bit */ + if(this_i2c->dir == WRITE_DIR) + { + this_i2c->master_tx_idx = 0u; + } + else + { + this_i2c->master_rx_idx = 0u; + } + + /* + * Clear the pending transaction. This condition will be true if the slave + * has acquired the bus to carry out pending master transaction which + * it had received during its slave transmission or reception mode. + */ + if(this_i2c->is_transaction_pending) + { + this_i2c->is_transaction_pending = 0u; + } + + /* + * Make sure to update proper transaction after master START + * or RESTART + */ + if(this_i2c->transaction != this_i2c->pending_transaction) + { + this_i2c->transaction = this_i2c->pending_transaction; + } + break; + + case ST_LOST_ARB: + /* Set start bit. Let's keep trying! Don't give up! */ + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + break; + + case ST_STOP_TRANSMIT: + /* Stop has been transmitted. Do nothing */ + break; + + /******************* MASTER TRANSMITTER *************************/ + case ST_SLAW_NACK: + /* SLA+W has been transmitted; not ACK has been received - let's stop. */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_FAILED; + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + case ST_SLAW_ACK: + case ST_TX_DATA_ACK: + /* data byte has been xmt'd with ACK, time to send stop bit or repeated start. */ + if (this_i2c->master_tx_idx < this_i2c->master_tx_size) + { + HAL_set_8bit_reg(this_i2c->base_address, DATA, (uint_fast8_t)this_i2c->master_tx_buffer[this_i2c->master_tx_idx++]); + } + else if ( this_i2c->transaction == MASTER_RANDOM_READ_TRANSACTION ) + { + /* We are finished sending the address offset part of a random read transaction. + * It is is time to send a restart in order to change direction. */ + this_i2c->dir = READ_DIR; + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + else /* done sending. let's stop */ + { + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + hold_bus = this_i2c->options & I2C_HOLD_BUS; + + /* Store the information of current I2C bus status in the bus_status*/ + this_i2c->bus_status = hold_bus; + if ( hold_bus == 0u ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); /*xmt stop condition */ + enable_slave_if_required(this_i2c); + } + else + { + I2C_disable_irq( this_i2c ); + clear_irq = 0u; + } + this_i2c->master_status = I2C_SUCCESS; + } + break; + + case ST_TX_DATA_NACK: + /* data byte SENT, ACK to be received + * In fact, this means we've received a NACK (This may not be + * obvious, but if we've rec'd an ACK then we would be in state + * 0x28!) hence, let's send a stop bit + */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u);/* xmt stop condition */ + this_i2c->master_status = I2C_FAILED; + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + /********************* MASTER (or slave?) RECEIVER *************************/ + + /* STATUS codes 08H, 10H, 38H are all covered in MTX mode */ + case ST_SLAR_ACK: /* SLA+R tx'ed. */ + /* Let's make sure we ACK the first data byte received (set AA bit in CTRL) unless + * the next byte is the last byte of the read transaction. + */ + if(this_i2c->master_rx_size > 1u) + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + } + else if(1u == this_i2c->master_rx_size) + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + else /* this_i2c->master_rx_size == 0u */ + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_SUCCESS; + this_i2c->transaction = NO_TRANSACTION; + } + break; + + case ST_SLAR_NACK: /* SLA+R tx'ed; let's release the bus (send a stop condition) */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_FAILED; + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + case ST_RX_DATA_ACK: /* Data byte received, ACK returned */ + /* First, get the data */ + this_i2c->master_rx_buffer[this_i2c->master_rx_idx++] = HAL_get_8bit_reg(this_i2c->base_address, DATA); + if( this_i2c->master_rx_idx >= (this_i2c->master_rx_size - 1u)) + { + /* If we're at the second last byte, let's set AA to 0 so + * we return a NACK at the last byte. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + break; + + case ST_RX_DATA_NACK: /* Data byte received, NACK returned */ + /* Get the data, then send a stop condition */ + this_i2c->master_rx_buffer[this_i2c->master_rx_idx] = HAL_get_8bit_reg(this_i2c->base_address, DATA); + + hold_bus = this_i2c->options & I2C_HOLD_BUS; + + /* Store the information of current I2C bus status in the bus_status*/ + this_i2c->bus_status = hold_bus; + if ( hold_bus == 0u ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); /*xmt stop condition */ + + /* Bus is released, now we can start listening to bus, if it is slave */ + enable_slave_if_required(this_i2c); + } + else + { + I2C_disable_irq( this_i2c ); + clear_irq = 0u; + } + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + this_i2c->master_status = I2C_SUCCESS; + break; + + /******************** SLAVE RECEIVER **************************/ + case ST_GCA_NACK: /* NACK after, GCA addressing */ + case ST_SLA_NACK: /* Re-enable AA (assert ack) bit for future transmissions */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + this_i2c->transaction = NO_TRANSACTION; + this_i2c->slave_status = I2C_SUCCESS; + + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + break; + + case ST_GCA_LA: /* Arbitr. lost (GCA rec'd) */ + case ST_SLV_LA: /* Arbitr. lost (SLA rec'd) */ + /* + * We lost arbitration and either the GCE or our address was the + * one received so pend the master operation we were starting. + */ + this_i2c->is_transaction_pending = 1u; + /* Fall through to normal ST processing as we are now in slave mode */ + + case ST_GCA: /* General call address received, ACK returned */ + case ST_SLAVE_SLAW: /* SLA+W received, ACK returned */ + this_i2c->transaction = WRITE_SLAVE_TRANSACTION; + this_i2c->slave_rx_idx = 0u; + this_i2c->random_read_addr = 0u; + /* + * If Start Bit is set clear it, but store that information since it is because of + * pending transaction + */ + if(HAL_get_8bit_reg_field(this_i2c->base_address, STA)) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + this_i2c->is_transaction_pending = 1u; + } + this_i2c->slave_status = I2C_IN_PROGRESS; +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + /* Fall through to put address as first byte in payload buffer */ +#else + /* Only break from this case if the slave address must NOT be included at the + * beginning of the received write data. */ + break; +#endif + case ST_GCA_ACK: /* DATA received; ACK sent after GCA */ + case ST_RDATA: /* DATA received; must clear DATA register */ + if((this_i2c->slave_rx_buffer != (uint8_t *)0) + && (this_i2c->slave_rx_idx < this_i2c->slave_rx_size)) + { + data = HAL_get_8bit_reg(this_i2c->base_address, DATA); + this_i2c->slave_rx_buffer[this_i2c->slave_rx_idx++] = data; + +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + if((ST_RDATA == status) || (ST_GCA_ACK == status)) + { + /* Ignore the slave address byte in the random read address + computation in the case where INCLUDE_SLA_IN_RX_PAYLOAD + is defined. */ +#endif + this_i2c->random_read_addr = (this_i2c->random_read_addr << 8) + data; +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + } +#endif + } + + if(this_i2c->slave_rx_idx >= this_i2c->slave_rx_size) + { + /* Rx buffer is full. NACK next received byte. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + break; + + case ST_RSTOP: + /* STOP or repeated START occurred. */ + /* We cannot be sure if the transaction has actually completed as + * this hardware state reports that either a STOP or repeated START + * condition has occurred. We assume that this is a repeated START + * if the transaction was a write from the master to this point.*/ + if ( this_i2c->transaction == WRITE_SLAVE_TRANSACTION ) + { + if ( this_i2c->slave_rx_idx == this_i2c->slave_mem_offset_length ) + { + this_i2c->slave_tx_idx = this_i2c->random_read_addr; + } + /* Call the slave's write transaction handler if it exists. */ + if ( this_i2c->slave_write_handler != 0u ) + { + i2c_slave_handler_ret_t h_ret; + h_ret = this_i2c->slave_write_handler( this_i2c, this_i2c->slave_rx_buffer, (uint16_t)this_i2c->slave_rx_idx ); + if ( I2C_REENABLE_SLAVE_RX == h_ret ) + { + /* There is a small risk that the write handler could + * call I2C_disable_slave() but return + * I2C_REENABLE_SLAVE_RX in error so we only enable + * ACKs if still in slave mode. */ + enable_slave_if_required(this_i2c); + } + else + { + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x0u ); + /* Clear slave mode flag as well otherwise in mixed + * master/slave applications, the AA bit will get set by + * subsequent master operations. */ + this_i2c->is_slave_enabled = 0u; + } + } + else + { + /* Re-enable address acknowledge in case we were ready to nack the next received byte. */ + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x01u ); + } + } + else /* A stop or repeated start outside a write/read operation */ + { + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * See if we need to re-enable acknowledgement as some error conditions, such + * as a master prematurely ending a transfer, can see us get here with AA set + * to 0 which will disable slave operation if we are not careful. + */ + enable_slave_if_required(this_i2c); + } + + /* Mark any previous master write transaction as complete. */ + this_i2c->slave_status = I2C_SUCCESS; + + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + + break; + + case ST_SLV_RST: /* SMBUS ONLY: timeout state. must clear interrupt */ + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction. + */ + this_i2c->transaction = NO_TRANSACTION; + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * Clear status to I2C_FAILED only if there was an operation in progress. + */ + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->slave_status = I2C_FAILED; + } + + enable_slave_if_required(this_i2c); /* Make sure AA is set correctly */ + + break; + + /****************** SLAVE TRANSMITTER **************************/ + case ST_SLAVE_SLAR_ACK: /* SLA+R received, ACK returned */ + case ST_SLARW_LA: /* Arbitration lost, and: */ + case ST_RACK: /* Data tx'ed, ACK received */ + if ( status == ST_SLAVE_SLAR_ACK ) + { + this_i2c->transaction = READ_SLAVE_TRANSACTION; + this_i2c->random_read_addr = 0u; + this_i2c->slave_status = I2C_IN_PROGRESS; + /* If Start Bit is set clear it, but store that information since it is because of + * pending transaction + */ + if(HAL_get_8bit_reg_field(this_i2c->base_address, STA)) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + this_i2c->is_transaction_pending = 1u; + } + } + if (this_i2c->slave_tx_idx >= this_i2c->slave_tx_size) + { + /* Ensure 0xFF is returned to the master when the slave specifies + * an empty transmit buffer. */ + HAL_set_8bit_reg(this_i2c->base_address, DATA, 0xFFu); + } + else + { + /* Load the data the data byte to be sent to the master. */ + HAL_set_8bit_reg(this_i2c->base_address, DATA, (uint_fast8_t)this_i2c->slave_tx_buffer[this_i2c->slave_tx_idx++]); + } + /* Determine if this is the last data byte to send to the master. */ + if (this_i2c->slave_tx_idx >= this_i2c->slave_tx_size) /* last byte? */ + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + /* Next read transaction will result in slave's transmit buffer + * being sent from the first byte. */ + this_i2c->slave_tx_idx = 0u; + } + break; + + case ST_SLAVE_RNACK: /* Data byte has been transmitted; not-ACK has been received. */ + case ST_FINAL: /* Last Data byte tx'ed, ACK received */ + /* We assume that the transaction will be stopped by the master. + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. */ + this_i2c->slave_tx_idx = 0u; + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + /* Mark previous state as complete */ + this_i2c->slave_status = I2C_SUCCESS; + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + + break; + + /* Master Reset has been activated Wait 35 ms for interrupt to be set, + * clear interrupt and proceed to 0xF8 state. */ + case ST_RESET_ACTIVATED: + case ST_BUS_ERROR: /* Bus error during MST or selected slave modes */ + default: + /* Some undefined state has encountered. Clear Start bit to make + * sure, next good transaction happen */ + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction. + */ + this_i2c->transaction = NO_TRANSACTION; + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * Clear statuses to I2C_FAILED only if there was an operation in progress. + */ + if(I2C_IN_PROGRESS == this_i2c->master_status) + { + this_i2c->master_status = I2C_FAILED; + } + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->slave_status = I2C_FAILED; + } + + break; + } + + if ( clear_irq ) + { + /* clear interrupt. */ + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + /* Read the status register to ensure the last I2C registers write took place + * in a system built around a bus making use of posted writes. */ + status = HAL_get_8bit_reg( this_i2c->base_address, STATUS); +} + +/*------------------------------------------------------------------------------ + * I2C_smbus_init() + * See "i2c.h" for details of how to use this function. + */ + +/* + * SMBSUS_NO = 1 + * SMBALERT_NO = 1 + * SMBus enable = 1 + */ +#define INIT_AND_ENABLE_SMBUS 0x54u +void I2C_smbus_init +( + i2c_instance_t * this_i2c +) +{ + /* + * Single byte register write, should be interrupt safe + */ + /* Enable SMBUS */ + HAL_set_8bit_reg(this_i2c->base_address, SMBUS, INIT_AND_ENABLE_SMBUS); +} + +/*------------------------------------------------------------------------------ + * I2C_enable_smbus_irq() + * See "i2c.h" for details of how to use this function. + */ +void I2C_enable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + if ( irq_type & I2C_SMBALERT_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_IE, 0x01u); + } + if ( irq_type & I2C_SMBSUS_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_IE, 0x01u); + } + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_smbus_irq() + * See "i2c.h" for details of how to use this function. + */ +void I2C_disable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + if ( irq_type & I2C_SMBALERT_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_IE, 0x00u); + } + if (irq_type & I2C_SMBSUS_IRQ ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_IE, 0x00u); + } + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_suspend_smbus_slave() + * See "i2c.h" for details of how to use this function. + */ +void I2C_suspend_smbus_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_NO_CONTROL, 0x00u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_resume_smbus_slave() + * See "i2c.h" for details of how to use this function. + */ +void I2C_resume_smbus_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_NO_CONTROL, 0x01u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_reset_smbus() + * See "i2c.h" for details of how to use this function. + */ +void I2C_reset_smbus +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + HAL_set_8bit_reg_field(this_i2c->base_address, SMBUS_MST_RESET, 0x01u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_smbus_alert() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_smbus_alert +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_NO_CONTROL, 0x00u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_clear_smbus_alert() + * See "i2c.h" for details of how to use this function. + */ +void I2C_clear_smbus_alert +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_NO_CONTROL, 0x01u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_get_irq_status() + * See "i2c.h" for details of how to use this function. + */ +uint8_t I2C_get_irq_status +( + i2c_instance_t * this_i2c +) +{ + uint8_t status ; + uint8_t irq_type = I2C_NO_IRQ ; + + status = HAL_get_8bit_reg(this_i2c->base_address, SMBUS); + + if( status & (uint8_t)SMBALERT_NI_STATUS_MASK ) + { + irq_type |= I2C_SMBALERT_IRQ ; + } + + if( status & (uint8_t)SMBSUS_NI_STATUS_MASK ) + { + irq_type |= I2C_SMBSUS_IRQ ; + } + + status = HAL_get_8bit_reg(this_i2c->base_address, CONTROL); + + if( status & (uint8_t)SI_MASK ) + { + irq_type |= I2C_INTR_IRQ ; + } + return(irq_type); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_addr2() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_user_data +( + i2c_instance_t * this_i2c, + void * p_user_data +) +{ + this_i2c->p_user_data = p_user_data ; +} + +/*------------------------------------------------------------------------------ + * I2C_get_user_data() + * See "i2c.h" for details of how to use this function. + */ +void * I2C_get_user_data +( + i2c_instance_t * this_i2c +) +{ + return( this_i2c->p_user_data); +} + +#ifdef __cplusplus +} +#endif + diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h new file mode 100644 index 0000000..3891ce0 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h @@ -0,0 +1,2306 @@ +/***************************************************************************//** + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * CoreI2C software driver Application Programming Interface. + * This file contains defines and function declarations allowing to interface + * with the CoreI2C software driver. + * + */ +/*=========================================================================*//** + @mainpage CoreI2C Bare Metal Driver. + The CoreI2C bare metal software driver supports I2C master and slave + operations. + + ============================================================================== + Introduction + ============================================================================== + The CoreI2C driver provides a set of functions for controlling the Microchip + CoreI2C hardware IP. The driver supports up to 16 separate I2C channels per + CoreI2C instance, with common slave address settings shared between channels + on a device. + + Optional features of the CoreI2C allow it to operate with I2C based protocols + such as System Management Bus (SMBus), Power Management Bus (PMBus), and + Intelligent Platform Management Interface (IPMI). This driver provides support + for these features when enabled in the CoreI2C IP. + + The major features provided by CoreI2C driver: + - Provides support to configuring the I2C channels of each CoreI2C peripheral device. + - I2C master operations. + - I2C slave operations. + - SMBus related operations. + + This driver is used as part of a bare metal system where no operating + system is available. The driver gets adapted as a part of an operating system, + but the implementation of the adaptation layer between the driver and the operating + system's driver model is outside the scope of this driver. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + Your application software should configure the CoreI2C driver through + calls to the I2C_init() function for each CoreI2C instance in the + hardware design. The configuration parameters include the CoreI2C hardware + instance base address and other runtime parameters, such as the I2C serial + clock frequency and the I2C device address. + + Once channel 0 of a CoreI2C peripheral has been initialized by I2C_init(), + any additional channels present should be configured by calling + I2C_channel_init() for each of the remaining channels. + + Apart from the CoreI2C hardware instance base address, no CoreI2C hardware configuration + parameters are used by the driver. Hence, no additional configuration files are required + to use the driver. + + -------------------------------- + Interrupt Control + -------------------------------- + The CoreI2C driver has to enable and disable the generation of interrupts by + CoreI2C at various times when it is operating. This enabling and disabling of + interrupts must be done through the system’s interrupt controller. For that + reason, the method of controlling the CoreI2C interrupt is system specific + and it is necessary to customize the I2C_enable_irq() and I2C_disable_irq() + functions. These functions are available in the i2c_interrupt.c file. + The default implementation calls HAL_ASSERT(0) to indicate to the application + developer that a suitable implementations for these functions must be provided. + + The implementation of the I2C_enable_irq() function should permit interrupts + generated by a CoreI2C instance to interrupt the processor. The implementation + of the I2C_disable_irq() function should prevent interrupts generated by a + CoreI2C instance from interrupting the processor. See the provided example + projects for a working implementation of these functions. + + The I2C_register_write_handler() function registers a write handler + function with the CoreI2C driver that calls on completion of an I2C write + transaction by the CoreI2C slave. It is your responsibility to create and + register the implementation of this handler function that processes or + trigger the processing of the received data. + + The SMBSUS and SMBALERT interrupts are related to the SMBus interface and are + enabled and disabled through I2C_enable_smbus_irq() and + I2C_disable_smbus_irq() respectively. It is your responsibility to create + interrupt handler functions in your application to get the desired response + for the SMBus interrupts. + + Note: You must include the path to any application header files that are + included in the i2c_interrupt.c file, as an include path in your + project's compiler settings. The details of how to do this will depend + on your development software. + + -------------------------------- + SMBus Logic Options + -------------------------------- + SMBus related APIs does not have any effect if the "Generate SMBus Logic" + is not enabled in the CoreI2C hardware configuration. Following are API's + that does not give the desired results if SMBus Logic is disabled. + + - I2C_smbus_init() + - I2C_reset_smbus() + - I2C_enable_smbus_irq() + - I2C_disable_smbus_irq() + - I2C_suspend_smbus_slave() + - I2C_resume_smbus_slave() + - I2C_set_smsbus_alert() + - I2C_clear_smsbus_alert() + - I2C_get_irq_status() + + -------------------------------- + Fixed Baud Rate Values + -------------------------------- + The serial clock frequency parameter passed to the I2C_init() and + I2C_channel_init() functions may not have any effect if fixed values were + selected for Baud rate in the hardware configuration of CoreI2C. When fixed + values are selected for these baud rates, the driver cannot overwrite + the fixed values. + + ----------------------------------- + Fixed Slave Address Options Values + ----------------------------------- + The primary slave address parameter passed to the I2C_init() function and + secondary address value passed to the I2C_set_slave_second_addr() function, + may not have the desired effect if fixed values were selected for the slave 0 + address and slave 1 address respectively. Proper operation of this version of + the driver requires the slave addresses to be programmable. + + ============================================================================== + Theory of Operation + ============================================================================== + The CoreI2C software driver is designed to allow the control of multiple + instances of CoreI2C with one or more I2C channels. Each channel in an + instance of CoreI2C in the hardware design is associated with a single + instance of the i2c_instance_t structure in the software. You must allocate + memory for one unique i2c_instance_t structure instance for each channel of + each CoreI2C hardware instance. The contents of these data structures are + initialised by calling I2C_init() and if necessary I2C_channel_init(). + A pointer to the structure is passed to the subsequent driver functions in order + to identify the CoreI2C hardware instance and channel to perform the + requested operation. + + Note: Do not attempt to directly manipulate the contents of i2c_instance_t + structures. These structures are only intended to be modified by the driver + functions. + + The CoreI2C driver functions are grouped into the following categories: + - Initialization and configuration functions + - Interrupt control + - I2C slave addressing functions + - I2C master operations functions to handle write, read, and write-read + transactions + - I2C slave operations functions to handle write, read, and write-read + transactions + - Mixed master-slave operations + - SMBus interface configuration and control + + -------------------------------- + Initialization and Configuration + -------------------------------- + The CoreI2C device is first initialized by calling the I2C_init() + function. Since each CoreI2C peripheral supports up to 16 channels, an + additional function, I2C_channel_init(), is required to initialize the + remaining channels with their own data structures. + + I2C_init() function initializes channel 0 of a CoreI2C and the i2c_instance_t + for channel 0 acts as the basis for further channel initialization as the + hardware base address and I2C serial address are same across all the channels. + Ensure to call I2C_init() function before calling any other I2C driver function + calls. The I2C_init() call for each CoreI2C takes the I2C serial address assigned + to the I2C and the serial clock divider to generate its I2C clock as configuration + parameters. + + I2C_channel_init() function takes as input parameters a pointer to the CoreI2C + i2c_instance_t which has been initialized by calling the I2C_init() and a pointer + to a separate i2c_instance_t which represents this new channel. Another input + parameter which is required by this function is serial clock divider which generates + its I2C clock. + + -------------------------------- + Interrupt Control + -------------------------------- + The CoreI2C driver is interrupt driven and it uses each channels INT + interrupt to drive the state machine which is at the heart of the driver. + The application is responsible for providing the link between the interrupt + generating hardware and the CoreI2C interrupt handler and must ensure that + the I2C_isr() function is called with the correct i2c_instance_t structure + pointer for the CoreI2C channel initiating the interrupt. + + The driver enables and disables the generation of INT interrupts by CoreI2C + at various times when it is operating through the user supplied + I2C_enable_irq() and I2C_disable_irq() functions. + + The I2C_register_write_handler() function is used to register a write + handler function with the CoreI2C driver which is called on completion + of an I2C write transaction by the CoreI2C slave. It is the user + applications responsibility to create and register the implementation of + this handler function that processes or triggers the processing of the + received data. + + The other two interrupt sources in the CoreI2C are related to SMBus + operation and are enabled and disabled through I2C_enable_smbus_irq() and + I2C_disable_smbus_irq() respectively. Due to the application specific + nature of the response to SMBus interrupts, you must design interrupt + handler functions in the application to get the desired behaviour for + SMBus related interrupts. + + If enabled, the SMBA_INT signal from the CoreI2C is asserted if an + SMBALERT condition is signalled on the SMBALERT_NI input for the channel. + + If enabled, the SMBS_INT signal from the CoreI2C is asserted if an + SMBSUSPEND condition is signalled on the SMBSUS_NI input for the channel. + + ## I2C Slave Addressing Functions + A CoreI2C peripheral responds to the following three slave addresses: + - Slave address 0 - This is the primary slave address that accesses + a CoreI2C channel when it acts as a slave in + I2C transactions. You must configure the primary slave + address using I2C_init(). + + - Slave address 1 - This is the secondary slave address which might be + required in certain application specific scenarios. + The secondary slave address is configured by + I2C_set_slave_second_addr() and is disabled by + I2C_disable_slave_second_addr(). + + - General call address - A CoreI2C slave can be configured to respond to + a broadcast command by a master transmitting the + general call address of 0x00. Use the I2C_set_gca() + function to enable the slave to respond to the general + call address. If the CoreI2C slave is not required to + respond to the general call address, disable this + address by calling I2C_clear_gca(). + + Note: All channels on a CoreI2C instance share the same slave address logic. + This means that they cannot have separate slave addresses and rely on + the separate physical I2C bus connections to distinguish them. + + -------------------------------- + Transaction Types + -------------------------------- + The I2C driver is designed to handle three types of I2C transaction: + - Write transactions + - Read transactions + - Write-read transactions + + ## Write Transaction + The master I2C device initiates a write transaction by sending a START bit + as soon as the bus becomes free. The START bit is followed by the 7-bit + serial address of the target slave device followed by the read/write bit + indicating the direction of the transaction. The slave acknowledges the + receipt of it's address with an acknowledge bit. The master sends data one + byte at a time to the slave, which must acknowledge the receipt of each byte + for the next byte to be sent. The master sends a STOP bit to complete the + transaction. The slave can abort the transaction by replying with a + non-acknowledge bit instead of an acknowledge bit. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ## Read Transaction + The master I2C device initiates a read transaction by sending a START bit + as soon as the bus becomes free. The START bit is followed by the 7-bit + serial address of the target slave device followed by the read/write bit + indicating the direction of the transaction. The slave acknowledges the + receipt of it's slave address with an acknowledge bit. The slave sends + data one byte at a time to the master, which must acknowledge the receipt of + each byte for the next byte to be sent. The master sends a non-acknowledge + bit following the last byte it wishes to read followed by a STOP bit. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ## Write-Read Transaction + The write-read transaction is a combination of a write transaction + immediately followed by a read transaction. There is no STOP bit in between + the write and read phases of a write-read transaction. A repeated START + bit is sent between the write and read phases. + + Whilst the write handler is being executed, the slave holds the clock line + low to stretch the clock until the response is ready. + + The write-read transaction is typically used to send a command or offset + in the write transaction specifying the logical data to be transferred + during the read phase. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ## Master Operations + The application can use the I2C_write(), I2C_read(), and I2C_write_read() + functions to initiate an I2C bus transaction. The application can then wait + for the transaction to complete using the I2C_wait_complete() function + or poll the status of the I2C transaction using the I2C_get_status() + function until it returns a value different from I2C_IN_PROGRESS. The + I2C_system_tick() function is used to set a time base for the + I2C_wait_complete() function's time out delay. + + ## Slave Operations + To configure the I2C driver to operate as an I2C slave requires the use + of the following functions: + - I2C_set_slave_tx_buffer() + - I2C_set_slave_rx_buffer() + - I2C_set_slave_mem_offset_length() + - I2C_register_write_handler() + - I2C_enable_slave() + + Use of all functions is not required if the slave I2C does not need to support + all types of I2C read transactions. The subsequent sections list the functions + that must be used to support each transaction type. + + ## Responding to Read Transactions + The following functions are used to configure the CoreI2C driver to + respond to I2C read transactions: + • I2C_set_slave_tx_buffer() + • I2C_enable_slave() + + The I2C_set_slave_tx_buffer() function specifies the data buffer that + is transmitted when the I2C slave is the target of an I2C read + transaction. It is then up to the application to manage the content of + that buffer to control the data that will be transmitted to the I2C + master as a result of the read transaction. + + The I2C_enable_slave() function enables the I2C hardware instance + to respond to the I2C transactions. It must be called after the I2C driver + has been configured to respond to the required transaction types. + + ## Responding to Write Transactions + The following functions are used to configure the I2C driver to respond + to I2C write transactions: + • I2C_set_slave_rx_buffer() + • I2C_register_write_handler() + • I2C_enable_slave() + + The I2C_set_slave_rx_buffer() function specifies the data buffer that + stored the data received by the I2C slave when it targets an I2C write + transaction. + + The I2C_register_write_handler() function specifies the handler function + that must be called on completion of the I2C write transaction. It is this + handler function that processes or triggers the processing of the received + data. + + The I2C_enable_slave() function enables the I2C hardware instance + to respond to I2C transactions. It must be called after the I2C driver + has been configured to respond to the required transaction types. + + ## Responding to Write-Read Transactions + The following functions are used to configure the CoreI2C driver to + respond to write-read transactions: + - I2C_set_slave_mem_offset_length() + - I2C_set_slave_tx_buffer() + - I2C_set_slave_rx_buffer() + - I2C_register_write_handler() + - I2C_enable_slave() + + The I2C_set_slave_mem_offset_length() function specifies the number of + bytes expected by the I2C slave during the write phase of the write-read + transaction. + + The I2C_set_slave_tx_buffer() function specifies the data that is + transmitted to the I2C master during the read phase of the write-read + transaction. The value received by the I2C slave during the write phase of + the transaction will be used as an index into the transmit buffer + specified by this function. It decides which part of the transmit buffer + will be transmitted to the I2C master as part of the read phase of the + write-read transaction. + + The I2C_set_slave_rx_buffer() function specifies the data buffer that + stores the data received by the I2C slave during the write phase of + the write-read transaction. This buffer must be large enough to accommodate + the number of bytes specified through the I2C_set_slave_mem_offset_length() + function. + + The I2C_register_write_handler() function can optionally be used to + specify a handler function that is called on completion of the write phase + of the I2C write-read transaction. If a handler function is registered, it + is responsible for processing the received data in the slave receive + buffer and populating the slave transmit buffer with the data that will be + transmitted to the I2C master as part of the read phase of the write-read + transaction. + + The I2C_enable_slave() function enables the CoreI2C hardware instance to + respond to the I2C transactions. It must be called after configuring the + CoreI2C driver to respond to the required transaction types. + + ## Mixed Master-Slave Operations + The CoreI2C device supports mixed master and slave operations. If the + CoreI2C slave has a transaction in progress and your application attempts to + begin a master mode transaction, the CoreI2C driver queues the master mode + transaction until the bus is released and the CoreI2C can switch to master + mode and acquire the bus. The CoreI2C master then starts the previously + queued master transaction. + + ## SMBus Control + The CoreI2C driver enables the CoreI2C peripheral’s SMBus functionality + using the I2C_smbus_init() function. + + The I2C_suspend_smbus_slave() function is used with a master mode CoreI2C + to force slave devices on the SMBus to enter their Power-Down/Suspend mode. + The I2C_resume_smbus_slave() function is used to end the suspend operation + on the SMBus. + + The I2C_reset_smbus() function is used with a master mode CoreI2C to force + all devices on the SMBus to reset their SMBUs interface. + + The I2C_set_smsbus_alert() function is used by a slave mode CoreI2C to + force communication with the SMBus master. Once communications with the + master is initiated, the I2C_clear_smsbus_alert() function clears the alert + condition. + + The I2C_enable_smbus_irq() and I2C_disable_smbus_irq() functions are used to + enable and disable the SMBSUS and SMBALERT SMBus interrupts. + + *//*=========================================================================*/ + +#ifndef CORE_I2C_H_ +#define CORE_I2C_H_ + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#include "hal_assert.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + I2C_RELEASE_BUS + ======================================= + The I2C_RELEASE_BUS constant is used to specify the options parameter to + functions I2C_read(), I2C_write() and I2C_write_read() to indicate + that a STOP bit must be generated at the end of the I2C transaction to release + the bus. + */ +#define I2C_RELEASE_BUS 0x00u + +/*-------------------------------------------------------------------------*//** + I2C_HOLD_BUS + ======================================= + The I2C_HOLD_BUS constant specify the options parameter to functions I2C_read(), + I2C_write(), and I2C_write_read() to indicate that a STOP bit must not be + generated at the end of the I2C transaction in order to retain the bus ownership. + This causes the next transaction to begin with a repeated START bit and no STOP + bit between the transactions. + */ +#define I2C_HOLD_BUS 0x01u + +/*-------------------------------------------------------------------------*//** + Interrupt Identifier Number + ======================================= + The following constants specify the interrupt identifier number which is + solely used by the driver API. This has nothing to do with hardware interrupt + line. I2C_INTR_IRQ is the primary interrupt signal which drives the state machine + of the CoreI2C driver. The I2C_SMBALERT_IRQ and I2C_SMBSUS_IRQ are used by + SMBus interrupt enable and disable functions. These IRQ numbers are also used + by I2C_get_irq_status(). + + | Constant | Description | + |--------------------|--------------------------------------------------------| + | I2C_NO_IRQ | No interrupt | + | I2C_SMBALERT_IRQ | Used by SMBus interrupt enable functions | + | I2C_SMBSUS_IRQ | Used by SMBus interrupt disable functions | + | I2C_INTR_IRQ | Primary interrupt signal which drives the state machine| + + */ +#define I2C_NO_IRQ 0x00u +#define I2C_SMBALERT_IRQ 0x01u +#define I2C_SMBSUS_IRQ 0x02u +#define I2C_INTR_IRQ 0x04u + +/*-------------------------------------------------------------------------*//** + I2C_NO_TIMEOUT + ======================================= + The I2C_wait_complete() function uses I2C_NO_TIMEOUT constant as a parameter + to indicate that the wait for completion of the transaction should not time out. + */ +#define I2C_NO_TIMEOUT 0u + +/***************************************************************************//** + The i2c_channel_number_t type is used to specify the channel number of a + CoreI2C instance. + */ +typedef enum i2c_channel_number { + I2C_CHANNEL_0 = 0u, + I2C_CHANNEL_1, + I2C_CHANNEL_2, + I2C_CHANNEL_3, + I2C_CHANNEL_4, + I2C_CHANNEL_5, + I2C_CHANNEL_6, + I2C_CHANNEL_7, + I2C_CHANNEL_8, + I2C_CHANNEL_9, + I2C_CHANNEL_10, + I2C_CHANNEL_11, + I2C_CHANNEL_12, + I2C_CHANNEL_13, + I2C_CHANNEL_14, + I2C_CHANNEL_15, + I2C_MAX_CHANNELS = 16u +} i2c_channel_number_t; + +/***************************************************************************//** + The i2c_clock_divider_t type specifies the divider to be applied + to the I2C PCLK or BCLK signal in order to generate the I2C clock. + The I2C_BCLK_DIV_8 value selects a clock frequency based on division of BCLK, + all other values select a clock frequency based on division of PCLK. + */ +typedef enum i2c_clock_divider { + I2C_PCLK_DIV_256 = 0u, + I2C_PCLK_DIV_224, + I2C_PCLK_DIV_192, + I2C_PCLK_DIV_160, + I2C_PCLK_DIV_960, + I2C_PCLK_DIV_120, + I2C_PCLK_DIV_60, + I2C_BCLK_DIV_8 +} i2c_clock_divider_t; + +/***************************************************************************//** + The i2c_status_t type is used to report the status of I2C transactions. + */ +typedef enum i2c_status +{ + I2C_SUCCESS = 0u, + I2C_IN_PROGRESS, + I2C_FAILED, + I2C_TIMED_OUT +} i2c_status_t; + +/***************************************************************************//** + The i2c_slave_handler_ret_t type is used by slave write handler functions + to indicate whether or not the received data buffer should be released. + */ +typedef enum i2c_slave_handler_ret { + I2C_REENABLE_SLAVE_RX = 0u, + I2C_PAUSE_SLAVE_RX = 1u +} i2c_slave_handler_ret_t; + +/***************************************************************************//** + This structure identifies various CoreI2C hardware instances in the system + and the I2C channels within them. The application software should declare + one instance of this structure for each channel of each instance of CoreI2C + in your system. I2C_init() and I2C_channel_init() functions initialize this + structure depending on whether it is channel 0 or one of the additional + channels, respectively. A pointer to an initialized instance of the + structure should be passed as the first parameter to the CoreI2C driver + functions, to identify which CoreI2C hardware instance and channel should + perform the requested operation. + + The contents of this data structure should not be modified or used outside of + the CoreI2C driver. Software using the CoreI2C driver should only need to + create one single instance of this data structure for each channel of each + CoreI2C hardware instance in the system then pass a pointer to these data + structures with each call to the CoreI2C driver in order to identify which + CoreI2C hardware instance to use. + */ +typedef struct i2c_instance i2c_instance_t ; +/***************************************************************************//* + Slave write handler functions prototype +/***************************************************************************//** + This defines the function prototype that must be followed by I2C slave write + handler functions. These functions are registered with the CoreI2C driver + through the I2C_register_write_handler() function. + + Declaring and Implementing Slave Write Handler Functions: + + Slave write handler functions should follow the following prototype: + @code + i2c_slave_handler_ret_t write_handler + ( + i2c_instance_t *instance, uint8_t * data, uint16_t size + ); + @endcode + + The instance parameter is a pointer to the i2c_instance_t for which this + slave write handler has been declared. + + The data parameter is a pointer to a buffer (received data buffer) holding + the data written to the I2C slave. + + Define the INCLUDE_SLA_IN_RX_PAYLOAD macro for the driver to insert the + actual address used to access the slave as the first byte in the buffer. + This allows the applications to tailor their response based on the actual + address used to access the slave (primary address, secondary address, or GCA). + + The size parameter is the number of bytes held in the received data buffer. + Handler functions must return one of the following values: + - I2C_REENABLE_SLAVE_RX + - I2C_PAUSE_SLAVE_RX + + If the handler function returns I2C_REENABLE_SLAVE_RX, the driver releases + the received data buffer and allows further I2C write transactions to the + I2C slave. + + If the handler function returns I2C_PAUSE_SLAVE_RX, the I2C slave responds + to subsequent write requests with a non-acknowledge bit (NACK), until the + received data buffer content gets processed by some other part of the + software application. + + Call the I2C_enable_slave() after returning the I2C_PAUSE_SLAVE_RX to release + the received data buffer in order to store the data received by the subsequent + I2C write transactions. + */ +typedef i2c_slave_handler_ret_t (*i2c_slave_wr_handler_t)(i2c_instance_t *instance, uint8_t *, uint16_t ); + +/***************************************************************************//** + This structure is used to identify the various CoreI2C hardware instances in + your system and the I2C channels within them. Your application software should + declare one instance of this structure for each channel of each instance of + CoreI2C in your system. The functions I2C_init() and I2C_channel_init() + initialize this structure depending on whether it is channel 0 or one of the + additional channels respectively. A pointer to an initialized instance of the + structure should be passed as the first parameter to the CoreI2C driver + functions, to identify which CoreI2C hardware instance and channel should + perform the requested operation. + + The contents of this data structure should not be modified or used outside of + the CoreI2C driver. Software using the CoreI2C driver should only need to + create one single instance of this data structure for each channel of each + CoreI2C hardware instance in the system then pass a pointer to these data + structures with each call to the CoreI2C driver in order to identify the + CoreI2C hardware instance it wishes to use. + */ +struct i2c_instance +{ + addr_t base_address; + uint_fast8_t ser_address; + + /* Transmit related info:*/ + uint_fast8_t target_addr; + + /* Current transaction type (WRITE, READ, RANDOM_READ)*/ + uint8_t transaction; + + uint_fast16_t random_read_addr; + + uint8_t options; + + /* Master TX INFO: */ + const uint8_t * master_tx_buffer; + uint_fast16_t master_tx_size; + uint_fast16_t master_tx_idx; + uint_fast8_t dir; + + /* Master RX INFO: */ + uint8_t * master_rx_buffer; + uint_fast16_t master_rx_size; + uint_fast16_t master_rx_idx; + + /* Master Status */ + volatile i2c_status_t master_status; + uint32_t master_timeout_ms; + + /* Slave TX INFO */ + const uint8_t * slave_tx_buffer; + uint_fast16_t slave_tx_size; + uint_fast16_t slave_tx_idx; + + /* Slave RX INFO */ + uint8_t * slave_rx_buffer; + uint_fast16_t slave_rx_size; + uint_fast16_t slave_rx_idx; + /* Slave Status */ + volatile i2c_status_t slave_status; + + /* Slave data: */ + uint_fast8_t slave_mem_offset_length; + i2c_slave_wr_handler_t slave_write_handler; + uint8_t is_slave_enabled; + + /* user specific data */ + void *p_user_data ; + + /* I2C bus status */ + uint8_t bus_status; + + /* Is transaction pending flag */ + uint8_t is_transaction_pending; + + /* I2C Pending transaction */ + uint8_t pending_transaction; +}; + +/*------------------------Public Function-------------------------------------*/ + +/***************************************************************************//** + The I2C_init() function configures channel 0 of a CoreI2C instance. It sets + the base hardware address which is used to locate the CoreI2C instance + in memory and also used internally by I2C_channel_init() to calculate the + register addresses for any additional channels. The slave serial address set + is shared by all channels on a CoreI2C instance. + + If only one channel is configured in a CoreI2C, the address of the + i2c_instance_t used in I2C_Init() will also be used in subsequent calls to the + CoreI2C driver functions. If more than one channel is configured in the + CoreI2C, I2C_channel_init() will be called after I2C_init(), which initializes + the i2c_instance_t data structure for a specific channel. + + @param this_i2c + Pointer to the i2c_instance_t data structure that holds all the data + related to channel 0 of the CoreI2C instance is initialized. A pointer + to this structure is used in all subsequent calls to the CoreI2C driver + functions which operates on channel 0 of this CoreI2C instance. + + @param base_address + Base address in the processor's memory map of the registers of the CoreI2C + instance being initialized. + + @param ser_address + This parameter sets the primary I2C serial address (SLAVE0 address) for the + CoreI2C to initialize. It is the principal I2C bus address to which the + CoreI2C instance will respond. CoreI2C can operate in master mode or slave + mode and the serial address is significant only in the case of I2C slave + mode. In master mode, CoreI2C does not require a serial address and the + value of this parameter is not important. If you do not intend to use the + CoreI2C device in slave mode, then provide any dummy slave address value + to this parameter. However, in systems where the CoreI2C is expected to + switch from master mode to slave mode, it is advisable to initialize the + CoreI2C device with a valid serial slave address. Call the I2C_init() + function whenever it is required to change the primary slave address as + there is no separate function to set the primary slave address of the + I2C device. The serial address initialized through this function is + basically the primary slave address or slave address0. + I2C_set_slave_second_addr() is used to set the secondary slave address + or slave address 1. + Note : ser_address parameter does not have any affect if fixed slave + address is enabled in CoreI2C hardware design. CoreI2C will + be always addressed with the hardware configured fixed slave + address. + Note : ser_address parameter will not have any affect if the CoreI2C + instance is only used in master mode. + + @param ser_clock_speed + This parameter sets the I2C serial clock frequency. It selects the divider + that generates the serial clock from the APB PCLK or from the BCLK. + It can be one of the following: + - I2C_PCLK_DIV_256 + - I2C_PCLK_DIV_224 + - I2C_PCLK_DIV_192 + - I2C_PCLK_DIV_160 + - I2C_PCLK_DIV_960 + - I2C_PCLK_DIV_120 + - I2C_PCLK_DIV_60 + - I2C_BCLK_DIV_8 + Note: serial_clock_speed value does not have any affect if the fixed baud + rate is enabled in CoreI2C hardware instance configuration dialogue + window. The fixed baud rate divider value overrides the value passed + as parameter in this function. + Note: serial_clock_speed value is not critical for devices that only operate + as slaves and can be set to any of the above values. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void system_init( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + } + @endcode + */ +void I2C_init +( + i2c_instance_t * this_i2c, + addr_t base_address, + uint8_t ser_address, + i2c_clock_divider_t ser_clock_speed +); + +/***************************************************************************//** + The I2C_channel_init() function initializes and configures hardware and data + structures of one of the additional channels of a CoreI2C instance. + I2C_init() must be called before calling this function to set the CoreI2C + instance hardware base address and I2C serial address. I2C_channel_init() also + initializes I2C serial clock divider to set the serial clock baud rate. + The pointer to data structure i2c_instance_t used for a particular channel + is used as an input parameter to subsequent CoreI2C driver functions + which operate on this channel. + + @param this_i2c_channel + Pointer to the i2c_instance_t data structure that holds all data related to + the CoreI2C channel gets initialized. A pointer to the same data structure + is used in subsequent calls to the CoreI2C driver functions in order to + identify the CoreI2C channel instance that should perform the operation + implemented by the called driver function. + + @param this_i2c + This is a pointer to an i2c_instance_t structure, previously initialized by + I2C_init(). It holds information regarding the hardware base address and + I2C serial address for the CoreI2C containing the channel to be + initialized. This information is required by I2C_channel_init() to + initialize the i2c_instance_t structure pointed by this_i2c_channel as + all channels in a CoreI2C instance share the same base address and serial + address. It is very important that the i2c_instance_t structure pointed + by this_i2c must be previously initialized by calling I2C_init(). + + @param channel_number + This parameter of type i2c_channel_number_t identifies the channel to be + initialized. + + @param ser_clock_speed + This parameter sets the I2C serial clock frequency. It selects the divider + that is used to generate the serial clock from the APB PCLK or from + the BCLK. It can be one of the following: + - I2C_PCLK_DIV_256 + - I2C_PCLK_DIV_224 + - I2C_PCLK_DIV_192 + - I2C_PCLK_DIV_160 + - I2C_PCLK_DIV_960 + - I2C_PCLK_DIV_120 + - I2C_PCLK_DIV_60 + - I2C_BCLK_DIV_8 + Note: serial_clock_speed value does not have any affect if the fixed baud + rate is enabled in CoreI2C hardware instance configuration dialogue + window. The fixed baud rate divider value will supersede the value + passed as parameter in this function. + Note: ser_clock_speed value is not critical for devices that only operate + as slaves and can be set to any of the above values. + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_SER_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + i2c_instance_t g_i2c_channel_1_inst; + + uint8_t tx_buffer[DATA_LENGTH]; + uint8_t write_length = DATA_LENGTH; + + void system_init( void ) + { + uint8_t target_slave_addr = 0x12; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize CoreI2C channel 1 with different clock speed + I2C_channel_init( &g_i2c_channel_1_inst, &g_i2c_inst, I2C_CHANNEL_1, + I2C_PCLK_DIV_224 ); + + // Write data to Channel 1 of CoreI2C instance. + I2C_write( &g_i2c_channel_1_inst, target_slave_addr, tx_buffer, + write_length, I2C_RELEASE_BUS ); + } + @endcode + +*/ +void I2C_channel_init +( + i2c_instance_t * this_i2c_channel, + i2c_instance_t * this_i2c, + i2c_channel_number_t channel_number, + i2c_clock_divider_t ser_clock_speed +); + +/***************************************************************************//** + The I2C_isr function is the CoreI2C interrupt service routine. User must + call this function from their application level CoreI2C interrupt handler + function. This function runs the I2C state machine based on previous and + current status. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREINTERRUPT_BASE_ADDR 0xCC000000u + #define COREI2C_SER_ADDR 0x10u + #define I2C_IRQ_NB 2u + + i2c_instance_t g_i2c_inst; + + void core_i2c_isr( void ) + { + I2C_isr( &g_i2c_inst ); + } + + void main( void ) + { + CIC_init( COREINTERRUPT_BASE_ADDR ); + NVIC_init(); + CIC_set_irq_handler( I2C_IRQ_NB, core_i2c_isr ); + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + NVIC_enable_interrupt( NVIC_IRQ_0 ); + } + @endcode + */ +void I2C_isr +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//* + #Master Specific Functions + + The following functions are only used within an I2C master's implementation. +/***************************************************************************//** + This function initiates an I2C master write transaction. This function returns + immediately after initiating the transaction. The content of the write buffer + passed as parameter should not be modified until the write transaction + completes. It also means that the memory allocated for the write buffer should + not be freed or should not go out of scope before the write completes. You can + check for the write transaction completion using the I2C_status() function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr + This parameter specifies the serial address of the target I2C device. + + @param write_buffer + This parameter is a pointer to a buffer holding the data to be written to + the target I2C device. Do not to release the memory used by this buffer + before the write transaction completes. For example, it is not appropriate + to return from a function allocating this buffer as an auto array variable + before the write transaction completes as this would result in the buffer's + memory being de-allocated from the stack when the function returns. This + memory could then be subsequently reused and modified causing unexpected + data to be written to the target I2C device. + + @param write_size + Number of bytes held in the write_buffer to be written to the target I2C + device. + + @param options + The options parameter is used to indicate if the I2C bus should be released + on completion of the write transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the write transaction causing the bus to be released for other I2C + devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the write + transaction, preventing other I2C devices from initiating a bus transaction. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t tx_buffer[DATA_LENGTH]; + uint8_t write_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Write data to Channel 0 of CoreI2C instance. + I2C_write( &g_i2c_inst, target_slave_addr, tx_buffer, write_length, + I2C_RELEASE_BUS ); + + // Wait for completion and record the outcome + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_write +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * write_buffer, + uint16_t write_size, + uint8_t options +); + +/***************************************************************************//** + This function initiates an I2C master read transaction. This function returns + immediately after initiating the transaction. + The contents of the read buffer passed as parameter should not be modified + until the read transaction completes. It also means that the memory allocated + for the read buffer should not be freed or should not go out of scope before + the read completes. You can check for the read transaction completion using + the I2C_status() function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr + This parameter specifies the serial address of the target I2C device. + + @param read_buffer + This is a pointer to a buffer where the data received from the target device + gets stored. Do not to release the memory used by this buffer before the read + transaction completes. For example, it is not appropriate to return from a + function allocating this buffer as an auto array variable before the read + transaction completes as this would result in the buffer's memory being + de-allocated from the stack when the function returns. This memory could + then be subsequently reallocated resulting in the read transaction + corrupting the newly allocated memory. + + @param read_size + This parameter specifies the number of bytes to read from the target device. + This size must not exceed the size of the read_buffer buffer. + + @param options + The options parameter is used to indicate if the I2C bus should be released + on completion of the read transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the read transaction causing the bus to be released for other I2C + devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the read transaction, + preventing other I2C devices from initiating a bus transaction. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t rx_buffer[DATA_LENGTH]; + uint8_t read_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Read data from target slave Channel 0 of CoreI2C instance. + I2C_read( &g_i2c_inst, target_slave_addr, rx_buffer, read_length, + I2C_RELEASE_BUS ); + + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +); + +/***************************************************************************//** + This function initiates an I2C write-read transaction where data is first + written to the target device before issuing a restart condition and changing + the direction of the I2C transaction in order to read from the target device. + + The same warnings about buffer allocation in I2C_write() and I2C_read() + applies to this function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr + This parameter specifies the serial address of the target I2C device. + + @param addr_offset + This parameter is a pointer to the buffer containing the data that is sent + to the slave during the write phase of the write-read transaction. This + data is typically used to specify an address offset specifying to the I2C + slave device what data it must return during the read phase of the + write-read transaction. + + @param offset_size + This parameter specifies the number of offset bytes to be written during the + write phase of the write-read transaction. This is typically the size of the + buffer pointed by the addr_offset parameter. + + @param read_buffer + This parameter is a pointer to the buffer where the data read from the I2C + slave will be stored. + + @param read_size + This parameter specifies the number of bytes to read from the target I2C + slave device. This size must not exceed the size of the buffer pointed by + the read_buffer parameter. + + @param options + The options parameter is used to indicate if the I2C bus should be released + on completion of the write-read transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the write-read transaction causing the bus to be released for other + I2C devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the write-read + transaction, preventing other I2C devices from initiating a bus transaction. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define TX_LENGTH 16u + #define RX_LENGTH 8u + + i2c_instance_t g_i2c_inst; + uint8_t rx_buffer[RX_LENGTH]; + uint8_t read_length = RX_LENGTH; + uint8_t tx_buffer[TX_LENGTH]; + uint8_t write_length = TX_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + I2C_write_read( &g_i2c_inst, target_slave_addr, tx_buffer, write_length, + rx_buffer, read_length, I2C_RELEASE_BUS ); + + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_write_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * addr_offset, + uint16_t offset_size, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +); + +/***************************************************************************//** + This function indicates the current state of a CoreI2C channel. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + The return value indicates the current state of a CoreI2C channel or the + outcome of the previous transaction if no transaction is in progress. + Following are the return values are: + - I2C_SUCCESS + The last I2C transaction has completed successfully. + - I2C_IN_PROGRESS + There is an I2C transaction in progress. + - I2C_FAILED + The last I2C transaction failed. + - I2C_TIMED_OUT + The request has failed to complete in the allotted time. + + @example + @code + i2c_instance_t g_i2c_inst; + + while( I2C_IN_PROGRESS == I2C_get_status( &g_i2c_inst ) ) + { + // Do something useful while waiting for I2C operation to complete + our_i2c_busy_task(); + } + + if( I2C_SUCCESS != I2C_get_status( &g_i2c_inst ) ) + { + // Something went wrong... + our_i2c_error_recovery( &g_i2c_inst ); + } + @endcode + */ +i2c_status_t I2C_get_status +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + This function waits for the current I2C transaction to complete. The return + value indicates whether the last I2C transaction was successful or not. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + @param timeout_ms + The timeout_ms parameter specifies the delay within which the current I2C + transaction should complete. The time out delay is given in + milliseconds. I2C_wait_complete() will return I2C_TIMED_OUT if the current + transaction has not completed after the time out delay has expired. This + parameter can be set to I2C_NO_TIMEOUT to indicate that I2C_wait_complete() + must not time out. + + @return + The return value indicates the outcome of the last I2C transaction. It can + be one of the following: + - I2C_SUCCESS + The last I2C transaction has completed successfully. + - I2C_FAILED + The last I2C transaction failed. + - I2C_TIMED_OUT + The last transaction failed to complete within the time out delay given + as second parameter. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t rx_buffer[DATA_LENGTH]; + uint8_t read_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Read data from Channel 0 of CoreI2C instance. + I2C_read( &g_i2c_inst, target_slave_addr, rx_buffer, read_length, + I2C_RELEASE_BUS ); + + // Wait for completion and record the outcome + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +i2c_status_t I2C_wait_complete +( + i2c_instance_t * this_i2c, + uint32_t timeout_ms +); + +/***************************************************************************//** + This function is used to control the expiration of the time out delay + specified as a parameter to the I2C_wait_complete() function. It must be + called from the interrupt service routine of a periodic interrupt source such + as the SysTick timer interrupt. It takes the period of the interrupt + source as its ms_since_last_tick parameter and uses it as the time base for + the I2C_wait_complete() function's time out delay. + + Note: This function does not need to be called if the I2C_wait_complete() + function is called with a timeout_ms value of I2C_NO_TIMEOUT. + + Note: If this function is not called then the I2C_wait_complete() function + will behave as if its timeout_ms was specified as I2C_NO_TIMEOUT and it + will not time out. + + Note: If this function is being called from an interrupt handler (for example, + SysTick) it is important that the calling interrupt have a lower priority + than the CoreI2C interrupt(s) to ensure any updates to the shared data are + protected. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + @param ms_since_last_tick + The ms_since_last_tick parameter specifies the number of milliseconds that + elapsed since the last call to I2C_system_tick(). This parameter would + typically be a constant specifying the interrupt rate of a timer used to + generate system ticks. + + @return None. + + @example + The following example shows how the I2C_system_tick() function. I2C_system_tick() + is called for each I2C channel from the SysTick timer interrupt service routine. + The following example shows how the SysTick is configured to generate an interrupt + in every 10 milliseconds. + @code + #define SYSTICK_INTERVAL_MS 10 + + void SysTick_Handler(void) + { + I2C_system_tick(&g_core_i2c0, SYSTICK_INTERVAL_MS); + I2C_system_tick(&g_core_i2c2, SYSTICK_INTERVAL_MS); + } + @endcode + */ +void I2C_system_tick +( + i2c_instance_t * this_i2c, + uint32_t ms_since_last_tick +); + +/***************************************************************************//* + #Slave Specific Functions + + The following functions are only used within the implementation of an I2C slave device. + +/***************************************************************************//** + This function specifies the memory buffer holding the data that will be sent + to the I2C master when this CoreI2C channel is the target of an I2C read or + write-read transaction. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param tx_buffer + This parameter is a pointer to the memory buffer holding the data to be + returned to the I2C master when this CoreI2C channel is the target of an + I2C read or write-read transaction. + + @param tx_size + Size of the transmit buffer pointed by the tx_buffer parameter. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Specify the transmit buffer containing the data that will be + // returned to the master during read and write-read transactions. + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + } + @endcode + */ +void I2C_set_slave_tx_buffer +( + i2c_instance_t * this_i2c, + const uint8_t * tx_buffer, + uint16_t tx_size +); + +/***************************************************************************//** + This function specifies the memory buffer that is used by the CoreI2C channel + to receive data when it is a slave. This buffer is the memory where data gets + stored when the CoreI2C channel is the target of an I2C master write + transaction (that is, when it is the slave). + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param rx_buffer + This parameter is a pointer to the memory buffer allocated by the caller + software to be used as a slave receive buffer. + + @param rx_size + Size of the slave receive buffer. This is the amount of memory allocated + to the buffer pointed by rx_buffer. + Note: Indirectly, this buffer size specifies the maximum I2C write + transaction length this CoreI2C channel targets. This is because + this CoreI2C channel responds to further received bytes with + a non-acknowledge bit (NACK) as soon as its receive buffer is + full. This causes the write transaction to fail. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_RX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_rx_buffer[SLAVE_RX_BUFFER_SIZE]; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Specify the buffer used to store the data written by the I2C master. + I2C_set_slave_rx_buffer( &g_i2c_inst, g_slave_rx_buffer, + sizeof(g_slave_rx_buffer) ); + } + @endcode + */ +void I2C_set_slave_rx_buffer +( + i2c_instance_t * this_i2c, + uint8_t * rx_buffer, + uint16_t rx_size +); + +/***************************************************************************//** + This function is used as part of the configuration of a CoreI2C channel to + operate as a slave supporting write-read transactions. It specifies the + number of bytes expected as part of the write phase of a write-read + transaction. The bytes received during the write phase of a write-read + transaction will be interpreted as an offset into the slave's transmit buffer. + This allows random access into the I2C slave transmit buffer from a remote + I2C master. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param offset_length + The offset_length parameter configures the number of bytes to be interpreted + by the CoreI2C slave as a memory offset value during the write phase of + write-read transactions. The maximum value for the offset_length parameter + is two. The value of offset_length has the following effect on the + interpretation of the received data. + • If offset_length is 0, the offset into the transmit buffer is fixed at 0. + • If offset_length is 1, a single byte of received data is interpreted as an + unsigned 8-bit offset value in the range 0 to 255. + • If offset_length is 2, 2 bytes of received data are interpreted as an + unsigned 16-bit offset value in the range 0 to 65535. The first byte + received in this case provides the high order bits of the offset and + the second byte provides the low order bits. + If the number of bytes received does not match the non 0 value of + offset_length, the transmit buffer offset is set to 0. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + I2C_set_slave_mem_offset_length( &g_i2c_inst, 1 ); + } + @endcode + */ +void I2C_set_slave_mem_offset_length +( + i2c_instance_t * this_i2c, + uint8_t offset_length +); + +/***************************************************************************//** + Register the function that is called to process the data written to this + CoreI2C channel when it is the slave in an I2C write transaction. + + Note: If a write handler is registered, it is called on completion of the + write phase of a write-read transaction and responsible for processing + the received data in the slave receive buffer and populating the slave + transmit buffer with the data that is transmitted to the I2C master + as part of the read phase of the write-read transaction. If a write + handler is not registered, the write data of a write-read transaction is + interpreted as an offset into the slave’s transmit buffer and handled by + the driver. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param handler + Pointer to the function that processes the I2C write request. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + // local function prototype + void slave_write_handler + ( + i2c_instance_t * this_i2c, + uint8_t * p_rx_data, + uint16_t rx_size + ); + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + I2C_set_slave_mem_offset_length( &g_i2c_inst, 1 ); + I2C_register_write_handler( &g_i2c_inst, slave_write_handler ); + } + @endcode +*/ +void I2C_register_write_handler +( + i2c_instance_t * this_i2c, + i2c_slave_wr_handler_t handler +); + +/***************************************************************************//** + This function enables slave mode operation for a CoreI2C channel. It enables + the CoreI2C slave to receive data when it is the target of an I2C read, write, + or write-read transaction. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + // Enable I2C slave + I2C_enable_slave( &g_i2c_inst ); + @endcode + */ +void I2C_enable_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + This function disables the slave mode operation for a CoreI2C channel. It stops + the CoreI2C slave that acknowledges the I2C read, write, or write-read + transactions targeted at it. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + // Disable I2C slave + I2C_disable_slave( &g_i2c_inst ); + @endcode + */ +void I2C_disable_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_slave_second_addr() function sets the secondary slave address for + a CoreI2C slave device. This is an additional slave address required in certain + applications, for example, to enable fail-safe operation in a system. As the + CoreI2C device supports 7-bit addressing, the highest value assigned to second + slave address is 127 (0x7F). + + Note: This function does not support CoreI2C hardware configured with a fixed + second slave address. The current implementation of the ADDR1[0] register + bit makes it difficult for the driver to support both programmable and + fixed second slave address, so we choose to support programmable only. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param second_slave_addr + The second_slave_addr parameter is the secondary slave address of the I2C + device. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SECOND_SLAVE_ADDR 0x20u + + i2c_instance_t g_i2c_inst; + void main( void ) + { + // Initialize the CoreI2C driver with its base address, primary I2C + // serial address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_second_addr( &g_i2c_inst, SECOND_SLAVE_ADDR ); + } + @endcode + */ +void I2C_set_slave_second_addr +( + i2c_instance_t * this_i2c, + uint8_t second_slave_addr +); + +/***************************************************************************//** + The I2C_disable_slave_second_addr() function disables the secondary slave + address of the CoreI2C slave device. + + Note: This version of the driver only supports CoreI2C hardware configured + with a programmable second slave address. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + i2c_instance_t g_i2c_inst; + I2C_disable_slave_second_addr( &g_i2c_inst); + @endcode + */ +void I2C_disable_slave_second_addr +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_gca() function is used to set the general call acknowledgement bit + of a CoreI2C slave device. This allows all channels of the CoreI2C slave + device to respond to a general call or broadcast message from an I2C master. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + i2c_instance_t g_i2c_inst; + + // Enable recognition of the General Call Address + I2C_set_gca( &g_i2c_inst ); + @endcode + */ +void I2C_set_gca +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_clear_gca() function is used to clear the general call acknowledgement + bit of a CoreI2C slave device. This will stop all channels of the I2C slave + device responding to any general call or broadcast message from the master. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + i2c_instance_t g_i2c_inst; + + // Disable recognition of the General Call Address + I2C_clear_gca( &g_i2c_inst ); + @endcode + */ + +void I2C_clear_gca +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//* + #I2C SMBUS Specific APIs + +/***************************************************************************//** + The I2C_smbus_init() function enables SMBus timeouts and status logic for a + CoreI2C channel. + + Note: This and any of the other SMBus related functionality will only have an + effect if the CoreI2C was instantiated with the Generate SMBus Logic + option checked. + + Note: If the CoreI2C was instantiated with the Generate IPMI Logic option + checked this function then enables the IPMI 3mS SCL low timeout but + none of the other SMBus functions will have any effect. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void system_init( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst); + } + @endcode + */ +void I2C_smbus_init +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_enable_smbus_irq() function is used to enable the CoreI2C channel’s + SMBSUS and SMBALERT SMBus interrupts. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param irq_type + The irq_type specify the SMBUS interrupt(s) which will be enabled. + The two possible interrupts are: + - I2C_SMBALERT_IRQ + - I2C_SMBSUS_IRQ + To enable both interrupts in one call, use I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ. + + @return + None + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both I2C_SMBALERT_IRQ & I2C_SMBSUS_IRQ interrupts + I2C_enable_smbus_irq( &g_i2c_inst, + (uint8_t)(I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ) ); + } + @endcode + */ +void I2C_enable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +); + +/***************************************************************************//** + The I2C_disable_smbus_irq() function disable the CoreI2C channel’s SMBSUS and + SMBALERT SMBus interrupts. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param irq_type + The irq_type specifies the SMBUS interrupt(s) which are disabled. + The two possible interrupts are: + • I2C_SMBALERT_IRQ + • I2C_SMBSUS_IRQ + To disable both ints in one call, use I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both SMBALERT & SMBSUS interrupts + I2C_enable_smbus_irq( &g_i2c_inst, + (uint8_t)(I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ)); + + ... + + // Disable the SMBALERT interrupt + I2C_disable_smbus_irq( &g_i2c_inst, I2C_SMBALERT_IRQ ); + } + @endcode + */ +void I2C_disable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +); + +/***************************************************************************//** + The I2C_suspend_smbus_slave() function forces any SMBUS slave devices + connected to a CoreI2C channel into Power-Down or Suspend mode by asserting + the channel's SMBSUS signal. The CoreI2C channel is the SMBus master in this + case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // suspend SMBus slaves + I2C_suspend_smbus_slave( &g_i2c_inst ); + + ... + + // Re-enable SMBus slaves + I2C_resume_smbus_slave( &g_i2c_inst ); + } + @endcode + */ +void I2C_suspend_smbus_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_resume_smbus_slave() function de-asserts the CoreI2C channel's SMBSUS + signal to take any connected slave devices out of the Suspend mode. The CoreI2C + channel is the SMBus master in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // suspend SMBus slaves + I2C_suspend_smbus_slave( &g_i2c_inst ); + + ... + + // Re-enable SMBus slaves + I2C_resume_smbus_slave( &g_i2c_inst ); + } + @endcode + */ +void I2C_resume_smbus_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_reset_smbus() function resets the CoreI2C channel's SMBus connection + by forcing SCLK low for 35 mS. The reset that automatically cleares after 35 ms + gets elapsed. The CoreI2C channel is the SMBus master in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Make sure the SMBus channel is in a known state by resetting it + I2C_reset_smbus( &g_i2c_inst ); + } + @endcode + */ +void I2C_reset_smbus +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_smbus_alert() function is used to force master communication with + an I2C slave device by asserting the CoreI2C channel's SMBALERT signal. The + CoreI2C channel is the SMBus slave in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Get the SMBus masters attention + I2C_set_smbus_alert( &g_i2c_inst ); + + ... + + // Once we are happy, drop the alert + I2C_clear_smbus_alert( &g_i2c_inst ); + } + @endcode + */ +void I2C_set_smbus_alert +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_clear_smbus_alert() function is used to de-assert the CoreI2C channel's + SMBALERT signal once a slave device gets a response from the master. The + CoreI2C channel is the SMBus slave in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Get the SMBus masters attention + I2C_set_smbus_alert( &g_i2c_inst ); + + ... + + // Once we are happy, drop the alert + I2C_clear_smbus_alert( &g_i2c_inst ); + } + @endcode + */ +void I2C_clear_smbus_alert +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_get_irq_status function returns information about which interrupts are + currently pending in a CoreI2C channel. + The interrupts supported by CoreI2C are: + • SMBUSALERT + • SMBSUS + • INTR + + The macros I2C_NO_IRQ, I2C_SMBALERT_IRQ, I2C_SMBSUS_IRQ, and I2C_INTR_IRQ are + provided to use with this function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + This function returns the status of the CoreI2C channel's interrupts as a + single byte bitmap where a bit is set to indicate a pending interrupt. + The following are the bit positions associated with each interrupt type: + Bit 0 - SMBUS_ALERT_IRQ + Bit 1 - SMBSUS_IRQ + Bit 2 - INTR_IRQ + It returns 0, if there are no pending interrupts. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + uint8_t irq_to_enable = I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ; + uint8_t pending_irq = 0u; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both I2C_SMBALERT_IRQ & I2C_SMBSUS_IRQ irq + I2C_enable_smbus_irq( &g_i2c_inst, irq_to_enable ); + + // Get I2C IRQ type + pending_irq = I2C_get_irq_status( &g_i2c_inst ); + + // Let's assume, in system, INTR and SMBALERT IRQ is pending. + // So pending_irq will return status of both the IRQs + + if( pending_irq & I2C_SMBALERT_IRQ ) + { + // if true, it means SMBALERT_IRQ is there in pending IRQ list + } + if( pending_irq & I2C_INTR_IRQ ) + { + // if true, it means I2C_INTR_IRQ is there in pending IRQ list + } + } + @endcode + */ +uint8_t I2C_get_irq_status +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_user_data() function allows the association of a block of application + specific data with a CoreI2C channel. The composition of the data block is an + application matter and the driver simply provides the means for the application + to set and retrieve the pointer. For example, this is used to provide additional + channel specific information to the slave write handler. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param p_user_data + The p_user_data parameter is a pointer to the user specific data block for + this channel. It is defined as void * as the driver does not know the actual + type of data being pointed to and simply stores the pointer for later + retrieval by the application. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + app_data_t channel_xdata; + + void main( void ) + { + app_data_t *p_xdata; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Store location of user data in instance structure + I2C_set_user_data( &g_i2c_inst, (void *)&channel_xdata ); + + ... + + // Retrieve location of user data and do some work on it + p_xdata = (app_data_t *)I2C_get_user_data( &g_i2c_inst ); + if( NULL != p_xdata ) + { + p_xdata->foo = 123; + } + } + @endcode + */ +void I2C_set_user_data +( + i2c_instance_t * this_i2c, + void * p_user_data +); + +/***************************************************************************//** + The I2C_get_user_data() function is used to allows the retrieval of the address + of a block of application specific data associated with a CoreI2C channel. + The composition of the data block is an application matter and the driver + simply provides the means for the application to set and retrieve the pointer. + For example, this is used to provide additional channel specific information + to the slave write handler. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + This function returns a pointer to the user specific data block for this + channel. It is defined as void * as the driver does not know the actual type + of data being pointed. If no user data has been registered for this channel + a NULL pointer is returned. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + app_data_t channel_xdata; + + void main( void ) + { + app_data_t *p_xdata; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Store location of user data in instance structure + I2C_set_user_data( &g_i2c_inst, (void *)&channel_xdata ); + + ... + + // Retrieve location of user data and do some work on it + p_xdata = (app_data_t *)I2C_get_user_data( &g_i2c_inst ); + if( NULL != p_xdata ) + { + p_xdata->foo = 123; + } + } + @endcode + */ +void * I2C_get_user_data +( + i2c_instance_t * this_i2c +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h new file mode 100644 index 0000000..b1d872d --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h @@ -0,0 +1,190 @@ +/******************************************************************************* + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + */ + +#ifndef __CORE_SMBUS_REGISTERS +#define __CORE_SMBUS_REGISTERS 1 + +/*------------------------------------------------------------------------------ + * CONTROL register details + */ +#define CONTROL_REG_OFFSET 0x00u + +/* + * CR0 bits. + */ +#define CR0_OFFSET 0x00u +#define CR0_MASK 0x01u +#define CR0_SHIFT 0u + +/* + * CR1 bits. + */ +#define CR1_OFFSET 0x00u +#define CR1_MASK 0x02u +#define CR1_SHIFT 1u + +/* + * AA bits. + */ +#define AA_OFFSET 0x00u +#define AA_MASK 0x04u +#define AA_SHIFT 2u + +/* + * SI bits. + */ +#define SI_OFFSET 0x00u +#define SI_MASK 0x08u +#define SI_SHIFT 3u + +/* + * STO bits. + */ +#define STO_OFFSET 0x00u +#define STO_MASK 0x10u +#define STO_SHIFT 4u + +/* + * STA bits. + */ +#define STA_OFFSET 0x00u +#define STA_MASK 0x20u +#define STA_SHIFT 5u + +/* + * ENS1 bits. + */ +#define ENS1_OFFSET 0x00u +#define ENS1_MASK 0x40u +#define ENS1_SHIFT 6u + +/* + * CR2 bits. + */ +#define CR2_OFFSET 0x00u +#define CR2_MASK 0x80u +#define CR2_SHIFT 7u + +/*------------------------------------------------------------------------------ + * STATUS register details + */ +#define STATUS_REG_OFFSET 0x04u + +/*------------------------------------------------------------------------------ + * DATA register details + */ +#define DATA_REG_OFFSET 0x08u + +/* + * TARGET_ADDR bits. + */ +#define TARGET_ADDR_OFFSET 0x08u +#define TARGET_ADDR_MASK 0xFEu +#define TARGET_ADDR_SHIFT 1u + +/* + * DIR bit. + */ +#define DIR_OFFSET 0x08u +#define DIR_MASK 0x01u +#define DIR_SHIFT 0u + + +/*------------------------------------------------------------------------------ + * ADDRESS register details + */ +#define ADDRESS_REG_OFFSET 0x0Cu + +/* + * GC bits. + */ +#define GC_OFFSET 0x0Cu +#define GC_MASK 0x01u +#define GC_SHIFT 0u + +/* + * ADR bits. + */ +#define OWN_SLAVE_ADDR_OFFSET 0x0Cu +#define OWN_SLAVE_ADDR_MASK 0xFEu +#define OWN_SLAVE_ADDR_SHIFT 1u + +/*------------------------------------------------------------------------------ + * SMBUS register details + */ +#define SMBUS_REG_OFFSET 0x10u + +/* + * SMBALERT_IE bits. + */ +#define SMBALERT_IE_OFFSET 0x10u +#define SMBALERT_IE_MASK 0x01u +#define SMBALERT_IE_SHIFT 0u + +/* + * SMBSUS_IE bits. + */ +#define SMBSUS_IE_OFFSET 0x10u +#define SMBSUS_IE_MASK 0x02u +#define SMBSUS_IE_SHIFT 1u + +/* + * SMB_IPMI_EN bits. + */ +#define SMB_IPMI_EN_OFFSET 0x10u +#define SMB_IPMI_EN_MASK 0x04u +#define SMB_IPMI_EN_SHIFT 2u + +/* + * SMBALERT_NI_STATUS bits. + */ +#define SMBALERT_NI_STATUS_OFFSET 0x10u +#define SMBALERT_NI_STATUS_MASK 0x08u +#define SMBALERT_NI_STATUS_SHIFT 3u + +/* + * SMBALERT_NO_CONTROL bits. + */ +#define SMBALERT_NO_CONTROL_OFFSET 0x10u +#define SMBALERT_NO_CONTROL_MASK 0x10u +#define SMBALERT_NO_CONTROL_SHIFT 4u + +/* + * SMBSUS_NI_STATUS bits. + */ +#define SMBSUS_NI_STATUS_OFFSET 0x10u +#define SMBSUS_NI_STATUS_MASK 0x20u +#define SMBSUS_NI_STATUS_SHIFT 5u + +/* + * SMBSUS_NO_CONTROL bits. + */ +#define SMBSUS_NO_CONTROL_OFFSET 0x10u +#define SMBSUS_NO_CONTROL_MASK 0x40u +#define SMBSUS_NO_CONTROL_SHIFT 6u + +/* + * SMBUS_MST_RESET bits. + */ +#define SMBUS_MST_RESET_OFFSET 0x10u +#define SMBUS_MST_RESET_MASK 0x80u +#define SMBUS_MST_RESET_SHIFT 7u + +/*------------------------------------------------------------------------------ + * SLAVE ADDRESS 1 register details + */ + +#define ADDRESS1_REG_OFFSET 0x1Cu + +/* + * SLAVE1_EN bit of Slave Address 1 . + */ +#define SLAVE1_EN_OFFSET 0x1Cu +#define SLAVE1_EN_MASK 0x01u +#define SLAVE1_EN_SHIFT 0u + +#endif /* __CORE_SMBUS_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c new file mode 100644 index 0000000..12e352d --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * CoreI2C driver interrupt control. + * + */ +#include "core_i2c.h" + +/*------------------------------------------------------------------------------ + * This function must be modified to enable interrupts generated from the + * CoreI2C instance identified as parameter. + */ +void I2C_enable_irq( i2c_instance_t * this_i2c ) +{ + HAL_ASSERT(0) +} + +/*------------------------------------------------------------------------------ + * This function must be modified to disable interrupts generated from the + * CoreI2C instance identified as parameter. + */ +void I2C_disable_irq( i2c_instance_t * this_i2c ) +{ + HAL_ASSERT(0) +} diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreSPI/core_spi.c b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreSPI/core_spi.c new file mode 100644 index 0000000..2e11750 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreSPI/core_spi.c @@ -0,0 +1,1345 @@ +/***************************************************************************//** + * Copyright 2013-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * CoreSPI bare metal driver implementation for CoreSPI. + * + * This Core SPI driver provides functions for implementing SPI master or + * SPI slave operations with the CoreSPI version 4.2.xxx It is not compatible + * with CoreSPI version 3.0.xxx. + * + * @file core_spi.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreSPI software configuration + * + */ + +#include "core_spi.h" +#include "corespi_regs.h" +#include + +/******************************************************************************* + * Null parameters with appropriate type definitions + */ +#define NULL_ADDR ( ( addr_t ) 0u ) +#define NULL_INSTANCE ( ( spi_instance_t * ) 0u ) +#define NULL_BUFF ( ( uint8_t * ) 0u ) +#define NULL_FRAME_HANDLER ( ( spi_frame_rx_handler_t ) 0u ) +#define NULL_BLOCK_HANDLER ( ( spi_block_rx_handler_t ) 0u ) +#define NULL_SLAVE_TX_UPDATE_HANDLER ( ( spi_slave_frame_tx_handler_t ) 0u ) +#define NULL_SLAVE_CMD_HANDLER NULL_BLOCK_HANDLER + +#define SPI_ALL_INTS (0xFFu) /* For clearing all active interrupts */ + +/******************************************************************************* + * Possible states for different register bit fields + */ + +#define DISABLE 0u +#define ENABLE 1u + + +/******************************************************************************* + * Function return values + */ +enum { + FAILURE = 0u, + SUCCESS = 1u +}; + +/******************************************************************************* + * Local function declarations + */ +static void fill_slave_tx_fifo( spi_instance_t * this_spi ); +static void read_slave_rx_fifo( spi_instance_t * this_spi ); +static void recover_from_rx_overflow( const spi_instance_t * this_spi ); + +/******************************************************************************* + * SPI_init() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_init +( + spi_instance_t * this_spi, + addr_t base_addr, + uint16_t fifo_depth +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( NULL_ADDR != base_addr ); + HAL_ASSERT( SPI_MAX_FIFO_DEPTH >= fifo_depth ); + HAL_ASSERT( SPI_MIN_FIFO_DEPTH <= fifo_depth ); + + if( ( NULL_INSTANCE != this_spi ) && ( base_addr != NULL_ADDR ) ) + { + /* + * Initialize all transmit / receive buffers and handlers + * + * Relies on the fact that byte filling with 0x00 will equate + * to 0 for any non byte sized items too. + */ + + /* First fill struct with 0s */ + memset( this_spi, 0, sizeof(spi_instance_t) ); + + /* Configure CoreSPI instance attributes */ + this_spi->base_addr = (addr_t)base_addr; + + /* Store FIFO depth or fall back to minimum if out of range */ + if( ( SPI_MAX_FIFO_DEPTH >= fifo_depth ) && ( SPI_MIN_FIFO_DEPTH <= fifo_depth ) ) + { + this_spi->fifo_depth = fifo_depth; + } + else + { + this_spi->fifo_depth = SPI_MIN_FIFO_DEPTH; + } + /* Make sure the CoreSPI is disabled while we configure it */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Ensure all slaves are deselected */ + HAL_set_8bit_reg( this_spi->base_addr, SSEL, 0u ); + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Ensure RXAVAIL, TXRFM, SSEND and CMDINT are disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, 0u ); + /* + * Enable the CoreSPI in the reset default of master mode + * with TXUNDERRUN, RXOVFLOW and TXDONE interrupts disabled. + * The driver does not currently use interrupts in master mode. + */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL1, ENABLE | CTRL1_MASTER_MASK ); + } +} + +/***************************************************************************//** + * SPI_configure_slave_mode() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_configure_slave_mode +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Don't yet know what slave transfer mode will be used */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_NONE; + + /* Make sure the CoreSPI is disabled while we configure it */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Ensure RXAVAIL, TXRFM, SSEND and CMDINT are disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, 0u ); + /* + * Enable the CoreSPI in slave mode with TXUNDERRUN, RXOVFLOW and TXDONE + * interrupts disabled. The appropriate interrupts will be enabled later + * on when the transfer mode is configured. + */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL1, ENABLE ); + } +} + +/***************************************************************************//** + * SPI_configure_master_mode() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_configure_master_mode +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Disable the CoreSPI for a little while, while we configure the CoreSPI */ + HAL_set_8bit_reg_field(this_spi->base_addr, CTRL1_ENABLE, DISABLE); + + /* Reset slave transfer mode to unknown in case it has been set previously */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_NONE; + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Ensure RXAVAIL, TXRFM, SSEND and CMDINT are disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, 0u ); + + /* Enable the CoreSPI in master mode with TXUNDERRUN, RXOVFLOW and TXDONE interrupts disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL1, ENABLE | CTRL1_MASTER_MASK ); + } +} + +/***************************************************************************//** + * SPI_set_slave_select() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +) +{ + spi_slave_t temp = (spi_slave_t)(0x00u) ; + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( SPI_MAX_NB_OF_SLAVES > slave ); + + if( ( NULL_INSTANCE != this_spi ) && ( SPI_MAX_NB_OF_SLAVES > slave ) ) + { + /* This function is only intended to be used with an SPI master */ + if( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW ) ) + { + recover_from_rx_overflow( this_spi ); + } + /* Set the correct slave select bit */ + temp = (spi_slave_t)( HAL_get_8bit_reg( this_spi->base_addr, SSEL ) | ((uint32_t)1u << (uint32_t)slave) ); + HAL_set_8bit_reg( this_spi->base_addr, SSEL, (uint_fast8_t)temp ); + } + } +} + +/***************************************************************************//** + * SPI_clear_slave_select() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_clear_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +) +{ + spi_slave_t temp = (spi_slave_t) (0x00u) ; + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( SPI_MAX_NB_OF_SLAVES > slave ); + + if( ( NULL_INSTANCE != this_spi ) && ( SPI_MAX_NB_OF_SLAVES > slave ) ) + { + /* This function is only intended to be used with an SPI master. */ + if( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW) ) + { + recover_from_rx_overflow( this_spi ); + } + /* Clear the correct slave select bit */ + temp = (spi_slave_t)( HAL_get_8bit_reg( this_spi->base_addr, SSEL ) & ~((uint32_t)1u << (uint32_t)slave) ); + HAL_set_8bit_reg( this_spi->base_addr, SSEL, (uint_fast8_t)temp ) ; + } + } +} + +/***************************************************************************//** + * SPI_transfer_frame() + * See "core_spi.h" for details of how to use this function. + */ +uint32_t SPI_transfer_frame +( + spi_instance_t * this_spi, + uint32_t tx_bits +) +{ + volatile uint32_t rx_data = 0u; /* Ensure consistent return value if in slave mode */ + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI master. */ + if( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Flush the receive and transmit FIFOs by resetting both */ + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK); + + /* Send frame. */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, tx_bits ); + + /* Wait for frame Tx to complete. */ + while ( ENABLE != HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_DONE ) ) + { + ; + } + + /* Read received frame. */ + rx_data = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + } + } + + /* Finally, return the frame we received from the slave or 0 */ + return( rx_data ); +} + + +/***************************************************************************//** + * SPI_transfer_block() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_transfer_block +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_buffer, + uint16_t rx_byte_size +) +{ + uint32_t transfer_size = 0U; /* Total number of bytes to transfer. */ + uint16_t transfer_idx = 0U; /* Number of bytes transferred so far */ + uint16_t tx_idx = 0u; /* Number of valid data bytes sent */ + uint16_t rx_idx = 0u; /* Number of valid response bytes received */ + uint16_t transit = 0U; /* Number of bytes "in flight" to avoid FIFO errors */ + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI master. */ + if( ( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) && + /* Check for empty transfer as well */ + ( 0u != ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) ) ) + { + /* + * tansfer_size is one less than the real amount as we have to write + * the last frame separately to trigger the slave deselect in case + * the SPS option is in place. + */ + transfer_size = ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) - 1u; + /* Flush the receive and transmit FIFOs */ + HAL_set_8bit_reg(this_spi->base_addr, CMD, (uint32_t)(CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK )); + + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW) ) + { + recover_from_rx_overflow( this_spi ); + } + + /* Disable the Core SPI for a little bit, while we load the TX FIFO */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + while( ( tx_idx < transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out 0s to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + } + ++transit; + ++tx_idx; + } + + /* If room left to put last frame in before the off, then do it */ + if( ( tx_idx == transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data, not expecting any reply this time */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out last 0 to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + } + + ++transit; + ++tx_idx; + } + + /* FIFO is all loaded up so enable Core SPI to start transfer */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + + /* Perform the remainder of the transfer by sending a byte every time a byte + * has been received. This should ensure that no Rx overflow can happen in + * case of an interrupt occurring during this function. + * + * We break the transfer down into stages to minimise the processing in + * each loop as the SPI interface is very demanding at higher clock rates. + * This works well with FIFOs but might be less efficient if there is only + * a single frame buffer. + * + * First stage transfers remaining command bytes (if any). + * At this stage anything in the RX FIFO can be discarded as it is + * not part of a valid response. + */ + while( tx_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + /* Send another byte. */ + if( tx_idx == transfer_size ) /* Last frame is special... */ + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Read and discard. */ + HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now, we are writing dummy bytes to push through the response from + * the slave but we still have to keep discarding any read data that + * corresponds with one of our command bytes. + */ + while( transfer_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + if( tx_idx < transfer_size ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Read and discard. */ + HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now we are now only sending dummy data to push through the + * valid response data which we store in the response buffer. + */ + while( tx_idx < transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received byte. */ + rx_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* If we still need to send the last frame */ + while( tx_idx == transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received byte. */ + rx_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* + * Finally, we are now finished sending data and are only reading + * valid response data which we store in the response buffer. + */ + while( transfer_idx <= transfer_size ) + { + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received byte. */ + rx_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + } + } + } + } +} + +/***************************************************************************//** + * SPI_transfer_block_store_all_resp() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_transfer_block_store_all_resp +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_data_buffer, + uint16_t rx_byte_size, + uint8_t * cmd_response_buffer +) +{ + uint32_t transfer_size = 0U; /* Total number of bytes to transfer. */ + uint16_t transfer_idx = 0U; /* Number of bytes transferred so far */ + uint16_t tx_idx = 0u; /* Number of valid data bytes sent */ + uint16_t rx_idx = 0u; /* Number of valid response bytes received */ + uint16_t transit = 0U; /* Number of bytes "in flight" to avoid FIFO errors */ + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI master. */ + if( ( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) && + /* Check for empty transfer as well */ + ( 0u != ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) ) ) + { + /* + * tansfer_size is one less than the real amount as we have to write + * the last frame separately to trigger the slave deselect in case + * the SPS option is in place. + */ + transfer_size = ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) - 1u; + /* Flush the receive and transmit FIFOs */ + HAL_set_8bit_reg(this_spi->base_addr, CMD, (uint32_t)(CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK )); + + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW) ) + { + recover_from_rx_overflow( this_spi ); + } + + /* Disable the Core SPI for a little bit, while we load the TX FIFO */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + while( ( tx_idx < transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out 0s to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + } + ++transit; + ++tx_idx; + } + + /* If room left to put last frame in before the off, then do it */ + if( ( tx_idx == transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data, not expecting any reply this time */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out last 0 to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + } + + ++transit; + ++tx_idx; + } + + /* FIFO is all loaded up so enable Core SPI to start transfer */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + + /* Perform the remainder of the transfer by sending a byte every time a byte + * has been received. This should ensure that no Rx overflow can happen in + * case of an interrupt occurring during this function. + * + * We break the transfer down into stages to minimise the processing in + * each loop as the SPI interface is very demanding at higher clock rates. + * This works well with FIFOs but might be less efficient if there is only + * a single frame buffer. + * + * First stage transfers remaining command bytes (if any). + * At this stage anything in the RX FIFO can be discarded as it is + * not part of a valid response. + */ + while( tx_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + /* Send another byte. */ + if( tx_idx == transfer_size ) /* Last frame is special... */ + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received command byte. */ + cmd_response_buffer[transfer_idx] = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now, we are writing dummy bytes to push through the response from + * the slave, which we store in the command response buffer. + */ + while( transfer_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + if( tx_idx < transfer_size ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received command byte. */ + cmd_response_buffer[transfer_idx] = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now we are now only sending dummy data to push through the + * valid response data which we store in the data response buffer. + */ + while( tx_idx < transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received data byte. */ + rx_data_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* If we still need to send the last frame */ + while( tx_idx == transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received data byte. */ + rx_data_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* + * Finally, we are now finished sending data and are only reading + * valid response data which we store in the data response buffer. + */ + while( transfer_idx <= transfer_size ) + { + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received data byte. */ + rx_data_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + } + } + } + } +} +/***************************************************************************//** + * SPI_set_frame_rx_handler() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_frame_rx_handler +( + spi_instance_t * this_spi, + spi_frame_rx_handler_t rx_handler +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if(NULL_INSTANCE != this_spi) + { + /* This function is only intended to be used with an SPI slave. */ + if(DISABLE == HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER)) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Disable SSEND and CMD interrupts as we are not doing block transfers */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTSSEND, DISABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + + /* Disable block Rx handler as they are mutually exclusive. */ + this_spi->block_rx_handler = 0U; + + /* Keep a copy of the pointer to the Rx handler function. */ + this_spi->frame_rx_handler = rx_handler; + + if( SPI_SLAVE_XFER_FRAME != this_spi->slave_xfer_mode ) + { + /* + * Either just coming from init or were previously in block mode + * so no tx frame handler is set at this point in time... + * + * Don't allow TXDONE interrupts. + */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXDONE, DISABLE ); + } + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK); + + /* Enable Rx and FIFO error interrupts */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTRXOVFLOW, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXURUN, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTRXDATA, ENABLE ); + + /* Make sure correct mode is selected */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_FRAME; + + /* Finally re-enable the CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } + } +} + +/***************************************************************************//** + * SPI_set_slave_tx_frame() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_slave_tx_frame +( + spi_instance_t * this_spi, + uint32_t frame_value, + spi_slave_frame_tx_handler_t slave_tx_frame_handler +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI slave. */ + if( DISABLE == HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Disable SSEND and CMD interrupts as we are not doing block transfers */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTSSEND, DISABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + + if( SPI_SLAVE_XFER_FRAME != this_spi->slave_xfer_mode ) + { + /* + * Either just coming from init or were previously in block mode + * so no rx frame handler is set at this point in time... + * + * Don't allow RXDATA interrupts. + */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTRXDATA, DISABLE ); + } + + /* Disable slave block tx buffer as it is mutually exclusive with frame + * level handling. */ + this_spi->slave_tx_buffer = NULL_BUFF; + this_spi->slave_tx_size = 0U; + this_spi->slave_tx_idx = 0U; + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK); + + /* Assign the slave frame update handler - NULL_SLAVE_TX_UPDATE_HANDLER for none */ + this_spi->slave_tx_frame_handler = slave_tx_frame_handler; + + /* Keep a copy of the slave Tx frame value. */ + this_spi->slave_tx_frame = frame_value; + + /* Load one frame into Tx data register. */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, this_spi->slave_tx_frame ); + + /* Enable Tx Done interrupt in order to reload the slave Tx frame after each + * time it has been sent. */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXDONE, ENABLE ); + + /* Make sure correct mode is selected */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_FRAME; + + /* Ready to go so enable CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } + } +} + +/***************************************************************************//** + * SPI_set_slave_block_buffers() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_slave_block_buffers +( + spi_instance_t * this_spi, + const uint8_t * tx_buffer, + uint32_t tx_buff_size, + uint8_t * rx_buffer, + uint32_t rx_buff_size, + spi_block_rx_handler_t block_rx_handler +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI slave. */ + if( DISABLE == HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Make sure correct mode is selected */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_BLOCK; + /* + * No command handler should be setup at this stage so fake this + * to ensure 0 padding works. + */ + this_spi->cmd_done = 1u; + + /* Disable frame handlers as they are mutually exclusive with block Rx handler. */ + this_spi->frame_rx_handler = NULL_FRAME_HANDLER; + this_spi->slave_tx_frame_handler = NULL_SLAVE_TX_UPDATE_HANDLER; + + /* Keep a copy of the pointer to the block Rx handler function. */ + this_spi->block_rx_handler = block_rx_handler; + + /* Assign slave receive buffer */ + this_spi->slave_rx_buffer = rx_buffer; + this_spi->slave_rx_size = rx_buff_size; + this_spi->slave_rx_idx = 0U; + + /* Assign slave transmit buffer*/ + this_spi->slave_tx_buffer = tx_buffer; + this_spi->slave_tx_size = tx_buff_size; + this_spi->slave_tx_idx = 0U; + + /* Flush the receive and transmit FIFOs */ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Preload the transmit FIFO. */ + while( !(HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_TXFULL)) && + ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->slave_tx_buffer[this_spi->slave_tx_idx] ); + ++this_spi->slave_tx_idx; + } + /* + * Disable TXDATA interrupt as we will look after transmission in rx handling + * because we know that once we have read a frame it is safe to send another one. + */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTTXDATA, DISABLE ); + + /* Enable Rx, FIFO error and SSEND interrupts */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTRXOVFLOW, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXURUN, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTRXDATA, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTSSEND, ENABLE ); + + /* Disable command handler until it is set explicitly */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + + /* Now enable the CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } + } +} + +/***************************************************************************//** + * SPI_set_cmd_handler() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_cmd_handler +( + spi_instance_t * this_spi, + spi_block_rx_handler_t cmd_handler, + uint32_t cmd_size +) +{ + uint32_t ctrl2 = 0u; + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( NULL_SLAVE_CMD_HANDLER != cmd_handler ); + HAL_ASSERT( 0u < cmd_size ); + + if( ( NULL_INSTANCE != this_spi ) && ( 0u < cmd_size ) && + ( NULL_SLAVE_CMD_HANDLER != cmd_handler ) ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + /* + * Note we don't flush the FIFOs as this has been done already when + * block mode was configured. + * + * Clear this flag so zero padding is disabled until command response + * has been taken care of. + */ + this_spi->cmd_done = 0u; + + /* Assign user handler for Command received interrupt */ + this_spi->cmd_handler = cmd_handler; + + /* Configure the command size and Enable Command received interrupt */ + ctrl2 = HAL_get_8bit_reg( this_spi->base_addr, CTRL2 ); + + /* First clear the count field then insert count and int enables */ + ctrl2 &= ~(uint32_t)CTRL2_CMDSIZE_MASK; + ctrl2 |= (uint32_t)((cmd_size & CTRL2_CMDSIZE_MASK) | CTRL2_INTCMD_MASK | CTRL2_INTRXDATA_MASK); + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, ctrl2 ); + + /* Now enable the CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } +} + +/***************************************************************************//** + * SPI_set_cmd_response() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_cmd_response +( + spi_instance_t * this_spi, + const uint8_t * resp_tx_buffer, + uint32_t resp_buff_size +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( NULL_BUFF != resp_tx_buffer ); + HAL_ASSERT( 0u < resp_buff_size ); + + if( ( NULL_INSTANCE != this_spi ) && ( 0u < resp_buff_size ) && + ( NULL_BUFF != resp_tx_buffer ) ) + { + this_spi->resp_tx_buffer = resp_tx_buffer; + this_spi->resp_buff_size = resp_buff_size; + this_spi->resp_buff_tx_idx = 0u; + + fill_slave_tx_fifo(this_spi); + } +} + + +/***************************************************************************//** + * SPI_enable() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_enable +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } +} + + +/***************************************************************************//** + * SPI_disable() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_disable +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + } +} + + +/***************************************************************************//** + * SPI interrupt service routine. + */ +void SPI_isr +( + spi_instance_t * this_spi +) +{ + uint32_t rx_frame; + int32_t guard; + +/* + * The assert and the NULL check here can be commented out to reduce the interrupt + * latency once you are sure the interrupt vector code is correct. + */ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + if( NULL_INSTANCE != this_spi ) + { + /* Handle receive. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_RXDATA ) ) + { + /* + * Service receive data according to transfer mode in operation. + * + * We check block mode first as this is most likely to have back to back + * transfers with multiple bytes. + * + * Note the order of the checks here will effect interrupt latency and + * for critical timing the mode you are using most often should probably be + * be the first checked. + */ + if( SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode ) /* Block handling mode. */ + { + while( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Read irrespective to clear the RX IRQ */ + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + if( this_spi->slave_rx_idx < this_spi->slave_rx_size ) + { + this_spi->slave_rx_buffer[this_spi->slave_rx_idx] = (uint8_t)rx_frame; + } + ++this_spi->slave_rx_idx; + } + /* + * Now handle updating of tx FIFO to keep the data flowing. + * First see if there is anything in slave_tx_buffer to send. + */ + while( ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) + && ( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->slave_tx_buffer[this_spi->slave_tx_idx] ); + ++this_spi->slave_tx_idx; + } + /* + * Next see if there is anything in resp_tx_buffer to send. + */ + if( this_spi->slave_tx_idx >= this_spi->slave_tx_size ) + { + while( ( this_spi->resp_buff_tx_idx < this_spi->resp_buff_size ) + && ( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->resp_tx_buffer[this_spi->resp_buff_tx_idx] ); + ++this_spi->resp_buff_tx_idx; + } + } + /* + * Lastly, see if we are ready to pad with 0s . + */ + if( this_spi->cmd_done && ( this_spi->slave_tx_idx >= this_spi->slave_tx_size ) && + ( this_spi->resp_buff_tx_idx >= this_spi->resp_buff_size ) ) + { + guard = 1 + ((int32_t)this_spi->fifo_depth / 4); + while( ( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) + && ( 0 != guard ) ) + { + /* + * Pad TX FIFO with 0s for consistent behaviour if the master + * tries to transfer more than we expected. + */ + HAL_set_32bit_reg(this_spi->base_addr, TXDATA, 0x00u); + /* + * We use the guard count to cover the event that we are never + * seeing the TX FIFO full because the data is being pulled + * out as fast as we can stuff it in. In this case we never spend + * more than our allocated time spinning here. + */ + guard--; + } + } + } + else if( SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode ) /* Single frame handling mode. */ + { + while( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + if( NULL_FRAME_HANDLER != this_spi->frame_rx_handler ) + { + this_spi->frame_rx_handler( rx_frame ); + } + } + } + else /* Slave transfer mode not set up so discard anything in RX FIFO */ + { + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_RXFIFORST_MASK ); + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_RXDATA, ENABLE ); + } + + /* Handle transmit. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_TXDONE ) ) + { + /* + * Note, the driver only currently uses the txdone interrupt when + * in frame transmit mode. In block mode all TX handling is done by the + * receive interrupt handling code as we know that for every frame received + * a frame must be placed in the TX FIFO. + */ + if( SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode ) + { + /* Execute the user callback to update the slave_tx_frame */ + if( NULL_SLAVE_TX_UPDATE_HANDLER != this_spi->slave_tx_frame_handler ) + { + this_spi->slave_tx_frame_handler ( this_spi ); + } + + /* Reload slave tx frame into Tx data register. */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, this_spi->slave_tx_frame ); + } + else if( SPI_SLAVE_XFER_BLOCK != this_spi->slave_xfer_mode ) + { + /* Slave transfer mode not set up so discard anything in TX FIFO */ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK ); + } + else + { + /* Nothing to do, no slave mode configured */ + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_TXDONE, ENABLE ); + } + + + /* Handle receive overflow. */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, INTMASK_RXOVERFLOW)) + { + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_RXFIFORST_MASK); + HAL_set_8bit_reg_field(this_spi->base_addr, INTCLR_RXOVERFLOW, ENABLE); + } + + /* Handle transmit under run. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_TXUNDERRUN ) ) + { + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK ); + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_TXUNDERRUN, ENABLE ); + } + + /* Handle command interrupt. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_CMDINT ) ) + { + read_slave_rx_fifo( this_spi ); + + /* + * Call the command handler if one exists. + */ + if( NULL_SLAVE_CMD_HANDLER != this_spi->cmd_handler ) + { + this_spi->cmd_handler( this_spi->slave_rx_buffer, this_spi->slave_rx_idx ); + } + this_spi->cmd_done = 1u; + /* Disable command interrupt until slave select becomes de-asserted to avoid retriggering. */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_CMDINT, ENABLE ); + } + + /* Handle slave select becoming de-asserted. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_SSEND) ) + { + /* Only supposed to do all this if transferring blocks... */ + if(SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode) + { + uint32_t rx_size; + + /* Empty any remaining bytes in RX FIFO */ + read_slave_rx_fifo( this_spi ); + rx_size = this_spi->slave_rx_idx; + /* + * Re-enable command interrupt if required. + * Must be done before re loading FIFO to ensure stale response + * data is not pushed into the FIFO. + */ + if(NULL_SLAVE_CMD_HANDLER != this_spi->cmd_handler) + { + this_spi->cmd_done = 0u; + this_spi->resp_tx_buffer = 0u; + this_spi->resp_buff_size = 0u; + this_spi->resp_buff_tx_idx = 0u; + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_CMDINT, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, ENABLE ); + } + /* + * Reset the transmit index to 0 to restart transmit at the start of the + * transmit buffer in the next transaction. This also requires flushing + * the Tx FIFO and refilling it with the start of Tx data buffer. + */ + this_spi->slave_tx_idx = 0u; + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + fill_slave_tx_fifo( this_spi ); + + /* Prepare to receive next packet. */ + this_spi->slave_rx_idx = 0u; + /* + * Call the receive handler if one exists. + */ + if( NULL_BLOCK_HANDLER != this_spi->block_rx_handler ) + { + this_spi->block_rx_handler( this_spi->slave_rx_buffer, rx_size ); + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_RXDATA, ENABLE ); + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_SSEND, ENABLE ); + } + } +} + +/******************************************************************************* + * Local function definitions + */ + +/***************************************************************************//** + * Fill the transmit FIFO (used for slave block transfers). + */ +static void fill_slave_tx_fifo +( + spi_instance_t * this_spi +) +{ + /* First see if slave_tx_buffer needs transmitting */ + while( ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) && + !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->slave_tx_buffer[this_spi->slave_tx_idx] ); + ++this_spi->slave_tx_idx; + } + + /* Then see if it is safe to look at putting resp_tx_buffer in FIFO? */ + if( this_spi->slave_tx_idx >= this_spi->slave_tx_size ) + { + while( ( this_spi->resp_buff_tx_idx < this_spi->resp_buff_size ) && + !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->resp_tx_buffer[this_spi->resp_buff_tx_idx] ); + ++this_spi->resp_buff_tx_idx; + } + } +} + +/***************************************************************************//** + * + */ +static void read_slave_rx_fifo +( + spi_instance_t * this_spi +) +{ + uint32_t rx_frame; + + if( SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode ) /* Block handling mode. */ + { + while( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); /* Read irresepective to clear the RX IRQ */ + if( this_spi->slave_rx_idx < this_spi->slave_rx_size ) + { + this_spi->slave_rx_buffer[this_spi->slave_rx_idx] = (uint8_t)rx_frame; + } + ++this_spi->slave_rx_idx; + } + } + else if( SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode ) /* Frame handling mode */ + { + while( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Single frame handling mode. */ + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + if( NULL_FRAME_HANDLER != this_spi->frame_rx_handler ) + { + this_spi->frame_rx_handler( rx_frame ); + } + } + } + else /* Slave transfer mode not set up so discard anything in RX FIFO */ + { + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_RXFIFORST_MASK ); + } +} + +/***************************************************************************//** + * This function is to recover the CoreSPI from receiver overflow. + * It temporarily disables the CoreSPI from interacting with external world, flushes + * the transmit and receiver FIFOs, clears all interrupts and then re-enables + * the CoreSPI instance referred by this_spi parameter. + */ +static void recover_from_rx_overflow +( + const spi_instance_t * this_spi +) +{ + /* Disable CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Reset TX and RX FIFOs */ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Enable CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); +} + + diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreSPI/core_spi.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreSPI/core_spi.h new file mode 100644 index 0000000..c6873f7 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreSPI/core_spi.h @@ -0,0 +1,1324 @@ +/***************************************************************************//** + * Copyright 2013-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Core SPI bare metal software driver public API. + * + * This Core SPI driver provides functions for implementing SPI master or + * SPI slave operations with the CoreSPI version 4.2.xxx It is not compatible + * with CoreSPI version 3.0.xxx. + * + * The Core SPI driver supports two classes of data transfer operation: + * SPI frame operation or SPI block transfer operations. + * + * Frame operations allow transferring individual SPI frames from 4 to 32-bits + * in length. Block operations allow transferring blocks of data organized as + * 8-bit frames. + * + * @file core_spi.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreSPI prototypes + * + */ + +/*=========================================================================*//** + @mainpage Core SPI Bare Metal Driver. + + ============================================================================== + Introduction + ============================================================================== + CoreSPI is an IP component that implements a full-duplex, synchronous, and + configurable serial peripheral interface (SPI) with frame sizes from 4 to 32 + bits and bus interface sizes of 8-, 16-, or 32-bit. Each CoreSPI instance + communicates with up to eight slave devices. + + This driver provides a set of functions for controlling CoreSPI as part of + the bare metal system where no operating system is available. These drivers + can be adapted to be used as a part of an operating system, but the + implementation of the adaptation layer between driver and the operating + system's driver model is outside the scope of this User's Guide. + + ============================================================================== + Driver Configuration + ============================================================================== + Your application software should configure the CoreSPI driver through calls + to the SPI_init() function for each CoreSPI instance in the hardware design. + This function configures a default set of parameters that include a CoreSPI + hardware instance base address and the depth of the FIFOs for this instance. + + The CoreSPI instance is configured at the time of instantiation in hardware + design for APB width, frame size, FIFO depth, serial clock speed, serial + clock polarity, serial clock phase, and slave select state parameters. + + CoreSPI can communicate with up to eight different slave devices that match + the CoreSPI configuration at the time of hardware instantiation. + + The functions SPI_configure_slave_mode() and SPI_configure_master_mode() are + used to configure the CoreSPI instance as a master or slave as required by + the application. + + When CoreSPI wishes to communicate with a specific slave device, call + the SPI_set_slave_select() function with the slave number as an argument. + This function selects the slave device. A previously selected slave gets + unselected by calling the SPI_clear_slave_select() function. + + ============================================================================== + Theory of Operation + ============================================================================== + The CoreSPI driver functions are grouped into the following categories: + • Initialization + • Configuration for either master or slave operations + • SPI master frame transfer control + • SPI master block transfer control + • SPI slave frame transfer control + • SPI slave block transfer control + + Frame transfers allow CoreSPI to write or read up to 32-bits of data in a + single SPI transaction. For example, a frame transfer of 12-bits might be used + to read the result of an ADC conversion from a SPI analog to digital converter. + + Block transfers allow CoreSPI to write and/or read a number of bytes in a single + SPI transaction. With the driver as is, block transfer transactions allow data + transfers in multiples of 8-bits (8, 16, 24, 32, 40,...) and the CoreSPI instance + has to be configured for 8-bit frames. For other frame sizes, the + SPI_transfer_block() code can act as a template for developing a frame block + transfer function. + Block transfers are typically used with byte oriented devices like SPI + FLASH devices. + + Note: The CoreSPI instance in the hardware design must be configured for + the frame size required by the application; configuration by driver is + not possible. + + -------------------------------- + Initialization + -------------------------------- + The CoreSPI driver is initialized through a call to the SPI_init() function. + The SPI_init() function takes a pointer to the global CoreSPI instance data + structure of type spi_instance_t and the base address of the CoreSPI instance + as defined by the hardware design. The CoreSPI instance global data structure + is used by the driver to store state information for each CoreSPI instance. + A pointer to these data structures is also used as the first parameter to + any of the driver functions to identify which CoreSPI will be used by the + called function. It is the responsibility of the application programmer to + create and maintain these global CoreSPI instance data structures. Any call + to a CoreSPI driver function should be of the form SPI_function_name + ( &g_core_spi0, ... ). + The SPI_init() function resets the transmit and receives FIFOs of CoreSPI + instance being initialized. + The SPI_init() function must be called before any other CoreSPI driver + functions can be called. + + ---------------------------------------------------- + Configuration + ---------------------------------------------------- + A CoreSPI instance can operate either as a master or as a slave SPI device. + There are two distinct functions for configuring a CoreSPI instance for + master or slave operations. + + ## Master Configuration + The SPI_configure_master_mode() function configures the specified CoreSPI + block for operations as an SPI master. This function must be called once + before the CoreSPI block communicates with an SPI slave device. + + ## Slave Configuration + The SPI_configure_slave_mode() function configures the specified CoreSPI + block for operations as a SPI slave. This function must be called after + calling the SPI_init() to configure the CoreSPI instance referred by this_spi + parameter to operate in the slave mode. + + ------------------------------------- + SPI Master Frame Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI master frame transfers: + • SPI_set_slave_select() + • SPI_transfer_frame() + • SPI_clear_slave_select() + + The master must first select the target slave or slaves to be addressed by + calling the SPI_set_slave_select() function. This causes the relevant select + line(s) to become asserted while data is clocked out onto the SPI data line. + + A function call is then made to SPI_transfer_frame() specifying the value + of the data frame to be sent and returning the value read. + + After the transfer is complete, use the SPI_clear_slave_select() function + to prevent this slave select line from being asserted during subsequent SPI + transactions. A call to this function is required only if the master is + communicating with multiple slave devices. + + ------------------------------------- + SPI Master Block Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI master block transfers: + • SPI_set_slave_select() + • SPI_transfer_block() + • SPI_clear_slave_select() + + The master must first select the target slave or slaves by calling + SPI_set_slave_select(). This causes the relevant slave select line(s) to + become asserted while data is clocked out onto the SPI data line. + Alternatively, a general purpose input/output (GPIO) can be used to control + the state of the target slave device's chip select signal. + + A call is then made to the SPI_transfer_block() function. The parameters of + this function specify the following: + • The number of bytes to be transmitted + • A pointer to the buffer containing the data to be transmitted + • The number of bytes to be received + • A pointer to the buffer where the received data gets stored + + The number of bytes to be transmitted can be set to zero to indicate that the + transfer is purely a block read transfer. The number of bytes to be received + can be set to zero to specify that the transfer is purely a block write + transfer. + + Block mode transfers as implemented by the driver are effectively half duplex + as we do not store the values received from the slave device whilst we are + transmitting. If full duplex operation is required, the driver + SPI_transfer_block() function can serve as a starting point for implementing + full duplex block transfers. + + The SPI_clear_slave_select() function can be used after the transfer is + complete to prevent this slave select line from being asserted during + subsequent SPI transactions. A call to this function is only required if + the master is communicating with multiple slave devices. + + ------------------------------------- + SPI Slave Frame Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI slave frame transfers: + • SPI_set_frame_rx_handler() + • SPI_set_slave_tx_frame() + + The SPI_set_frame_rx_handler() function specifies the receive handler + function that is called when a frame of data has been received by the + SPI when it is configured as a slave. The receive handler function specified + through this call processes the frame data written over the SPI bus to the + SPI slave by the remote SPI master. The receive handler function must be + implemented as part of the application. It is only required if the SPI slave + is the target of SPI frame write transactions. + + The SPI_set_slave_tx_frame() function specifies the frame data that is + returned to the SPI master. The frame data specified through this function + is the value that will be read over the SPI bus by the remote SPI master, + when it initiates a transaction. Call the SPI_set_slave_tx_frame() function + only if the SPI slave is the target of SPI read transactions. That is, if + data is meant to be read over CoreSPI. + + If both frame handlers are required, call the SPI_set_frame_rx_handler() + first, otherwise the initial TX frame gets discarded when SPI_set_frame_rx_handler() + clears the FIFOs as part of its initialization. + + ------------------------------------- + SPI Slave Block Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI slave block transfers: + • SPI_set_slave_block_buffers() + • SPI_set_cmd_handler() + • SPI_set_cmd_response() + + The SPI_set_slave_block_buffers() function is used to configure an SPI slave + for block transfer operations. It specifies the following: + • The buffer containing the data that will be returned to the remote SPI + master + • The buffer where data received from the remote SPI master will be + stored + • The optional handler function that will be called after the receive + buffer is filled + + The SPI_set_cmd_handler() function specifies a command handler function that + is called by the driver once a specific number of frames have been + received after the SPI chip select signal becomes active. The number of + bytes making up the command part of the transaction is specified as part of + the parameters to the SPI_set_cmd_handler() function. The command handler + function is implemented as a part of the application making use of the SPI + driver and typically calls the SPI_set_cmd_response() function. + + The SPI_set_cmd_response() function specifies the data that gets returned + to the master. Typically, the SPI_set_slave_block_buffers() function is + called as a part of the system initialisation to specify the data sent to + the master while the command bytes are being received. The transmit buffer + specified through calling the SPI_set_slave_block_buffers() function would + also typically include one or more bytes allowing the turn around time + for the command handler function to execute and call the + SPI_set_cmd_response() function. + + *//*=========================================================================*/ +#ifndef CORE_SPI_H_ +#define CORE_SPI_H_ + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#include "hal_assert.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + SPI FIFO Depth + ======================================= + SPI_MAX_FIFO_DEPTH & SPI_MIN_FIFO_DEPTH constants define the maximum and minimum + FIFO depths allowed for the CoreSPI instance. User need to inform the driver of + the FIFO depth for each CoreSPI instance to ensure that the FIFOs are managed correctly. + + | Constant | Description | + |--------------------|----------------------------------------------------| + | SPI_MAX_FIFO_DEPTH | Maximum FIFO depth allowed for the CoreSPI instance| + | SPI_MIN_FIFO_DEPTH | Minimum FIFO depth allowed for the CoreSPI instance| + + */ +#define SPI_MAX_FIFO_DEPTH 32u +#define SPI_MIN_FIFO_DEPTH 1u + +/***************************************************************************//** + Instances of this structure are used to identify the specific CoreSPI hardware + instances. A pointer to an instance of the spi_instance_t structure is passed + as the first parameter to the CoreSPI driver functions to identify which SPI + performs the requested operation. + */ +typedef struct spi_instance spi_instance_t; + +/***************************************************************************//** + This function pointer type is to assign a callback function for TX interrupt + when slave wants to send the next updated frame. + + Declaring and Implementing Slave Frame Transmit Handler Functions: + Slave transmit frame update handler functions should follow the following + prototype: + void slave_tx_frame_update_handler ( spi_instance_t * this_spi ); + The actual name of the transmit handler is unimportant. You can use any name + of your choice for the frame update handler. + + A common handler function may be used when multiple CoreSPI instances are + configured as slave, as the particular slave device currently requiring + service is indicated by the function parameter. + */ +typedef void (*spi_slave_frame_tx_handler_t)( spi_instance_t * this_spi ); + +/***************************************************************************//** + This defines the function prototype that must be followed by the SPI slave + frame receive handler functions. These functions are registered with the SPI + driver through the SPI_set_frame_rx_handler() function. + + Declaring and Implementing the Slave Frame Receive Handler Functions: + The Slave frame receive handler functions should follow the following + prototype: + void slave_frame_receive_handler(uint32_t rx_frame); + The actual name of the receive handler is unimportant. You can use any name + of your choice for the receive frame handler. The rx_frame parameter contains + the value of the received frame. + + Separate handler functions are required for each slave instance as there is + no indication of the slave requiring service passed to the handler. + + */ +typedef void (*spi_frame_rx_handler_t)( uint32_t rx_frame ); + +/***************************************************************************//** + This defines the function prototype that must be followed by SPI slave + block receive handler functions. These functions are registered with the + SPI driver through the SPI_set_slave_block_buffers() function. + + Declaring and Implementing Slave Block Receive Handler Functions: + Slave block receive handler functions should follow the following prototype: + void spi_block_rx_handler ( uint8_t * rx_buff, uint16_t rx_size ); + The actual name of the receive handler is unimportant. You can use any name + of your choice for the receive frame handler. The rx_buff parameter contains + a pointer to the start of the received block. The rx_size parameter contains + the number of bytes of the received block. + + Separate handler functions are required for each slave instance as there is + no indication of the slave requiring service passed to the handler. + + */ +typedef void (*spi_block_rx_handler_t)( uint8_t * rx_buff, uint32_t rx_size ); + +/***************************************************************************//** + This enumeration is used to select a specific SPI slave device (0 to 7). It is + used as a parameter to the SPI_configure_master_mode(), SPI_set_slave_select(), + and SPI_clear_slave_select() functions. + */ +typedef enum __spi_slave_t +{ + SPI_SLAVE_0 = 0, + SPI_SLAVE_1 = 1, + SPI_SLAVE_2 = 2, + SPI_SLAVE_3 = 3, + SPI_SLAVE_4 = 4, + SPI_SLAVE_5 = 5, + SPI_SLAVE_6 = 6, + SPI_SLAVE_7 = 7, + SPI_MAX_NB_OF_SLAVES = 8 +} spi_slave_t; + +/***************************************************************************//** + This enumeration is used to indicate the current slave mode transfer type so + that we are not relying on buffer comparisons to dictate the logic of the driver. + */ +typedef enum __spi_sxfer_mode_t +{ + SPI_SLAVE_XFER_NONE = 0, /* Not configured yet */ + SPI_SLAVE_XFER_BLOCK = 1, /* Block transfers, with SSEND delimiting end of block */ + SPI_SLAVE_XFER_FRAME = 2 /* Single frame transfers */ +} spi_sxfer_mode_t; + +/***************************************************************************//** + There is one instance of this structure for each of the core SPIs. Instances + of this structure are used to identify a specific SPI. A pointer to an + instance of the spi_instance_t structure is passed as the first parameter to + SPI driver functions to identify which SPI should perform the requested operation. + */ +struct spi_instance{ + + /* Base address in the processor's memory map for the + registers of the CoreSPI instance being initialized */ + addr_t base_addr; /* Base address of SPI hardware instance */ + + uint32_t rx_frame; /* received data */ + + /* Internal transmit state: */ + const uint8_t * slave_tx_buffer; /* Pointer to slave transmit buffer */ + uint32_t slave_tx_size; /* Size of slave transmit buffer */ + uint32_t slave_tx_idx; /* Current index into slave transmit buffer */ + + /* Slave command response buffer: */ + const uint8_t * resp_tx_buffer; + uint32_t resp_buff_size; + uint32_t resp_buff_tx_idx; + spi_block_rx_handler_t cmd_handler; + uint32_t cmd_done; /* Flag which indicates response has been set up and + it is safe to pad with 0s once the response is sent */ + + /* Internal receive state: */ + uint8_t * slave_rx_buffer; /* Pointer to buffer where data received by a slave will be stored */ + uint32_t slave_rx_size; /* Slave receive buffer size */ + uint32_t slave_rx_idx; /* Current index into slave receive buffer */ + + /* Slave received frame handler: */ + spi_frame_rx_handler_t frame_rx_handler; /* Pointer to function that will be called when a frame + is received when the SPI block is configured as slave */ + /* Slave transmitted frame handler: */ + uint32_t slave_tx_frame; /* Value of the data frame that will be transmitted + when the SPI block is configured as slave */ + spi_slave_frame_tx_handler_t slave_tx_frame_handler; /* Callback function pointer to update slave_tx_frame */ + + /* Slave block rx handler: */ + spi_block_rx_handler_t block_rx_handler; /* Pointer to the function that will be called when a data block has been received */ + + /* Per instance specific hardware information that the driver needs to know */ + uint16_t fifo_depth; /* Depth of RX and TX FIFOs in frames */ + + /* How we are expecting to deal with slave transfers */ + spi_sxfer_mode_t slave_xfer_mode; /* Current slave mode transfer configuration */ +}; + +/*------------------------Public Function-------------------------------------*/ + +/***************************************************************************//** + The SPI_init() function initializes the hardware and data structures of a + CoreSPI instance referenced by this_spi parameter. This function must be + called for each CoreSPI instance with a unique this_spi and base_addr + parameter combination. The SPI_init() function must be called before any + other CoreSPI driver functions are called. + + After calling the SPI_init() the CoreSPI is configured as a master, + all interrupt sources will be masked and all the slaves are deselected. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to be initialized. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @param base_addr + The base_addr parameter is the base address in the processor's memory map for + the registers of the CoreSPI instance being initialized. It is assumed that + any non NULL value passed in here points to a valid instance of a CoreSPI as + the driver has no way of verifying this. Failure to pass in a valid address + can result in system instability. + + @param fifo_depth + The fifo_depth parameter specifies the number of frames in the receive + and transmit FIFOs of the CoreSPI instance being initialized. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + @endcode + */ +void SPI_init +( + spi_instance_t * this_spi, + addr_t base_addr, + uint16_t fifo_depth +); + +/***************************************************************************//** + The SPI_configure_slave_mode() function is used when a CoreSPI instance is + to be configured as a SPI slave. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to be configured. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + + int main(void) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_slave_mode ( &g _spi0 ); + } + @endcode + */ +void SPI_configure_slave_mode +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_configure_master_mode() function is used when a CoreSPI instance is + to be configured as a SPI master. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to be configured. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + + int main(void) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_master_mode ( &g _spi0 ); + } + @endcode + */ +void SPI_configure_master_mode +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_set_slave_select() function is used by a CoreSPI master to select a + specific slave. This function causes the relevant slave select signal to be + asserted while data is clocked out onto the SPI data line. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param slave + The slave parameter is one of the spi_slave_t enumerated constants + identifying a slave. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + const uint32_t master_tx_frame = 0x0100A0E1; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0 ); + SPI_transfer_frame( &g_spi0, master_tx_frame ); + SPI_clear_slave_select( &g_spi0, SPI_SLAVE_0 ); + + @endcode + */ +void SPI_set_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +); + +/***************************************************************************//** + The SPI_clear_slave_select() function is used by a CoreSPI master to + deselect a specific slave. This function causes the relevant slave select + signal to be de-asserted. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param slave + The slave parameter is one of the spi_slave_t enumerated constants + identifying a slave. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + const uint32_t master_tx_frame = 0x0100A0E1; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0 ); + SPI_transfer_frame( &g_spi0, master_tx_frame ); + SPI_clear_slave_select( &g_spi0, SPI_SLAVE_0 ); + @endcode + */ +void SPI_clear_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +); + +/***************************************************************************//** + The SPI_transfer_frame() function is used by a SPI master to transmit and + receive a single frame of the size that has been configured at the time of + CoreSPI hardware instantiation. This function is typically used for + transactions with a SPI slave where the number of transmit and receive bits + are not divisible by 8 or where full duplex exchange of frames is required. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param tx_bits + The tx_bits parameter is a 32-bit word containing the value that will be + transmitted. If the frame size configured for the CoreSPI is less than 32-bits, + the upper bits will be ignored. + Note: The bit length of the value to be transmitted to the slave is + set when the CoreSPI is instantiated in the hardware design. + + @return + This function returns a 32-bit word containing the value that is received + from the slave. If the frame size configured for the CoreSPI in question is + less that 32-bits, the upper bits will be 0. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + const uint32_t master_tx_frame = 0x0100A0E1; + uint32_t master_rx; + + SPI_init(&g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ); + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0 ); + master_rx = SPI_transfer_frame( &g_spi0, master_tx_frame ); + SPI_clear_slave_select( &g_spi0, SPI_SLAVE_0 ); + @endcode + */ +uint32_t SPI_transfer_frame +( + spi_instance_t * this_spi, + uint32_t tx_bits +); + +/***************************************************************************//** + The SPI_transfer_block() function is used by the SPI master to transmit and + receive blocks of data organized as a specified number of 8-bit frames. It + can be used for the following: + • Writing a data block to a slave + • Reading a data block from a slave + • Sending a command to a slave followed by reading the outcome of + the command in a single SPI transaction. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param cmd_buffer + The cmd_buffer parameter is a pointer to the buffer that contains the data + sent by the master from the beginning of the transfer. This pointer can be + null (0) if the master does not need to send a command before reading data. + + @param cmd_byte_size + The cmd_byte_size parameter specifies the number of bytes in cmd_buffer that + will be sent. A value ‘0’ indicates that no data needs to be sent to the slave. + + @param rx_buffer + The rx_buffer parameter is a pointer to the buffer that stores the data received + from the slave after sending the command. This pointer can be null (0) if the + master does not receive any data from the slave. + + @param rx_byte_size + The rx_byte_size parameter specifies the number of bytes received from + the slave and stored in the rx_buffer. A value ‘0’ indicates that no data is + to be read from the slave. + + @return + This function does not return any value. + + @example + @code + Polled write transfer example + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + + uint8_t master_tx_buffer[MASTER_TX_BUFFER] = + { + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A + }; + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0) ; + SPI_transfer_block + ( + &g_spi0, + master_tx_buffer, + sizeof(master_tx_buffer), + 0, + 0 + ); + SPI_clear_slave_select(&g_spi0, SPI_SLAVE_0 ); + @endcode + */ +void SPI_transfer_block +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_buffer, + uint16_t rx_byte_size +); + +/***************************************************************************//** + The SPI_transfer_block_store_all_resp() function is used by the SPI master + to transmit and receive blocks of data organized as a specified number + of 8-bit frames. It can be used for the following: + • Writing a data block to a slave + • Reading a data block from a slave + • Sending a command to a slave followed by reading the outcome of + the command in a single SPI transaction + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param cmd_buffer + The cmd_buffer parameter is a pointer to the buffer that contains the data sent by + the master from the beginning of the transfer. This pointer can be null (0) + if the master does not need to send a command before reading data. + + @param cmd_byte_size + The cmd_byte_size parameter specifies the number of bytes contained in + cmd_buffer that will be sent. A value ‘0’ indicates that no data needs + to be sent to the slave. + + @param rx_data_buffer + The rx_data_buffer parameter is a pointer to the buffer that stores the data received + from the slave after sending the command. This pointer can be null (0) if the + master does not receive any data from the slave. + + @param rx_byte_size + The rx_byte_size parameter specifies the number of bytes received from + the slave and stores in the rx_buffer. A value ‘0’ indicates that no data is + to be read from the slave. + + @param cmd_response_buffer + The cmd_response_buffer parameter is a pointer to the buffer which stores the + command response from the slave, while the master is transmitting the number + of bytes indicated by cmd_byte_size parameter. + + @return + This function does not return any value. + + @example + @code + Polled write transfer example + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + + uint8_t master_tx_buffer[MASTER_TX_BUFFER] = + { + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A + }; + + uint8_t cmd_rx_buffer[CMD_RX_BUFFER]={0}; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0) ; + SPI_transfer_block_store_all_resp + ( + &g_spi0, + master_tx_buffer, + sizeof(master_tx_buffer), + 0, + 0, + cmd_response_buffer + ); + SPI_clear_slave_select(&g_spi0, SPI_SLAVE_0 ); + @endcode + */ +void SPI_transfer_block_store_all_resp +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_data_buffer, + uint16_t rx_byte_size, + uint8_t * cmd_response_buffer +); + +/***************************************************************************//** + The SPI_set_frame_rx_handler() function is used by the SPI slaves to specify + the receive handler function that is called by the SPI driver interrupt + handler when a frame of data is received by the SPI slave. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param rx_handler + The rx_handler parameter is a pointer to the frame receive handler that must + be called when a frame is received by the CoreSPI slave. Passing in a NULL + pointer disables the receive handler but does enable the receive interrupt to + ensure the RX FIFO is empty each time a frame is received. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + uint32_t g_slave_rx_frame = 0; + spi_instance_t g_spi0; + + void slave_frame_handler(uint32_t rx_frame) + { + g_slave_rx_frame = rx_frame; + } + int setup_slave( void ) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_slave_mode( &g_spi0 ); + SPI_set_frame_rx_handler( &g_spi0, slave_frame_handler ); + } + @endcode + */ +void SPI_set_frame_rx_handler +( + spi_instance_t * this_spi, + spi_frame_rx_handler_t rx_handler +); + +/***************************************************************************//** + The SPI_set_slave_tx_frame() function is used by the SPI slaves to specify + the frame that gets transmitted when a transaction is initiated by the SPI + master. This function allows you to assign a slave_tx_frame_handler function, + which will be executed upon transmit interrupt when the SPI is in slave mode. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param frame_value + The frame_value parameter contains the value of the frame to be sent to the + master. + Note: The bit length of the value to be transmitted to the master is + set when the CoreSPI is instantiated in the hardware design. + + @param slave_tx_frame_handler + The slave_tx_frame_handler function pointer is executed upon occurrence of + transmit interrupt when CoreSPI is operating in slave mode. This parameter + is optional and if set to NULL it is assumed that the frame value is static or + updated asynchronously. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + const uint32_t slave_tx_frame[2] = { 0x0110F761, 0x0110F671 }; + uint32_t master_rx; + uint32_t slave_frame_idx = 0 ; + + slave_frame_update( spi_instance_t * this_spi ) + { + this_spi->slave_tx_frame = slave_tx_frame[slave_frame_idx++]; + if( slave_frame_idx > 2 ) + slave_frame_idx = 0; + } + main() + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ) ; + SPI_set_slave_tx_frame( &g_spi0, slave_tx_frame[slave_frame_idx++], + &slave_frame_update ); + } + @endcode + */ +void SPI_set_slave_tx_frame +( + spi_instance_t * this_spi, + uint32_t frame_value, + spi_slave_frame_tx_handler_t slave_tx_frame_handler +); + +/***************************************************************************//** + The SPI_set_slave_block_buffers() function is used to configure an SPI slave + for block transfer operations. It specifies one or more of the following: + • The data that is transmitted when accessed by a master. + • The buffer where the data received from a master is stored. + • The handler function that must be called after the receive buffer has + been filled. + • The number of bytes that must be received from the master before calling + the recieve handler function. + These parameters allow the following use cases: + • Slave performing an action after receiving a block of data from a + master containing a command. This action is performed by the + receive handler based on the content of the receive data buffer. + • Slave returning a block of data to the master. The type of information + is always the same but the actual values change over time. For example, + returning the voltage of a predefined set of analog inputs. + • Slave returning data based on a command contained in the first part of + the SPI transaction. For example, reading the voltage of the analog + input specified by the first data byte by the master. This is achieved + by using the SPI_set_slave_block_buffers() function in conjunction with + functions SPI_set_cmd_handler() and SPI_set_cmd_response(). + + See the SPI_set_cmd_handler() function description for details of + this use case. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param tx_buffer + The tx_buffer parameter is a pointer to a buffer containing the data that + will be sent to the master. This parameter can be set to ‘0’ if the SPI + slave is not intended to be the target of SPI read transactions. + + @param tx_buff_size + The tx_buff_size parameter specifies the number of bytes that are + transmitted by the SPI slave. It is the number of bytes contained in the + tx_buffer. This parameter can be set to ‘0’ if the SPI slave is not + intended to be the target of SPI read transactions. The driver returns 0s + to the master if there is no buffer specified or the master reads beyond the + end of the buffer. + Note: If SPI_transfer_block() is used to read from this slave and there is + no command handler involved, the buffer size here must be at least the + combined length of the command and response specified by the master. + On receiving this data, the master discards the data bytes equal to + command length bytes from the start of the received buffer. + + @param rx_buffer + The rx_buffer parameter is a pointer to the buffer where data received + from the master is stored. This parameter can be set to ‘0’ if the + SPI slave is not intended to be the target of SPI write or write-read + transactions. + + @param rx_buff_size + The rx_buff_size parameter specifies the size of the receive buffer. It is + also the number of bytes that must be received before the receive handler + is called, if a receive handler is specified using the block_rx_handler + parameter. Any bytes received in excess of the size specified by the + rx_buff_size parameter are discarded. This parameter can be set to ‘0’ + if the SPI slave is not intended to be the target of SPI write or + write-read transactions. + + @param block_rx_handler + The block_rx_handler parameter is a pointer to a function that is called + when receive buffer has been filled or the slave select has been de-asserted. + This parameter can be set to ‘0’ if the SPI slave is not intended to be the + target of SPI write or write-read transactions. + + @return + This function does not return any value. + + @example + @code + Slave Performing Operation Based on Master Command: + In this example the SPI slave is configured to receive 10 bytes of data + or command from the SPI slave, and process the data received from the master. + + #define SPI0_BASE_ADDR 0xC2000000 + + uint32_t nb_of_rx_handler_calls = 0; + spi_instance_t g_spi0; + + void spi1_block_rx_handler_b + ( + uint8_t * rx_buff, + uint16_t rx_size + ) + { + ++nb_of_rx_handler_calls; + } + + void setup_slave( void ) + { + uint8_t slave_rx_buffer[10] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_slave_mode( &g_spi0 ); + + SPI_set_slave_block_buffers + ( + &g_spi0, + 0, + 0, + slave_rx_buffer, + sizeof( master_tx_buffer ), + spi1_block_rx_handler_b + ); + } + @endcode + */ +void SPI_set_slave_block_buffers +( + spi_instance_t * this_spi, + const uint8_t * tx_buffer, + uint32_t tx_buff_size, + uint8_t * rx_buffer, + uint32_t rx_buff_size, + spi_block_rx_handler_t block_rx_handler +); + +/***************************************************************************//** + The SPI_isr() function is the top level interrupt handler function for the + CoreSPI driver. You must call SPI_isr() from the system level + (CoreInterrupt and NVIC level) interrupt handler assigned to the interrupt + triggered by the CoreSPI SPIINT signal. Your system level interrupt handler + must also clear the system level interrupt triggered by the CoreSPI SPIINT + signal before returning, to prevent a re-assertion of the same interrupt. + + This function supports all types of interrupt triggered by CoreSPI. It is not + a complete interrupt handler by itself; rather, it is a top level wrapper that + abstracts CoreSPI command interrupt and slave mode transmit interrupt handling + by calling lower level handler functions specific to each type of CoreSPI + interrupt. You must create the lower level handler functions to suit your + application and register them with the driver through calling the + SPI_set_cmd_handler(), SPI_set_cmd_response(), and SPI_set_slave_tx_frame() + functions. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + + @example + @code + + Example of configuring a CoreInterrupt connected to the Fabric Interrupt on a + SmartFusion device to handle CoreSPI interrupt. + + #define #define SPI1_INT_IRQ_NB 0 + spi_instance_t g_spi0; + + Void CIC_irq1_handler(void) + { + SPI_isr( &g_spi0 ); + } + + void Fabric_IRQHandler( void ) + { + // Call the CoreInterrupt driver ISR to determine the source of the + // interrupt and call the relevant ISR registered to it. + CIC_irq_handler(); + + // Clear NVIC interrupt status to allow further interrupts + NVIC_ClearPendingIRQ( Fabric_IRQn ); + } + + main() + { + ... + + CIC_init( CIC_BASE_ADDR ); + + // Install handler for SPI IRQ + CIC_set_irq_handler( SPI0_INT_IRQ_NB, CIC_irq1_handler ); + + NVIC_ClearPendingIRQ( Fabric_IRQn ); + NVIC_EnableIRQ( Fabric_IRQn ); + + CIC_enable_irq( SPI1_INT_IRQ_NB ); + + ... + } + @endcode + */ +void SPI_isr +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_set_cmd_handler() function specifies a command handler function that + will be called when the number of bytes received reaches the command size + specified as cmd_size parameter. + + This function is used by the SPI slaves performing block transfers. Its + purpose is to allow an SPI slave to decide the data that will be returned to + the master while an SPI transaction is taking place. Typically, one or more + command bytes are sent by the master to request some specific data. The slave + interprets the command byte(s) while one or more turn-around bytes are + transmitted. The slave adjusts its transmit data buffer based on the command + during the turn around time. + + The following table provides an example of the use of this function where the + SPI slave returns data bytes D0 to D6 based on the value of a command. The + 3 bytes long command is made up of a command opcode byte followed by an + address byte followed by a size byte. The cmd_handler() function specified + through an earlier call to SPI_set_cmd_handler() is called by the CoreSPI + driver once the third byte is received. The cmd_handler() function + interprets the command bytes and calls SPI_set_cmd_response() to set the SPI + slave's response transmit buffer with the data to be transmitted after the + turnaround bytes (T0 to T3). The number of turnaround bytes must be + sufficient to give enough time for the cmd_handler() to execute. The number + of turnaround bytes is specified by the protocol used on top of the SPI + transport layer so that master and slave agree on the number of turn around + bytes. + +|Timestamp| SPI Transaction | Bytes | Comments | +|---------|-------------|----------------------|---------------| +| t0|COMMAND|C A S |C - command opcode byte, A - address byte, S - size byte| +|t1| TURN-AROUND|T0 T1 |cmd_handler() called here (T0 to T3 are TURN-AROUND bytes)| +|t2|TURN-AROUND|T2 T3|SPI_set_cmd_response() called here by implementation of cmd_handler() +|| | |to set the data that will be transmitted by the SPI slave.| +|t3| DATA | D0 D1 D2 D3 D4 D5 D6 |Data transmition (SPI slave return data bytes)| + + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure identifying + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @param cmd_handler + The cmd_handler parameter is a pointer to a function with the prototype: + void cmd_handler(uint8_t * rx_buff, uint32_t rx_size); + It specifies the function that will be called when the number of bytes + specified by the cmd_size parameter has been received. + + @param cmd_size + The cmd_size parameter specifies the number of bytes that must be received + before calling the command handler function specified by the cmd_handler. + The CoreSPI supports cmd_size values in the range 1 to 7. + + @return + This function does not return any value. + + @example + @code + The following example demonstrates how to configure CoreSPI to implement + the protocol given as an example above. The configure_slave() function + configures CoreSPI. It sets receive and transmit buffers. The transmit + buffer specified through the call to SPI_set_slave_block_buffers() function + specifies the data that will be returned to the master in bytes between + t0 and t3. These bytes will be sent to the master while the master transmits + the command and dummy bytes. The spi_slave_cmd_handler() function will be + called by the driver at time t1 after the 3 command bytes have been received. + The spi_block_rx_handler() function will be called by the driver at time t4, + when the transaction completes and the slave select signal becomes + de-asserted. + + #define SPI0_BASE_ADDR 0xC2000000 + #define COMMAND_SIZE 3 + #define NB_OF_DUMMY_BYTES 4 + #define MAX_TRANSACTION_SIZE 16 + + spi_instance_t g_spi0; + uint8_t slave_tx_buffer[COMMAND_SIZE + NB_OF_DUMMY_BYTES]; + uint8_t slave_rx_buffer[MAX_TRANSACTION_SIZE]; + + void configure_slave( void ) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_slave_mode( &g_spi0 ); + SPI_set_slave_block_buffers + ( + &g_spi0, + slave_tx_buffer, + COMMAND_SIZE + NB_OF_DUMMY_BYTES, + slave_rx_buffer, + sizeof(slave_rx_buffer), + spi_block_rx_handler + ); + + SPI_set_cmd_handler + ( + &g_spi0, + spi_slave_cmd_handler, + COMMAND_SIZE + ); + } + + void spi_slave_cmd_handler + ( + uint8_t * rx_buff, + uint32_t rx_size + ) + { + uint8_t command; + uint8_t address; + uint8_t size; + uint8_t * p_response; + uint32_t response_size; + + command = rx_buff[0]; + address = rx_buff[1]; + size = rx_buff[2]; + + p_response = get_response_data( command, address, size, &response_size ); + SPI_set_cmd_response( &g_spi0, p_response, response_size ); + } + + void spi_block_rx_handler + ( + uint8_t * rx_buff, + uint32_t rx_size + ) + { + process_rx_data( rx_buff, rx_size ); + } + @endcode + */ +void SPI_set_cmd_handler +( + spi_instance_t * this_spi, + spi_block_rx_handler_t cmd_handler, + uint32_t cmd_size +); + +/***************************************************************************//** + The SPI_set_cmd_response() function specifies the data that will be returned + to the master. See the description of SPI_set_cmd_handler() for details. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param resp_tx_buffer + The resp_tx_buffer parameter is a pointer to the buffer containing the data + that must be returned to the host in the data phase of an SPI transaction. + + @param resp_buff_size + The resp_buff_size parameter specifies the size of the buffer pointed by the + resp_tx_buffer parameter. + + @return + This function does not return any value. + */ +void SPI_set_cmd_response +( + spi_instance_t * this_spi, + const uint8_t * resp_tx_buffer, + uint32_t resp_buff_size +); + +/***************************************************************************//** + The SPI_enable() function enables the CoreSPI and allows it to respond to the external + signals. It is usually called to re-enable a CoreSPI instance which has been + disabled previously via by calling the SPI_disable() as the normal state of a CoreSPI + after enabling the initialization. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + */ +void SPI_enable +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_disable() function disables the CoreSPI and stops responding to the + external signals. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + */ +void SPI_disable +( + spi_instance_t * this_spi +); + +#ifdef __cplusplus +} +#endif + +#endif /* CORE_SPI_H_*/ diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreSPI/corespi_regs.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreSPI/corespi_regs.h new file mode 100644 index 0000000..a3e5b2a --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreSPI/corespi_regs.h @@ -0,0 +1,270 @@ +/***************************************************************************//** + * Copyright 2011-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file corespi_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreSPI memory map + * + */ + +#ifndef CORESPI_REGS_H_ +#define CORESPI_REGS_H_ + +/******************************************************************************* + * Control register 1: + *------------------------------------------------------------------------------ + */ +#define CTRL1_REG_OFFSET 0x00u + +#define CTRL1_ENABLE_OFFSET 0x00u +#define CTRL1_ENABLE_MASK 0x01u +#define CTRL1_ENABLE_SHIFT 0x00 + +#define CTRL1_MASTER_OFFSET 0x00u +#define CTRL1_MASTER_MASK 0x02u +#define CTRL1_MASTER_SHIFT 0x01 + +#define CTRL1_INTRXDATA_OFFSET 0x00u +#define CTRL1_INTRXDATA_MASK 0x04u +#define CTRL1_INTRXDATA_SHIFT 0x02 + +#define CTRL1_INTTXDONE_OFFSET 0x00u +#define CTRL1_INTTXDONE_MASK 0x08u +#define CTRL1_INTTXDONE_SHIFT 0x03 + +#define CTRL1_INTRXOVFLOW_OFFSET 0x00u +#define CTRL1_INTRXOVFLOW_MASK 0x10u +#define CTRL1_INTRXOVFLOW_SHIFT 0x04 + +#define CTRL1_INTTXURUN_OFFSET 0x00u +#define CTRL1_INTTXURUN_MASK 0x20u +#define CTRL1_INTTXURUN_SHIFT 0x05 + +#define CTRL1_FRAMEURUN_OFFSET 0x00u +#define CTRL1_FRAMEURUN_MASK 0x40u +#define CTRL1_FRAMEURUN_SHIFT 0x06 + +#define CTRL1_OENOFF_OFFSET 0x00u +#define CTRL1_OENOFF_MASK 0x80u +#define CTRL1_OENOFF_SHIFT 0x07 + +/******************************************************************************* + * Interrupt clear register: + *------------------------------------------------------------------------------ + */ +#define INTCLR_REG_OFFSET 0x04u + +#define INTCLR_TXDONE_OFFSET 0x04u +#define INTCLR_TXDONE_MASK 0x01u +#define INTCLR_TXDONE_SHIFT 0x00 + +#define INTCLR_RXDONE_OFFSET 0x04u +#define INTCLR_RXDONE_MASK 0x02u +#define INTCLR_RXDONE_SHIFT 0x01 + +#define INTCLR_RXOVERFLOW_OFFSET 0x04u +#define INTCLR_RXOVERFLOW_MASK 0x04u +#define INTCLR_RXOVERFLOW_SHIFT 0x02 + +#define INTCLR_TXUNDERRUN_OFFSET 0x04u +#define INTCLR_TXUNDERRUN_MASK 0x08u +#define INTCLR_TXUNDERRUN_SHIFT 0x03 + +#define INTCLR_CMDINT_OFFSET 0x04u +#define INTCLR_CMDINT_MASK 0x10u +#define INTCLR_CMDINT_SHIFT 0x04 + +#define INTCLR_SSEND_OFFSET 0x04u +#define INTCLR_SSEND_MASK 0x20u +#define INTCLR_SSEND_SHIFT 0x05 + +#define INTCLR_RXDATA_OFFSET 0x04u +#define INTCLR_RXDATA_MASK 0x40u +#define INTCLR_RXDATA_SHIFT 0x06 + +#define INTCLR_TXDATA_OFFSET 0x04u +#define INTCLR_TXDATA_MASK 0x80u +#define INTCLR_TXDATA_SHIFT 0x07 + +/******************************************************************************* + * Receive data register: + *------------------------------------------------------------------------------ + */ +#define RXDATA_REG_OFFSET 0x08u + +/******************************************************************************* + * Transmit data register: + *------------------------------------------------------------------------------ + */ +#define TXDATA_REG_OFFSET 0x0Cu + +/******************************************************************************* + * Masked interrupt status register: + *------------------------------------------------------------------------------ + */ +#define INTMASK_REG_OFFSET 0x10u + +#define INTMASK_TXDONE_OFFSET 0x10u +#define INTMASK_TXDONE_MASK 0x01u +#define INTMASK_TXDONE_SHIFT 0x00 + +#define INTMASK_RXDONE_OFFSET 0x10u +#define INTMASK_RXDONE_MASK 0x02u +#define INTMASK_RXDONE_SHIFT 0x01 + +#define INTMASK_RXOVERFLOW_OFFSET 0x10u +#define INTMASK_RXOVERFLOW_MASK 0x04u +#define INTMASK_RXOVERFLOW_SHIFT 0x02 + +#define INTMASK_TXUNDERRUN_OFFSET 0x10u +#define INTMASK_TXUNDERRUN_MASK 0x08u +#define INTMASK_TXUNDERRUN_SHIFT 0x03 + +#define INTMASK_CMDINT_OFFSET 0x10u +#define INTMASK_CMDINT_MASK 0x10u +#define INTMASK_CMDINT_SHIFT 0x04 + +#define INTMASK_SSEND_OFFSET 0x10u +#define INTMASK_SSEND_MASK 0x20u +#define INTMASK_SSEND_SHIFT 0x05 + +#define INTMASK_RXDATA_OFFSET 0x10u +#define INTMASK_RXDATA_MASK 0x40u +#define INTMASK_RXDATA_SHIFT 0x06 + +#define INTMASK_TXDATA_OFFSET 0x10u +#define INTMASK_TXDATA_MASK 0x80u +#define INTMASK_TXDATA_SHIFT 0x07 + +/******************************************************************************* + * Raw interrupt status register: + *------------------------------------------------------------------------------ + */ +#define INTRAW_REG_OFFSET 0x14u + +#define INTRAW_TXDONE_OFFSET 0x14u +#define INTRAW_TXDONE_MASK 0x01u +#define INTRAW_TXDONE_SHIFT 0x00 + +#define INTRAW_RXDONE_OFFSET 0x14u +#define INTRAW_RXDONE_MASK 0x02u +#define INTRAW_RXDONE_SHIFT 0x01 + +#define INTRAW_RXOVERFLOW_OFFSET 0x14u +#define INTRAW_RXOVERFLOW_MASK 0x04u +#define INTRAW_RXOVERFLOW_SHIFT 0x02 + +#define INTRAW_TXUNDERRUN_OFFSET 0x14u +#define INTRAW_TXUNDERRUN_MASK 0x08u +#define INTRAW_TXUNDERRUN_SHIFT 0x03 + +#define INTRAW_CMDINT_OFFSET 0x14u +#define INTRAW_CMDINT_MASK 0x10u +#define INTRAW_CMDINT_SHIFT 0x04 + +#define INTRAW_SSEND_OFFSET 0x14u +#define INTRAW_SSEND_MASK 0x20u +#define INTRAW_SSEND_SHIFT 0x05 + +#define INTRAW_RXDATA_OFFSET 0x14u +#define INTRAW_RXDATA_MASK 0x40u +#define INTRAW_RXDATA_SHIFT 0x06 + +#define INTRAW_TXDATA_OFFSET 0x14u +#define INTRAW_TXDATA_MASK 0x80u +#define INTRAW_TXDATA_SHIFT 0x07 + +/******************************************************************************* + * Control register 2: + *------------------------------------------------------------------------------ + */ +#define CTRL2_REG_OFFSET 0x18u + +#define CTRL2_CMDSIZE_OFFSET 0x18u +#define CTRL2_CMDSIZE_MASK 0x07u +#define CTRL2_CMDSIZE_SHIFT 0x00 + +#define CTRL2_INTCMD_OFFSET 0x18u +#define CTRL2_INTCMD_MASK 0x10u +#define CTRL2_INTCMD_SHIFT 0x04 + +#define CTRL2_INTSSEND_OFFSET 0x18u +#define CTRL2_INTSSEND_MASK 0x20u +#define CTRL2_INTSSEND_SHIFT 0x05 + +#define CTRL2_INTRXDATA_OFFSET 0x18u +#define CTRL2_INTRXDATA_MASK 0x40u +#define CTRL2_INTRXDATA_SHIFT 0x06 + +#define CTRL2_INTTXDATA_OFFSET 0x18u +#define CTRL2_INTTXDATA_MASK 0x80u +#define CTRL2_INTTXDATA_SHIFT 0x07 + +/******************************************************************************* + * Command register: + *------------------------------------------------------------------------------ + */ +#define CMD_REG_OFFSET 0x1Cu + +#define CMD_RXFIFORST_OFFSET 0x1Cu +#define CMD_RXFIFORST_MASK 0x01u +#define CMD_RXFIFORST_SHIFT 0x00 + +#define CMD_TXFIFORST_OFFSET 0x1Cu +#define CMD_TXFIFORST_MASK 0x02u +#define CMD_TXFIFORST_SHIFT 0x01 + +/******************************************************************************* + * Status register: + *------------------------------------------------------------------------------ + */ +#define STATUS_REG_OFFSET 0x20u + +#define STATUS_FIRSTFRAME_OFFSET 0x20u +#define STATUS_FIRSTFRAME_MASK 0x01u +#define STATUS_FIRSTFRAME_SHIFT 0x00 + +#define STATUS_DONE_OFFSET 0x20u +#define STATUS_DONE_MASK 0x02u +#define STATUS_DONE_SHIFT 0x01 + +#define STATUS_RXEMPTY_OFFSET 0x20u +#define STATUS_RXEMPTY_MASK 0x04u +#define STATUS_RXEMPTY_SHIFT 0x02 + +#define STATUS_TXFULL_OFFSET 0x20u +#define STATUS_TXFULL_MASK 0x08u +#define STATUS_TXFULL_SHIFT 0x03 + +#define STATUS_RXOVFLOW_OFFSET 0x20u +#define STATUS_RXOVFLOW_MASK 0x10u +#define STATUS_RXOVFLOW_SHIFT 0x04 + +#define STATUS_TXUNDERRUN_OFFSET 0x20u +#define STATUS_TXUNDERRUN_MASK 0x20u +#define STATUS_TXUNDERRUN_SHIFT 0x05 + +#define STATUS_SSEL_OFFSET 0x20u +#define STATUS_SSEL_MASK 0x40u +#define STATUS_SSEL_SHIFT 0x06 + +#define STATUS_ACTIVE_OFFSET 0x20u +#define STATUS_ACTIVE_MASK 0x80u +#define STATUS_ACTIVE_SHIFT 0x07 + +/******************************************************************************* + * Slave select register: + *------------------------------------------------------------------------------ + */ +#define SSEL_REG_OFFSET 0x24u + +/******************************************************************************* + * Transmit data last register: + *------------------------------------------------------------------------------ + */ +#define TXLAST_REG_OFFSET 0x28u + + +#endif /*CORESPI_REGS_H_*/ diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.c b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.c new file mode 100644 index 0000000..b8adaed --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.c @@ -0,0 +1,889 @@ +/******************************************************************************* + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * PF_System_Services driver implementation. See file "core_syservices_pf.h" for + * description of the functions implemented in this file. + * + */ + +#include "core_sysservices_pf.h" +#include "coresysservicespf_regs.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define NULL_BUFFER (( uint8_t* ) 0) + +static uint8_t execute_ss_command +( + uint8_t cmd_opcode, + const uint8_t* cmd_data, + uint16_t cmd_data_size, + const uint8_t* p_response, + uint16_t response_size, + uint16_t mb_offset, + uint16_t response_offset +); + +uint32_t g_css_pf_base_addr = 0u; + +/***************************************************************************//** + * SYS_init() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +void +SYS_init +( + uint32_t base_addr +) +{ + g_css_pf_base_addr = base_addr; +} + +/***************************************************************************//** + * SYS_get_serial_number() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_serial_number +( + const uint8_t * p_serial_number, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if (p_serial_number == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(SERIAL_NUMBER_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_serial_number, + SERIAL_NUMBER_RESP_LEN, + mb_offset, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_get_user_code() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_user_code +( + const uint8_t * p_user_code, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_user_code == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(USERCODE_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_user_code, + USERCODE_RESP_LEN, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_get_design_info() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_design_info +( + const uint8_t * p_design_info, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_design_info == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(DESIGN_INFO_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_design_info, + DESIGN_INFO_RESP_LEN, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_get_device_certificate() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_device_certificate +( + const uint8_t * p_device_certificate, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_device_certificate == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(DEVICE_CERTIFICATE_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_device_certificate, + DEVICE_CERTIFICATE_RESP_LEN, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_read_digest() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_read_digest +( + const uint8_t * p_digest, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_digest == NULL_BUFFER) + { + return status; + } + +#ifndef CORESYSSERVICES_MPFS + status = execute_ss_command(READ_DIGEST_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_digest, + READ_DIGEST_RESP_LEN, + mb_offset, + 0u); +#else + status = execute_ss_command(READ_DIGEST_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_digest, + READ_DIGEST_MPFS_RESP_LEN, + mb_offset, + 0u); +#endif + return status; + +} + +/***************************************************************************//** + * SYS_query_security() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_query_security +( + uint8_t * p_security_locks, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint8_t idx = 0u; + + if(p_security_locks == NULL_BUFFER) + { + return status; + } + +#ifndef CORESYSSERVICES_MPFS + uint8_t buf[12] = {0}; + /* Actual QUERY_SECURITY_RESP_LEN is 9 or 33 but PF_System_Services core + * needs number of words instead of number of bytes to be written to or read + * from MailBox */ + status = execute_ss_command(QUERY_SECURITY_REQUEST_CMD, + NULL_BUFFER, + 0u, + buf, + (QUERY_SECURITY_RESP_LEN + 3u), + mb_offset, + 0u); + + for (idx = 0u; idx < 9u; idx++) + { + *(p_security_locks+idx) = buf[idx]; + } + +#else + uint8_t buf[36] = {0}; + + status = execute_ss_command(QUERY_SECURITY_REQUEST_CMD, + NULL_BUFFER, + 0u, + buf, + (QUERY_SECURITY_MPFS_RESP_LEN + 3u), + mb_offset, + 0u); + + for (idx = 0u; idx < 33u; idx++) + { + *(p_security_locks+idx) = buf[idx]; + } + +#endif + + return status; +} + +/***************************************************************************//** + * SYS_read_debug_info() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_read_debug_info +( + const uint8_t * p_debug_info, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_debug_info == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(READ_DEBUG_INFO_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_debug_info, + READ_DEBUG_INFO_RESP_LEN, + mb_offset, + 0u); + return status; +} + +#ifdef CORESYSSERVICES_MPFS +/***************************************************************************//** + * SYS_read_envm_parameter() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_read_envm_parameter +( + uint8_t * p_envm_param, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_envm_param == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(READ_ENVM_PARAM_REQUEST_CMD, + NULL_BUFFER, + 0, + p_envm_param, + READ_ENVM_PARAM_RESP_LEN, + mb_offset, + 0); + return status; +} + +#endif + +/***************************************************************************//** + * SYS_puf_emulation_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_puf_emulation_service +( + const uint8_t * p_challenge, + uint8_t op_type, + uint8_t* p_response, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint8_t mb_format[20] = {0x00}; + uint8_t index = 0u; + + if((p_response == NULL_BUFFER) || (p_challenge == NULL_BUFFER)) + { + return status; + } + + /* Frame the data required for mailbox */ + mb_format[index] = op_type; + + for (index = 4u; index < 20u; index++) + { + mb_format[index] = p_challenge[index - 4u]; + } + + status = execute_ss_command(PUF_EMULATION_SERVICE_REQUEST_CMD, + mb_format, + PUF_EMULATION_SERVICE_CMD_LEN, + p_response, + PUF_EMULATION_SERVICE_RESP_LEN, + mb_offset, + 5u); /* mentioning offset to number of words instead of bytes */ + + return status; +} + +/***************************************************************************//** + * SYS_digital_signature_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_digital_signature_service +( + const uint8_t* p_hash, + uint8_t format, + uint8_t* p_response, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if((p_hash == NULL_BUFFER) || (p_response == NULL_BUFFER)) + { + return status; + } + + if (format == DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD) + { + status = execute_ss_command(DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD, + p_hash, + DIGITAL_SIGNATURE_HASH_LEN, + p_response, + DIGITAL_SIGNATURE_RAW_FORMAT_RESP_SIZE, + mb_offset, + 12u); /* mentioning offset to number of words instead of bytes */ + } + else + { + status = execute_ss_command(DIGITAL_SIGNATURE_DER_FORMAT_REQUEST_CMD, + p_hash, + DIGITAL_SIGNATURE_HASH_LEN, + p_response, + DIGITAL_SIGNATURE_DER_FORMAT_RESP_SIZE, + mb_offset, + 12u); /* mentioning offset to number of words instead of bytes */ + } + + return status; +} + +/***************************************************************************//** + * SYS_secure_nvm_write() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_secure_nvm_write +( + uint8_t format, + uint8_t snvm_module, + const uint8_t* p_data, + const uint8_t* p_user_key, + uint16_t mb_offset +) +{ + uint8_t frame[256] = {0x00}; + uint8_t* p_frame = &frame[0]; + uint16_t index = 0u; + uint8_t status = SYS_PARAM_ERR; + + HAL_ASSERT(!(NULL_BUFFER == p_data)); + HAL_ASSERT(!(snvm_module >= 221u)); + if (format != SNVM_NON_AUTHEN_TEXT_REQUEST_CMD) + { + HAL_ASSERT(!(NULL_BUFFER == p_user_key)); + } + + if ((p_data == NULL_BUFFER) || (snvm_module >= 221)) + { + return status; + } + + if ((format != SNVM_NON_AUTHEN_TEXT_REQUEST_CMD) + && (p_user_key == NULL_BUFFER)) + { + return status; + } + + if ((format != SNVM_NON_AUTHEN_TEXT_REQUEST_CMD) + && (format != SNVM_AUTHEN_TEXT_REQUEST_CMD) + && (format != SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD)) + { + return status; + } + + *p_frame = snvm_module; /* SNVMADDR - SNVM module */ + + p_frame += 4u; /* Next 3 bytes RESERVED - For alignment */ + + /* Copy user key and send the command/data to mailbox. */ + if ((format == SNVM_AUTHEN_TEXT_REQUEST_CMD) || + (format == SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD)) + { + /* Copy user data */ + for (index = 0u; index < (AUTHENTICATED_TEXT_DATA_LEN - USER_SECRET_KEY_LEN - 4u); index++) + { + *p_frame = p_data[index]; + p_frame++; + } + + /* Copy user key */ + for (index = 0u; index < USER_SECRET_KEY_LEN; index++) + { + *p_frame = p_user_key[index]; + p_frame++; + } + + status = execute_ss_command(format, + &frame[0], + AUTHENTICATED_TEXT_DATA_LEN, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + } + else + { + /* Copy user data */ + for (index = 0u; index < (NON_AUTHENTICATED_TEXT_DATA_LEN - 4u); index++) + { + *(p_frame+index) = p_data[index]; + } + + status = execute_ss_command(format, + &frame[0], + NON_AUTHENTICATED_TEXT_DATA_LEN, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + } + + return status; +} + +/***************************************************************************//** + * SYS_secure_nvm_read() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_secure_nvm_read +( + uint8_t snvm_module, + const uint8_t* p_user_key, + uint8_t* p_admin, + uint8_t* p_data, + uint16_t data_len, + uint16_t mb_offset +) +{ + /* Frame the message. */ + uint8_t frame[16] = {0x00u}; + uint8_t* p_frame = &frame[0u]; + uint8_t status = SYS_PARAM_ERR; + uint8_t response[256] = {0x00u}; + uint16_t index = 0u; + + HAL_ASSERT(!(NULL_BUFFER == p_data)); + HAL_ASSERT(!(NULL_BUFFER == p_admin)); + HAL_ASSERT(!(snvm_module > 221u)); + + HAL_ASSERT(data_len == 236u || data_len == 252u); + + if((p_data == NULL_BUFFER) || + (snvm_module >= 221) || + (p_admin == NULL_BUFFER)) + { + return status; + } + + *p_frame = snvm_module; /* SNVMADDR - SNVM module */ + + p_frame += 4u; /* RESERVED - For alignment */ + + /* Copy user key */ + if (236u == data_len) + { + HAL_ASSERT(p_user_key != NULL_BUFFER); + + if(p_user_key == NULL_BUFFER) + { + return status; + } + + for (index = 0u; index < 12u; index++) + { + *p_frame = p_user_key[index]; + p_frame++; + } + } + else + { + p_frame += 12u; + } + + status = execute_ss_command(SNVM_READ_REQUEST_CMD, + &frame[0], + 16u, + response, + (data_len + 4u), + mb_offset, + 4u); /* mentioning offset to number of words instead of bytes */ + + if (SYS_SUCCESS == status) + { + for (index = 0u; index < 4u; index++) + { + *(p_admin+index) = (uint32_t)response[index]; + } + + + /* Copy data into user buffer. */ + for (index = 4u; index < (data_len + 4u); index++) + { + *(p_data + (index - 4u)) = response[index]; + } + } + else + { + ; + } + + return status; +} + +/***************************************************************************//** + * SYS_nonce_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_nonce_service +( + const uint8_t * p_nonce, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if((p_nonce == NULL_BUFFER)) + { + return status; + } + + status = execute_ss_command(NONCE_SERVICE_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_nonce, + NONCE_SERVICE_RESP_LEN, + mb_offset, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_bitstream_authenticate_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_bitstream_authenticate_service +( + uint32_t spi_flash_address, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint32_t l_spi_flash_address = spi_flash_address; + status = execute_ss_command(BITSTREAM_AUTHENTICATE_CMD, + (uint8_t* )&l_spi_flash_address, + 4u, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_IAP_image_authenticate_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_IAP_image_authenticate_service +( + uint8_t spi_idx +) +{ + uint8_t status = SYS_PARAM_ERR; + + HAL_ASSERT(!(spi_idx == 1u)); + + if (spi_idx == 1u) + { + return status; + } + + status = execute_ss_command(IAP_BITSTREAM_AUTHENTICATE_CMD, + NULL_BUFFER, + 0u, + NULL_BUFFER, + 0u, + spi_idx, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_digest_check_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_digest_check_service +( + uint32_t options, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint32_t l_options = options; + + status = execute_ss_command(DIGEST_CHECK_CMD, + (uint8_t* )&l_options, + 4u, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_iap_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_iap_service +( + uint8_t iap_cmd, + uint32_t spiaddr, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint16_t l_mb_offset = 0u; + uint16_t cmd_data_size = 0u; + uint8_t* cmd_data = NULL_BUFFER; + bool invalid_param = false; + + if (((IAP_PROGRAM_BY_SPIIDX_CMD == iap_cmd) + || (IAP_VERIFY_BY_SPIIDX_CMD == iap_cmd)) + && (1u == spiaddr)) + { + invalid_param = true; + HAL_ASSERT(!invalid_param); + } + + if (!invalid_param) + { + switch(iap_cmd) + { + case IAP_PROGRAM_BY_SPIIDX_CMD: + case IAP_VERIFY_BY_SPIIDX_CMD: + /*In SPI_IDX based program and verify commands, + * Mailbox is not Required. Instead of mailbox offset + * SPI_IDX is passed as parameter.*/ + l_mb_offset = (uint16_t)(0xFFu & spiaddr); + break; + + case IAP_PROGRAM_BY_SPIADDR_CMD: + case IAP_VERIFY_BY_SPIADDR_CMD: + /*In SPI_ADDR based program and verify commands, + * Mailbox is Required*/ + l_mb_offset = mb_offset; + /*command data size is four bytes holding the + * SPI Address in it.*/ + cmd_data_size = 4u; + cmd_data = (uint8_t*)&spiaddr; + break; + + case IAP_AUTOUPDATE_CMD: + /*In auto update command Mailbox is not Required*/ + l_mb_offset = 0u; + break; + + default: + l_mb_offset = 0u; + + } + + status = execute_ss_command( + (uint8_t)iap_cmd, + cmd_data, + cmd_data_size, + NULL_BUFFER, + 0, + (uint16_t)l_mb_offset, + 0); + } + + return status; +} + +/***************************************************************************//** + Internal functions. +*/ +/* +This function executes the SS command. If Mailbox input data is required by the +it will first load it from cmd_data into the Mailbox. If the service requires +the response data to be read from mailbox, it will do so and store it in p_response. +*/ +static uint8_t execute_ss_command +( + uint8_t cmd_opcode, + const uint8_t* cmd_data, + uint16_t cmd_data_size, + const uint8_t* p_response, + uint16_t response_size, + uint16_t mb_offset, + uint16_t response_offset +) +{ + /* Pointer used during Writing to Mailbox memory. */ + uint32_t status = 0u; + uint16_t idx = 0u; + uint16_t ss_command = 0u; + uint32_t* word_buf; + uint16_t timeout_count = SS_TIMEOUT_COUNT; + + /* making sure that the system controller is not executing any service i.e. + SS_USER_BUSY is gone 0 */ + + while (1u == HAL_get_32bit_reg_field(g_css_pf_base_addr, SS_USER_BUSY)) + { + --timeout_count; + + if (timeout_count == 0) + { + return SS_USER_BUSY_TIMEOUT; + } + } + + /* Form the SS command: bit 0to6 is the opcode, bit 7to15 is the Mailbox offset + For some services this field has another meaning + (e.g. for IAP bitstream auth. it means spi_idx) */ + ss_command = ((mb_offset << 7u) | (cmd_opcode & 0x7Fu)); + + /* Load the command register with the SS request command code*/ + HAL_set_32bit_reg(g_css_pf_base_addr, SS_CMD, ss_command); + + if (cmd_data_size > 0u) + { + HAL_ASSERT(!(NULL_BUFFER == cmd_data)); + HAL_ASSERT(!(cmd_data_size % 4u)); + + /* Load the MBX_WCNT register with number of words */ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_WCNT, (cmd_data_size/4u)); + + /* Load the MBX_WADDR register with offset of input data (write to Mailbox) + For all the services this offset remains either 0 or Not applicable + for the services in which no Mailbox write is required.*/ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_WADDR, (0x00u + mb_offset)); + + } + + if (response_size > 0u) + { + HAL_ASSERT(!(NULL_BUFFER == p_response)); + HAL_ASSERT(!(response_size % 4u)); + + /* + Load the MBX_RWCNT register with number of words to be read from Mailbox + */ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_RCNT, (response_size/4u)); + + /* + Load the MBX_RADRDESC register with offset address within the mailbox + format for that particular service. + It will be 0 for the services where there is no output data from G5CONTROL + is expected. + This function assumes that this value is pre-calculated by service specific + functions as this value is fixed for each service. + */ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_RADDR, (response_offset + mb_offset)); + } + + /*Set the request bit in SYS_SERV_REQ register to start the service*/ + HAL_set_32bit_reg_field(g_css_pf_base_addr, SS_REQ_REQ, 0x01u); + + if (cmd_data_size > 0u) + { + word_buf = (uint32_t*)cmd_data; + + /* Write the user data into mail box. */ + for (idx = 0u; idx < (cmd_data_size/4u); idx++) + { + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_WDATA, word_buf[idx]); + } + } + + timeout_count = SS_TIMEOUT_COUNT; + if (response_size > 0u) + { + word_buf = (uint32_t*)p_response; + + for (idx = 0u; idx < (response_size/4u); idx++) + { + while (0u == HAL_get_32bit_reg_field(g_css_pf_base_addr, + SS_USER_RDVLD)) + { + --timeout_count; + + if (timeout_count == 0) + { + return SS_USER_RDVLD_TIMEOUT; + } + } + word_buf[idx] = HAL_get_32bit_reg(g_css_pf_base_addr, MBX_RDATA); + } + } + + timeout_count = SS_TIMEOUT_COUNT; + /* make sure that service is complete i.e. SS_USER_BUSY is gone 0 */ + while (1u == HAL_get_32bit_reg_field(g_css_pf_base_addr, SS_USER_BUSY)) + { + --timeout_count; + + if (timeout_count == 0) + { + return SS_USER_RDVLD_TIMEOUT; + } + } + + /* Read the status returned by System Controller */ + status = HAL_get_32bit_reg(g_css_pf_base_addr, SS_STAT); + + return (uint8_t)status; +} + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h new file mode 100644 index 0000000..8e0ebb6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h @@ -0,0 +1,1249 @@ +/******************************************************************************* + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the + * CoreSysServices_PF bare metal driver. + */ +/*=========================================================================*//** + @mainpage CoreSysServices_PF Bare Metal Driver. + + @section intro_sec Introduction + The PolarFire System Services (PF_SYSTEM_SERVICES) SgCore enables executing + the system services on the PolarFire and PolarFire SoC device. The system services + are the system controller actions initiated by the System Controller's System + Service Interface (SSI). The PolarFire System Services "SgCore" provides a + method to initiate these system services. The PF_SYSTEM_SERVICES interacts + with the system controller on SSI and Mailbox interface to initiate system + services, exchange data required for that services, and to know the successful + completion or error status. + + The PF_SYSTEM_SERVICES provides an APB interface for controlling the registers + functions for controlling the PF_SYSTEM_SERVICES as part of a bare metal system + register implemented within it. This software driver provides a set of where no + part of an operating system but the implementation of the adaptation layer + operating system is available. This driver is adapted for use in + between this driver and the operating system's driver model is outside the + scope of this driver. + + ## Features + The CoreSysServices_PF driver provides the following features: + - Executing device and design information services + - Executing design services + - Executing data security services + - Executing Fabric services + + The CoreSysServices_PF driver is provided as C source code. + + @section Driver Configuration + The application software should configure the CoreSysServices_PF driver through + calling the SYS_init() function. Only one instance of PF_SYSTEM_SERVICES SgCore is + supported. No additional configuration files are required to use the driver. + If using this driver on RT PolarFire device FPGA, define RT_DEVICE_FAMILY + macro in application. + + @section theory_op Theory of Operation + The CoreSysServices_PF driver provides access to the PolarFire system services. + These system services are grouped into the following categories: + + Device and Design Information Service + - Serial Number Service + - USERCODE Service + - Design Info Service + - Device Certificate Services + - Read Digests + - Query Security + - Read Debug Info + - Read eNVM param + + Design Services + - Bitstream authentication service + - IAP bitstream authentication service + + Data Security Services + - Digital Signature Service + - Secure NVM (SNVM) Functions + - PUF Emulation Service + - Nonce Service + + Fabric Services + - Digest Check Service + - In Application programming(IAP)/Auto-Update service + + Initialization and Configuration + + The CoreSysServices_PF driver is initialized by calling the SYS_init() + function. The SYS_init() function must be called before calling any other + CoreSysServices_PF driver functions. + + Device and Design Information Services + + The CoreSysServices_PF driver is used to read information about the device + and the design using the following functions: + - SYS_get_serial_number() + - SYS_get_user_code() + - SYS_get_design_info() + - SYS_get_device_certificate() + - SYS_read_digest() + - SYS_query_security() + - SYS_read_debug_info() + + Design Authentication Services + + The CoreSysServices_PF driver is used to execute design services using the + following functions: + - SYS_bitstream_authenticate_service() + - SYS_IAP_image_authenticate_service() + + Data Security Services + + The CoreSysServices_PF driver is used to execute data security services + using the following functions: + - SYS_digital_signature_service() + - SYS_secure_nvm_write() + - SYS_secure_nvm_read() + - SYS_puf_emulation_service () + - SYS_nonce_service () + + Executing Fabric Services + + The CoreSysServices_PF driver is used to execute fabric services using the + following functions: + - SYS_digest_check_service() + - SYS_iap_service() + + All the service execution functions return the 8-bit status, which is returned + by the system controller on executing the given service. A '0' value indicates + successful execution of that service. A non-zero value indicates error. + The error codes for each service are different. See individual function + description to know the exact meanings of the error codes for each service. + + The function descriptions in this file mainly focus on the details required + by the user to use the APIs provided by this driver to execute the services. + To know the complete details of the system services, see the + PolarFire FPGA and PolarFire SoC FPGA System Services [document](https://onlinedocs.microchip.com/pr/GUID-1409CF11-8EF9-4C24-A94E-70979A688632-en-US-3/index.html) + + *//*=========================================================================*/ +#ifndef __CORE_SYSSERV_PF_H +#define __CORE_SYSSERV_PF_H 1 + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#include "hal_assert.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** +* # Service Execution Success and Error Status Codes +* +* The following status codes are the return values from the system service functions. +* For any service, a return value '0' indicates that the service was executed +* successfully. A non-zero return value indicates that the service was not +* executed successfully. For all the services, the return value represents the +* status code returned by the system controller for the respective service, +* except the values SYS_PARAM_ERR, SS_USER_BUSY_TIMEOUT, and SS_USER_RDVLD_TIMEOUT. +* These three values indicate the error conditions detected by this driver and +* they do not overlap with the status code returned by the system controller for +* any of the system service. +* +* SYS_SUCCESS +* System service executed successfully +* +* SYS_PARAM_ERR +* System service cannot be executed as one or more parameters are not as +* expected by this driver. No read/write access is performed with the +* IP. +* +* SS_USER_BUSY_TIMEOUT +* The System service request is initiated and the driver timed-out while +* waiting for the system service to complete. The System Service +* completion is indicated by de-assertion of the SS_USER_BUSY bit by the +* IP. +* +* SS_USER_RDVLD_TIMEOUT +* The System service request is initiated and the driver timed-out while +* waiting for SS_USER_RDVLD bit, which indicates availability of data to +* be read from the mailbox, to become active. +*/ +#define SYS_SUCCESS 0u +#define SYS_PARAM_ERR 0xFFu +#define SS_USER_BUSY_TIMEOUT 0xFAu +#define SS_USER_RDVLD_TIMEOUT 0xFBu + +/** +* # System Service Timeout Count +* +* The SS_TIMEOUT_COUNT value is used by the driver as a timeout count +* while waiting for either the SS_USER_BUSY or SS_USER_RDVLD. This empirical +* value is sufficiently large so that the operations are falsely +* timeout in the normal circumstance. It is provided as a way to provide +* more debug information to the application in case there are some +* unforeseen issues. You may change this value for your need based on your +* system design. +*/ +#define SS_TIMEOUT_COUNT 40000u +/* + * SYS_DCF_DEVICE_MISMATCH + * Public key or FSN do not match device + * + * + * SYS_DCF_INVALID_SIGNATURE + * Certificate signature is invalid + * + * SYS_DCF_SYSTEM_ERROR + * PUF or storage failure + */ +#define SYS_DCF_DEVICE_MISMATCH 1u +#define SYS_DCF_INVALID_SIGNATURE 2u +#define SYS_DCF_SYSTEM_ERROR 3u + +/* + * SYS_NONCE_PUK_FETCH_ERROR + * Error fetching PUK + * + * SYS_NONCE_SEED_GEN_ERROR + * Error generating seed + */ +#define SYS_NONCE_PUK_FETCH_ERROR 1u +#define SYS_NONCE_SEED_GEN_ERROR 2u + +/** + * # Secure Nvm Write Error Codes + * + * SNVM_WRITE_INVALID_SNVMADDR + * Illegal page address + * + * SNVM_WRITE_FAILURE + * PNVM program/verify failed + * + * SNVM_WRITE_SYSTEM_ERROR + * PUF or storage failure + * + * SNVM_WRITE_NOT_PERMITTED + * Write is not permitted + */ +#define SNVM_WRITE_INVALID_SNVMADDR 1u +#define SNVM_WRITE_FAILURE 2u +#define SNVM_WRITE_SYSTEM_ERROR 3u +#define SNVM_WRITE_NOT_PERMITTED 4u + +/** + * # Secure Nvm Read Error Codes + * + * SNVM_READ_INVALID_SNVMADDR + * Illegal page address + * + * SNVM_READ_AUTHENTICATION_FAILURE + * Storage corrupt or incorrect USK + * + * SNVM_READ_SYSTEM_ERROR + * PUF or storage failure + * + */ +#define SNVM_READ_INVALID_SNVMADDR 1u +#define SNVM_READ_AUTHENTICATION_FAILURE 2u +#define SNVM_READ_SYSTEM_ERROR 3u + +/** + * # Digital Signature Service Error Codes + * + * DIGITAL_SIGNATURE_FEK_FAILURE_ERROR + * Error retrieving FEK + * + * DIGITAL_SIGNATURE_DRBG_ERROR + * Failed to generate nonce + * + * DIGITAL_SIGNATURE_ECDSA_ERROR + * ECDSA failed + */ +#define DIGITAL_SIGNATURE_FEK_FAILURE_ERROR 1u +#define DIGITAL_SIGNATURE_DRBG_ERROR 2u +#define DIGITAL_SIGNATURE_ECDSA_ERROR 3u + +/** + * # Digest Check Error Codes + * + * NOTE: When these error occur, the DIGEST tamper flag is triggered. + * + * DIGEST_CHECK_FABRICERR + * Fabric digest check error + * + * DIGEST_CHECK_CCERR + * UFS Fabric Configuration (CC) segment digest check error + * + * DIGEST_CHECK_SNVMERR + * ROM digest in SNVM segment digest check error + * + * DIGEST_CHECK_ULERR + * UFS UL segment digest check error + * + * DIGEST_CHECK_UK0ERR + * UKDIGEST0 in User Key segment digest check error + * + * DIGEST_CHECK_UK1ERR + * UKDIGEST1 in User Key segment digest check error + * + * DIGEST_CHECK_UK2ERR + * UKDIGEST2 in User Key segment (UPK1) digest check error + * + * DIGEST_CHECK_UK3ERR + * UKDIGEST3 in User Key segment (UK1) digest check error + * + * DIGEST_CHECK_UK4ERR + * UKDIGEST4 in User Key segment (DPK) digest check error + * + * DIGEST_CHECK_UK5ERR + * UKDIGEST5 in User Key segment (UPK2) digest check error + * + * DIGEST_CHECK_UK6ERR + * UKDIGEST6 in User Key segment (UK2) digest check error + * + * DIGEST_CHECK_UPERR + * UFS Permanent Lock (UPERM) segment digest check error + * + * DIGEST_CHECK_SYSERR + * M3 ROM, Factory and Factory Key Segments digest check error + * + */ +#define DIGEST_CHECK_FABRICERR 0x00u +#define DIGEST_CHECK_CCERR 0x01u +#define DIGEST_CHECK_SNVMERR 0x02u +#define DIGEST_CHECK_ULERR 0x03u +#define DIGEST_CHECK_UK0ERR 0x04u +#define DIGEST_CHECK_UK1ERR 0x05u +#define DIGEST_CHECK_UK2ERR 0x06u +#define DIGEST_CHECK_UK3ERR 0x07u +#define DIGEST_CHECK_UK4ERR 0x08u +#define DIGEST_CHECK_UK5ERR 0x09u +#define DIGEST_CHECK_UK6ERR 0x10u +#define DIGEST_CHECK_UPERR 0x11u +#define DIGEST_CHECK_SYSERR 0x12u + +/** + * # Bitstream Authentication and Iap Bitstream Authentication Return Status + * + * BSTREAM_AUTH_CHAINING_MISMATCH_ERR + * Validator or hash chaining mismatch. Incorrectly constructed bitstream or + * wrong key used. + * + * BSTREAM_AUTH_UNEXPECTED_DATA_ERR + * Unexpected data received. + * Additional data received after end of EOB component. + * + * BSTREAM_AUTH_INVALID_ENCRY_KEY_ERR + * Invalid/corrupt encryption key. + * The requested key mode is disabled or the key could not be read/reconstructed. + * + * BSTREAM_AUTH_INVALID_HEADER_ERR + * Invalid component header + * + * BSTREAM_AUTH_BACK_LEVEL_NOT_SATISFIED_ERR + * Back level not satisfied + * + * BSTREAM_AUTH_ILLEGAL_BITSTREAM_MODE_ERR + * Illegal bitstream mode. + * Requested bitstream mode is disabled by user security. + * + * BSTREAM_AUTH_DNS_BINDING_MISMATCH_ERR + * DSN binding mismatch + * + * BSTREAM_AUTH_ILLEGAL_COMPONENT_SEQUENCE_ERR + * Illegal component sequence + * + * BSTREAM_AUTH_INSUFF_DEVICE_CAPAB_ERR + * Insufficient device capabilities + * + * BSTREAM_AUTH_INCORRECT_DEVICEID_ERR + * Incorrect DEVICEID + * + * BSTREAM_AUTH_PROTOCOL_VERSION_ERR + * Unsupported bitstream protocol version (regeneration required) + * + * BSTREAM_AUTH_VERIFY_ERR + * Verify not permitted on this bitstream + * + * BSTREAM_AUTH_INVALID_DEV_CERT_ERR + * Invalid Device Certificate. + * Device SCAC is invalid or not present. + * + * BSTREAM_AUTH_INVALID_DIB_ERR + * Invalid DIB + * + * BSTREAM_AUTH_SPI_NOT_MASTER_ERR + * Device not in SPI Master Mode. + * Error may occur only when bitstream is executed through IAP mode. + * + * BSTREAM_AUTH_AUTOIAP_NO_VALID_IMAGE_ERR + * No valid images found. + * Error may occur when bitstream is executed through Auto Update mode. + * Occurs when no valid image pointers are found. + * + * BSTREAM_AUTH_INDEXIAP_NO_VALID_IMAGE_ERR + * No valid images found. + * Error may occur when bitstream is executed through IAP mode via Index Mode. + * Occurs when No valid image pointers are found. + * + * BSTREAM_AUTH_NEWER_DESIGN_VERSION_ERR + * Programmed design version is newer than AutoUpdate image found. + * Error may occur when bitstream is executed through Auto Update mode. + * + * BSTREAM_AUTH_INVALID_IMAGE_ERR + * Selected image was invalid and no recovery was performed due to valid design + * in device. + * Error may occur only when bitstream is executed through Auto Update or IAP mode + * (This error is here for completeness but only can be observed by running the + * READ_DEBUG_INFO instruction and looking at IAP Error code field). + * + * BSTREAM_AUTH_IMAGE_PROGRAM_FAILED_ERR + * Selected and Recovery image failed to program. + * Error may occur only when bitstream is executed through Auto Update or + * IAP mode + * (This error is here for completeness but only can be observed by running the + * READ_DEBUG_INFO instruction and looking at IAP Error code field). + * + * BSTREAM_AUTH_ABORT_ERR + * Abort. + * Non-bitstream instruction executed during bitstream loading. + * + * BSTREAM_AUTH_NVMVERIFY_ERR + * Fabric/UFS verification failed (min or weak limit) + * + * BSTREAM_AUTH_PROTECTED_ERR + * Device security prevented modification of non-volatile memory + * + * BSTREAM_AUTH_NOTENA + * Programming mode not enabled + * + * BSTREAM_AUTH_PNVMVERIFY + * pNVM verify operation failed + * + * BSTREAM_AUTH_SYSTEM + * System hardware error (PUF or DRBG) + * + * BSTREAM_AUTH_BADCOMPONENT + * An internal error was detected in a component payload + * + * BSTREAM_AUTH_HVPROGERR + * HV programming subsystem failure (pump failure) + * + * BSTREAM_AUTH_HVSTATE + * HV programming subsystem in unexpected state (internal error) + * + */ +#define BSTREAM_AUTH_CHAINING_MISMATCH_ERR 1 +#define BSTREAM_AUTH_UNEXPECTED_DATA_ERR 2 +#define BSTREAM_AUTH_INVALID_ENCRY_KEY_ERR 3 +#define BSTREAM_AUTH_INVALID_HEADER_ERR 4 +#define BSTREAM_AUTH_BACK_LEVEL_NOT_SATISFIED_ERR 5 +#define BSTREAM_AUTH_ILLEGAL_BITSTREAM_MODE_ERR 6 +#define BSTREAM_AUTH_DNS_BINDING_MISMATCH_ERR 7 +#define BSTREAM_AUTH_ILLEGAL_COMPONENT_SEQUENCE_ERR 8 +#define BSTREAM_AUTH_INSUFF_DEVICE_CAPAB_ERR 9 +#define BSTREAM_AUTH_INCORRECT_DEVICEID_ERR 10 +#define BSTREAM_AUTH_PROTOCOL_VERSION_ERR 11 +#define BSTREAM_AUTH_VERIFY_ERR 12 +#define BSTREAM_AUTH_INVALID_DEV_CERT_ERR 13 +#define BSTREAM_AUTH_INVALID_DIB_ERR 14 +#define BSTREAM_AUTH_SPI_NOT_MASTER_ERR 21 +#define BSTREAM_AUTH_AUTOIAP_NO_VALID_IMAGE_ERR 22 +#define BSTREAM_AUTH_INDEXIAP_NO_VALID_IMAGE_ERR 23 +#define BSTREAM_AUTH_NEWER_DESIGN_VERSION_ERR 24 +/* 25 Reserved */ +#define BSTREAM_AUTH_INVALID_IMAGE_ERR 26 +#define BSTREAM_AUTH_IMAGE_PROGRAM_FAILED_ERR 27 +#define BSTREAM_AUTH_ABORT_ERR 127 +#define BSTREAM_AUTH_NVMVERIFY_ERR 128 +#define BSTREAM_AUTH_PROTECTED_ERR 129 +#define BSTREAM_AUTH_NOTENA 130 +#define BSTREAM_AUTH_PNVMVERIFY 131 +#define BSTREAM_AUTH_SYSTEM 132 +#define BSTREAM_AUTH_BADCOMPONENT 133 +#define BSTREAM_AUTH_HVPROGERR 134 +#define BSTREAM_AUTH_HVSTATE 135 + +/***************************************************************************//** + * # Mailbox ECC Status + * Provides ECC status when the mailbox is read. The values are as follows: + * 00: No ECC errors detected, data is correct. + * 01: Exactly one bit error occurred and has been corrected. + * 10: Exactly two bits error occurred and no correction performed. + * 11: Reserved. + */ +#define SYS_MBOX_ECC_NO_ERROR_MASK 0x00u +#define SYS_MBOX_ONEBIT_ERROR_CORRECTED_MASK 0x40u +#define SYS_MBOX_TWOBIT_ERROR_MASK 0xC0u + +/***************************************************************************//** + * Service request command opcodes: +*/ +#define SERIAL_NUMBER_REQUEST_CMD 0x00u +#define USERCODE_REQUEST_CMD 0x01u +#define DESIGN_INFO_REQUEST_CMD 0x02u +#define DEVICE_CERTIFICATE_REQUEST_CMD 0x03u +#define READ_DIGEST_REQUEST_CMD 0x04u +#define QUERY_SECURITY_REQUEST_CMD 0x05u +#define READ_DEBUG_INFO_REQUEST_CMD 0x06u +#define READ_ENVM_PARAM_REQUEST_CMD 0x07u +#define SNVM_NON_AUTHEN_TEXT_REQUEST_CMD 0x10u +#define SNVM_AUTHEN_TEXT_REQUEST_CMD 0x11u +#define SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD 0x12u +#define SNVM_READ_REQUEST_CMD 0x18u +#define DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD 0x19u +#define PUF_EMULATION_SERVICE_REQUEST_CMD 0x20u +#define NONCE_SERVICE_REQUEST_CMD 0x21u +#define DIGITAL_SIGNATURE_DER_FORMAT_REQUEST_CMD 0x1Au + +#define BITSTREAM_AUTHENTICATE_CMD 0x23u +#define IAP_BITSTREAM_AUTHENTICATE_CMD 0x22u + +#define DIGEST_CHECK_CMD 0x47u + +#define IAP_PROGRAM_BY_SPIIDX_CMD 0x42u +#define IAP_VERIFY_BY_SPIIDX_CMD 0x44u +#define IAP_PROGRAM_BY_SPIADDR_CMD 0x43u +#define IAP_VERIFY_BY_SPIADDR_CMD 0x45u +#define IAP_AUTOUPDATE_CMD 0x46u + +/***************************************************************************//** + * Service request Mailbox return data length + */ +#define SERIAL_NUMBER_RESP_LEN 16u +#define USERCODE_RESP_LEN 4u +#define DESIGN_INFO_RESP_LEN 36u +#define DEVICE_CERTIFICATE_RESP_LEN 1024u +#define READ_DIGEST_RESP_LEN 416u +#define QUERY_SECURITY_RESP_LEN 9u +#define READ_DEBUG_INFO_RESP_LEN 76u +#define READ_ENVM_PARAM_RESP_LEN 256u +#define NONCE_SERVICE_RESP_LEN 32u + +#define PUF_EMULATION_SERVICE_CMD_LEN 20u +#define PUF_EMULATION_SERVICE_RESP_LEN 32u + +#define DIGITAL_SIGNATURE_HASH_LEN 48u +#define DIGITAL_SIGNATURE_RAW_FORMAT_RESP_SIZE 96u +#define DIGITAL_SIGNATURE_DER_FORMAT_RESP_SIZE 104u + +#define USER_SECRET_KEY_LEN 12u + +/* Same driver can be used on PolarFire SoC platform and the response length + * is different for PolarFire SoC. Constants defined below are used only when the + * PF System services driver is used with PolarFire SoC Platform. + */ +#define READ_DIGEST_MPFS_RESP_LEN 576u +#define QUERY_SECURITY_MPFS_RESP_LEN 33u + +/* SNVM Input data length from sNVM write. */ +#ifndef RT_DEVICE_FAMILY +/* SNVMADDR + RESERVED + PT + USK */ +#define NON_AUTHENTICATED_TEXT_DATA_LEN 256u + +/* SNVMADDR + RESERVED + PT */ +#define AUTHENTICATED_TEXT_DATA_LEN 252u +#else +/* SNVMADDR + RESERVED + PT + USK */ +#define NON_AUTHENTICATED_TEXT_DATA_LEN 224u + +/* SNVMADDR + RESERVED + PT */ +#define AUTHENTICATED_TEXT_DATA_LEN 220u +#endif + +/** + * # Digest Check Input Options + * + * DIGEST_CHECK_FABRIC + * Carry out digest check on Fabric + * + * DIGEST_CHECK_CC + * Carry out digest check on UFS Fabric Configuration (CC) segment + * + * DIGEST_CHECK_SNVM + * Carry out digest check on ROM digest in SNVM segment + * + * DIGEST_CHECK_UL + * Carry out digest check on UFS UL segment + * + * DIGEST_CHECK_UKDIGEST0 + * Carry out digest check on UKDIGEST0 in User Key segment + * + * DIGEST_CHECK_UKDIGEST1 + * Carry out digest check on UKDIGEST1 in User Key segment + * + * DIGEST_CHECK_UKDIGEST2 + * Carry out digest check on UKDIGEST2 in User Key segment (UPK1) + * + * DIGEST_CHECK_UKDIGEST3 + * Carry out digest check on UKDIGEST3 in User Key segment (UK1) + * + * DIGEST_CHECK_UKDIGEST4 + * Carry out digest check on UKDIGEST4 in User Key segment (DPK) + * + * DIGEST_CHECK_UKDIGEST5 + * Carry out digest check on UKDIGEST5 in User Key segment (UPK2) + * + * DIGEST_CHECK_UKDIGEST6 + * Carry out digest check on UKDIGEST6 in User Key segment (UK2) + * + * DIGEST_CHECK_UPERM + * Carry out digest check on UFS Permanent lock (UPERM) segment + * + * DIGEST_CHECK_SYS + * Carry out digest check on Factory and Factory Key Segments + * + */ +#define DIGEST_CHECK_FABRIC (0x01<<0x00u) /*Fabric digest*/ +#define DIGEST_CHECK_CC (0x01<<0x01u) /*UFS Fabric Configuration (CC) segment*/ +#define DIGEST_CHECK_SNVM (0x01<<0x02u) /*ROM digest in SNVM segment*/ +#define DIGEST_CHECK_UL (0x01<<0x03u) /*UFS UL segment*/ +#define DIGEST_CHECK_UKDIGEST0 (0x01<<0x04u) /*UKDIGEST0 in User Key segment*/ +#define DIGEST_CHECK_UKDIGEST1 (0x01<<0x05u) /*UKDIGEST1 in User Key segment*/ +#define DIGEST_CHECK_UKDIGEST2 (0x01<<0x06u) /*UKDIGEST2 in User Key segment (UPK1)*/ +#define DIGEST_CHECK_UKDIGEST3 (0x01<<0x07u) /*UKDIGEST3 in User Key segment (UK1)*/ +#define DIGEST_CHECK_UKDIGEST4 (0x01<<0x08u) /*UKDIGEST4 in User Key segment (DPK)*/ +#define DIGEST_CHECK_UKDIGEST5 (0x01<<0x09u) /*UKDIGEST5 in User Key segment (UPK2)*/ +#define DIGEST_CHECK_UKDIGEST6 (0x01<<0x0au) /*UKDIGEST6 in User Key segment (UK2)*/ +#define DIGEST_CHECK_UPERM (0x01<<0x0bu) /*UFS Permanent lock (UPERM) segment*/ +#define DIGEST_CHECK_SYS (0x01<<0x0cu) /*Factory and Factory Key Segments.*/ + +/***************************************************************************//** + * The function SYS_init() is used to initialize the internal data structures of + * this driver. Currently this function is empty. + * + * @param base_addr The base_addr parameter specifies the base address of the + * PF_System_services core. + * + * @return This function does not return a value. + */ +void +SYS_init +( + uint32_t base_addr +); + +/***************************************************************************//** + * The function SYS_get_serial_number() is used to execute "serial number" system + * service. + * + * @param p_serial_number The p_serial_number parameter is a pointer to a buffer + * in which the data returned by system controller + * is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t +SYS_get_serial_number +( + const uint8_t * p_serial_number, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_get_user_code() is used to execute "USERCODE" system + * service. + * @param p_user_code The p_user_code parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t +SYS_get_user_code +( + const uint8_t * p_user_code, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_get_design_info() is used to execute "Get Design Info" system + * service. + * + * @param p_design_info The p_design_info parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. Total size of debug information is 36 bytes. + * The data from the system controller includes the 256-bit + * user-defined design ID, 16-bit design version, and 16-bit + * design back level. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t +SYS_get_design_info +( + const uint8_t * p_design_info, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_get_device_certificate() is used to execute "Get Device + * Certificate" system service. + * + * @param p_device_certificate The p_device_certificate parameter is a pointer + * to a buffer in which the data returned by the + * system controller is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code means that + * the service was executed successfully. + * + */ +uint8_t +SYS_get_device_certificate +( + const uint8_t * p_device_certificate, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_read_digest() is used to execute "Read Digest" system service. + * + * @param p_digest The p_digest parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t SYS_read_digest +( + const uint8_t * p_digest, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_query_security() is used to execute "Query Security" system + * service. + * + * @param p_security_locks The p_security_locks parameter is a pointer to a buffer + * in which the data returned by system controller is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code means that + * the service was executed successfully. + */ +uint8_t SYS_query_security +( + uint8_t * p_security_locks, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_read_debug_info() is used to execute "Read Debug info" system + * service. + * + * @param p_debug_info The p_debug_info parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t SYS_read_debug_info +( + const uint8_t * p_debug_info, + uint16_t mb_offset +); + +#ifdef CORESYSSERVICES_PFSOC +/***************************************************************************//** + * The function SYS_read_envm_parameter() is used to retrieve all parameters needed + * for the eNVM operation and programming. + * + * NOTE: This service is available only on PolarFire SoC Platform. + * This service is not yet supported by PF_SYSTEM_SERVICES 3.0.100. + * + * @param p_envm_param The p_envm_param parameter is a pointer to a buffer + * in which the data returned by system controller is copied. + * This buffer stores all the eNVM parameters. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_read_envm_parameter service will return zero if the + * service executed successfully, otherwise, it will return + * one indicating error. + */ +uint8_t SYS_read_envm_parameter +( + uint8_t * p_envm_param, + uint16_t mb_offset +); +#endif +/***************************************************************************//** + * The function SYS_puf_emulation_service() is used to authenticate a device. + * + * The SYS_puf_emulation_service() function accept a challenge comprising a + * 8-bit optype and 128-bit challenge and return a 256-bit response unique to + * the given challenge and the device. + * + * @param p_challenge The p_challenge parameter specifies the 128-bit challenge + * to generate the 256-bits unique response. + * + * @param op_type The op_type parameter specifies the operational parameter + * to generate the 256-bits unique response. + * + * @param p_response The p_response parameter is a pointer to a buffer where + * the data returned which is the response by system controller + * is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_puf_emulation_service function will return zero + * if the service executed successfully, otherwise, it will + * return one indicating error. + */ +uint8_t SYS_puf_emulation_service +( + const uint8_t * p_challenge, + uint8_t op_type, + uint8_t* p_response, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_digital_signature_service() function is used to generate P-384 ECDSA + * signature based on SHA384 hash value. + * + * @param p_hash The p_hash parameter is a pointer to the buffer which + * contain the 48 bytes SHA384 Hash value (input value). + * + * @param format The format parameter specifies the output format of + * generated SIGNATURE field. The different types of output + * signature formats are as follow: + * - DIGITAL_SIGNATURE_RAW_FORMAT + * - DIGITAL_SIGNATURE_DER_FORMAT + * + * @param p_response The p_response parameter is a pointer to a buffer that + * contains the generated ECDSA signature. The field may be + * 96 bytes or 104 bytes depending upon the output format. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digital_signature_service function returns + * zero if the service executed successfully, otherwise, it + * returns non-zero values indicating error. + */ +uint8_t SYS_digital_signature_service +( + const uint8_t* p_hash, + uint8_t format, + uint8_t* p_response, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_secure_nvm_write() function writes data in the sNVM region. + * Data gets stored in the following format: + * - Non-authenticated plaintext + * - Authenticated plaintext + * - Authenticated ciphertext + * + * Note: If you are executing this function with Authenticated plaintext + * or Authenticated ciphertext on a device whose sNVM was never previously + * written to, then the service may fail. For it to work, you must first write + * Authenticated data to the sNVM using Libero along with USK client and + * custom security. This flow generates the SMK. See UG0753 PolarFire FPGA + * Security User Guide for further details. + + * @param format The format parameter specifies the format used to write + * data in sNVM region. The different type of text formats + * are as follow: + * - NON_AUTHENTICATED_PLAINTEXT_FORMAT + * - AUTHENTICATED_PLAINTEXT_FORMAT + * - AUTHENTICATED_CIPHERTEXT_FORMAT + * + * @param snvm_module The snvm_module parameter specifies the the sNVM module + * in which the data need to be written. + * + * @param p_data The p_data parameter is a pointer to a buffer which + * contains the data to be stored in sNVM region. The data + * length to be written is fixed depending on the format + * parameter. If NON_AUTHENTICATED_PLAINTEXT_FORMAT is + * selected, then you can write 252 bytes in the sNVM module. + * For other two formats the data length is 236 bytes. + * + * @param p_user_key The p_user_key parameter is a pointer to a buffer which + * contain the 96-bit key USK (user secret key). This user + * secret key will enhance the security when authentication + * is used. That is, when Authenticated plaintext and + * Authenticated ciphertext format is selected. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digital_signature_service function returns + * zero if the service executed successfully, otherwise, it + * returns non-zero values indicating error. + */ +uint8_t SYS_secure_nvm_write +( + uint8_t format, + uint8_t snvm_module, + const uint8_t* p_data, + const uint8_t* p_user_key, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_secure_nvm_read() function is used to read data present in sNVM region. + * User should provide USK key, if the data was programmed using authentication. + * If the data was written in the sNVM using the authenticated plaintext or the + * authenticated ciphertext service option then this service will return the + * valid data only when authentication is successful. For more details, see + * SYS_secure_nvm_write() function. If the data was written in + * the sNVM using the authenticated plaintext or the authenticated ciphertext + * service option then this service will return the valid data only when + * authentication is successful. For more details, see SYS_secure_nvm_write() + * function and its parameter description. + * + * @param snvm_module The snvm_module parameter specifies the sNVM module + * from which the data need to be read. + * + * @param p_user_key The p_user_key parameter is a pointer to a buffer which + * contain the 96-bit key USK (user secret key). User should + * provide same secret key which is previously used for + * authentication while writing data in sNVM region. + * + * @param p_admin The p_admin parameter is a pointer to the buffer where + * the output page admin data is stored. The page admin + * data is 4 bytes long. + * + * @param p_data The p_data parameter is a pointer to a buffer which + * contains the data read from sNVM region. User should + * provide the buffer large enough to store the read data. + * + * @param data_len The data_len parameter specifies the number of bytes to be + * read from sNVM. + * The application should know whether the data written in the + * chose sNVM module was previously stored using Authentication + * or not. + * The data_len should be 236 bytes, for authenticated data. + * For not authenticated data the data_len should be 252 bytes. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digital_signature_service function returns + * zero if the service executed successfully, otherwise, it + * returns non-zero values indicating error. + */ +uint8_t SYS_secure_nvm_read +( + uint8_t snvm_module, + const uint8_t* p_user_key, + uint8_t* p_admin, + uint8_t* p_data, + uint16_t data_len, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_nonce_service() is used to issue "Nonce Service" system + * service to the system controller. + * + * @param p_nonce The p_nonce parameter is a pointer to a buffer + * in which the data returned by system controller is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code means + * that the service was executed successfully and a non-zero + * value indicates error. See the document link + * provided in the theory of operation section to know more + * about the service and service response. + */ +uint8_t SYS_nonce_service +( + const uint8_t * p_nonce, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_bitstream_authenticate_service() function is used to authenticate + * the Bitstream which is located in SPI through a system service routine. Prior + * to using the IAP service, it may be required to first validate the new + * bitstream before committing the device to reprogramming, thus avoiding the + * need to invoke recovery procedures if the bitstream is invalid. + * + * This service is applicable to bitstreams stored in SPI Flash memory only. + * + * @param spi_flash_address + * The spi_flash_address parameter specifies the address within + * SPI Flash memory where the bit-stream is stored. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_bitstream_authenticate_service function will return + * zero if the service executed successfully and the non-zero + * response from system controller indicates error. See + * the document link provided in the theory of + * operation section to know more about the service and service + * response. + */ +uint8_t SYS_bitstream_authenticate_service +( + uint32_t spi_flash_address, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_IAP_image_authenticate_service() function is used to authenticate + * the IAP image which is located in SPI through a system service routine. The + * service checks the image descriptor and the referenced bitstream and optional + * initialization data. If the image is authenticated successfully, then the + * image is guaranteed to be valid when used by an IAP function. + * + * This service is applicable to bitstreams stored in SPI Flash memory only. + * + * @param spi_idx + * The spi_idx parameter specifies the index in the SPI directory to + * be used where the IAP bit-stream is stored. + * Note: To support recovery SPI_IDX=1 should be an empty slot and the recovery + * image should be located in SPI_IDX=0. Since SPI_IDX=1 should be an + * empty slot, it shouldn’t be passed into the system service. + * + * @return The SYS_IAP_image_authenticate_service function will return + * zero if the service executed successfully the non-zero + * response from system controller indicates error. Please + * refer to the document link provided in the theory of + * operation section to know more about the service and service + * response. + */ +uint8_t SYS_IAP_image_authenticate_service +( + uint8_t spi_idx +); + +/***************************************************************************//** + * The SYS_digest_check_service() function is used to Recalculates and compares + * digests of selected non-volatile memories. If the fabric digest is to be + * checked, then the user design must follow all prerequisite steps for the + * FlashFreeze service before invoking this service. + * This service is applicable to bitstreams stored in SPI Flash memory only. + * @param options + * The options parameter specifies the digest check options which + * indicate the area on which the digest check should be performed. + * Below is the list of options. You can OR these options to indicate + * to perform digest check on multiple segments. + * Note: The options parameter is of 2 bytes when used with PF + * device and 4 bytes when used with PolarFire SoC device. + * Options[i] | Description + * ---------------|---------------------------------- + * 0x01 | Fabric digest + * 0x02 | Fabric Configuration (CC) segment + * 0x04 | ROM digest in SNVM segment + * 0x08 | UL segment + * 0x10 | UKDIGEST0 in User Key segment + * 0x20 | UKDIGEST1 in User Key segment + * 0x40 | UKDIGEST2 in User Key segment (UPK1) + * 0x80 | UKDIGEST3 in User Key segment (UK1) + * 0x100 | UKDIGEST4 in User Key segment (DPK) + * 0x200 | UKDIGEST5 in User Key segment (UPK2) + * 0x400 | UKDIGEST6 in User Key segment (UK2) + * 0x800 | UFS Permanent lock (UPERM) segment + * 0x1000 | Factory and Factory Key Segments. + * 0x2000 | UKDIGEST7 in User Key segment (HWM) (PFSoC) + * 0x4000 | ENVMDIGEST (PFSoC only) + * 0x8000 | UKDIGEST8 for MSS Boot Info (PFSoC only) + * 0x10000 | SNVM_RW_ACCESS_MAP Digest (PFSoC only) + * 0x20000 | SBIC revocation digest (PFSoC only) + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digest_check_service function will return + * zero if the service executed successfully the non-zero + * response from system controller indicates error. Pleaes + * refer to the document link provided in the theory of + * operation section to know more about the service and service + * response. + */ +uint8_t SYS_digest_check_service +( + uint32_t options, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_iap_service() function is used to IAP service. The IAP service allows + * the user to reprogram the device without the need for an external master. The + * user design writes the bitstream to be programmed into a SPI Flash connected + * to the SPI port. When the service is invoked, the System Controller + * automatically reads the bitstream from the SPI flash and programs the device. + * The service allows the image to be executed in either VERIFY or PROGRAM modes. + * Another option for IAP is to perform the auto-update sequence. In this case + * the newest image of the first two images in the SPI directory is chosen to be + * programmed. + * + * @param iap_cmd + * The iap_cmd parameter specifies the specific IAP command which + * depends upon VERIFY or PROGRAM modes and the SPI address method. + * iap_cmd | Description + * -----------------------|------------ + * IAP_PROGRAM_BY_SPIIDX_CMD | IAP program. + * IAP_VERIFY_BY_SPIIDX_CMD | Fabric Configuration (CC) segment + * IAP_PROGRAM_BY_SPIADDR_CMD | ROM digest in SNVM segment + * IAP_VERIFY_BY_SPIADDR_CMD | UL segment + * IAP_AUTOUPDATE_CMD | UKDIGEST0 in User Key segment + * + * @param spiaddr + * The spiaddr parameter specifies either the index + * in the SPI directory or the SPI address in the SPI Flash memory. + * Below is the list of the possible meaning of spiaddr parameter + * in accordance with the iap_cmd parameter. + * iap_cmd | spiaddr + * ----------------------|----------------- + * IAP_PROGRAM_BY_SPIIDX_CMD | Index in the SPI directory. + * IAP_VERIFY_BY_SPIIDX_CMD | Index in the SPI directory. + * IAP_PROGRAM_BY_SPIADDR_CMD | SPI address in the SPI Flash memory + * IAP_VERIFY_BY_SPIADDR_CMD | SPI address in the SPI Flash memory + * IAP_AUTOUPDATE_CMD | spiaddr is ignored as No index/address required for this command. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * Note: For the IAP services with command IAP_PROGRAM_BY_SPIIDX_CMD and + * IAP_VERIFY_BY_SPIIDX_CMD To support recovery SPI_IDX=1 should be an + * empty slot and the recovery image should be located in SPI_IDX=0. + * Since SPI_IDX=1 should be an empty slot it shouldn’t be passed into + * the system service. + * + * @return The SYS_iap_service function will return zero if the service + * executed successfully and the non-zero response from system + * controller indicates error. Please refer to the document + * link provided in the theory of operation section to know + * more about the service and service response. + */ +uint8_t SYS_iap_service +( + uint8_t iap_cmd, + uint32_t spiaddr, + uint16_t mb_offset +); + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_SYSSERV_PF_H */ diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h new file mode 100644 index 0000000..8b14b7e --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h @@ -0,0 +1,149 @@ +/******************************************************************************* + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Register bit offsets and masks definitions for CoreSysServices_PF driver. + */ + +#ifndef __CORE_SYSSERV_PF_REGISTERS +#define __CORE_SYSSERV_PF_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * SYS_SERV_CMD (offset 0x04) register details + */ +#define SS_CMD_REG_OFFSET 0x04u + +#define SS_CMD_OFFSET 0x04 +#define SS_CMD_MASK 0x0000FFFFu +#define SS_CMD_SHIFT 0u + +/*------------------------------------------------------------------------------ + * SYS_SERV_STAT (offset 0x08) register details + */ +#define SS_STAT_REG_OFFSET 0x08u + +#define SS_STAT_OFFSET 0x08 +#define SS_STAT_MASK 0x0000FFFFu +#define SS_STAT_SHIFT 0u + +/*------------------------------------------------------------------------------ + * SYS_SERV_REQ (offset 0x0C) register details + */ +#define SS_REQ_REG_OFFSET 0x0Cu + + +#define SS_REQ_REQ_OFFSET 0x0Cu +#define SS_REQ_REQ_MASK 0x00000001UL +#define SS_REQ_REQ_SHIFT 0u + +#define SS_REQ_ABUSY_OFFSET 0x0Cu +#define SS_REQ_ABUSY_MASK 0x00000002UL +#define SS_REQ_ABUSY_SHIFT 1u + +#define SS_REQ_NABUSY_OFFSET 0x0Cu +#define SS_REQ_NABUSY_MASK 0x00000004UL +#define SS_REQ_NABUSY_SHIFT 2u + +#define SS_REQ_SSBUSY_OFFSET 0x0Cu +#define SS_REQ_SSBUSY_MASK 0x00000008UL +#define SS_REQ_SSBUSY_SHIFT 3u + +#define SS_REQ_AREQ_OFFSET 0x0Cu +#define SS_REQ_AREQ_MASK 0x00000010UL +#define SS_REQ_AREQ_SHIFT 4u + +#define SS_REQ_NAREQ_OFFSET 0x0Cu +#define SS_REQ_NAREQ_MASK 0x00000020UL +#define SS_REQ_NAREQ_SHIFT 5u +/*------------------------------------------------------------------------------ + * MBX_ECCSTATUS (offset 0x10) register details + */ +#define MBX_ECCSTATUS_REG_OFFSET 0x10u + +#define MBX_ECCSTATUS_OFFSET 0x10 +#define MBX_ECCSTATUS_MASK 0x03u +#define MBX_ECCSTATUS_SHIFT 0u + + +/*------------------------------------------------------------------------------ + * MBX_WCNT (offset 0x14) register details + */ +#define MBX_WCNT_REG_OFFSET 0x14u + +#define MBX_WCNT_OFFSET 0x14 +#define MBX_WCNT_MASK 0x000001FFu +#define MBX_WCNT_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_RWCNT (offset 0x18) register details + */ +#define MBX_RCNT_REG_OFFSET 0x18u + +#define MBX_RCNT_OFFSET 0x18 +#define MBX_RCNT_MASK 0x000001FFu +#define MBX_RCNT_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_WADRDESC (offset 0x1C) register details + */ +#define MBX_WADDR_REG_OFFSET 0x1Cu + +#define MBX_WADDR_OFFSET 0x1C +#define MBX_WADDR_MASK 0x000001FFu +#define MBX_WADDR_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_RADRDESC (offset 0x20) register details + */ +#define MBX_RADDR_REG_OFFSET 0x20u + +#define MBX_RADDR_OFFSET 0x20 +#define MBX_RADDR_MASK 0x000001FFu +#define MBX_RADDR_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_WDATA (offset 0x28) register details + */ +#define MBX_WDATA_REG_OFFSET 0x28u + +#define MBX_WDATA_OFFSET 0x28 +#define MBX_WDATA_MASK 0xFFFFFFFFu +#define MBX_WDATA_SHIFT 0u + + +/*------------------------------------------------------------------------------ + * MBX_RDATA (offset 0x2C) register details + */ +#define MBX_RDATA_REG_OFFSET 0x2Cu + +#define MBX_RDATA_OFFSET 0x2C +#define MBX_RDATA_MASK 0xFFFFFFFFu +#define MBX_RDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * SS_USER (offset 0x30) register details + */ +#define SS_USER_REG_OFFSET 0x30u + +#define SS_USER_BUSY_OFFSET 0x30 +#define SS_USER_BUSY_MASK 0x00000001u +#define SS_USER_BUSY_SHIFT 0u + +#define SS_USER_RDVLD_OFFSET 0x30 +#define SS_USER_RDVLD_MASK 0x00000002u +#define SS_USER_RDVLD_SHIFT 1u + +#define SS_USER_CMDERR_OFFSET 0x30 +#define SS_USER_CMDERR_MASK 0x00000004u +#define SS_USER_CMDERR_SHIFT 2u + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_SYSSERV_PF_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c new file mode 100644 index 0000000..0c0a866 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c @@ -0,0 +1,297 @@ +/******************************************************************************* + * (c) Copyright 2007-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file core_uart_apb.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreUARTapb driver implementation. See file "core_uart_apb.h" for + * description of the functions implemented in this file. + * + */ + +#include "coreuartapb_regs.h" +#include "core_uart_apb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define NULL_INSTANCE ( ( UART_instance_t* ) 0 ) +#define NULL_BUFFER ( ( uint8_t* ) 0 ) + +#define MAX_LINE_CONFIG ( ( uint8_t )( DATA_8_BITS | ODD_PARITY ) ) +#define MAX_BAUD_VALUE ( ( uint16_t )( 0x1FFF ) ) +#define STATUS_ERROR_MASK ( ( uint8_t )( STATUS_PARITYERR_MASK | \ + STATUS_OVERFLOW_MASK | \ + STATUS_FRAMERR_MASK ) ) +#define BAUDVALUE_LSB ( (uint16_t) (0x00FF) ) +#define BAUDVALUE_MSB ( (uint16_t) (0xFF00) ) +#define BAUDVALUE_SHIFT ( (uint8_t) (5) ) + +#define STATUS_ERROR_OFFSET STATUS_PARITYERR_SHIFT + +/***************************************************************************//** + * UART_init() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_init +( + UART_instance_t * this_uart, + addr_t base_addr, + uint16_t baud_value, + uint8_t line_config +) +{ + uint8_t rx_full; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( line_config <= MAX_LINE_CONFIG ) + HAL_ASSERT( baud_value <= MAX_BAUD_VALUE ) + + if( ( this_uart != NULL_INSTANCE ) && + ( line_config <= MAX_LINE_CONFIG ) && + ( baud_value <= MAX_BAUD_VALUE ) ) + { + /* + * Store lower 8-bits of baud value in CTRL1. + */ + HAL_set_8bit_reg( base_addr, CTRL1, (uint_fast8_t)(baud_value & + BAUDVALUE_LSB ) ); + + /* + * Extract higher 5-bits of baud value and store in higher 5-bits + * of CTRL2, along with line configuration in lower 3 three bits. + */ + HAL_set_8bit_reg( base_addr, CTRL2, (uint_fast8_t)line_config | + (uint_fast8_t)((baud_value & + BAUDVALUE_MSB) >> BAUDVALUE_SHIFT ) ); + + this_uart->base_address = base_addr; +#ifndef NDEBUG + { + uint8_t config; + uint8_t temp; + uint16_t baud_val; + baud_val = HAL_get_8bit_reg( this_uart->base_address, CTRL1 ); + config = HAL_get_8bit_reg( this_uart->base_address, CTRL2 ); + /* + * To resolve operator precedence between & and << + */ + temp = ( config & (uint8_t)(CTRL2_BAUDVALUE_MASK ) ); + baud_val |= (uint16_t)( (uint16_t)(temp) << BAUDVALUE_SHIFT ); + config &= (uint8_t)(~CTRL2_BAUDVALUE_MASK); + HAL_ASSERT( baud_val == baud_value ); + HAL_ASSERT( config == line_config ); + } +#endif + + /* + * Flush the receive FIFO of data that may have been received before the + * driver was initialized. + */ + rx_full = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_RXFULL_MASK; + while ( rx_full ) + { + HAL_get_8bit_reg( this_uart->base_address, RXDATA ); + rx_full = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_RXFULL_MASK; + } + + /* + * Clear status of the UART instance. + */ + this_uart->status = (uint8_t)0; + } +} + +/***************************************************************************//** + * UART_send() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_send +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +) +{ + size_t char_idx; + uint8_t tx_ready; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( tx_buffer != NULL_BUFFER ) + HAL_ASSERT( tx_size > 0 ) + + if( (this_uart != NULL_INSTANCE) && + (tx_buffer != NULL_BUFFER) && + (tx_size > (size_t)0) ) + { + for ( char_idx = (size_t)0; char_idx < tx_size; char_idx++ ) + { + /* Wait for UART to become ready to transmit. */ + do { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( !tx_ready ); + /* Send next character in the buffer. */ + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)tx_buffer[char_idx] ); + } + } +} + +/***************************************************************************//** + * UART_fill_tx_fifo() + * See "core_uart_apb.h" for details of how to use this function. + */ +size_t +UART_fill_tx_fifo +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +) +{ + uint8_t tx_ready; + size_t size_sent = 0u; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( tx_buffer != NULL_BUFFER ) + HAL_ASSERT( tx_size > 0 ) + + /* Fill the UART's Tx FIFO until the FIFO is full or the complete input + * buffer has been written. */ + if( (this_uart != NULL_INSTANCE) && + (tx_buffer != NULL_BUFFER) && + (tx_size > 0u) ) + { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + if ( tx_ready ) + { + do { + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)tx_buffer[size_sent] ); + size_sent++; + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( (tx_ready) && ( size_sent < tx_size ) ); + } + } + return size_sent; +} + +/***************************************************************************//** + * UART_get_rx() + * See "core_uart_apb.h" for details of how to use this function. + */ +size_t +UART_get_rx +( + UART_instance_t * this_uart, + uint8_t * rx_buffer, + size_t buff_size +) +{ + uint8_t new_status; + uint8_t rx_full; + size_t rx_idx = 0u; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( rx_buffer != NULL_BUFFER ) + HAL_ASSERT( buff_size > 0 ) + + if( (this_uart != NULL_INSTANCE) && + (rx_buffer != NULL_BUFFER) && + (buff_size > 0u) ) + { + rx_idx = 0u; + new_status = HAL_get_8bit_reg( this_uart->base_address, STATUS ); + this_uart->status |= new_status; + rx_full = new_status & STATUS_RXFULL_MASK; + while ( ( rx_full ) && ( rx_idx < buff_size ) ) + { + rx_buffer[rx_idx] = HAL_get_8bit_reg( this_uart->base_address, + RXDATA ); + rx_idx++; + new_status = HAL_get_8bit_reg( this_uart->base_address, STATUS ); + this_uart->status |= new_status; + rx_full = new_status & STATUS_RXFULL_MASK; + } + } + return rx_idx; +} + +/***************************************************************************//** + * UART_polled_tx_string() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_polled_tx_string +( + UART_instance_t * this_uart, + const uint8_t * p_sz_string +) +{ + uint32_t char_idx; + uint8_t tx_ready; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( p_sz_string != NULL_BUFFER ) + + if( ( this_uart != NULL_INSTANCE ) && ( p_sz_string != NULL_BUFFER ) ) + { + char_idx = 0U; + while( 0U != p_sz_string[char_idx] ) + { + /* Wait for UART to become ready to transmit. */ + do { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( !tx_ready ); + /* Send next character in the buffer. */ + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)p_sz_string[char_idx] ); + char_idx++; + } + } +} + +/***************************************************************************//** + * UART_get_rx_status() + * See "core_uart_apb.h" for details of how to use this function. + */ +uint8_t +UART_get_rx_status +( + UART_instance_t * this_uart +) +{ + uint8_t status = UART_APB_INVALID_PARAM; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + /* + * Extract UART error status and place in lower bits of "status". + * Bit 0 - Parity error status + * Bit 1 - Overflow error status + * Bit 2 - Frame error status + */ + if( this_uart != NULL_INSTANCE ) + { + status = ( ( this_uart->status & STATUS_ERROR_MASK ) >> + STATUS_ERROR_OFFSET ); + /* + * Clear the sticky status for this instance. + */ + this_uart->status = (uint8_t)0; + } + return status; +} + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h new file mode 100644 index 0000000..c016403 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h @@ -0,0 +1,451 @@ +/******************************************************************************* + * (c) Copyright 2007-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file core_uart_apb.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief This file contains the application programming interface for the + * CoreUARTapb bare metal driver. + * + */ +/*=========================================================================*//** + @mainpage CoreUARTapb Bare Metal Driver. + + @section intro_sec Introduction + CoreUARTapb is an implementation of the Universal Asynchronous + Receiver/Transmitter aimed at minimal FPGA tile usage within a Microchip FPGA. + The CoreUARTapb bare metal software driver is designed to be used in systems + with no operating system. + + The CoreUARTapb driver provides functions for basic polled transmitting and + receiving operations. It also provide functions that allow the use of the + CoreUARTapb in interrupt-driven mode but leaves the management of interrupts + to the calling application, as interrupt enabling and disabling are not + controlled through the CoreUARTapb registers. The CoreUARTapb driver is + provided as C source code. + + @section driver_configuration Driver Configuration + Your application software should configure the CoreUARTapb driver by calling + the UART_init() function for each CoreUARTapb instance in the hardware design. + The configuration parameters include the CoreUARTapb hardware instance base + address and other runtime parameters, such as baud rate, bit width, and + parity. No CoreUARTapb hardware configuration parameters are needed by the + driver, apart from the CoreUARTapb hardware instance base address. Hence, no + additional configuration files are required to use the driver. + + A CoreUARTapb hardware instance is generated with fixed baud rate, character + size, and parity configuration settings as part of the hardware flow. The + baud_value and line_config parameter values passed to the UART_init() function + have no effect if fixed values were selected for the baud rate, character + size, and parity in the hardware configuration of CoreUARTapb. When fixed + values are selected for these hardware configuration parameters, the driver is + unable to overwrite the fixed values in the CoreUARTapb control registers, + CTRL1 and CTRL2. + + @section theory_op Theory of Operation + The CoreUARTapb software driver is designed to allow the control of multiple + instances of CoreUARTapb. Each instance of CoreUARTapb in the hardware design + is associated with a single instance of the UART_instance_t structure in the + software. You need to allocate memory for one unique UART_instance_t structure + instance for each CoreUARTapb hardware instance. The contents of these data + structures are initialized while calling the UART_init() function. A pointer + to the structure is passed to the subsequent driver functions in order to + identify the CoreUARTapb hardware instance you wish to perform the requested + operation on. + + Note: Do not attempt to directly manipulate the content of UART_instance_t + structures. This structure is only intended to be modified by the driver + function. + + Once initialized, the driver transmits and receives data. Transmit is + performed using the UART_send() function. If this function blocks, then it + returns only when the data passed to it has been sent to the CoreUARTapb + hardware. Data received by the CoreUARTapb hardware is read by the user + application using the UART_get_rx() function. + + The UART_fill_tx_fifo() function is also provided as a part of the + interrupt-driven transmit. This function fills the CoreUARTapb hardware + transmit FIFO with the content of a data buffer passed as a parameter before + returning. The control of the interrupts must be implemented outside the + driver, as the CoreUARTapb hardware does not provide the ability to enable + or disable its interrupt sources. + + The UART_polled_tx_string() function is provided to transmit a NULL-terminated + string in polled mode. If this function blocks, then it returns only when the + data passed to it has been sent to the CoreUARTapb hardware. + + The UART_get_rx_status() function returns the error status of the CoreUARTapb + receiver. This is used by applications to take appropriate action in case of + receiver errors. +*//*=========================================================================*/ +#ifndef __CORE_UART_APB_H +#define __CORE_UART_APB_H 1 + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + Data Bits Length Defines + ======================== + These constants define the data length in a UART packet. + | Constant | Description | + |-------------|---------------------------------------| + | DATA_7_BITS | Data length is 7-bits | + | DATA_8_BITS | Data length is 8-bits | + */ +#define DATA_7_BITS 0x00u +#define DATA_8_BITS 0x01u + +/***************************************************************************//** + Parity Defines + ============== + These constants define parity check options. + | Constant | Description | + |-------------|---------------------------------------| + | NO_PARITY | No Parity bit | + | EVEN_PARITY | Even Parity bit | + | ODD_PARITY | ODD Parity bit | + */ +#define NO_PARITY 0x00u +#define EVEN_PARITY 0x02u +#define ODD_PARITY 0x06u + +/***************************************************************************//** + Error Status Definitions + ======================== + These constants define the different types of possible errors in UART + transmission of data. + | Constant | Description | + |-------------------------|---------------------------------------| + | UART_APB_PARITY_ERROR | Data parity error | + | UART_APB_OVERFLOW_ERROR | Data overflow error | + | UART_APB_FRAMING_ERROR | Data framing error | + | UART_APB_NO_ERROR | No error | + | UART_APB_INVALID_PARAM | Invalid parameter | + */ +#define UART_APB_PARITY_ERROR 0x01u +#define UART_APB_OVERFLOW_ERROR 0x02u +#define UART_APB_FRAMING_ERROR 0x04u +#define UART_APB_NO_ERROR 0x00u +#define UART_APB_INVALID_PARAM 0xFFu + +/***************************************************************************//** + * There should be one instance of this structure for each instance of + * CoreUARTapb in your system. This structure instance identifies various UARTs + * in a system and should be passed as first parameter to UART functions to + * identify which UART performs the requested operation. The 'status' element in + * the structure is used to provide sticky status information. + */ +typedef struct +{ + addr_t base_address; + uint8_t status; +} UART_instance_t; + +/***************************************************************************//** + * The UART_init() function initializes the UART with the configuration passed + * as parameters. The configuration parameters are the baud_value that generates + * the baud rate and the line configuration (bit length and parity). + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data regarding + * this instance of the CoreUARTapb. This pointer is used to + * identify the target CoreUARTapb hardware instance in + * subsequent calls to the CoreUARTapb functions. + * @param base_addr The base_address parameter is the base address in the + * processor's memory map for the registers of the + * CoreUARTapb instance being initialized. + * @param baud_value The baud_value parameter selects the baud rate for the + * UART. The baud value is calculated from the frequency of + * the system clock in hertz and the desired baud rate using + * the following equation: + * baud_value = (clock / (baud_rate * 16)) - 1. + * The baud_value parameter must be a value in the range 0 + * to 8191 (or 0x0000 to 0x1FFF). + * @param line_config This parameter is the line configuration, specifies the + * bit length and parity settings. This is the logical OR of: + * - DATA_7_BITS + * - DATA_8_BITS + * - NO_PARITY + * - EVEN_PARITY + * - ODD_PARITY + * For example, 8 bits even parity would be specified as + * (DATA_8_BITS | EVEN_PARITY). + * @return This function does not return a value. + * @example + * @code + * #define BAUD_VALUE_57600 25 + * + * #define COREUARTAPB0_BASE_ADDR 0xC3000000UL + * + * UART_instance_t g_uart; + * int main() + * { + * UART_init(&g_uart, COREUARTAPB0_BASE_ADDR, + BAUD_VALUE_57600, (DATA_8_BITS | EVEN_PARITY)); + * } + * @endcode + */ +void +UART_init +( + UART_instance_t * this_uart, + addr_t base_addr, + uint16_t baud_value, + uint8_t line_config +); + +/***************************************************************************//** + * The UART_send() function is used to transmit data. It transfers the content + * of the transmitter data buffer, passed as a function parameter, into the + * UART's hardware transmitter FIFO. It returns when the full content of the + * transmitter data buffer has been transferred to the UART's transmitter FIFO. + * + * Note: You should not assume that the data you are sending using this function + * has been received at the other end by the time this function returns. The + * actual transmission over the serial connection is still be taking place at + * the time of the function return. It is safe to release or reuse the memory + * used as the transmit buffer once this function returns. + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data + * regarding this instance of the CoreUARTapbUART. + * @param tx_buffer The tx_buffer parameter is a pointer to a buffer that + * contains the data to be transmitted. + * @param tx_size The tx_size parameter is the size in bytes of the + * transmitted data. + * + * @return This function does not return a value. + * + * @example + * @code + * uint8_t testmsg1[] = {"\n\r\n\r\n\rUART_send() test message 1"}; + * UART_send(&g_uart,(const uint8_t *)&testmsg1,sizeof(testmsg1)); + * @endcode + */ +void +UART_send +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +); + +/***************************************************************************//** + * The UART_fill_tx_fifo() function fills the UART's transmitter hardware FIFO + * with the data found in the transmitter buffer that is passed in as a + * function parameter. The function returns either when the FIFO is full or + * when the complete contents of the transmitter buffer have been copied into + * the FIFO. It returns the number of bytes copied into the UART's transmitter + * hardware FIFO. This function is intended to be used as part of + * interrupt-driven transmission. + * + * Note: You should not assume that the data you transmit using this function + * has been received at the other end by the time this function returns. The + * actual transmission over the serial connection is still be taking place at + * the time of the function return. + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data + * regarding this instance of the UART. + * @param tx_buffer The tx_buffer parameter is a pointer to a buffer that + * contains the data to be transmitted. + * @param tx_size The tx_size parameter is the size in bytes of the + * transmitted data. + * @return This function returns the number of bytes copied into + * the UART's transmitter hardware FIFO. + * + * @example + * @code + * void send_using_interrupt + * ( + * uint8_t * pbuff, + * size_t tx_size + * ) + * { + * size_t size_in_fifo; + * size_in_fifo = UART_fill_tx_fifo( &g_uart, pbuff, tx_size ); + * } + * @endcode + */ +size_t +UART_fill_tx_fifo +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +); + +/***************************************************************************//** + * The UART_get_rx() function reads the content of the UART's receiver hardware + * FIFO and stores it in the receiver buffer that is passed in as a function + * parameter. It copies either the full contents of the FIFO into the receiver + * buffer, or just enough data from the FIFO to fill the receiver buffer, + * depending on the size of the receiver buffer. The size of the receiver + * buffer is passed in as a function parameter. UART_get_rx() returns the number + * of bytes copied into the receiver buffer. If no data was received at the time + * the function is called, the function returns 0. + * + * Note: This function reads and accumulates the receiver status of the + * CoreUARTapb instance before reading each byte from the receiver's + * data register/FIFO. This allows the driver to maintain a sticky + * record of any receiver errors that occur as the UART receives each + * data byte; receiver errors would otherwise be lost after each read + * from the receiver's data register. A call to the UART_get_rx_status() + * function returns any receiver errors accumulated during the execution + * of the UART_get_rx() function. + * + * Note: When FIFO mode is disabled in the CoreUARTapb hardware configuration, + * the driver accumulates a sticky record of any parity errors, framing + * errors, or overflow errors. When FIFO mode is enabled, the driver + * accumulates a sticky record of overflow errors only; in this case, + * interrupts must be used to handle parity errors or framing errors. + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data + * regarding this instance of the UART. + * @param rx_buffer The rx_buffer parameter is a pointer to a buffer where + * the received data is copied. + * @param buff_size The buff_size parameter is the size of the receive + * buffer in bytes. + * @return This function returns the number of bytes copied into + * the receive buffer. + * + * @example + * @code + * #define MAX_RX_DATA_SIZE 256 + * + * uint8_t rx_data[MAX_RX_DATA_SIZE]; + * uint8_t rx_size = 0; + * + * rx_size = UART_get_rx( &g_uart, rx_data, sizeof(rx_data) ); + * @endcode + */ +size_t +UART_get_rx +( + UART_instance_t * this_uart, + uint8_t * rx_buffer, + size_t buff_size +); + +/***************************************************************************//** + * The UART_polled_tx_string() function is used to transmit a NULL ('\0') + * terminated string. Internally, it polls for the transmit ready status and + * transfers the text starting at the address pointed by p_sz_string into + * the UART's hardware transmitter FIFO. It is a blocking function and returns + * only when the complete string has been transferred to the UART's transmit + * FIFO. + * + * Note: You should not assume that the data you transmit using this function + * has been received at the other end by the time this function returns. The + * actual transmission over the serial connection is still be taking place at + * the time of the function return. + * + * @param this_uart The this_uart parameter is the pointer to a + * UART_instance_t structure, which holds all data + * regarding this instance of the UART. + * @param p_sz_string The p_sz_string parameter is a pointer to a buffer + * containing the NULL ('\0') terminated string to be + * transmitted. + * @return This function does not return a value. + * + * @example + * @code + * uint8_t testmsg1[] = {"\r\n\r\nUART_polled_tx_string() test message 1\0"}; + * UART_polled_tx_string(&g_uart,(const uint8_t *)&testmsg1); + * @endcode + */ +void +UART_polled_tx_string +( + UART_instance_t * this_uart, + const uint8_t * p_sz_string +); + +/***************************************************************************//** + * The UART_get_rx_status() function returns the receiver error status of the + * CoreUARTapb instance. It reads both the current error status of the receiver + * and the accumulated error status from preceding calls to the UART_get_rx() + * function and combines them using a bitwise OR. It returns the cumulative + * parity, framing, and overflow error status of the receiver, since the + * previous call to UART_get_rx_status() as an 8-bit encoded value. + * + * Note: The UART_get_rx() function reads and accumulates the receiver status + * of the CoreUARTapb instance before reading each byte from the receiver's data + * register/FIFO. The driver maintains a sticky record of the cumulative error + * status, which persists after the UART_get_rx() function returns. The + * UART_get_rx_status() function clears this accumulated record of receiver + * errors before returning. + * + * @param this_uart The this_uart parameter is a pointer to a + * UART_instance_t structure which holds all data regarding + * this instance of the UART. + * @return This function returns the UART receiver error status as + * an 8-bit encoded value. The return value is 0, if there + * are no receiver errors occurred. The driver provides a + * set of bit mask constants, which should be compared with + * and/or used to mask the returned value to determine the + * receiver error status. + * When the return value is compared to the following bit + * masks, a non-zero result indicates that the + * corresponding error occurred: + * UART_APB_PARITY_ERROR (bit mask = 0x01) + * UART_APB_OVERFLOW_ERROR (bit mask = 0x02) + * UART_APB_FRAMING_ERROR (bit mask = 0x04) + * When the return value is compared to the following bit + * mask, a non-zero result indicates that no error + * occurred: + * UART_APB_NO_ERROR (0x00) + * + * @example + * @code + * UART_instance_t g_uart; + * uint8_t rx_data[MAX_RX_DATA_SIZE]; + * uint8_t err_status; + * err_status = UART_get_err_status(&g_uart); + * + * if(UART_APB_NO_ERROR == err_status ) + * { + * rx_size = UART_get_rx( &g_uart, rx_data, MAX_RX_DATA_SIZE ); + * } + * @endcode + */ +uint8_t +UART_get_rx_status +( + UART_instance_t * this_uart +); + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_UART_APB_H */ diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h new file mode 100644 index 0000000..c123cc3 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h @@ -0,0 +1,133 @@ +/******************************************************************************* + * (c) Copyright 2007-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file coreuartapb_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreUARTapb register definitions + */ + +#ifndef __CORE_UART_APB_REGISTERS +#define __CORE_UART_APB_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * TxData register details + */ +#define TXDATA_REG_OFFSET 0x0u + +/* + * TxData bits. + */ +#define TXDATA_OFFSET 0x0u +#define TXDATA_MASK 0xFFu +#define TXDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * RxData register details + */ +#define RXDATA_REG_OFFSET 0x4u + +/* + * RxData bits. + */ +#define RXDATA_OFFSET 0x4u +#define RXDATA_MASK 0xFFu +#define RXDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * ControReg1 register details + */ +#define CTRL1_REG_OFFSET 0x8u + +/* + * Baud value (Lower 8-bits) + */ +#define CTRL1_BAUDVALUE_OFFSET 0x8u +#define CTRL1_BAUDVALUE_MASK 0xFFu +#define CTRL1_BAUDVALUE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * ControReg2 register details + */ +#define CTRL2_REG_OFFSET 0xCu + +/* + * Bit length + */ +#define CTRL2_BIT_LENGTH_OFFSET 0xCu +#define CTRL2_BIT_LENGTH_MASK 0x01u +#define CTRL2_BIT_LENGTH_SHIFT 0u + +/* + * Parity enable. + */ +#define CTRL2_PARITY_EN_OFFSET 0xCu +#define CTRL2_PARITY_EN_MASK 0x02u +#define CTRL2_PARITY_EN_SHIFT 1u + +/* + * Odd/even parity selection. + */ +#define CTRL2_ODD_EVEN_OFFSET 0xCu +#define CTRL2_ODD_EVEN_MASK 0x04u +#define CTRL2_ODD_EVEN_SHIFT 2u + +/* + * Baud value (Higher 5-bits) + */ +#define CTRL2_BAUDVALUE_OFFSET 0xCu +#define CTRL2_BAUDVALUE_MASK 0xF8u +#define CTRL2_BAUDVALUE_SHIFT 3u + +/*------------------------------------------------------------------------------ + * StatusReg register details + */ +#define StatusReg_REG_OFFSET 0x10u + +#define STATUS_REG_OFFSET 0x10u + +/* + * Transmit ready. + */ +#define STATUS_TXRDY_OFFSET 0x10u +#define STATUS_TXRDY_MASK 0x01u +#define STATUS_TXRDY_SHIFT 0u + +/* + * Receive full. + */ +#define STATUS_RXFULL_OFFSET 0x10u +#define STATUS_RXFULL_MASK 0x02u +#define STATUS_RXFULL_SHIFT 1u + +/* + * Parity error. + */ +#define STATUS_PARITYERR_OFFSET 0x10u +#define STATUS_PARITYERR_MASK 0x04u +#define STATUS_PARITYERR_SHIFT 2u + +/* + * Overflow. + */ +#define STATUS_OVERFLOW_OFFSET 0x10u +#define STATUS_OVERFLOW_MASK 0x08u +#define STATUS_OVERFLOW_SHIFT 3u + +/* + * Frame Error. + */ +#define STATUS_FRAMERR_OFFSET 0x10u +#define STATUS_FRAMERR_MASK 0x10u +#define STATUS_FRAMERR_SHIFT 4u + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_UART_APB_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.c b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.c new file mode 100644 index 0000000..a2f4911 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.c @@ -0,0 +1,765 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Mi-V I2C Soft IP bare-metal driver. This module is delivered as part of + * Extended Sub System(ESS) MIV_ESS. + * Please refer to miv_i2c.h file for more information. + */ + +#include "miv_i2c.h" + +#define MIV_I2C_ERROR 0xFFu + +/*------------------------------------------------------------------------------ + * MIV I2C transaction direction. + */ +#define MIV_I2C_WRITE_DIR 0u +#define MIV_I2C_READ_DIR 1u + +/* -- TRANSACTIONS TYPES -- */ +#define MIV_I2C_NO_TRANSACTION 0u +#define MIV_I2C_MASTER_WRITE_TRANSACTION 1u +#define MIV_I2C_MASTER_READ_TRANSACTION 2u +#define MIV_I2C_MASTER_SEQUENTIAL_READ_TRANSACTION 3u + +/*------------------------------------------------------------------------------ + * MIV I2C HW states + */ +#define MIV_I2C_IDLE 0x00u +#define MIV_I2C_TX_STA_CB 0x01u +#define MIV_I2C_TX_DATA 0x02u +#define MIV_I2C_RX_DATA 0x03u + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_disable_irq() disables the Mi-V I2C interrupt. + */ +void +MIV_I2C_disable_irq +( + void +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_enable_irq() enables the Mi-V I2C interrupt. + */ +void +MIV_I2C_enable_irq +( + void +); + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_init +( + miv_i2c_instance_t *this_i2c, + addr_t base_addr +) +{ + /* Assign the base address + * Clock Prescale value set + * MIV_I2C interrupt enabled + * I2C core enable + */ + psr_t processor_state; + + /* Disabling the interrupts */ + processor_state = HAL_disable_interrupts(); + + /* + * Initialize all items of the this_miv_i2c data structure to zero. This + * initializes all state variables to their init value. It relies on + * the fact that NO_TRANSACTION, MIV_I2C_SUCCESS and I2C_RELEASE_BUS all + * have an actual value of zero. + */ + memset(this_i2c, 0, sizeof(miv_i2c_instance_t)); + + this_i2c->base_addr = base_addr; + + HAL_restore_interrupts(processor_state); +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_config +( + miv_i2c_instance_t *this_i2c, + uint16_t clk_prescale +) +{ + /* Assign the base address + * Clock Prescale value set + * MIV_I2C interrupt enabled + * I2C core enable + */ + psr_t processor_state; + + /* Disabling the interrupts */ + processor_state = HAL_disable_interrupts(); + + /* Before writing to prescale reg, the core enable must be zero */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CTRL_CORE_EN, 0x00u); + + /* Set the prescale value */ + HAL_set_16bit_reg(this_i2c->base_addr, PRESCALE, clk_prescale); + + /* Enable the MIV I2C interrupts */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CTRL_IRQ_EN, 0x01u); + + /* Enable the MIV I2C core */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CTRL_CORE_EN, 0x01u); + + this_i2c->master_state = MIV_I2C_IDLE; + + HAL_restore_interrupts(processor_state); +} + +/* + * Please refer to miv_i2c.h for more info + */ +uint8_t +MIV_I2C_start +( + miv_i2c_instance_t *this_i2c +) +{ + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + /* Generate I2C start condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + HAL_restore_interrupts(processor_state); + + return 0u; +} + +/* + * Please refer to miv_i2c.h for more info + */ +uint8_t +MIV_I2C_stop +( + miv_i2c_instance_t *this_i2c +) +{ + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + /* Generate I2C stop condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + HAL_restore_interrupts(processor_state); + + return 0u; +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_write +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t bus_options, + uint8_t ack_polling_options +) +{ + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + /* I2C write flow + * + * Check I2C status for ongoing transaction + * Populate the structure with input data + * Generate start condition + * Set the write_direction and target address. + */ + + /* Update the transaction only when there is no ongoing I2C transaction */ + if (this_i2c->transaction == MIV_I2C_NO_TRANSACTION) + { + this_i2c->transaction = MIV_I2C_MASTER_WRITE_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MIV_I2C_MASTER_WRITE_TRANSACTION ; + + /* Populate the i2c instance structure */ + + /* Set the target addr */ + this_i2c->target_addr = i2c_target_addr; + this_i2c->dir = MIV_I2C_WRITE_DIR; + + /* Set up the tx buffer */ + this_i2c->master_tx_buffer = write_buffer; + this_i2c->master_tx_size = write_size; + this_i2c->master_tx_idx = 0u; + + /* Set the I2C status in progress and setup the options */ + this_i2c->bus_options = bus_options; + this_i2c->ack_polling_options = ack_polling_options; + this_i2c->master_status = MIV_I2C_IN_PROGRESS; + + + /* Generate I2C start condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* write target address and write bit */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, MIV_I2C_WRITE_DIR); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, i2c_target_addr); + + /* Set WR bit to transmit start condition and control byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + /* Set current master hw state -> transmitted start condition and + * control byte + */ + this_i2c->master_state = MIV_I2C_TX_STA_CB; + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( MIV_I2C_HOLD_BUS == this_i2c->bus_status ) + { + /* Must toggle IACK bit to clear the MIV_I2C IRQ*/ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00); + } + + MIV_I2C_enable_irq(); + + HAL_restore_interrupts(processor_state); + +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_read +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +) +{ + psr_t processor_state; + uint8_t status = MIV_I2C_SUCCESS; + + processor_state = HAL_disable_interrupts(); + + /* MIV I2C Read operation flow + * + * Check for ongoing transaction + * Populate the i2c instance structure + * Generate the start condition + * Set the READ_direction bit and target addr + */ + + uint8_t read_stat = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_TIP); + + /* Update the transaction only when there is no ongoing I2C transaction */ + if (this_i2c->transaction == MIV_I2C_NO_TRANSACTION) + { + this_i2c->transaction = MIV_I2C_MASTER_READ_TRANSACTION; + } + + this_i2c->pending_transaction = MIV_I2C_MASTER_READ_TRANSACTION; + + /* Populate the MIV I2C instance structure */ + + this_i2c->target_addr = i2c_target_addr; + this_i2c->dir = MIV_I2C_READ_DIR; + + /* Populate read buffer */ + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set the BUS and ACK polling options */ + this_i2c->bus_options = bus_options; + this_i2c->ack_polling_options = ack_polling_options; + + /* Generate the start condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* Set the DIR bit and target addr */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, MIV_I2C_READ_DIR); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, i2c_target_addr); + + /* Set the WR bit to transmit the start condition and command byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + /* Set the i2c master state and status transmitting STA and Command Byte */ + this_i2c->master_state = MIV_I2C_TX_STA_CB; + this_i2c->master_status = MIV_I2C_IN_PROGRESS; + + /* Toggle the IACK bit if required */ + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( MIV_I2C_HOLD_BUS == this_i2c->bus_status ) + { + /* Must toggle IACK bit to clear the MIV_I2C IRQ*/ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00); + } + /* Enable the I2C interrupt */ + MIV_I2C_enable_irq(); + + HAL_restore_interrupts(processor_state); +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_write_read +( + miv_i2c_instance_t *this_i2c, + uint8_t target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +) +{ + uint8_t status = MIV_I2C_SUCCESS; + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + uint8_t read_stat = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_TIP); + + /* I2C write read operation flow + * + * Used to read the data from set address offset + * + * Configure the i2c instance structure + * generate the start and configure the dir and target addr + * set wr bit to transmit the start and command byte + * + */ + + /* Update the transaction only when there is no ongoing I2C transaction */ + if (this_i2c->transaction == MIV_I2C_NO_TRANSACTION) + { + this_i2c->transaction = MIV_I2C_MASTER_READ_TRANSACTION; + } + + this_i2c->pending_transaction = MIV_I2C_MASTER_READ_TRANSACTION; + + /* Populate the I2C instance */ + + this_i2c->target_addr = target_addr; + + /* setup the i2c direction */ + this_i2c->dir = MIV_I2C_WRITE_DIR; + + /* set up transmit buffer */ + this_i2c->master_tx_buffer = write_buffer; + this_i2c->master_tx_size = write_size; + this_i2c->master_tx_idx = 0u; + + /* set up receive buffer */ + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set the bus and ack polling options */ + this_i2c->bus_options = bus_options; + this_i2c->ack_polling_options = ack_polling_options; + + /* Generate the start command */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* Set the DIR and target addr */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + /* Set the WR bit to transmit the start command and command byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + /* Set the i2c master state and status transmitting STA and Command Byte */ + this_i2c->master_state = MIV_I2C_TX_STA_CB; + this_i2c->master_status = MIV_I2C_IN_PROGRESS; + + /* + * Clear interrupt if required + */ + if ( MIV_I2C_HOLD_BUS == this_i2c->bus_status ) + { + /* Must toggle IACK bit to clear the MIV_I2C IRQ*/ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00u); + } + + /* Enable the I2C interrupt */ + MIV_I2C_enable_irq(); + + HAL_restore_interrupts(processor_state); +} + +/* MIV_I2C_isr() + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_isr +( + miv_i2c_instance_t *this_i2c +) +{ + uint8_t i2c_state; + uint8_t i2c_ack_status; + uint8_t i2c_al_status; + uint8_t hold_bus; + + /* Read the I2C master state */ + i2c_state = this_i2c->master_state; + + /* Read the ack and al status */ + i2c_ack_status = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_RXACK); + i2c_al_status = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_AL); + + switch (i2c_state) + { + /* I2C ISR State Machine + * + * Cases: + * - Transmit start condition and control byte + * - Received ACK and bus arbitration was not lost (Read or Write) + * - Received NACK + * - Bus arbitration lost + * + * - Transmit data + * - Received ACK and bus arbitration was not lost (Read or Write) + * - Received NACK + * - Bus arbitration lost + * + * - Receive data + * - Received ACK and bus arbitration was not lost (Read or Write) + * - Bus arbitration lost + */ + + case MIV_I2C_TX_STA_CB: + + /* Received ACK from target and I2C bus arbitration is not lost */ + if (i2c_ack_status == 0u && i2c_al_status == 0u) + { + /* If I2C master write operation */ + if (this_i2c->dir == MIV_I2C_WRITE_DIR) + { + /* write first byte of data and set the WR bit to transfer the data */ + HAL_set_8bit_reg(this_i2c->base_addr, TRANSMIT, + this_i2c->master_tx_buffer[this_i2c->master_tx_idx]); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + /* Increment the index */ + this_i2c->master_tx_idx++; + + /* Set the master state to TX data */ + this_i2c->master_state = MIV_I2C_TX_DATA; + } + /* Master read operation */ + else + { + if (this_i2c->master_rx_size == 1u) + { + /* Send the ACK if the rx size is 1, transmit NACK to slave + * after receiving 1 byte to indicate slave to stop sending + * the data + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_ACK, 0x01u); + } + + /* Send the RD command to slave */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_RD, 0x01u); + + /* Increment the index */ + this_i2c->master_rx_idx++; + + /* Change state to receive data */ + this_i2c->master_state = MIV_I2C_RX_DATA; + } + } + else if (i2c_ack_status == 1u) + { + if (this_i2c->ack_polling_options == MIV_I2C_ACK_POLLING_ENABLE) + { + /* Target responded with NACK and ACK polling option is enabled + * + * Re-send the start condition and control byte + * + * TO-DO: This might become infinite loop check for timeout + * options. + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + this_i2c->master_tx_idx = 0u; + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + else + { + /* Target responded with NACK and ACK polling is disabled + * Abort the transaction and move to IDLE state + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + + this_i2c->master_status = MIV_I2C_FAILED; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + + this_i2c->master_state = MIV_I2C_IDLE; + } + } + + else if (i2c_al_status == 1u) + { + /* Arbitration was lost on the BUS during the transmission of + * previous start condition and control byte. + * Re-send the STA and CB + */ + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + break; + + /* Transmit master data */ + case MIV_I2C_TX_DATA: + + /* ACK received and arbitration was not lost */ + if (i2c_ack_status == 0u && i2c_al_status == 0u) + { + uint8_t tx_buff[this_i2c->master_tx_size]; + if (this_i2c->master_tx_idx < this_i2c->master_tx_size) + { + HAL_set_8bit_reg(this_i2c->base_addr, TRANSMIT, + this_i2c->master_tx_buffer[this_i2c->master_tx_idx]); + + tx_buff[this_i2c->master_tx_idx] = this_i2c->master_tx_buffer[this_i2c->master_tx_idx]; + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + /* Increment the index */ + this_i2c->master_tx_idx++; + + /* Set the master state to TX data */ + this_i2c->master_state = MIV_I2C_TX_DATA; + } + + /* All the bytes are transmitted */ + else if (this_i2c->master_tx_idx == this_i2c->master_tx_size) + { + /* If this is a MASTER_READ_TRANSACTION, hold bus and start a + new transfer in read mode now that the read address has been + written to the slave */ + if(this_i2c->transaction == MIV_I2C_MASTER_READ_TRANSACTION) + + { + //Switch direction to READ + this_i2c->dir = MIV_I2C_READ_DIR; + + // Set the STA bit + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* Set the DIR bit and target addr */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, MIV_I2C_READ_DIR); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, this_i2c->target_addr); + + /* Set the WR bit to transmit the start condition and command byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + // Reset the buffer index + this_i2c->master_tx_idx = 0u; + this_i2c->master_rx_idx = 0u; + + /* Set the master state to RX data */ + this_i2c->master_state = MIV_I2C_RX_DATA; + } + + else + { + /* If releasing the bus, transmit the stop condition at the end + * of the transfer. + */ + hold_bus = this_i2c->bus_status & MIV_I2C_HOLD_BUS; + + if (hold_bus == 0) + { + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + } + else + { + MIV_I2C_disable_irq(); + } + this_i2c->master_status = MIV_I2C_SUCCESS; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + this_i2c->master_state = MIV_I2C_IDLE; + } + } + } + + else if (i2c_ack_status == 1u) + { + /* Received NACK from target device + * + * Release the bus and end the transfer + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + + this_i2c->master_status = MIV_I2C_FAILED; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + + this_i2c->master_state = MIV_I2C_IDLE; + } + + else if (i2c_al_status == 1u) + { + /* Arbitration was lost on the BUS during the transmission of + * previous start condition and control byte. + * Re-send the STA and CB + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, + this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + break; + + /* Receive target device data */ + case MIV_I2C_RX_DATA: + + if (i2c_al_status == 0u) + { + if (this_i2c->master_rx_idx < this_i2c->master_rx_size) + { + this_i2c->master_rx_buffer[this_i2c->master_rx_idx - 1u] = + HAL_get_8bit_reg(this_i2c->base_addr, RECEIVE); + + /* If next byte is last one + * Send NACK to target device to stop sending data + */ + if (this_i2c->master_rx_idx == (this_i2c->master_rx_size - 1u)) + { + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_ACK, 0x01u); + } + + else + { + /* Send ACK to receive next bytes */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_ACK, 0x00u); + } + + /* Set RD bit to receive next byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_RD, 0x01u); + + this_i2c->master_rx_idx++; + } + + /* Received all bytes */ + else //if (this_i2c->master_rx_idx == this_i2c->master_rx_size) + { + this_i2c->master_rx_buffer[this_i2c->master_rx_idx - 1] = + HAL_get_8bit_reg(this_i2c->base_addr, RECEIVE); + + hold_bus = this_i2c->bus_status & MIV_I2C_HOLD_BUS; + + if (hold_bus == 0) + { + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + } + else + { + MIV_I2C_disable_irq(); + } + this_i2c->master_status = MIV_I2C_SUCCESS; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + + this_i2c->master_state = MIV_I2C_IDLE; + } + } + + else if (i2c_al_status == 1u) + { + /* Arbitration was lost on the BUS during the transmission of + * previous start condition and control byte. + * Re-send the STA and CB + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, + this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + break; + } + + /* Toggle the IACK bit to clear interrupt */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00u); +} + +/* + * Please refer to miv_i2c.h for more info + */ +uint8_t +MIV_I2C_get_status +( + miv_i2c_instance_t *this_i2c +) +{ + uint8_t i2c_status; + + i2c_status = HAL_get_8bit_reg(this_i2c->base_addr, STATUS); + + return i2c_status; +} diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.h new file mode 100644 index 0000000..c5e704d --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.h @@ -0,0 +1,854 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * I2C module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(MIV_ESS). + */ + +/*=========================================================================*//** + @mainpage Mi-V I2C Bare Metal Driver + + ============================================================================== + Introduction + ============================================================================== + The Mi-V I2C driver provides a set of functions for controlling the Mi-V I2C + Soft-IP module. This module is delivered as a part of the Mi-V Extended + Sub System(MIV_ESS). The driver provides a minimal APB-driven I2C interface, + supporting initiator read and write access to peripheral I2C devices. + + The major features provided by the Mi-V I2C driver are: + - Support for configuring the I2C instance. + - I2C master operations. + - I2C ISR. + + This driver can be used as part of a bare metal system where no operating + system is available. The driver can be adapted for use as part of an + operating system, but the implementation of the adaptation layer between the + driver and the operating system's driver model is outside the scope of this + driver. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + The application software should initialize and configure the Mi-V I2C through + the call to the MIV_I2C_init() and MIV_I2C_config() function for Mi-V I2C + instance in the design. The configuration parameter include base address and + Prescaler value. + + ------------------------------ + Interrupt Control + ------------------------------ + The Mi-V I2C driver has to enable and disable the generation of interrupts by + Mi-V I2C at various times while operating. This enabling and disabling of the + interrupts must be done through the Mi-V RV32 HAL provided interrupt handlers. + For that reason, the method controlling the Mi-V I2C interrupts is system + specific and it is necessary to customize the MIV_I2C_enable_irq() and + MIV_I2C_disable_irq() functions as per requirement. + + The implementation of MIV_I2C_enable_irq() should permit the interrupts + generated by the Mi-V I2C to the processor through a call to respective miv-hal + interrupt handler. The implementation of MIV_I2C_disable_irq() should prevent + the interrupts generated by a Mi-V I2C from interrupting the processor. + Please refer to the miv_i2c_interrupt.c for more information about the + implementation. + + No MIV_I2C hardware configuration parameters are used by the driver, apart + from the MIV_I2C base address. Hence, no additional configuration files + are required to use the driver. + + ============================================================================== + Theory of Operation + ============================================================================== + The Mi-V I2C software driver is designed to allow the control of multiple + instances of Mi-V I2C. Each instance of Mi-V I2C in the hardware design is + associated with a single instance of the miv_i2c_instance_t structure in the + software. User must allocate memory for one unique miv_i2c_instance_t + structure for each instance of Mi-V I2C in the hardware. + A pointer to the structure is passed to the subsequent driver functions in + order to identify the MIV_I2C hardware instance and to perform requested + operation. + + Note: Do not attempt to directly manipulate the contents of the + miv_i2c_instance_t structure. These structures are only intended to be modified + by the driver functions. + + The Mi-V I2C driver functions are grouped into following categories: + - Initialization and configuration + - I2C master operation functions to handle write, read and write_read + operations. + - Interrupt control + + -------------------------------- + Initialization and configuration + -------------------------------- + The Mi-V I2C device is first initialized by the call to MIV_I2C_init(). This + function initializes the instance of Mi-V I2C with the base address. + MIV_I2C_init() function must be called before any other Mi-V I2C driver API. + + The configuration of the Mi-V I2C instance is done via call to the + MIV_I2C_config() function. This function will set the prescale value which is + used to set the frequency of the I2C clock(SCLK) generated by I2C module. + + --------------------------------- + Transaction types + --------------------------------- + The driver is designed to handle three types of transactions: + - Write transactions + - Read transactions + - Write-Read transaction + + ### Write Transaction + The write transaction begins with master sending a start condition, followed + by device address byte with the R/W bit set to logic '0', and then by the + word address bytes. The slave acknowledges the receipt of its address with + acknowledge bit. The master sends one byte at a time to the slave, which must + acknowledge the receipt of each byte for the next byte to be sent. The master + sends STOP condition to complete the transaction. The slave can abort the + transaction by replying with negative acknowledge. + + The application programmer can choose not to send the STOP bit at the end of + the transaction causing repetitive start conditions. + + ### Read Transaction + The master I2C device initiates a read transaction by sending a START bit + as soon as the bus becomes free. The start condition is followed by the + control byte which contains 7-bit slave address followed by R/W bit set to + logic '1'. The slave sends data one byte at a time to the master, which must + acknowledge receipt of each byte for the next byte to be sent. The master + sends a non-acknowledge bit following the last byte it wishes to read + followed by a STOP bit. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ### Write-Read Transaction + The write read transaction is a combination of a write transaction + immediately followed by a read transaction. There is no STOP condition sent + between the write and read phase of write-read transaction. A repeated START + condition is sent between the write and read phases. + + Whilst the write handler is being executed, the slave holds the clock line + low to stretch the clock until the response is ready. + + The write-read transaction is typically used to send an memory/register + address in the write transaction specifying the start address of the data to + be transferred during the read phase. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ------------------------------------- + Interrupt Control + ------------------------------------- + The Mi-V I2C driver is interrupt driven and it uses the MIV_I2C_irq() function + to drive the ISR state machine which is at the heart of the driver. The + application is responsible for providing the link between the interrupt + generating hardware and the Mi-V I2C interrupt handler and must ensure that + the MIV_I2C_isr() function is called with the correct miv_i2c_instance_t + structure pointer for the Mi-V I2C instance initiating the interrupt. + +*//*=========================================================================*/ +#ifndef MIV_I2C_H_ +#define MIV_I2C_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "miv_i2c_regs.h" +#include + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#else +#include "hal.h" +#endif + +/*-------------------------------------------------------------------------*//** + The miv_i2c_status_t type is used to report the status of I2C transactions. + */ +typedef enum miv_i2c_status +{ + MIV_I2C_SUCCESS = 0u, + MIV_I2C_IN_PROGRESS, + MIV_I2C_FAILED, + MIV_I2C_TIMED_OUT +}miv_i2c_status_t; + +/*-------------------------------------------------------------------------*//** + This structure is used to identify the MIV_I2C hardware instances in a system. + Your application software should declare one instance of this structure for + each instance of the MIV_I2C in your system. The function MIV_I2C_init() + Initializes this structure. A pointer to an initialised instance of the structure + should be passed as the first parameter to the MIV_I2C driver functions, to + identify which MIV_I2C hardware instance should perform the requested operation. + + The contents of this data structure should not be modified or used outside of + the MIV_I2C driver. Software using the MIV_I2C driver should only need to + create one single instance of this data structure for each MIV_I2C hardware + instance in the system, then pass a pointer to these data structures with each + call to the MIV_I2C driver in order to identify the MIV_I2C hardware instance + it wishes to use. +*/ + +typedef struct miv_i2c_instance +{ + addr_t base_addr; + + /* Transmit related info:*/ + uint_fast8_t target_addr; + + /* Current transaction type */ + uint8_t transaction; + + uint8_t bus_options; + + uint8_t ack_polling_options; + + /* Current State of the I2C master */ + uint8_t master_state; + + /* Master TX INFO: */ + const uint8_t * master_tx_buffer; + uint_fast16_t master_tx_size; + uint_fast16_t master_tx_idx; + uint_fast8_t dir; + + /* Master RX INFO: */ + uint8_t * master_rx_buffer; + uint_fast16_t master_rx_size; + uint_fast16_t master_rx_idx; + + /* Master Status */ + volatile miv_i2c_status_t master_status; + uint32_t master_timeout_ms; + + /* user specific data */ + void *p_user_data ; + + /* I2C bus status */ + uint8_t bus_status; + + /* Is transaction pending flag */ + uint8_t is_transaction_pending; + + /* I2C Pending transaction */ + uint8_t pending_transaction; + +}miv_i2c_instance_t; + + +/*-------------------------------------------------------------------------*//** + MIV_I2C_RELEASE_BUS + ===================== + The MIV_I2C_RELEASE_BUS constant is used to specify the bus_options parameter + for MIV_I2C_read(), MIV_I2C_write() and MIV_I2C_write_read() to indicate + that a STOP bit must be generated at the end of the I2C transaction to release + the bus. + */ +#define MIV_I2C_RELEASE_BUS 0x00u + + +/*-------------------------------------------------------------------------*//** + MIV_I2C_HOLD_BUS + ===================== + The MIV_I2C_HOLD_BUS constant is used to specify the bus_optionsparameter + for MIV_I2C_read(), MIV_I2C_write() and MIV_I2C_write_read() to indicate + that a STOP bit must not be generated at the end of the I2C transaction in + order to retain the bus ownership. This causes the next transaction to + begin with a repeated START bit and no STOP bit between the transactions. + */ +#define MIV_I2C_HOLD_BUS 0x01u + +/*-------------------------------------------------------------------------*//** + MIV_I2C_ACK_POLLING_DISABLE + ===================== + The MIV_I2C_ACK_POLLING_DISABLE constant is used to specify the + ack_polling_options parameter to functions MIV_I2C_write(), + MIV_I2C_write_read() and MIV_I2C_read(). Acknowledgment polling is used when + working with I2C memory devices such as EEPROM, which feature an internal + write cycle. + + With acknowledgment polling disabled, if the target slave device responds to the + control byte with a NACK, the MIV_I2C will abort the transfer. + */ +#define MIV_I2C_ACK_POLLING_DISABLE 0x00u + +/*-------------------------------------------------------------------------*//** + MIV_I2C_ACK_POLLING_ENABLE + ===================== + The MIV_I2C_ACK_POLLING_ENABLE constant is used to specify the + ack_polling_options parameter to functions MIV_I2C_write(), + MIV_I2C_write_read() and MIV_I2C_read(). acknowledgment polling is used when + working with I2C memory devices such as EEPROM, which feature an internal + write cycle. + + With acknowledgment polling enabled, if the slave device responds to the + control byte with a NACK, the MIV_I2C will repeatedly transmit another control + byte until the slave device accepts the connection with an ACK, or the timeout + specified in the MIV_I2C_wait_complete() function is reached. Acknowledgment + polling allows for the next read/write operation to be started as soon as the + EEPROM has completed its internal write cycle. + */ +#define MIV_I2C_ACK_POLLING_ENABLE 0x01u + +/*--------------------------------Public APIs---------------------------------*/ + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_init() function is used to initialize the Mi-V I2C module instance + with the base address. + + Note: This function should be called before calling any other Mi-V I2C + functions. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + @param base_addr + Base address of the Mi-V I2C module instance in the MIV_ESS + soft IP. + + @return + This function does not return any value. + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + } + @endcode + */ +void +MIV_I2C_init +( + miv_i2c_instance_t *this_i2c, + addr_t base_addr +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_config() function is used to configure the Mi-V I2C module. This + function will set the prescale value which is used to set the frequency of + the I2C clock(SCLK) generated by I2C module and also enables the I2C core and + interrupts. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param clk_prescale + The value used to set the frequency of Mi-V I2C serial clock + (SCLK) generated by the Mi-V I2C module instance. The + prescaler value required to set particular frequency of + Mi-V I2C can be calculated using following formula: + + prescaler = (System Clock Frequency) / (5 * (Desired I2C Clock Frequency)) - 1 + + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + } + @endcode + */ +void +MIV_I2C_config +( + miv_i2c_instance_t *this_i2c, + uint16_t clk_prescale +); + + +uint8_t +MIV_I2C_start +( + miv_i2c_instance_t *this_i2c +); + + +uint8_t +MIV_I2C_stop +( + miv_i2c_instance_t *this_i2c +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_write() is used to set up and start the Mi-V I2C master write + transaction. This function is used for all Mi-V master write operation. + + For more information about the operation, please refer to the 'theory of + operations' section at the start of this document. + + This function returns immediately after initiating the transaction. The content + of the write buffer passed as parameter should not be modified until the write + transaction completes. It also means that the memory allocated for the write + buffer should not be freed or should not go out of scope before the write + completes. + You can check for the write transaction completion by polling the master_status + from miv_i2c_instance_t structure as shown in the sample code. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param i2c_target_addr + This parameter specifies the serial address for the slave + device. + + @param write_buffer + This parameter is a pointer to the buffer holding data to be + written to target I2C device. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param write_size + Number of bytes held in the write_buffer to be written to the + I2C device. + @param bus_options: + The bus_options parameter is used to indicate if the I2C bus + should be released on completion of the write transaction. + Using the MIV_I2C_RELEASE_BUS constant for the bus_options + parameter causes a STOP bit to be generated at the end of the + write transaction causing the bus to be released for other I2C + devices to use. Using the MIV_I2C_HOLD_BUS constant as + bus_options parameter prevents a STOP bit from being generated + at the end of the write transaction, preventing other I2C + devices from initiating a bus transaction. + + @param ack_polling_options: + The ack_polling_options parameter is used to indicate how the + MIV_I2C will respond if the slave device transmits a NACK to + the I2C control byte. Using the MIV_I2C_ACK_POLLING_DISABLE + constant for the ack_polling_options parameter causes the + MIV_I2C to abort the transfer if the slave device responds to + the I2C control byte with a NACK. Using the + MIV_I2C_ACK_POLLING_ENABLE constant for the ack_polling_options + parameter causes the MIV_I2C to repeatedly transmit a control + byte to the slave device until the slave device responds with + an ACK. + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + + MIV_I2C_write (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_tx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + } + @endcode + */ +void +MIV_I2C_write +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t bus_options, + uint8_t ack_polling_options +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_read() is used to set up and start the Mi-V I2C master read + transaction. This function is used for all MIV_I2C master read operation. + + For more information about the operation, please refer to the 'theory of + operations' section at the start of this document. + + This function returns immediately after initiating the transaction. The content + of the read buffer passed as parameter should not be modified until the write + transaction completes. It also means that the memory allocated for the read + buffer should not be freed or should not go out of scope before the read + completes. + You can check for the write transaction completion by polling the master_status + from miv_i2c_instance_t structure as shown in the sample code. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param i2c_target_addr + This parameter specifies the serial address for the slave + device. + + @param read_buffer + This parameter is a pointer to the buffer where the data + received from the I2C slave device is stored. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param read_size + Number of bytes held in the write_buffer to be read from the + I2C device. + + @param bus_options: + The bus_options parameter is used to indicate if the I2C bus + should be released on completion of the write transaction. + Using the MIV_I2C_RELEASE_BUS constant for the bus_options + parameter causes a STOP bit to be generated at the end of the + write transaction causing the bus to be released for other I2C + devices to use. Using the MIV_I2C_HOLD_BUS constant as + bus_options parameter prevents a STOP bit from being generated + at the end of the write transaction, preventing other I2C + devices from initiating a bus transaction. + + @param ack_polling_options: + The ack_polling_options parameter is used to indicate how the + MIV_I2C will respond if the slave device transmits a NACK to + the I2C control byte. Using the MIV_I2C_ACK_POLLING_DISABLE + constant for the ack_polling_options parameter causes the + MIV_I2C to abort the transfer if the slave device responds to + the I2C control byte with a NACK. Using the + MIV_I2C_ACK_POLLING_ENABLE constant for the ack_polling_options + parameter causes the MIV_I2C to repeatedly transmit a control + byte to the slave device until the slave device responds with + an ACK. + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + + MIV_I2C_write (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_tx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + + // reset miv_i2c_status variable + miv_i2c_status = 0u; + + MIV_I2C_read (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_rx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + } + @endcode + */ +void +MIV_I2C_read +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_write_read() is used to set up and start the Mi-V I2C master + write_read transaction. This function is used for all MIV_I2C master write_read + operation. + + This function is used in cases where data is being requested from a specific + address offset inside the target I2C slave device. + In this type of I2C operation, the I2C master starts by initiating a write + operation. During this write operation, the specific address offset is written + to the I2C slave. Once the address offset has been written to the I2C slave, + the I2C master transmits a repeated start, and initiates a read operation to + read data from the set address. + + For more information about the operation, please refer to the 'theory of + operations' section at the start of this document. + + This function returns immediately after initiating the transaction. The content + of the write and read buffer passed as parameter should not be modified until + the write transaction completes. It also means that the memory allocated for + the write and read buffer should not be freed or should not go out of scope + before the operation completes. + You can check for the write_read transaction completion by polling the + master_status from miv_i2c_instance_t structure. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param i2c_target_addr + This parameter specifies the serial address for the slave + device. + + @param write_buffer + This parameter is a pointer to the buffer holding data to be + written to target I2C device. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param write_size + Number of bytes held in the write_buffer to be written to the + I2C device. + + @param read_buffer + This parameter is a pointer to the buffer where the data + received from the I2C slave device is stored. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param read_size + Number of bytes held in the write_buffer to be read from the + I2C device. + + @param bus_options: + The bus_options parameter is used to indicate if the I2C bus + should be released on completion of the write transaction. + Using the MIV_I2C_RELEASE_BUS constant for the bus_options + parameter causes a STOP bit to be generated at the end of the + write transaction causing the bus to be released for other I2C + devices to use. Using the MIV_I2C_HOLD_BUS constant as + bus_options parameter prevents a STOP bit from being generated + at the end of the write transaction, preventing other I2C + devices from initiating a bus transaction. + + @param ack_polling_options: + The ack_polling_options parameter is used to indicate how the + MIV_I2C will respond if the slave device transmits a NACK to + the I2C control byte. Using the MIV_I2C_ACK_POLLING_DISABLE + constant for the ack_polling_options parameter causes the + MIV_I2C to abort the transfer if the slave device responds to + the I2C control byte with a NACK. Using the + MIV_I2C_ACK_POLLING_ENABLE constant for the ack_polling_options + parameter causes the MIV_I2C to repeatedly transmit a control + byte to the slave device until the slave device responds with + an ACK or the timeout specified in the MIV_I2C_wait_complete() + function is reached. + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + + MIV_I2C_write (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_tx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + + // reset miv_i2c_status variable + miv_i2c_status = 0u; + + uint8_t addr_offset[2] = {0x00, 0x00}; + MIV_I2C_write_read(&miv_i2c, + DUALEE_SLAVEADDRESS_1, + addr_offset, + sizeof(addr_offset), + i2c_rx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + } + @endcode + */ +void +MIV_I2C_write_read +( + miv_i2c_instance_t *this_i2c, + uint8_t target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_isr() function contains the MIV_I2C's interrupt service routine. + This ISR is at the heart of the MIV_I2C driver, and is used to control the + interrupt-driven, byte-by-byte I2C read and write operations. + + The ISR operates as a Finite State Machine (FSM), which uses the previously + completed I2C operation and its result to determine which I2C operation will + be performed next. + + The ISR operation is divided into following categories: + - MIV_I2C_IDLE + - MIV_I2C_TX_STA_CB + - MIV_I2C_TX_DATA + - MIV_I2C_RX_DATA + + ##### MIV_I2C_IDLE + The MIV_I2C_IDLE is entered on reset, or when an I2C master operation has been + completed or aborted. + Upon entering, the FSM will remain in this state until a write, read, or + write-read operation is requested + + ##### MIV_I2C_STA_CB + The MIV_I2C_TX_STA_CB operation is performed when the start condition and + control byte(i2c target address(7-bit) and direction of transaction(1-bit)) is + transmitted by the Mi-V I2C master device to the slave. + If the target I2C slave device responded to the previous START Condition + + Control Byte with an ACK, the MIV_I2C will start the requested I2C + read/write operation. + If the target slave I2C slave device responds with NACK, the MIV_I2C will + remain in this state or return to the idle state based on ack_polling + configuration. + + ##### MIV_I2C_TX_DATA + The MIV_I2C_TX_DATA state is entered after the target slave device accepts a + write request with an ACK. + This state is used to handle the byte-by-byte MIV_I2C write operations. + The FSM will remain in this state until either all data bytes have been + written to the target slave device, or an error occurs during the write + operation. + + ##### MIV_I2C_RX_DATA + The MIV_I2C_RX_DATA state is entered after the target slave device accepts a + read request with an ACK. + This state is used to handle the byte-by-byte MIV_I2C read operations. + The FSM will remain in this state until either all data bytes have been + received from the target slave device, or an error occurs. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + */ +void +MIV_I2C_isr +( + miv_i2c_instance_t *this_i2c +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_get_status() returns the 8-bit Mi-V I2C status register value. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + @return + This function returns 8-bit Mi-V I2C status register value. + */ +uint8_t +MIV_I2C_get_status +( + miv_i2c_instance_t *this_i2c +); + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_I2C_H_ */ diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_interrupt.c b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_interrupt.c new file mode 100644 index 0000000..871eafe --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_interrupt.c @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains functions used for MIV_I2C driver interrupt control. + * User should enable and disable the interrupts according to their design. + * Please refer to miv_i2c.h file for more information. + */ + +#include "miv_rv32_hal/miv_rv32_hal.h" + +void MIV_I2C_disable_irq(void) +{ +/* Disable I2C interrupt */ + MRV_disable_local_irq(MRV32_MSYS_EIE2_IRQn); +} + +void MIV_I2C_enable_irq(void) +{ +/* Enable I2C interrupt */ + MRV_enable_local_irq(MRV32_MSYS_EIE2_IRQn); +} + + diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_regs.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_regs.h new file mode 100644 index 0000000..9a4bfbf --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_regs.h @@ -0,0 +1,158 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP I2C module driver. This module is delivered as a part of Mi-V extended + * Sub-System(MIV_ESS). + */ + +#ifndef MIV_I2C_APB_REGISTERS +#define MIV_I2C_APB_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * Prescale register details + */ +#define PRESCALE_REG_OFFSET 0x00u + +/* Prescale register bits */ +#define PRESCALE_OFFSET 0x00u +#define PRESCALE_MASK 0xFFFFu +#define PRESCALE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Control register details + */ +#define CONTROL_REG_OFFSET 0x04u + +/* Control register bits */ +#define CONTROL_OFFSET 0x04u +#define CONTROL_MASK 0xC0u +#define CONTROL_SHIFT 0u + +/* Control register Core Enable Bit */ +#define CTRL_CORE_EN_OFFSET 0x04u +#define CTRL_CORE_EN_MASK 0x80u +#define CTRL_CORE_EN_SHIFT 7u + +/* Control register IRQ Enable bit */ +#define CTRL_IRQ_EN_OFFSET 0x04u +#define CTRL_IRQ_EN_MASK 0x40u +#define CTRL_IRQ_EN_SHIFT 6u + +/*------------------------------------------------------------------------------ + * Transmit register details + */ +#define TRANSMIT_REG_OFFSET 0x08u + +/* Transmit register bits */ +#define TRANSMIT_OFFSET 0x08u +#define TRANSMIT_MASK 0xFFu +#define TRANSMIT_SHIFT 0u + +/* Transmit register DIR bit */ +#define TX_DIR_OFFSET 0x08u +#define TX_DIR_MASK 0x01u +#define TX_DIR_SHIFT 0u + +/* Transmit register TARGET_ADDR bit */ +#define TX_TARGET_ADDR_OFFSET 0x08u +#define TX_TARGET_ADDR_MASK 0xFEu +#define TX_TARGET_ADDR_SHIFT 1u + +/*------------------------------------------------------------------------------ + * Receive register details + */ +#define RECEIVE_REG_OFFSET 0x0Cu + +/* Receive register bits */ +#define RECEIVE_OFFSET 0x0Cu +#define RECEIVE_MASK 0xFFu +#define RECEIVE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Command register details + */ +#define COMMAND_REG_OFFSET 0x10u + +/* Command register bits */ +#define COMMAND_OFFSET 0x10u +#define COMMAND_MASK 0xF9u +#define COMMAND_SHIFT 0u + +/* Command register IACK bit */ +#define CMD_IACK_OFFSET 0x10u +#define CMD_IACK_MASK 0x01u +#define CMD_IACK_SHIFT 0u + +/* Command register ACK bit */ +#define CMD_ACK_OFFSET 0x10u +#define CMD_ACK_MASK 0x08u +#define CMD_ACK_SHIFT 3u + +/* Command register WR bit */ +#define CMD_WR_OFFSET 0x10u +#define CMD_WR_MASK 0x10u +#define CMD_WR_SHIFT 4u + +/* Command register RD bit */ +#define CMD_RD_OFFSET 0x10u +#define CMD_RD_MASK 0x20u +#define CMD_RD_SHIFT 5u + +/* Command register STO bit */ +#define CMD_STO_OFFSET 0x10u +#define CMD_STO_MASK 0x40u +#define CMD_STO_SHIFT 6u + +/* Command register STA bit */ +#define CMD_STA_OFFSET 0x10u +#define CMD_STA_MASK 0x80u +#define CMD_STA_SHIFT 7u + +/*------------------------------------------------------------------------------ + * Status register details + */ +#define STATUS_REG_OFFSET 0x14u + +/* Command register bits */ +#define STATUS_OFFSET 0x14u +#define STATUS_MASK 0xFFu +#define STATUS_SHIFT 0u + +/* Status register Interrupt Flag(IF) bit */ +#define STAT_IF_OFFSET 0x14u +#define STAT_IF_MASK 0x01u +#define STAT_IF_SHIFT 0u + +/* Status register Transfer in Progress(TIP) bit */ +#define STAT_TIP_OFFSET 0x14u +#define STAT_TIP_MASK 0x02u +#define STAT_TIP_SHIFT 1u + +/* Status register Arbitration Lost(AL) bit */ +#define STAT_AL_OFFSET 0x14u +#define STAT_AL_MASK 0x20u +#define STAT_AL_SHIFT 5u + +/* Status register Busy(BUSY) bit */ +#define STAT_BUSY_OFFSET 0x14u +#define STAT_BUSY_MASK 0x40u +#define STAT_BUSY_SHIFT 6u + +/* Status register Ack received(RXACK) bit */ +#define STAT_RXACK_OFFSET 0x14u +#define STAT_RXACK_MASK 0x80u +#define STAT_RXACK_SHIFT 7u + + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_I2C_APB_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_plic/miv_plic.c b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_plic/miv_plic.c new file mode 100644 index 0000000..903f029 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_plic/miv_plic.c @@ -0,0 +1,283 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * MI-V Soft IP fabric bare-metal driver for Mi-V PLIC module. This module is + * delivered as a part of Mi-V Extended Sub System(MIV_ESS). + * Please refer to miv_plic.h file for more information. + */ + +#include "miv_plic.h" + +/***************************************************************************//** + * Mi-V PLIC interrupt handler function declaration. + * These functions are called by the external interrupt handler of the MIV_RV32 + * core base on the PLIC source causing the interrupt. + */ +uint8_t Invalid_IRQHandler(void); +uint8_t MIV_PLIC_EXT0_IRQHandler(void); +uint8_t MIV_PLIC_EXT1_IRQHandler(void); +uint8_t MIV_PLIC_EXT2_IRQHandler(void); +uint8_t MIV_PLIC_EXT3_IRQHandler(void); +uint8_t MIV_PLIC_EXT4_IRQHandler(void); +uint8_t MIV_PLIC_EXT5_IRQHandler(void); +uint8_t MIV_PLIC_EXT6_IRQHandler(void); +uint8_t MIV_PLIC_EXT7_IRQHandler(void); +uint8_t MIV_PLIC_EXT8_IRQHandler(void); +uint8_t MIV_PLIC_EXT9_IRQHandler(void); +uint8_t MIV_PLIC_EXT10_IRQHandler(void); +uint8_t MIV_PLIC_EXT11_IRQHandler(void); +uint8_t MIV_PLIC_EXT12_IRQHandler(void); +uint8_t MIV_PLIC_EXT13_IRQHandler(void); +uint8_t MIV_PLIC_EXT14_IRQHandler(void); +uint8_t MIV_PLIC_EXT15_IRQHandler(void); +uint8_t MIV_PLIC_EXT16_IRQHandler(void); +uint8_t MIV_PLIC_EXT17_IRQHandler(void); +uint8_t MIV_PLIC_EXT18_IRQHandler(void); +uint8_t MIV_PLIC_EXT19_IRQHandler(void); +uint8_t MIV_PLIC_EXT20_IRQHandler(void); +uint8_t MIV_PLIC_EXT21_IRQHandler(void); +uint8_t MIV_PLIC_EXT22_IRQHandler(void); +uint8_t MIV_PLIC_EXT23_IRQHandler(void); +uint8_t MIV_PLIC_EXT24_IRQHandler(void); +uint8_t MIV_PLIC_EXT25_IRQHandler(void); +uint8_t MIV_PLIC_EXT26_IRQHandler(void); +uint8_t MIV_PLIC_EXT27_IRQHandler(void); +uint8_t MIV_PLIC_EXT28_IRQHandler(void); +uint8_t MIV_PLIC_EXT29_IRQHandler(void); +uint8_t MIV_PLIC_EXT30_IRQHandler(void); + +/***************************************************************************//** + * MIV_PLIC interrupt handler for external interrupts. + * The array of the function pointers pointing to the weak handler of the Mi-V + * PLIC interrupt handlers. + * These functions are called by the external interrupt handler of the MIV_RV32 + * core base on the PLIC source causing the interrupt. + */ +uint8_t (* const ext_irq_handler_table[32]) (void) = +{ + Invalid_IRQHandler, + MIV_PLIC_EXT0_IRQHandler, + MIV_PLIC_EXT1_IRQHandler, + MIV_PLIC_EXT2_IRQHandler, + MIV_PLIC_EXT3_IRQHandler, + MIV_PLIC_EXT4_IRQHandler, + MIV_PLIC_EXT5_IRQHandler, + MIV_PLIC_EXT6_IRQHandler, + MIV_PLIC_EXT7_IRQHandler, + MIV_PLIC_EXT8_IRQHandler, + MIV_PLIC_EXT9_IRQHandler, + MIV_PLIC_EXT10_IRQHandler, + MIV_PLIC_EXT11_IRQHandler, + MIV_PLIC_EXT12_IRQHandler, + MIV_PLIC_EXT13_IRQHandler, + MIV_PLIC_EXT14_IRQHandler, + MIV_PLIC_EXT15_IRQHandler, + MIV_PLIC_EXT16_IRQHandler, + MIV_PLIC_EXT17_IRQHandler, + MIV_PLIC_EXT18_IRQHandler, + MIV_PLIC_EXT19_IRQHandler, + MIV_PLIC_EXT20_IRQHandler, + MIV_PLIC_EXT21_IRQHandler, + MIV_PLIC_EXT22_IRQHandler, + MIV_PLIC_EXT23_IRQHandler, + MIV_PLIC_EXT24_IRQHandler, + MIV_PLIC_EXT25_IRQHandler, + MIV_PLIC_EXT26_IRQHandler, + MIV_PLIC_EXT27_IRQHandler, + MIV_PLIC_EXT28_IRQHandler, + MIV_PLIC_EXT29_IRQHandler, + MIV_PLIC_EXT30_IRQHandler +}; + +/* Mi-V PLIC interrupt weak handlers */ +__attribute__((weak)) uint8_t Invalid_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT0_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT1_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT2_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT3_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT4_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT5_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT6_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT7_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT8_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT9_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT10_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT11_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT12_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT13_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT14_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT15_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT16_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT17_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT18_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT19_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT20_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT21_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT22_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT23_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT24_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT25_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT26_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT27_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT28_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT29_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT30_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +/*-------------------------------------------------------------------------*//** + * Please refer to miv_plic.h for more information about this function. +*/ +void +MIV_PLIC_isr +( + miv_plic_instance_t *this_plic +) +{ + unsigned long hart_id = read_csr(mhartid); + + /* claim the interrupt from PLIC controller */ + + uint32_t int_num = HAL_get_32bit_reg(this_plic->base_addr + + (0x1000 * hart_id), INT_CLAIM_COMPLETE); + + uint8_t disable = EXT_IRQ_KEEP_ENABLED; + disable = ext_irq_handler_table[int_num](); + + /* Indicate the PLIC controller that the interrupt is processed and claim is + * complete. */ + HAL_set_32bit_reg(this_plic->base_addr + + (0x1000 * hart_id), INT_CLAIM_COMPLETE, int_num); + + if (EXT_IRQ_DISABLE == disable) + { + MIV_PLIC_disable_irq(this_plic, (miv_plic_irq_num_t)int_num); + } +} diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_plic/miv_plic.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_plic/miv_plic.h new file mode 100644 index 0000000..f5d64cd --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_plic/miv_plic.h @@ -0,0 +1,425 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * PLIC module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(ESS). + */ + /*=========================================================================*//** + @mainpage Mi-V PLIC Bare Metal Driver + + ============================================================================== + Introduction + ============================================================================== + The Mi-V driver provides a set of functions for controlling the Mi-V PLIC + (platform level interrupt controller) soft-IP module. This module is delivered + as a part of the MIV_ESS. The PLIC multiplexes external interrupt signals into + a single interrupt signal that is connected to an external interrupt of the + processor. + + The major features provided by the driver are: + - Support for configuring the PLIC instances. + - Enabling and Disabling interrupts + - Interrupt Handling + + This driver can be used as part of a bare metal system where no operating + system is available. The driver can be adapted for use as part of an + operating system, but the implementation of the adaptation layer between the + driver and the operating system's driver model is outside the scope of this + driver. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + The application software should initialize the Mi-V PLIC through the call to + the MIV_PLIC_init() function for Mi-V PLIC instance in the design. + + No Mi-V PLIC hardware configuration parameters are used by the driver, apart + from the Mi-V PLIC base address. Hence, no additional configuration files + are required to use the driver. + + ============================================================================== + Theory of Operation + ============================================================================== + The operation of Mi-V PLIC driver is divided into following steps: + - Initialization + - Enabling and Disabling interrupts + - Interrupt control + + -------------------------------------------- + Initialization + -------------------------------------------- + The Mi-V PLIC module is first initialized by the call to MIV_PLIC_init(). This + function takes a pointer to the Mi-V PLIC instance data structure and the base + address of the Mi-V PLIC instance is defined by the hardware design. The + instance data structure is used to store the base address of the Mi-V PLIC + module and a pointer to the Mi-V PLIC register data structure. The Mi-V PLIC + register data structure maps the address of the Mi-V PLIC registers. + + --------------------------------------------- + Enabling and Disabling interrupts + --------------------------------------------- + The MIV_PLIC_enable_irq() function enables the specific interrupt provided by + user. A call to this function will allow the enabling of each of the global + interrupts corresponding to the bit in the interrupt enable register of Mi-V + PLIC. + The MIV_PLIC_disable_irq() function disables the specific interrupt provided + by the user. This function can be used to disable the interrupts from outside + of the external interrupt handler. + + ---------------------------------------- + Interrupt Control + ---------------------------------------- + When an interrupt occurs on an enabled interrupt, the PLIC gateway captures + the interrupt and asserts the corresponding interrupt pending bit. Once + the enable bit and pending bit are asserted, then the PLIC_IRQ signal asserts + until the interrupt is claimed by the driver interrupt handler MIV_PLIC_irq() + function. + When multiple interrupts assert then the lowest interrupt number will be + serviced first, for example, if interrupt 1 and 6 assert at the same time, + interrupt 1 will be serviced first, followed by interrupt 6. + +*/ + +#ifndef MIV_PLIC_H_ +#define MIV_PLIC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "miv_plic_regs.h" + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#include "miv_rv32_hal/miv_rv32_hal.h" +#else +#include "hal.h" +#include "miv_rv32_hal.h" +#endif + +/*-------------------------------------------------------------------------*//** + This enumeration is used to select a specific Mi-V PLIC interrupt. It is + used as a parameter to enable or disable the interrupt. +*/ +typedef enum miv_plic_irq_num +{ + NoInterrupt_IRQn = 0, + MIV_PLIC_EXT0_IRQn = 1, + MIV_PLIC_EXT1_IRQn = 2, + MIV_PLIC_EXT2_IRQn = 3, + MIV_PLIC_EXT3_IRQn = 4, + MIV_PLIC_EXT4_IRQn = 5, + MIV_PLIC_EXT5_IRQn = 6, + MIV_PLIC_EXT6_IRQn = 7, + MIV_PLIC_EXT7_IRQn = 8, + MIV_PLIC_EXT8_IRQn = 9, + MIV_PLIC_EXT9_IRQn = 10, + MIV_PLIC_EXT10_IRQn = 11, + MIV_PLIC_EXT11_IRQn = 12, + MIV_PLIC_EXT12_IRQn = 13, + MIV_PLIC_EXT13_IRQn = 14, + MIV_PLIC_EXT14_IRQn = 15, + MIV_PLIC_EXT15_IRQn = 16, + MIV_PLIC_EXT16_IRQn = 17, + MIV_PLIC_EXT17_IRQn = 18, + MIV_PLIC_EXT18_IRQn = 19, + MIV_PLIC_EXT19_IRQn = 20, + MIV_PLIC_EXT20_IRQn = 21, + MIV_PLIC_EXT21_IRQn = 22, + MIV_PLIC_EXT22_IRQn = 23, + MIV_PLIC_EXT23_IRQn = 24, + MIV_PLIC_EXT24_IRQn = 25, + MIV_PLIC_EXT25_IRQn = 26, + MIV_PLIC_EXT26_IRQn = 27, + MIV_PLIC_EXT27_IRQn = 28, + MIV_PLIC_EXT28_IRQn = 29, + MIV_PLIC_EXT29_IRQn = 30, + MIV_PLIC_EXT30_IRQn = 31 +} miv_plic_irq_num_t; + +/*--------------------------------------------------------------------------*//* + * This structure maps the priority threshold and claim complete register in + * the memory. + */ +typedef struct +{ + volatile uint32_t PRIORITY_THRESHOLD; + volatile uint32_t CLAIM_COMPLETE; + volatile uint32_t reserved[1022]; +} IRQ_Target_Type; + +/*--------------------------------------------------------------------------*//* + * This structure maps the Interrupt enable sources from 0 - 1023 for one + * context. + */ +typedef struct +{ + volatile uint32_t ENABLES[32]; +} Target_Enables_Type; + +/*-------------------------------------------------------------------------*//** + This structure holds the base address of the Mi-V PLIC module. This structure + is used by all the functions to access the Mi-V PLIC registers. +*/ +typedef struct miv_plic_instance +{ + addr_t base_addr; +} miv_plic_instance_t; + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_isr is the top level interrupt handler function for the Mi-V PLIC + * driver. You must call the MIV_PLIC_isr() from the system level interrupt + * handler(External_IRQHandler). + * This function must be called from the external interrupt handler function + * provided by the processor hardware abstraction layer. In case of MIV_RV32 + * soft processor, it must be called from External_IRQHandler() function + * provided by MIV_RV32 HAL. + * + * The MIV_PLIC_isr() function claims the interrupt number + * that triggered the interrupt and then invokes the appropriate PLIC interrupt + * handler. + * After handling the PLIC interrupt, this function will complete the interrupt + * by clearing the claim complete bit for the particular interrupt source. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * + * @return + * This function does not return any value. + * + * Example: + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * uint8_t MIV_PLIC_EXT0_IRQHandler(void) + * { + * *** ISR operation *** + * + * return(EXT_IRQ_KEEP_ENABLED); + * } + * + * void External_IRQHandler(void) + * { + * uint32_t reg_val = read_csr(mip); + * MIV_PLIC_isr(&g_plic); + * } + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * } + * @endcode + */ +void MIV_PLIC_isr(miv_plic_instance_t *this_plic); + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_init() function initializes the Mi-V PLIC instance with base + * address. This function resets the PLIC controller by disabling all the PLIC + * interrupts. + * + * Note: This function must be called before calling any other Mi-V PLIC driver + * function. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * + * @param base_addr + * Base address of the Mi-V PLIC instance in the MIV_ESS soft-IP. + * + * @param ext_intr_sources + * Number of interrupts initialized in the design. + * + * @return + * This function does not return any value. + * + * Example + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * } + * @endcode + */ +static inline void +MIV_PLIC_init +( + miv_plic_instance_t *this_plic, + addr_t base_addr, + uint8_t ext_intr_sources +) +{ + uint32_t inc; + unsigned long hart_id = read_csr(mhartid); + + this_plic->base_addr = base_addr; + + /* Disable all interrupts for the current hart. + * The PLIC_EXT_INTR_SOURCES should be defined in the hw_platform.h. This + * macro holds the number of PLIC interrupts enabled in the design. + */ + for(inc = 0; inc < ((ext_intr_sources + 32u) / 32u); ++inc) + { + HAL_set_32bit_reg( + (this_plic->base_addr + inc + (hart_id * 128)), INT_ENABLE , 0x0u); + } +} + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_enable_irq() function enables the PLIC interrupt provided with + * IRQn parameter. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * @param IRQn + * Number of PLIC interrupt to enable. + * + * @return + * This function does not return any value. + * + * Example + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * } + * @endcode + */ +static inline void +MIV_PLIC_enable_irq +( + miv_plic_instance_t *this_plic, + miv_plic_irq_num_t IRQn +) +{ + unsigned long hart_id = read_csr(mhartid); + + uint32_t current = HAL_get_32bit_reg( + (this_plic->base_addr + (IRQn/32) + (hart_id * 128)) , INT_ENABLE); + + current |= (uint32_t)1 << (IRQn % 32); + + HAL_set_32bit_reg( + (this_plic->base_addr + (IRQn/32) + (hart_id * 128)), INT_ENABLE, current); + +} + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_disable_irq() function disables the PLIC interrupt provided with + * IRQn parameter. + * + * NOTE: + * This function can be used to disable the PLIC interrupt from outside the + * external interrupt handler functions. + * If you wish to disable the PLIC interrupt from the external interrupt handler, + * you should use the return value of EXT_IRQ_DISABLE. This will disable the + * selected PLIC interrupt from the Mi-V PLIC driver interrupt handler. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * @param IRQn + * Number of PLIC interrupt to disable. + * + * @return + * This function does not return any value. + * + * Example + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * } + * @endcode + */ +static inline void +MIV_PLIC_disable_irq +( + miv_plic_instance_t *this_plic, + miv_plic_irq_num_t IRQn +) +{ + unsigned long hart_id = read_csr(mhartid); + + uint32_t current = HAL_get_32bit_reg((this_plic->base_addr + (IRQn/32) + (hart_id * 128)) , INT_ENABLE); + + current &= ~((uint32_t)1 << (IRQn % 32)); + + HAL_set_32bit_reg((this_plic->base_addr + (IRQn/32) + (hart_id * 128)), INT_ENABLE, current); + +} + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_PLIC_H_ */ diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_plic/miv_plic_regs.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_plic/miv_plic_regs.h new file mode 100644 index 0000000..76cbc0b --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_plic/miv_plic_regs.h @@ -0,0 +1,31 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP PLIC module driver. This module is delivered as a part of Mi-V extended + * Sub-System(MIV_ESS). + */ + +#ifndef MIV_PLIC_REGISTERS +#define MIV_PLIC_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Interrupt pending register offset */ +#define INT_PENDING_REG_OFFSET 0x1000u + +/* Interrupt enable register */ +#define INT_ENABLE_REG_OFFSET 0x2000u + +/* Interrupt claim complete register */ +#define INT_CLAIM_COMPLETE_REG_OFFSET 0x200004u + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_PLIC_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_timer/miv_timer.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_timer/miv_timer.h new file mode 100644 index 0000000..5f00889 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_timer/miv_timer.h @@ -0,0 +1,329 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Mi-V Timer Soft IP bare-metal driver. This module is delivered as part of + * the Mi-V Extended Sub System(ESS) MIV_ESS. + */ + +/*=========================================================================*//** + @mainpage Mi-V Timer Bare Metal Driver. + The Mi-V Timer bare metal software driver supports the timer module which + serves as a system timer for the Mi-V Extended Sub System(ESS). + + @section intro_sec Introduction + The MI-V Timer driver supports set of functions for controlling the Mi-V + Timer module. + The Mi-V Timer can generate a timer interrupt signal for the system based on + special system clock intervals specified by the parameters that can be passed + in by the user. + + The major features provided by Mi-V Timer driver are: + - Support for Mi-V Timer instance for each Mi-V Timer peripheral. + - Read current time + - Write to the machine time compare register + + @section hw_dependencies Hardware Flow dependency + The application should configure the Mi-V Timer driver through calls to + MIV_TIMER_init() functions for each MIV_TIMER instance in the hardware + design. The configuration parameter include the MIV_TIMER hardware instance, + base address and number of ticks to generate timer interrupt. + + MIV_RV32 core offers flexibility in terms of generating the MTIME and MTIMECMP + registers internal to the core or using external time reference. + When MIV_ESS is interfaced with MIV_RV32 core, the timer module in the MIV_ESS + can be configured as follows: + - Internal MTIME External MTIME IRQ + Generate the MTIME internally(MIV_RV32) and have a timer interrupt input + to the core as external pin(from MIV_ESS). + + - External MTIME Internal MTIME IRQ + Generate the time value externally(from MIV_ESS), in this case a 64-bit + port will open in the MIV_RV32 core as input and MIV_ESS will output the + 64-bit TIME_COUNT value. The generation of mtimecmp and interrupt is + done internally(MIV_RV32). + + - External MTIME External MTIME IRQ + Generate both the time and timer interrupt externally. + In this case 64-bit port will be available on the Mi-V RV32 core as input + and a 1 pin port will be available for timer interrupt. + + The design must be configured accordingly to use these combinations in the + firmware. + + No MIV_TIMER hardware configuration parameters are used by the driver, apart + from MIV_TIMER base address. Hence, no additional configuration files are + required to use the driver. + + @section theory_op Theory of Operation + + The MIV_TIMER module is a simple systick timer which can generate a timer + interrupt signal for the system at specific intervals specified by the + parameters that can be passed by the user. + These interrupt signal are then fed to the MIV_RV32 core via timer interrupt. + + The operation of MIV_TIMER is divided into following steps: + - Initialization + - Configuration + - Read/Write TIME + + ## Initialization + The MIV_TIMER is first initialized by a call to MIV_TIMER_init(). This + function initializes the instance of Mi-V TIMER with the base address. + The MIV_TIMER_init() function must be called before any other Mi-V Timer driver + function. + + ## Configuration + The Mi-V TIMER configuration includes writing the mtimecmp register with the + initial time value at which timer interrupt should be generated. + When the mtime register value becomes greater than or equal to mtimecmp value, + a timer interrupt signal(TIMER_IRQ) is generated. + + ## Read/Write TIME + The time value can be read by reading the mtime register via call to the + MIV_TIMER_read_mtime(). This function reads the MTIME register which contains + the 64-bit value of the timer count. The count increments by 1 every time the + prescale ticks. This function returns 64-bit MTIME_COUNT value which is the + current value of timer count. + + The time value read in the MIV_TIMER_read_mtime() function can be written to + the mtimecmp register by calling MIV_TIMER_write_mtimecmp() to generate + periodic interrupts. + The writing of the mtimecmp register should be done in the systick_handler() + function. + */ + +#ifndef MIV_TIMER_H_ +#define MIV_TIMER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#endif +/*-------------------------------------------------------------------------*//** +MIV_TIMER_SUCCESS +===================== + +The MIV_TIMER_SUCCESS constant indicates successful configuration of +Mi-V Timer module. +*/ +#define MIV_TIMER_SUCCESS 0u + +/*-------------------------------------------------------------------------*//** +MIV_TIMER_ERROR +===================== + +The MIV_TIMER_ERROR constant indicates that there is an error with +configuring the Mi-V Timer module. +*/ +#define MIV_TIMER_ERROR 1u + +/*-------------------------------------------------------------------------*//* +MIV_TIMER_MASK_32BIT +===================== + +32-bit mask constant used in calculation of 64-bit register value. +*/ +#define MIV_TIMER_MASK_32BIT 0xFFFFFFFFu + +/*-------------------------------------------------------------------------*//* +Mi-V Timer register offsets +===================== +The MTIMECMP is the 64-bit timer compare register, it pre-sets the threshold +which needs to be reached by the timer count register. +This 64-bit register is accessed with 2 32-bit address offset, lower 32-bits +and higher 32-bits. + - MIV_TIMER_MTIMECMP_L_REG_OFFSET + - MIV_TIMER_MTIMECMP_H_REG_OFFSET + +The MTIME is the 64-bit register that contains the 64-bit timer count. The +count increments by 1 every time the prescaler ticks. +This 64-bit register is accessed with 2 32-bit address offset, lower 32-bits +and higher 32-bits. + - MIV_TIMER_MTIME_L_REG_OFFSET + - MIV_TIMER_MTIME_H_REG_OFFSET + +The PRESCALE register is used to determine the amount of clock cycles the +selected clock needs to go through, for MTIME register to increment count. + - MIV_TIMER_PRESCALAR_REG_OFFSET +*/ + +/// @cond private +#define MIV_TIMER_MTIMECMP_L_REG_OFFSET 0x4000u +#define MIV_TIMER_MTIMECMP_H_REG_OFFSET 0x4004u + +#define MIV_TIMER_MTIME_L_REG_OFFSET 0xBFF8u +#define MIV_TIMER_MTIME_H_REG_OFFSET 0xBFFCu + +#define MIV_TIMER_PRESCALAR_REG_OFFSET 0x5000u +/// @endcond + +/*-------------------------------------------------------------------------*//** + This structure holds the base address of the Mi-V Timer module and instance + of the Mi-V Timer register structure. +*/ +typedef struct miv_timer_instance +{ + addr_t base_addr; +} miv_timer_instance_t; + +/** The MIV_TIMER_init() is used to initialize the Mi-V Timer module. This + function will assign the base addresses of the Mi-V Timer module. + User should call this function before calling any of the Mi-V Timer driver + APIs. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @param base_address + Base address of the Mi-V Timer module. + + @return + This function does not return any value. + */ +static inline void +MIV_TIMER_init +( + miv_timer_instance_t* this_timer, + addr_t base_addr +) +{ + this_timer->base_addr = base_addr; +} + +/** MIV_TIMER_read_current_time() is used to read the mtimecmp register values. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @return + This function returns 64-bit mtimecmp register value. + */ +static inline uint64_t +MIV_TIMER_read_current_time +( + miv_timer_instance_t* this_timer +) +{ + volatile uint64_t read_data = 0u; + volatile uint32_t mtime_hi = 0u; + volatile uint32_t mtime_lo = 0u; + + /* when mtime lower word is 0xFFFFFFFF, there will be rollover and + * returned value could be wrong. */ + do { + mtime_hi = HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIME_H); + mtime_lo = HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIME_L); + + } while(mtime_hi != HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIME_H)); + + read_data = mtime_hi; + + return(((read_data) << 32u) | mtime_lo); +} + +/** MIV_TIMER_write_compare_time() is used to write to the MTIMECMP register in + the event of interrupt. User must use this function in the interrupt handler + to de-assert the MIV_TIMER interrupt. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @param write_value + Value to write into the mtimecmp register. + + @return + This function does not return any value. + */ +static inline void +MIV_TIMER_write_compare_time +( + miv_timer_instance_t* this_timer, + uint64_t compare_reg_value +) +{ + HAL_set_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIMECMP_H, MIV_TIMER_MASK_32BIT); + + HAL_set_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIMECMP_L, + (compare_reg_value & MIV_TIMER_MASK_32BIT)); + + HAL_set_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIMECMP_H, + ((compare_reg_value >> 32u) & MIV_TIMER_MASK_32BIT)); +} + +/** The MIV_TIMER_config() is used to configure the MIV_ESS Timer module. The + prescale value serves to divide the count of clock cycles for the timer and + provides control over what point in time, the timer interrupt gets + asserted. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @param ticks + Number of ticks after which interrupt will be generated. + + @return + This function returns Mi-V Timer configuration status. + */ +static inline uint32_t +MIV_TIMER_config +( + miv_timer_instance_t* this_timer, + uint64_t ticks +) +{ + uint32_t ret_val = MIV_TIMER_ERROR; + uint64_t mtime_val = 0u; + uint32_t prescalar = 0u; + uint64_t miv_timer_increment = 0U; + + prescalar = HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_PRESCALAR); + + miv_timer_increment = (uint64_t)(ticks) / prescalar; + + if (miv_timer_increment > 0U) + { + mtime_val = MIV_TIMER_read_current_time(this_timer); + + MIV_TIMER_write_compare_time(this_timer ,(mtime_val + miv_timer_increment)); + + ret_val = MIV_TIMER_SUCCESS; + } + + return ret_val; +} + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_TIMER_H */ diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c new file mode 100644 index 0000000..cbd9652 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c @@ -0,0 +1,109 @@ +/******************************************************************************* + * (c) Copyright 2022-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Mi-V uDMA Soft IP bare-metal driver. This module is delivered as part of + * Mi-V Extended Sub System(MIV_ESS) + */ + +#include "miv_udma_regs.h" +#include "miv_udma.h" + +/***************************************************************************//** + * MIV_uDMA_init() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_init +( + miv_udma_instance_t* this_udma, + addr_t base_addr +) +{ + /* Assign the Mi-V uDMA base address to the uDMA instance structure */ + this_udma->base_address = base_addr; +} + +/***************************************************************************//** + * MIV_uDMA_config() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_config +( + miv_udma_instance_t* this_udma, + addr_t src_addr, + addr_t dest_addr, + uint32_t transfer_size, + uint32_t irq_config +) +{ + /* Source memory start address */ + HAL_set_32bit_reg(this_udma->base_address, SRC_START_ADDR, src_addr); + + /* Destination memory start address */ + HAL_set_32bit_reg(this_udma->base_address, DEST_START_ADDR, dest_addr); + + /* Data transfer size */ + HAL_set_32bit_reg(this_udma->base_address, BLK_SIZE, transfer_size); + + /* Configure the uDMA IRQ */ + HAL_set_32bit_reg(this_udma->base_address, IRQ_CFG, irq_config); +} + +/***************************************************************************//** + * MIV_uDMA_start() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_start +( + miv_udma_instance_t* this_udma +) +{ + /* Start the uDMA transfer */ + HAL_set_32bit_reg(this_udma->base_address, CONTROL_SR, CTRL_START_TX_MASK); +} + +/***************************************************************************//** + * MIV_uDMA_reset() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_reset +( + miv_udma_instance_t* this_udma +) +{ + /* Toggle the uDMA_reset bit to reset the uDMA. + * Resetting the uDMA will clear all the configuration made by + * MIV_uDMA_config(). + * + * This function should be called from the interrupt handler to clear the + * IRQ. + */ + HAL_set_32bit_reg_field(this_udma->base_address, CTRL_RESET_TX, 0x1u); + HAL_set_32bit_reg_field(this_udma->base_address, CTRL_RESET_TX, 0x0u); +} + +/***************************************************************************//** + * MIV_uDMA_read_status() + * See "miv_udma.h" for details of how to use this function. + */ +uint32_t +MIV_uDMA_read_status +( + miv_udma_instance_t* this_udma +) +{ + uint32_t status = 0u; + + /* Read the status of the uDMA transfer. + * The transfer status register can be Error or Busy depending on the + * current uDMA transfer. + */ + status = HAL_get_32bit_reg(this_udma->base_address, TX_STATUS); + + return status; +} diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h new file mode 100644 index 0000000..efa8731 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h @@ -0,0 +1,290 @@ +/******************************************************************************* + * Copyright 2022-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * uDMA module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(MIV_ESS). + */ + +/*=========================================================================*//** + @mainpage Mi-V uDMA Bare Metal Driver. + The Mi-V uDMA bare metal software driver. + + @section intro_sec Introduction + The Mi-V uDMA driver provides a set of functions to control the Mi-V uDMA + module in the Mi-V Extended Subsystem (MIV_ESS) soft-IP. The Mi-V uDMA module + allows peripherals with AHB interfaces to transfer data independently of the + MIV_RV32 RISC-V processor. + + Following are the major features provided by the Mi-V uDMA driver: + - Initialization and configuration + - Start and reset the transaction + + This driver can be used as part of a bare metal system where no operating + system is available. The driver can be adapted for use as part of an + operating system, but the implementation of the adaptation layer between the + driver and the operating system's driver model is outside the scope of this + driver. + + @section hw_dependencies Hardware Flow Dependency + The application software should initialize and configure the Mi-V uDMA through + calling the MIV_uDMA_init() and MIV_uDMA_config() functions for each Mi-V + uDMA instance in the design. + + The uDMA can operate in two possible transfer configurations: + + - AHBL Read -> AHBL Write: + In this configuration, the uDMA reads data from the source memory over an + AHBL (mirrored main/initiator) read interface and writes data to the + destination memory over an AHBL (mirrored main/initiator) write interface. + + - AHBL Read -> TAS Write: + In this configuration, the uDMA reads data from the source memory over an + AHBL (mirrored main/initiator) read interface and writes data to the + destination memory over the TAS (mirrored main/initiator) write interface. + + Note: The AHBL Read -> TAS Write configuration is out of scope for this + driver. + + @section theory_op Theory of Operation + The uDMA module in the Mi-V Extended Sub System (MIV_ESS) is a single-channel + uDMA module that allows peripherals to perform read-write operations between + source and destination memory. The Mi-V uDMA driver is used in + interrupt-driven mode and uses the Mi-V uDMA IRQ signal to drive the + interrupt service routine (ISR), which signifies a transfer has completed. + The status is checked in the ISR to ensure the transfer is completed + successfully. + The reset operation in the ISR resets the Mi-V uDMA controller. Once the Mi-V + uDMA transfer is complete, Mi-V uDMA retires. To initiate another + transaction, Mi-V uDMA needs to be configured again. + + The operation of the Mi-V uDMA driver is divided into the following + categories: + - Initialization + - Configuration + - Start and reset the transfer + + Initialization and configuration: + Mi-V uDMA is first initialized by calling MIV_uDMA_init() function. This + function initializes the instance of Mi-V uDMA with the base address. The + MIV_uDMA_init() function must be called before calling any other Mi-V uDMA + driver functions. + + The Mi-V uDMA is configured by calling MIV_uDMA_config() function. This + function configures the source_addr and dest_addr registers of the Mi-V + uDMA with source and destination addresses for Mi-V uDMA transfers. + This function also configures the transfer size and interrupt preference for + successful transfers using Mi-V uDMA. + + Start and reset the transfer: + Once the Mi-V uDMA is configured, initiate the transfers by calling the + MIV_uDMA_start() function. Once the Mi-V uDMA transfer is started, it cannot + be aborted, and the status of the transfer should be read from the ISR by + calling the MIV_uDMA_read_status() function. + + Reset the Mi-V uDMA to the default state by calling the MIV_uDMA_reset() + function. After performing the reset operation, reconfigure the Mi-V uDMA to + perform transfers as MIV_uDMA_reset() resets the Mi-V uDMA controller. + */ + +#ifndef MIV_uDMA_H_ +#define MIV_uDMA_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#include "hal/cpu_types.h" + +#else +#include "hal.h" +#include "cpu_types.h" +#endif + +/*-------------------------------------------------------------------------*//** + MIV_uDMA_CTRL_IRQ_CONFIG + ===================== + + The MIV_uDMA_CTRL_IRQ_CONFIG macro is used to assert the uDMA IRQ when an error + occurs during a uDMA transfer or on the completion of a uDMA transfer. + */ +#define MIV_uDMA_CTRL_IRQ_CONFIG 1u + +/*-------------------------------------------------------------------------*//** + MIV_uDMA_STATUS_BUSY + ===================== + + The MIV_uDMA_STATUS_BUSY macro is used to indicate that the uDMA transfer is + in progress. + */ +#define MIV_uDMA_STATUS_BUSY 1u + +/*-------------------------------------------------------------------------*//** + MIV_uDMA_STATUS_ERROR + ===================== + + The MIV_uDMA_STATUS_ERROR macro is used to indicate that the last uDMA + transfer has caused an error. + */ +#define MIV_uDMA_STATUS_ERROR 2u + +/***************************************************************************//** + * This structure holds the base of the Mi-V uDMA module, which is used in the + * other functions of the driver to access the uDMA registers. + */ +typedef struct miv_udma_instance +{ + addr_t base_address; +} miv_udma_instance_t; + +/***************************************************************************//** + * The MIV_uDMA_init() function assigns the base address of the Mi-V uDMA module + * to the uDMA instance structure. + * This address is used in a later part of the driver to access the uDMA + * registers. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure. + * + * @param base_addr + * Base address of the Mi-V uDMA module. + * + * @return + * This function does not return a value. + */ +void +MIV_uDMA_init +( + miv_udma_instance_t* this_udma, + addr_t base_addr +); + +/***************************************************************************//** + * The MIV_uDMA_config() function is used to configure the Mi-V uDMA controller. + * This function will set the source address, destination address, block size, + * and IRQ configuration register. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @param base_addr + * Base address of the Mi-V uDMA. + * + * @param src_addr + * Source address of memory from where the uDMA reads the data. + * + * @param dest_addr + * Destination address where the data is written from src_addr. + * + * @param transfer_size + * Number of 32-bit words to transfer. + * + * @param irq_config + * uDMA IRQ configuration + * - When set, the IRQ is asserted when an error occurs during a uDMA + * transfer or on the completion of the uDMA transfer. + * - When clear, the IRQ is only asserted when an error occurs during a + * uDMA transfer. + * + * @return + * This function does not return any value. + */ +void +MIV_uDMA_config +( + miv_udma_instance_t* this_udma, + addr_t src_addr, + addr_t dest_addr, + uint32_t transfer_size, + uint32_t irq_config +); + +/***************************************************************************//** + * The MIV_uDMA_start() function is used to start the uDMA transfer. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @return + * This function does not return any value. + */ +void +MIV_uDMA_start +( + miv_udma_instance_t* this_udma +); + +/***************************************************************************//** + * The MIV_uDMA_reset() function is used to clear the uDMA interrupt and reset + * the uDMA transfer. + * + * This function should be called from the interrupt handler to reset the values + * set during MIV_uDMA_config(). + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @return + * This function does not return any value. + */ +void +MIV_uDMA_reset +( + miv_udma_instance_t* this_udma +); + +/***************************************************************************//** + * The MIV_uDMA_read_status() function is used to read the status of the uDMA + * transfer. When interrupt is enabled, this function can be called from the + * interrupt handler to know the reason for a uDMA interrupt. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @return + * The return value indicates an error due to the busy status of the uDMA + * channel. + * + * |Bit Number| Name | Description | + * |----------|---------|------------------------------------------------------| + * | 0 | Busy | When set indicates that uDMA transfer is in progress| + * | 1 | Error | When set indicates that last uDMA transfer caused an| + * | | | error. | + */ +uint32_t +MIV_uDMA_read_status +( + miv_udma_instance_t* this_pdma +); + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_uDMA_H_ */ diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h new file mode 100644 index 0000000..14d0759 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h @@ -0,0 +1,94 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP uDMA module driver. This module is delivered as a part of Mi-V + * extended Sub-System(ESS) MIV_ESS. + */ + +#ifndef MIV_UDMA_APB_REGISTERS +#define MIV_UDMA_APB_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/**************************************************************************//** + * Control start/Reset register details + */ + +#define CONTROL_SR_REG_OFFSET 0x0u + +/* Control start/Reset register bits */ +#define CONTROL_SR_OFFSET 0x00u +#define CONTROL_SR_MASK 0x03u +#define CONTROL_SR_SHIFT 0u + +/* uDMA Control Start Transfer */ + +#define CTRL_START_TX_OFFSET 0x00u +#define CTRL_START_TX_MASK 0x01u +#define CTRL_START_TX_SHIFT 0u + +/* uDMA Control Reset Transfer */ +#define CTRL_RESET_TX_OFFSET 0x00u +#define CTRL_RESET_TX_MASK 0x02u +#define CTRL_RESET_TX_SHIFT 1u + +/**************************************************************************//** + * IRQ Configuration register details + */ +#define IRQ_CFG_REG_OFFSET 0x4u + +/* Control start/Reset register bits */ +#define IRQ_CFG_OFFSET 0x04u +#define IRQ_CFG_MASK 0x01u +#define IRQ_CFG_SHIFT 0u + +/***************************************************************************//** + * Transfer Status register details + */ +#define TX_STATUS_REG_OFFSET 0x08u + +/* Transfer status register bits */ +#define TX_STATUS_OFFSET 0x08u +#define TX_STATUS_MASK 0x03u +#define TX_STATUS_SHIFT 0u + +/***************************************************************************//** + * Source Memory Start Address Register + */ +#define SRC_START_ADDR_REG_OFFSET 0x0cu + +/* Source Memory Start Address Register bits */ +#define SRC_START_ADDR_OFFSET 0x0cu +#define SRC_START_ADDR_MASK 0xFFFFFFFFu +#define SRC_START_ADDR_SHIFT 0u + +/***************************************************************************//** + * Destination Memory Start Address register details + */ +#define DEST_START_ADDR_REG_OFFSET 0x10u + +/* Destination Memory Start Address register bits */ +#define DEST_START_ADDR_OFFSET 0x10u +#define DEST_START_ADDR_MASK 0xFFFFFFFFu +#define DEST_START_ADDR_SHIFT 0x0u + +/***************************************************************************//** + * Block Size register details + */ +#define BLK_SIZE_REG_OFFSET 0x14u + +/* Destination Memory Start Address register bits */ +#define BLK_SIZE_OFFSET 0x14u +#define BLK_SIZE_MASK 0xFFFFFFFFu +#define BLK_SIZE_SHIFT 0x0u + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_UDMA_APB_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c new file mode 100644 index 0000000..525928a --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Mi-V Watchdog Soft IP bare-metal driver. This module is delivered as part of + * Extended Sub System(ESS) MIV_ESS. + * Please refer to miv_watchdog.h file for more information. + */ + +#include "miv_watchdog.h" + +addr_t g_this_wdog; + +/***************************************************************************//* + * Please refer to miv_watchdog.h for more info about this function + */ +void +MIV_WDOG_init +( + addr_t base_addr +) +{ + /* Register the Mi-V Watchdog base address to the driver */ + g_this_wdog = base_addr; +} + +/***************************************************************************//* + * Please refer to miv_watchdog.h for more info about this function + */ +uint8_t MIV_WDOG_configure +( + const miv_wdog_config_t *config +) +{ + uint8_t error = 0u; + + /* check load value and trigger max value */ + if (config->timeout_val <= MIV_WDOG_TRIGGER_MAX) + { + HAL_set_32bit_reg(g_this_wdog, WDOGTRIG,(config->timeout_val)); + } + else + { + error = 1u; + } + + if (config->time_val <= MIV_WDOG_TIMER_MAX) + { + HAL_set_32bit_reg(g_this_wdog, WDOGMSVP,(config->mvrp_val)); + } + else + { + error = 1u; + } + + HAL_set_32bit_reg_field(g_this_wdog, WDOGCNTL_NEXT_ENFORBIDDEN, + config->forbidden_en); + + /* Reload watchdog with new load if it is not in forbidden window */ + if (!(WDOGSTAT_FORBIDDEN_MASK & (HAL_get_32bit_reg(g_this_wdog, WDOGSTAT)))) + { + HAL_set_32bit_reg(g_this_wdog, WDOGRFSH, MIV_WDOG_REFRESH_KEY); + } + else + { + error = 1u; + } + + return (error); +} + +/***************************************************************************//* + * Please refer to miv_watchdog.h for more info about this function + */ +void MIV_WDOG_get_config +( + miv_wdog_config_t *config +) +{ + if (0 != g_this_wdog) + { + + config->time_val = HAL_get_32bit_reg(g_this_wdog, WDOGTIME); + + config->timeout_val = HAL_get_32bit_reg(g_this_wdog, WDOGTRIG); + + config->mvrp_val = HAL_get_32bit_reg(g_this_wdog, WDOGMSVP); + + config->forbidden_en = HAL_get_32bit_reg_field(g_this_wdog, + WDOGCNTL_NEXT_ENFORBIDDEN); + } +} + diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h new file mode 100644 index 0000000..8877e55 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h @@ -0,0 +1,553 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * Watchdog module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(MIV_ESS). + */ +/*=========================================================================*//** + @mainpage MiV Watchdog Bare Metal Driver + + ============================================================================== + Introduction + ============================================================================== + The Mi-V Watchdog module in the MIV_ESS is used to generate a reset for the + system automatically if the software doesn't periodically update or refresh + the timer countdown register. This software driver provides set of functions + for controlling Mi-V Watchdog module as a part of bare metal system where no + operating system is available. The driver can be adapted for use as a part of + an operating system, but the implementation of the adaptation layer between + the driver and the operating system's driver model is outside the scope of the + driver. + + Mi-V Watchdog provides following features: + - Initializing the Mi-V Watchdog + - Reading current value and status of watchdog timer + - Refreshing the watchdog timer value + - Enabling, disabling and clearing timeout and Maximum Value up to which + Refresh is Permitted (MVRP) interrupts. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + The application software should initialize and configure the Mi-V Watchdog + module the the call to the MIV_WDOG_init() and MIV_WDOG_configure() functions. + + No MIV_WDOG hardware configuration parameter are used by the driver, apart + from the MIV_WDOG base address. Hence, no additional configuration files are + required to use the driver. + + ============================================================================== + Theory of Operation + ============================================================================== + The Mi-V Watchdog driver functions are grouped into the following categories: + - Initialization and configuration + - Reading the current value and status of the watchdog timer + - Refreshing the watchdog timer value + - Support for enabling, disabling and clearing time-out and MVRP interrupts. + + -------------------------------- + Initialization and Configuration + -------------------------------- + The MIV_WDOG_init() function stores the base of MIV_WDT module in the MIV_ESS. + This base address is used by rest of the functions to access the Mi-V Watchdog + registers. Please make call this function before calling any other function + from this driver. + Note: The Mi-V Watchdog driver supports only one instance of MIV_WDT in the + hardware. + The Mi-V Watchdog driver provides the MIV_WDOG_configure() function to + configure the MIV_WDOG module with desired configuration values. It also + provides the MIV_WDOG_get_config() to read back the current configuration of + the MIV_WDOG. You can use this function to retrieve the current configurations + and then overwrite them with the application specific values, such as initial + watchdog timer value, Maximum Value (up to which) Refresh (is) Permitted, + watchdog time-out value, enable/disable forbidden region, enable/disable + MVRP interrupt and interrupt type. + + -------------------------------------------- + Reading the Watchdog Timer Value and Status + -------------------------------------------- + Mi-V Watchdog is a down counter. A refresh forbidden window can be created by + configuring the watchdog Maximum Value up to which Refresh is Permitted (MVRP). + When the current value of the watchdog timer is greater than the MVRP value, + refreshing the watchdog is forbidden. Attempting to refresh the watchdog timer + in the forbidden window will assert a timeout interrupt. The + MIV_WDOG_forbidden_status() function can be used to know whether the watchdog + timer is in forbidden window or has crossed it. By default, the forbidden + window is disabled. It can be enabled by providing an appropriate value as + parameter to the MIV_WDOG_configure() function. When the forbidden window is + disabled, any attempt to refresh the watchdog timer is ignored and the counter + keeps on down counting. + + The current value of the watchdog timer can be read using the + MIV_WDOG_current_value() function. This function can be called at any time. + + -------------------------------------------- + Refreshing the Watchdog Timer Value + -------------------------------------------- + The watchdog timer value is refreshed using the MIV_WDOG_reload() function. + The value reloaded into the watchdog timer down-counter is specified at the + configuration time with an appropriate value as parameter to the + MIV_WDOG_get_config() function. + + -------------------------------------------- + Interrupt Control + -------------------------------------------- + The Mi-V Watchdog generates two interrupts, The MVRP interrupt and + the timeout interrupt. + The MVRP interrupt is generated when the watchdog down-counter crosses the + Maximum Value up to which Refresh is Permitted (MVRP). Following functions to + control MVRP interrupt: + - MIV_WDOG_enable_mvrp_irq + - MIV_WDOG_disable_mvrp_irq + - MIV_WDOG_clear_mvrp_irq + + The timeout interrupt is generated when the watchdog down-counter crosses the + watchdog timeout value. The timeout value is a non-zero value and it can be + set to a maximum of MIV_WDOG_TRIGGER_MAX. The non-maskable interrupt is + generated when the watchdog crosses this timeout value, the down counter + keeps on down counting and a reset signal is generated when reaches zero. + Following functions to control timeout interrupt: + - MIV_WDOG_enable_timeout_irq + - MIV_WDOG_disable_timeout_irq + - MIV_WDOG_clear_timeout_irq + +*//*=========================================================================*/ + +#ifndef MIV_WATCHDOG_H_ +#define MIV_WATCHDOG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "miv_watchdog_regs.h" + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#else +#include "hal.h" +#endif + +/****************************************************************************//* + * The following constants can be used to configure the Mi-V Watchdog where a + * zero or non-zero value such as enable or disable is to be provided as a input + * parameter as shown below: + */ +#define MIV_WDOG_ENABLE 1u +#define MIV_WDOG_DISABLE 0u + +/***************************************************************************//** + The miv_wdog_config_t type for the watchdog Configuration structure. This + type is used as a parameter for the MIV_WDOG_configure() and the + MIV_WDOG_get_config() functions. + + Following are the values as part of this structure +| Parameter | Description | +|------------------|-----------------------------------------------------------| +| time_val | The value from which the watchdog timer counts down | +| mvrp_val | The Watchdog MVRP value | +| timeout_val | The watchdog timeout value | +| forbidden_en | Enable/disable the forbidden window | +| | When set, if a refresh occurs in the forbidden window, | +| | the watchdog timeout interrupt will be generated. | + +Time calculation example: + + time_val = 0xFFFFF0u + mvrp_val = 0x989680u + timeout_val = 0x3e8u + + A prescaler = 256 is used. + Considering clock = 50Mhz + + The MVRP interrupt will happen after + (0xFFFFF0 - 0x989680) * ( 1/(50MHz/256)) + mvrp interrupt will happen after 34 sec. after system reset + + (0xFFFFF0 - 0x3e8) * ( 1/(50MHz/256)) + timeout interrupt will happen after 85 sec. after system reset + */ +typedef struct miv_wdog_config +{ + uint32_t time_val; + uint32_t mvrp_val; + uint32_t timeout_val; + uint32_t forbidden_en; + uint32_t intr_type; +}miv_wdog_config_t; + +extern addr_t g_this_wdog; + +/***************************************************************************//* + Internal constants and types +*******************************************************************************/ + +/// @cond private +#define MIV_WDOG_TRIGGER_MAX 4095u +#define MIV_WDOG_TIMER_MAX 16777200u +/// @endcond + +/*-------------------------------------------------------------------------*//* +MIV_WDOG_REFRESH_KEY +===================== + +The MIV_WDOG_REFRESH_KEY macro holds the magic value which will cause a +reload of the watchdog's down counter when written to the watchdog's +WDOGREFRESH register. +*/ +#define MIV_WDOG_REFRESH_KEY (uint32_t)0xDEADC0DEU + +/*-------------------------------------------------------------------------*//* +MIV_WDOG_FORCE_RESET_KEY +===================== +The MIV_WDOG_FORCE_RESET_KEY macro holds the magic value which will force a +reset if the watchdog is already timeout. Writing any other value or writing +TRIGGER register at other times will trigger the watchdog NMI sequence +(i.e raise a timeout interrupt) + */ +#define MIV_WDOG_FORCE_RESET_KEY (uint32_t)0xDEADU + +/***************************************************************************//** + * The MIV_WDOG_init() is used to register the Mi-V Watchdog module base + * address to the driver. + * + * Note: User should call this function before calling any other Mi-V watchdog + * driver function. + * + * @param base_addr + * The base address of the Mi-V watchdog module. This address is used by + * rest of the watchdog driver functions to access the registers. + * + * @return + * This function does not return any value. + */ +void +MIV_WDOG_init +( + addr_t base_addr +); + +/***************************************************************************//** + * The MIV_WDOG_get_config() function returns the current configurations of the + * Mi-V Watchdog. The Mi-V Watchdog is pre-initialized by the flash + * bits at the design time. When used for the first time before calling the + * MIV_WDOG_configure() function, this function will return the default + * configurations as configured at the design time. + * + * @param config + * The config parameter is used to store the current configuration of the Mi-V + * Watchdog. + * + * Please see the description of miv_wdog_config_t for details. + * + * @return + * This function does not return any value. + * + * Example: + */ +void +MIV_WDOG_get_config +( + miv_wdog_config_t* config +); + +/***************************************************************************//** + * The MIV_WDOG_configure() function configures the watchdog module. The + * Watchdog module is pre-initialized by the flash bits at the design time to the + * default values. You can reconfigure the Watchdog module using + * MIV_WDOG_configure() function. + * + * Note that the MIV_WDOG_configure() function can be used only once, as it + * writes into the TIME register. After a write into the TIME register, the TIME, + * TRIGGER and MSVP register values are frozen and can't be altered again unless + * a system reset happens. + * + * Note also that the Mi-V Watchdog is not enabled at reset, calling this function + * will start the watchdog, it cannot then be disabled and must be refreshed + * periodically. + * + * @param config + * The config parameter is the input parameter in which the configurations to + * be applied to the watchdog module are provided by the application. + * Please see the description of miv_wdog_config_t for details. + * + * @return + * This function returns a zero value when executed successfully. A non-zero + * value is returned when the configuration values are out of bound. + * + * Example: + */ +uint8_t +MIV_WDOG_configure +( + const miv_wdog_config_t * config +); + +/***************************************************************************//** + * The MIV_WDOG_reload() function causes the watchdog to reload its down-counter + * timer with the load value configured through interrupt handler. This function + * must be called regularly to avoid a system reset or a watchdog interrupt. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_reload +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg(g_this_wdog, WDOGRFSH, MIV_WDOG_REFRESH_KEY); + } +} + +/***************************************************************************//** + * The MIV_WDOG_current_value() function returns the current value of the + * watchdog's down-counter. + * + * @param + * Void + * + * @return + * This function returns the current value of the watchdog’s down-counter as + * a 32-bit unsigned integer. + */ +static inline uint32_t +MIV_WDOG_current_value +( + void +) +{ + return (HAL_get_32bit_reg(g_this_wdog, WDOGRFSH)); +} + +/***************************************************************************//** + * The MIV_WDOG_forbidden_status() function returns the refresh status of the + * Mi-V Watchdog. + * + * @param + * Void + * + * @return + * This function returns the refresh status of the watchdog. A value of 1 + * indicates that watchdog's down-counter is within the forbidden window and + * that a reload should not be done. A value of 0 indicates that the watchdog's + * down counter is within the permitted window and that a reload is allowed. + */ +static inline uint32_t +MIV_WDOG_forbidden_status +( + void +) +{ + return (HAL_get_32bit_reg_field(g_this_wdog, WDOGSTAT_FORBIDDEN)); +} + +/***************************************************************************//** + * The MIV_WDOG_enable_mvrp_irq() function enables the MVRP interrupt. + * This interrupt is asserted when the timer countdown register leaves the + * maximum value up to which refresh is permitted (MVRP) window. + * + * @param + * Void + * + * @return + * This function does not return a value. + * + * Example: + */ +static inline void +MIV_WDOG_enable_mvrp_irq +( + void +) +{ + + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGCNTL_NEXT_INTENT_MSVP, 0x01u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_disable_mvrp_irq() function disables the generation of the + * MVRP interrupt. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_disable_mvrp_irq +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGCNTL_NEXT_INTENT_MSVP, 0x0u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_clear_timeout_irq() function clears the watchdog’s timeout + * interrupt which is connected to the MIV-RV32 interrupt. Calling + * MIV_WDOG_clear_timeout_irq() results in clearing the MIV-RV32 interrupt. + * Note: You must call the MIV_WDOG_clear_timeout_irq() function as part of your + * implementation of the interrupt handler in order to prevent the same + * interrupt event re-triggering a call to the timeout ISR. + * + * @param + * Void + * + * @return + * This function does not return any value. + * + */ +static inline void +MIV_WDOG_clear_timeout_irq +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_WDOG_TRIPPED, 0x01u); + /* + * Perform a second write to ensure that the first write completed before + * returning from this function. This is to account for posted writes across + * the AHB matrix. The second write ensures that the first write has + * completed and that the interrupt line has been de-asserted by the time + * the function returns. Omitting the second write may result in a delay + * in the de-assertion of the interrupt line going to the RISC-V and a + * retriggering of the interrupt. + */ + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_WDOG_TRIPPED, 0x01u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_clear_mvrp_irq() function clears the mvrp interrupt. + * + * Note: You must call the MIV_WDOG_clear_mvrp_irq() function as part of your + * implementation of the interrupt service routine (ISR) in order to + * prevent the same interrupt event re-triggering a call to the mvrp ISR. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_clear_mvrp_irq +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_MSVP_TRIPPED, 0x01u); + /* + * Perform a second write to ensure that the first write completed before + * returning from this function. This is to account for posted writes across + * the AHB matrix. The second write ensures that the first write has + * completed and that the interrupt line has been de-asserted by the time + * the function returns. Omitting the second write may result in a delay + * in the de-assertion of the interrupt line going to the RISC-V and a + * re-triggering of the interrupt. + */ + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_MSVP_TRIPPED, 0x01u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_timeout_occured() function reports the occurrence of a timeout + * event. + * + * @param + * Void + * + * @return + * A zero value indicates no watchdog timeout event occurred. A value of 1 + * indicates that a timeout event occurred. + */ +static inline uint32_t +MIV_WDOG_timeout_occured +( + void +) +{ + return (HAL_get_32bit_reg_field(g_this_wdog, WDOGSTAT_TRIGGERED)); +} + +/***************************************************************************//** + * The MIV_WDOG_force_reset() function is used to force an immediate reset + * if the watchdog has already triggered. Writing any value in this condition + * will result in watchdog timeout. + * The time out interrupt WDOG_IRQ will be set to high and watchdog timer + * countdown register updated with watchdog trigger timeout register value. + * If the Watchdog has timed out, a special 16-bit value needs to be written + * to the register to force a reset on CPU_RESETN, 0xDEAD + * Then the Watchdog countdown is reset/updated with the top Watchdog Runtime + * register value. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_force_reset +( + void +) +{ + if (WDOGSTAT_TRIGGERED_MASK == + HAL_get_32bit_reg_field(g_this_wdog, WDOGSTAT_TRIGGERED)) + + { + HAL_set_32bit_reg(g_this_wdog, WDOGFORCE, MIV_WDOG_FORCE_RESET_KEY); + } + + else + { + HAL_set_32bit_reg(g_this_wdog, WDOGFORCE, 0x0u); + } +} + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_WATCHDOG_H_ */ diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h new file mode 100644 index 0000000..2fca983 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h @@ -0,0 +1,122 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP watchdog module driver. This module is delivered as a part of Mi-V + * extended Sub-System(ESS) MIV_ESS. + */ + +#ifndef MIV_WDOG_REGISTERS +#define MIV_WDOG_REGISTERS 1u + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * Refresh register details + */ +#define WDOGRFSH_REG_OFFSET 0x00u + +/* Refresh register bits */ +#define WDOGRFSH_OFFSET 0x00u +#define WDOGRFSH_MASK 0xFFFFFFFFu +#define WDOGRFSH_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Control register details + */ +#define WDOGCNTL_REG_OFFSET 0x04u + +/* Control register next intent msvp bit */ +#define WDOGCNTL_NEXT_INTENT_MSVP_OFFSET 0x04u +#define WDOGCNTL_NEXT_INTENT_MSVP_MASK 0x01u +#define WDOGCNTL_NEXT_INTENT_MSVP_SHIFT 0u + +/* Control register next intent wdog bit */ +#define WDOGCNTL_NEXT_INTENT_WDOG_OFFSET 0x04u +#define WDOGCNTL_NEXT_INTENT_WDOG_MASK 0x02u +#define WDOGCNTL_NEXT_INTENT_WDOG_SHIFT 1u + +/* Control register next enforbidden bit */ +#define WDOGCNTL_NEXT_ENFORBIDDEN_OFFSET 0x04u +#define WDOGCNTL_NEXT_ENFORBIDDEN_MASK 0x10u +#define WDOGCNTL_NEXT_ENFORBIDDEN_SHIFT 4u + +/*------------------------------------------------------------------------------ + * Watchdog status register + */ +#define WDOGSTAT_REG_OFFSET 0x08u + +/* msvp_tripped bit */ +#define WDOGSTAT_MSVP_TRIPPED_OFFSET 0x08u +#define WDOGSTAT_MSVP_TRIPPED_MASK 0x01u +#define WDOGSTAT_MSVP_TRIPPED_SHIFT 0u + +/* WDOG Tripped bit */ +#define WDOGSTAT_WDOG_TRIPPED_OFFSET 0x08u +#define WDOGSTAT_WDOG_TRIPPED_MASK 0x02u +#define WDOGSTAT_WDOG_TRIPPED_SHIFT 1u + +/* Forbidden bit */ +#define WDOGSTAT_FORBIDDEN_OFFSET 0x08u +#define WDOGSTAT_FORBIDDEN_MASK 0x04u +#define WDOGSTAT_FORBIDDEN_SHIFT 2u + +/* Triggered bit */ +#define WDOGSTAT_TRIGGERED_OFFSET 0x08u +#define WDOGSTAT_TRIGGERED_MASK 0x08u +#define WDOGSTAT_TRIGGERED_SHIFT 3u + +/* wdoglocked bit */ +#define WDOGSTAT_WDOGLOCKED_OFFSET 0x08u +#define WDOGSTAT_WDOGLOCKED_MASK 0x10u +#define WDOGSTAT_WDOGLOCKED_SHIFT 4u + +/*------------------------------------------------------------------------------ + * Watchdog runtime register + */ +#define WDOGTIME_REG_OFFSET 0x0Cu + +/* wdogmsvp bit */ +#define WDOGTIME_WDOGVALUE_OFFSET 0x0Cu +#define WDOGTIME_WDOGVALUE_MASK 0xFFFFFFu +#define WDOGTIME_WDOGVALUE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Watchdog MVRP register + */ +#define WDOGMSVP_REG_OFFSET 0x10u + +/* wdogmsvp bit */ +#define WDOGMSVP_OFFSET 0x10u +#define WDOGMSVP_MASK 0xFFFFFFu +#define WDOGMSVP_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Watchdog Trigger Timeout register + */ +#define WDOGTRIG_REG_OFFSET 0x14u + +/* wdogmsvp bit */ +#define WDOGTRIG_WDOGRST_OFFSET 0x14u +#define WDOGTRIG_WDOGRST_MASK 0xFFFFFFu +#define WDOGTRIG_WDOGRST_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Watchdog Force Reset register details + */ +#define WDOGFORCE_REG_OFFSET 0x18u + +/* Refresh register bits */ +#define WDOGFORCE_OFFSET 0x18u +#define WDOGFORCE_MASK 0xFFFFFFFFu +#define WDOGFORCE_SHIFT 0u + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_WATCHDOG_REGS_H_ */ diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/hal/cpu_types.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/hal/cpu_types.h new file mode 100644 index 0000000..ef8ab20 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/hal/cpu_types.h @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file cpu_types.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Type definitions which can be commonly used by the fabric-ip drivers. + * + */ +#ifndef __CPU_TYPES_H +#define __CPU_TYPES_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned int size_t; + +/*------------------------------------------------------------------------------ + * addr_t: address type. + * Used to specify the address of peripherals present in the processor's memory + * map. + */ +typedef unsigned int addr_t; + +/*------------------------------------------------------------------------------ + * psr_t: processor state register. + * Used by HAL_disable_interrupts() and HAL_restore_interrupts() to store the + * processor's state between disabling and restoring interrupts. + */ +typedef unsigned int psr_t; + +#ifdef __cplusplus +} +#endif + +#endif /* CPU_TYPES_H */ + diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/hal/hal.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/hal/hal.h new file mode 100644 index 0000000..7eec17a --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/hal/hal.h @@ -0,0 +1,235 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file hal.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware abstraction layer functions for peripheral register accesses. + * + */ +#ifndef __HAL_H +#define __HAL_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include "cpu_types.h" +#include "hw_reg_access.h" +#include "hal_assert.h" +/***************************************************************************//** + * Enable all interrupts at the processor level. + */ +void HAL_enable_interrupts( void ); + +/***************************************************************************//** + * Disable all interrupts at the processor core level. + * Return the interrupts enable state before disabling occurred so that it can + * later be restored. + */ +psr_t HAL_disable_interrupts( void ); + +/***************************************************************************//** + * Restore the interrupts enable state at the processor core level. + * This function is normally passed the value returned from a previous call to + * HAL_disable_interrupts(). + */ +void HAL_restore_interrupts( psr_t saved_psr ); + +/***************************************************************************//** + */ +#define FIELD_OFFSET(FIELD_NAME) (FIELD_NAME##_OFFSET) +#define FIELD_SHIFT(FIELD_NAME) (FIELD_NAME##_SHIFT) +#define FIELD_MASK(FIELD_NAME) (FIELD_NAME##_MASK) + +/***************************************************************************//** + * The macro HAL_set_32bit_reg() allows writing a 32 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint32_t containing the value to write. + */ +#define HAL_set_32bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_32bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_32bit_reg() is used to read the value of a 32 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint32_t value. + */ +#define HAL_get_32bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_32bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)) )) + +/***************************************************************************//** + * The macro HAL_set_32bit_reg_field() is used to write a field within a + * 32 bits wide register. The field written can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * VALUE: A variable of type uint32_t containing the field value to write. + */ +#define HAL_set_32bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_32bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_32bit_reg_field() is used to read a register field from + * within a 32 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint32_t value. + */ +#define HAL_get_32bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_32bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +/***************************************************************************//** + * The macro HAL_set_16bit_reg() allows writing a 16 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint_fast16_t containing the value to write. + */ +#define HAL_set_16bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_16bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_16bit_reg() is used to read the value of a 16 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint16_t value. + */ +#define HAL_get_16bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_16bit_reg( (BASE_ADDR) + (REG_NAME##_REG_OFFSET) )) + +/***************************************************************************//** + * The macro HAL_set_16bit_reg_field() is used to write a field within a + * 16 bits wide register. The field written can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * VALUE: A variable of type uint16_t containing the field value to write. + */ +#define HAL_set_16bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_16bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_16bit_reg_field() is used to read a register field from + * within a 8 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint16_t value. + */ +#define HAL_get_16bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_16bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +/***************************************************************************//** + * The macro HAL_set_8bit_reg() allows writing a 8 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint_fast8_t containing the value to write. + */ +#define HAL_set_8bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_8bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_8bit_reg() is used to read the value of a 8 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint8_t value. + */ +#define HAL_get_8bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_8bit_reg( (BASE_ADDR) + (REG_NAME##_REG_OFFSET) )) + +/***************************************************************************//** + */ +#define HAL_set_8bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_8bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_8bit_reg_field() is used to read a register field from + * within a 8 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint8_t value. + */ +#define HAL_get_8bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_8bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +#ifdef __cplusplus +} +#endif + +#endif /*HAL_H*/ + diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/hal/hal_assert.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/hal/hal_assert.h new file mode 100644 index 0000000..1e18b54 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/hal/hal_assert.h @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hal_assert.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief HAL assert functions + */ +#ifndef __HAL_ASSERT_HEADER +#define __HAL_ASSERT_HEADER 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Disable assertions if we do not recognize the compiler. */ +#if defined ( __GNUC__ ) +#if defined(NDEBUG) +/***************************************************************************//** + * HAL_ASSERT() is defined out when the NDEBUG symbol is used. + ******************************************************************************/ +#define HAL_ASSERT(CHECK) + +#else + +/***************************************************************************//** + * Default behavior for HAL_ASSERT() macro: + *------------------------------------------------------------------------------ + The behavior is toolchain specific and project setting specific. + ******************************************************************************/ +#define HAL_ASSERT(CHECK)\ + do { \ + if (!(CHECK)) \ + { \ + __asm__ volatile ("ebreak"); \ + }\ + } while(0); + +#endif /* NDEBUG */ +#endif /*__GNUC__*/ + +#ifdef __cplusplus +} +#endif +#endif /* __HAL_ASSERT_HEADER */ + diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/hal/hal_irq.c b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/hal/hal_irq.c new file mode 100644 index 0000000..95a0775 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/hal/hal_irq.c @@ -0,0 +1,45 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hal_irq.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Legacy interrupt control functions for the Microchip driver library + * hardware abstraction layer. + * + */ +#include "hal.h" +#include "miv_rv32_hal/miv_rv32_hal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * + */ +void HAL_enable_interrupts(void) { + MRV_enable_interrupts(); +} + +/*------------------------------------------------------------------------------ + * + */ +psr_t HAL_disable_interrupts(void) { + psr_t psr; + psr = read_csr(mstatus); + MRV_disable_interrupts(); + return(psr); +} + +/*------------------------------------------------------------------------------ + * + */ +void HAL_restore_interrupts(psr_t saved_psr) { + write_csr(mstatus, saved_psr); +} + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/hal/hw_macros.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/hal/hw_macros.h new file mode 100644 index 0000000..189609c --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/hal/hw_macros.h @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hw_macros.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware registers access macros. + * + * THE MACROS DEFINED IN THIS FILE ARE DEPRECATED. DO NOT USE FOR NEW + * DEVELOPMENT. + * + * These macros are used to access peripheral registers. They allow access to + * 8, 16 and 32 bit wide registers. All accesses to peripheral registers should + * be done through these macros in order to ease porting across different + * processors/bus architectures. + * + * Some of these macros also allow access to a specific register field. + * + */ +#ifndef __HW_REGISTER_MACROS_H +#define __HW_REGISTER_MACROS_H 1 +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * 32 bits registers access: + */ +#define HW_get_uint32_reg(BASE_ADDR, REG_OFFSET) (*((uint32_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint32_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint32_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint32_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint32_t) \ + ( \ + (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint32_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint32_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 32 bits memory access: + */ +#define HW_get_uint32(BASE_ADDR) (*((uint32_t volatile *)(BASE_ADDR))) + +#define HW_set_uint32(BASE_ADDR, VALUE) (*((uint32_t volatile *)(BASE_ADDR)) = (VALUE)) + +/*------------------------------------------------------------------------------ + * 16 bits registers access: + */ +#define HW_get_uint16_reg(BASE_ADDR, REG_OFFSET) (*((uint16_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint16_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint16_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint16_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint16_t) \ + ( \ + (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint16_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint16_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 8 bits registers access: + */ +#define HW_get_uint8_reg(BASE_ADDR, REG_OFFSET) (*((uint8_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint8_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint8_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint8_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint8_t) \ + ( \ + (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint8_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint8_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 8 bits memory access: + */ +#define HW_get_uint8(BASE_ADDR) (*((uint8_t volatile *)(BASE_ADDR))) + +#define HW_set_uint8(BASE_ADDR, VALUE) (*((uint8_t volatile *)(BASE_ADDR)) = (VALUE)) + +#ifdef __cplusplus +extern "C" { +#endif + +#endif /* __HW_REGISTER_MACROS_H */ + diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/hal/hw_reg_access.S b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/hal/hw_reg_access.S new file mode 100644 index 0000000..dd29223 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/hal/hw_reg_access.S @@ -0,0 +1,215 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hw_reg_access.S + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware registers access functions. + * The implementation of these function is platform and toolchain specific. + * The functions declared here are implemented using assembler as part of the + * processor/toolchain specific HAL. This implementation is for the combination + * of the 32 bit RISC-V processors and GNU tool chain. + * + */ + +.section .text + .globl HW_set_32bit_reg + .globl HW_get_32bit_reg + .globl HW_set_32bit_reg_field + .globl HW_get_32bit_reg_field + .globl HW_set_16bit_reg + .globl HW_get_16bit_reg + .globl HW_set_16bit_reg_field + .globl HW_get_16bit_reg_field + .globl HW_set_8bit_reg + .globl HW_get_8bit_reg + .globl HW_set_8bit_reg_field + .globl HW_get_8bit_reg_field + + +/***************************************************************************//** + * HW_set_32bit_reg is used to write the content of a 32 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint32_t value + */ +HW_set_32bit_reg: + sw a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_32bit_reg is used to read the content of a 32 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + + * @return 32 bits value read from the peripheral register. + */ +HW_get_32bit_reg: + lw a0, 0(a0) + ret + +/***************************************************************************//** + * HW_set_32bit_reg_field is used to set the content of a field in a 32 bits + * wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint32_t mask + * a3: uint32_t value + */ +HW_set_32bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lw t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sw t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_32bit_reg_field is used to read the content of a field out of a + * 32 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint32_t mask + * + * @return 32 bits value containing the register field value specified + * as parameter. + */ +HW_get_32bit_reg_field: + lw a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +/***************************************************************************//** + * HW_set_16bit_reg is used to write the content of a 16 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint_fast16_t value + */ +HW_set_16bit_reg: + sh a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_16bit_reg is used to read the content of a 16 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + + * @return 16 bits value read from the peripheral register. + */ +HW_get_16bit_reg: + lh a0, (a0) + ret + +/***************************************************************************//** + * HW_set_16bit_reg_field is used to set the content of a field in a 16 bits + * wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast16_t mask + * a3: uint_fast16_t value + * @param value Value to be written in the specified field. + */ +HW_set_16bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lh t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sh t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_16bit_reg_field is used to read the content of a field from a + * 16 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast16_t mask + * + * @return 16 bits value containing the register field value specified + * as parameter. + */ +HW_get_16bit_reg_field: + lh a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +/***************************************************************************//** + * HW_set_8bit_reg is used to write the content of a 8 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint_fast8_t value + */ +HW_set_8bit_reg: + sb a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_8bit_reg is used to read the content of a 8 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + + * @return 8 bits value read from the peripheral register. + */ +HW_get_8bit_reg: + lb a0, 0(a0) + ret + +/***************************************************************************//** + * HW_set_8bit_reg_field is used to set the content of a field in a 8 bits + * wide peripheral register. + * + * a0: addr_t reg_addr, + * a1: int_fast8_t shift + * a2: uint_fast8_t mask + * a3: uint_fast8_t value + */ +HW_set_8bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lb t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sb t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_8bit_reg_field is used to read the content of a field from a + * 8 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast8_t mask + * + * @return 8 bits value containing the register field value specified + * as parameter. + */ +HW_get_8bit_reg_field: + lb a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +.end diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/hal/hw_reg_access.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/hal/hw_reg_access.h new file mode 100644 index 0000000..1a24309 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/hal/hw_reg_access.h @@ -0,0 +1,239 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hw_reg_access.S + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware registers access functions. + * The implementation of these function is platform and tool-chain specific. + * The functions declared here are implemented using assembler as part of the + * processor/tool-chain specific HAL. This implementation is for the combination + * of the 32 bit RISC-V processors and GNU tool chain. + * + */ +#ifndef __HW_REG_ACCESS +#define __HW_REG_ACCESS +#ifdef __cplusplus +extern "C" { +#endif + +#include "cpu_types.h" +/***************************************************************************//** + * HW_set_32bit_reg is used to write the content of a 32 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_32bit_reg +( + addr_t reg_addr, + uint32_t value +); + +/***************************************************************************//** + * HW_get_32bit_reg is used to read the content of a 32 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 32 bits value read from the peripheral register. + */ +uint32_t +HW_get_32bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_32bit_reg_field is used to set the content of a field in a 32 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void +HW_set_32bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint32_t mask, + uint32_t value +); + +/***************************************************************************//** + * HW_get_32bit_reg_field is used to read the content of a field out of a + * 32 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 32 bits value containing the register field value specified + * as parameter. + */ +uint32_t +HW_get_32bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint32_t mask +); + +/***************************************************************************//** + * HW_set_16bit_reg is used to write the content of a 16 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_16bit_reg +( + addr_t reg_addr, + uint_fast16_t value +); + +/***************************************************************************//** + * HW_get_16bit_reg is used to read the content of a 16 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 16 bits value read from the peripheral register. + */ +uint16_t +HW_get_16bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_16bit_reg_field is used to set the content of a field in a 16 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void HW_set_16bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast16_t mask, + uint_fast16_t value +); + +/***************************************************************************//** + * HW_get_16bit_reg_field is used to read the content of a field from a + * 16 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 16 bits value containing the register field value specified + * as parameter. + */ +uint16_t HW_get_16bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast16_t mask +); + +/***************************************************************************//** + * HW_set_8bit_reg is used to write the content of a 8 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_8bit_reg +( + addr_t reg_addr, + uint_fast8_t value +); + +/***************************************************************************//** + * HW_get_8bit_reg is used to read the content of a 8 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 8 bits value read from the peripheral register. + */ +uint8_t +HW_get_8bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_8bit_reg_field is used to set the content of a field in a 8 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void HW_set_8bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast8_t mask, + uint_fast8_t value +); + +/***************************************************************************//** + * HW_get_8bit_reg_field is used to read the content of a field from a + * 8 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 8 bits value containing the register field value specified + * as parameter. + */ +uint8_t HW_get_8bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast8_t mask +); + +#ifdef __cplusplus +} +#endif + +#endif /* __HW_REG_ACCESS */ + diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld new file mode 100644 index 0000000..474eb43 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld @@ -0,0 +1,154 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-execute-in-place.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * image executing from a one address space whereas the data, sdata and stack + * sections are placed in another address space. This could be used in cases such + * as: + * 1) When using MIV_RV32, the reset vector points to the LSRAM at address + * 0x80000000 and the data, sdata, bss and stack sections are placed in the + * TCM region. + * + * 2) Executing from a Non Volatile memory. The actual memory will depend on + * the FPGA platform. For exameple, it could be the eNVM on SmartFusion2, + * Igloo2 or on-board non-volatile memory which supports code execution. + * + * NOTE: Modify the memory section addresses and the sizes according to your + * Libero design. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + + +MEMORY +{ + rom (rx) : ORIGIN = 0x80000000, LENGTH = 16k + ram (rwx) : ORIGIN = 0x80004000, LENGTH = 16k +} + +STACK_SIZE = 1k; /* needs to be calculated for your application */ +HEAP_SIZE = 1k; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > rom + + .text : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.text.entry))) + . = ALIGN(0x10); + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } >rom + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } >ram AT>rom + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } >ram AT>rom + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram +} + diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv-rv32-ram.ld b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv-rv32-ram.ld new file mode 100644 index 0000000..53076a0 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv-rv32-ram.ld @@ -0,0 +1,150 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-ram.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * debug image executing in SRAM. + * + * This linker script assumes that a RAM is connected at on Mi-V soft processor + * memory space pointed by the reset vector address. + * + * NOTE : Modify the memory section address and the size according to your + * Libero design. + * For example: + * 1) If you want to download and step debug at a different RAM memory address in + * your design (For example TCM base address) than the one provided in this file. + * 2) The MIV_RV32, when used with MIV_ESS IP, provides ways to copy the executable + * HEX file from external Non-Volatile memory into the TCM at reset. In this + * case your executable must be linked to the TCM address. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +MEMORY +{ + ram (rwx) : ORIGIN = 0x80000000, LENGTH = 32k +} + +STACK_SIZE = 2k; /* needs to be calculated for your application */ +HEAP_SIZE = 1k; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > ram + + .text : ALIGN(0x10) + { + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } > ram + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } > ram + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } > ram + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram +} + diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv_rv32_assert.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv_rv32_assert.h new file mode 100644 index 0000000..b3912ed --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv_rv32_assert.h @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * MIV_RV32 HAL Embedded Software + * + */ +#ifndef MIV_RV32_ASSERT_HEADER +#define MIV_RV32_ASSERT_HEADER + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + * ASSERT() implementation. + ******************************************************************************/ +/* Disable assertions if we do not recognize the compiler. */ +#if defined ( __GNUC__ ) +#if defined(NDEBUG) +#define ASSERT(CHECK) +#else +#define ASSERT(CHECK)\ + do { \ + if (!(CHECK)) \ + { \ + __asm__ volatile ("ebreak"); \ + }\ + } while(0); + +#endif /* NDEBUG check */ +#endif /* compiler check */ + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_RV32_ASSERT_HEADER */ + diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv_rv32_entry.S b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv_rv32_entry.S new file mode 100644 index 0000000..0ea3172 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv_rv32_entry.S @@ -0,0 +1,590 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_entry.S + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor vectors, trap handling and startup code. + * + */ +#ifndef ENTRY_S +#define ENTRY_S + +#define A_EXTENSION_MASK 0x00000001u +#define MTVEC_MODE_BIT_MASK 0x00000003u +#define MTVEC_VECTORED_MODE_VAL 0x00000001u + +#define MTIMEH_ADDR 0x200BFFCu + + +#if __riscv_xlen == 64 +# define LREG ld +# define SREG sd +# define REGBYTES 8 +#else +# define LREG lw +# define SREG sw +# define REGBYTES 4 +#endif + +#if defined(MIV_FP_CONTEXT_SAVE) && defined(__riscv_flen) +#define SP_SHIFT_OFFSET 64 +#else +#define SP_SHIFT_OFFSET 32 +#endif + +.macro STORE_CONTEXT + addi sp, sp, -SP_SHIFT_OFFSET*REGBYTES + SREG x1, 0 * REGBYTES(sp) + SREG x1, 0 * REGBYTES(sp) + SREG x2, 1 * REGBYTES(sp) + SREG x3, 2 * REGBYTES(sp) + SREG x4, 3 * REGBYTES(sp) + SREG x5, 4 * REGBYTES(sp) + SREG x6, 5 * REGBYTES(sp) + SREG x7, 6 * REGBYTES(sp) + SREG x8, 7 * REGBYTES(sp) + SREG x9, 8 * REGBYTES(sp) + SREG x10, 9 * REGBYTES(sp) + SREG x11, 10 * REGBYTES(sp) + SREG x12, 11 * REGBYTES(sp) + SREG x13, 12 * REGBYTES(sp) + SREG x14, 13 * REGBYTES(sp) + SREG x15, 14 * REGBYTES(sp) + SREG x16, 15 * REGBYTES(sp) + SREG x17, 16 * REGBYTES(sp) + SREG x18, 17 * REGBYTES(sp) + SREG x19, 18 * REGBYTES(sp) + SREG x20, 19 * REGBYTES(sp) + SREG x21, 20 * REGBYTES(sp) + SREG x22, 21 * REGBYTES(sp) + SREG x23, 22 * REGBYTES(sp) + SREG x24, 23 * REGBYTES(sp) + SREG x25, 24 * REGBYTES(sp) + SREG x26, 25 * REGBYTES(sp) + SREG x27, 26 * REGBYTES(sp) + SREG x28, 27 * REGBYTES(sp) + SREG x29, 28 * REGBYTES(sp) + SREG x30, 29 * REGBYTES(sp) + SREG x31, 30 * REGBYTES(sp) + + #ifdef __riscv_flen + #ifdef MIV_FP_CONTEXT_SAVE + fsw f0, 31*REGBYTES(sp) + fsw f1, 32*REGBYTES(sp) + fsw f2, 33*REGBYTES(sp) + fsw f3, 34*REGBYTES(sp) + fsw f4, 35*REGBYTES(sp) + fsw f5, 36*REGBYTES(sp) + fsw f6, 37*REGBYTES(sp) + fsw f7, 38*REGBYTES(sp) + fsw f8, 39*REGBYTES(sp) + fsw f9, 40*REGBYTES(sp) + fsw f10, 41*REGBYTES(sp) + fsw f11, 42*REGBYTES(sp) + fsw f12, 43*REGBYTES(sp) + fsw f13, 44*REGBYTES(sp) + fsw f14, 45*REGBYTES(sp) + fsw f15, 46*REGBYTES(sp) + fsw f16, 47*REGBYTES(sp) + fsw f17, 48*REGBYTES(sp) + fsw f18, 49*REGBYTES(sp) + fsw f19, 50*REGBYTES(sp) + fsw f20, 51*REGBYTES(sp) + fsw f21, 52*REGBYTES(sp) + fsw f22, 53*REGBYTES(sp) + fsw f23, 54*REGBYTES(sp) + fsw f24, 55*REGBYTES(sp) + fsw f25, 56*REGBYTES(sp) + fsw f26, 57*REGBYTES(sp) + fsw f27, 58*REGBYTES(sp) + fsw f28, 59*REGBYTES(sp) + fsw f29, 60*REGBYTES(sp) + fsw f30, 61*REGBYTES(sp) + fsw f31, 62*REGBYTES(sp) + #endif /* __riscv_flen */ + #endif /* MIV_FP_CONTEXT_SAVE */ +.endm + + .section .entry, "ax" + .globl _start + +_start: + j handle_reset + +/* Some of the Mi-V soft IP cores support compressed 'C' extension. If the Mi-V + core in your design doesn't support 'C' extension and you enable 'C' extension + in firmware project compiler options, then it would result in a trap. For this + case, we are avoiding compressed instruction here so you can put a breakpoint + at the jump and you can at least look at mcause, mepc and get some hints + about the crash. */ +trap_entry: +.option push +.option norvc +j generic_trap_handler +.option pop + .word 0 + .word 0 + +sw_trap_entry: + j vector_sw_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + +tmr_trap_entry: + j vector_tmr_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + +ext_trap_entry: + j vector_ext_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + .word 0 + +#ifndef MIV_LEGACY_RV32 +MGEUI_trap_entry: + j vector_MGEUI_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MGECI_trap_entry: + j vector_MGECI_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + .word 0 + +#ifndef MIV_RV32_V3_0 +MSYS_MIE22_trap_entry: +#ifndef MIV_RV32_V3_0 + j vector_SUBSYSR_IRQHandler +#endif /*MIV_RV32_V3_0*/ +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE23_trap_entry: + j vector_SUBSYS_IRQHandler +#ifdef __riscv_compressed + .2byte 0 +#endif +#endif /*MIV_RV32_V3_0*/ + +MSYS_MIE24_trap_entry: + j vector_MSYS_EI0_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE25_trap_entry: + j vector_MSYS_EI1_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE26_trap_entry: + j vector_MSYS_EI2_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE27_trap_entry: + j vector_MSYS_EI3_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE28_trap_entry: + j vector_MSYS_EI4_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE29_trap_entry: + j vector_MSYS_EI5_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE30_trap_entry: +#ifndef MIV_RV32_V3_0 + j vector_MSYS_EI6_trap_handler +#else + j vector_SUBSYS_IRQHandler +#endif +#ifdef __riscv_compressed + .2byte 0 +#endif + +#ifndef MIV_RV32_V3_0 +MSYS_MIE31_trap_entry: + j vector_MSYS_EI7_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif +#endif /* MIV_RV32_V3_0 */ +#endif /* MIV_LEGACY_RV32 */ + +.align 4 +generic_trap_handler: + STORE_CONTEXT + csrr a0, mcause + csrr a1, mepc + jal handle_trap + j generic_restore + +vector_sw_trap_handler: + STORE_CONTEXT + jal handle_m_soft_interrupt + j generic_restore + +vector_tmr_trap_handler: + STORE_CONTEXT + jal handle_m_timer_interrupt + j generic_restore + +vector_ext_trap_handler: + STORE_CONTEXT +#ifdef MIV_LEGACY_RV32 + jal handle_m_ext_interrupt +#else + jal External_IRQHandler +#endif /* MIV_LEGACY_RV32 */ + j generic_restore + +#ifndef MIV_LEGACY_RV32 +vector_MGEUI_trap_handler: + STORE_CONTEXT + jal MGEUI_IRQHandler + j generic_restore + +vector_MGECI_trap_handler: + STORE_CONTEXT + jal MGECI_IRQHandler + j generic_restore + +vector_MSYS_EI0_trap_handler: + STORE_CONTEXT + jal MSYS_EI0_IRQHandler + j generic_restore + +vector_MSYS_EI1_trap_handler: + STORE_CONTEXT + jal MSYS_EI1_IRQHandler + j generic_restore + +vector_MSYS_EI2_trap_handler: + STORE_CONTEXT + jal MSYS_EI2_IRQHandler + j generic_restore + +vector_MSYS_EI3_trap_handler: + STORE_CONTEXT + jal MSYS_EI3_IRQHandler + j generic_restore + +vector_MSYS_EI4_trap_handler: + STORE_CONTEXT + jal MSYS_EI4_IRQHandler + j generic_restore + +vector_MSYS_EI5_trap_handler: + STORE_CONTEXT + jal MSYS_EI5_IRQHandler + j generic_restore + +vector_SUBSYS_IRQHandler: + STORE_CONTEXT + jal SUBSYS_IRQHandler + j generic_restore + +#ifndef MIV_RV32_V3_0 +vector_MSYS_EI6_trap_handler: + STORE_CONTEXT + jal MSYS_EI6_IRQHandler + j generic_restore + +vector_MSYS_EI7_trap_handler: + STORE_CONTEXT + jal MSYS_EI7_IRQHandler + j generic_restore + + +vector_SUBSYSR_IRQHandler: + STORE_CONTEXT + jal SUBSYSR_IRQHandler + j generic_restore + +#endif /*MIV_RV32_V3_0*/ +#endif /* MIV_LEGACY_RV32 */ + +generic_restore: + LREG x1, 0 * REGBYTES(sp) + LREG x2, 1 * REGBYTES(sp) + LREG x3, 2 * REGBYTES(sp) + LREG x4, 3 * REGBYTES(sp) + LREG x5, 4 * REGBYTES(sp) + LREG x6, 5 * REGBYTES(sp) + LREG x7, 6 * REGBYTES(sp) + LREG x8, 7 * REGBYTES(sp) + LREG x9, 8 * REGBYTES(sp) + LREG x10, 9 * REGBYTES(sp) + LREG x11, 10 * REGBYTES(sp) + LREG x12, 11 * REGBYTES(sp) + LREG x13, 12 * REGBYTES(sp) + LREG x14, 13 * REGBYTES(sp) + LREG x15, 14 * REGBYTES(sp) + LREG x16, 15 * REGBYTES(sp) + LREG x17, 16 * REGBYTES(sp) + LREG x18, 17 * REGBYTES(sp) + LREG x19, 18 * REGBYTES(sp) + LREG x20, 19 * REGBYTES(sp) + LREG x21, 20 * REGBYTES(sp) + LREG x22, 21 * REGBYTES(sp) + LREG x23, 22 * REGBYTES(sp) + LREG x24, 23 * REGBYTES(sp) + LREG x25, 24 * REGBYTES(sp) + LREG x26, 25 * REGBYTES(sp) + LREG x27, 26 * REGBYTES(sp) + LREG x28, 27 * REGBYTES(sp) + LREG x29, 28 * REGBYTES(sp) + LREG x30, 29 * REGBYTES(sp) + LREG x31, 30 * REGBYTES(sp) + + #ifdef __riscv_flen + #ifdef MIV_FP_CONTEXT_SAVE + flw f0, 0 * REGBYTES(sp) + flw f1, 1 * REGBYTES(sp) + flw f2, 2 * REGBYTES(sp) + flw f3, 3 * REGBYTES(sp) + flw f4, 4 * REGBYTES(sp) + flw f5, 5 * REGBYTES(sp) + flw f6, 6 * REGBYTES(sp) + flw f7, 7 * REGBYTES(sp) + flw f8, 8 * REGBYTES(sp) + flw f9, 9 * REGBYTES(sp) + flw f10, 10 * REGBYTES(sp) + flw f11, 11 * REGBYTES(sp) + flw f12, 12 * REGBYTES(sp) + flw f13, 13 * REGBYTES(sp) + flw f14, 14 * REGBYTES(sp) + flw f15, 15 * REGBYTES(sp) + flw f16, 16 * REGBYTES(sp) + flw f17, 17 * REGBYTES(sp) + flw f18, 18 * REGBYTES(sp) + flw f19, 19 * REGBYTES(sp) + flw f20, 20 * REGBYTES(sp) + flw f21, 21 * REGBYTES(sp) + flw f22, 22 * REGBYTES(sp) + flw f23, 23 * REGBYTES(sp) + flw f24, 24 * REGBYTES(sp) + flw f25, 25 * REGBYTES(sp) + flw f26, 26 * REGBYTES(sp) + flw f27, 27 * REGBYTES(sp) + flw f28, 28 * REGBYTES(sp) + flw f29, 29 * REGBYTES(sp) + flw f30, 30 * REGBYTES(sp) + flw f31, 31 * REGBYTES(sp) + #endif /* __riscv_flen */ + #endif /* MIV_FP_CONTEXT_SAVE */ + + addi sp, sp, SP_SHIFT_OFFSET*REGBYTES + mret + + .section .text, "ax" +handle_reset: +/* Ensure instructions are not relaxed, since gp is not yet set */ +.option push +.option norelax + +#ifndef MIV_RV32_V3_0 + csrwi mstatus, 0 + csrwi mie, 0 + la ra, _start + +/* Clearnig this to be on safer side as RTL doesnt seem to clear it on reset. */ +#ifndef MIV_LEGACY_RV32 + li t0, MTIMEH_ADDR + sw x0, 0(t0) +#endif + + csrr t0, misa + andi t0, t0, A_EXTENSION_MASK + bnez t0, ima_cores_setup /* Jump to IMA core handling */ + + +/* For MIV_RV32 cores the mtvec exception base address is fixed at Reset vector + address + 0x4. Check the mode bits. */ +/* In the MIV_RV32 v3.1, the MTVEC exception base address is WARL, and can be + configured by the user at runtime */ + + csrr t0, mtvec + andi t0, t0, MTVEC_MODE_BIT_MASK + li t1, MTVEC_VECTORED_MODE_VAL + bne t0, t1, ima_cores_setup /* Jump to IMA core handling */ + + /* When mode = 1 => this is vectored mode on MIV_RV32 core. + Verify that the trap_handler address matches the configuration in MTVEC */ + csrr t0, mtvec + andi t0, t0, 0xFFFFFFFC + la t1, trap_entry + bne t0, t1, vector_address_not_matching + j generic_reset_handling + +#else /* MIV_RV32_V3_0 */ + +/* Clearnig this to be on safer side as RTL doesnt seem to clear it on reset. */ +#ifndef MIV_LEGACY_RV32 + li t0, MTIMEH_ADDR + sw x0, 0(t0) +#endif + +/* In the MIV_RV32 v3.1, the MTVEC exception base address is WARL, and can be + configured by the user at runtime */ + csrr t0, mtvec + andi t0, t0, MTVEC_MODE_BIT_MASK + li t1, MTVEC_VECTORED_MODE_VAL + bne t0, t1, ima_cores_setup /* Jump to IMA core handling */ + +/* When mode = 1 => this is vectored mode on MIV_RV32 core. + Verify that the trap_handler address matches the configuration in MTVEC */ + csrr t0, mtvec + andi t0, t0, 0xFFFFFFFC + la t1, trap_entry + bne t0, t1, vector_address_not_matching + j generic_reset_handling +#endif /*MIV_RV32_V3_0*/ + +ima_cores_setup: + la t0, trap_entry + +#ifdef MIV_LEGACY_RV32_VECTORED_INTERRUPTS + addi t0, t0, 0x01 /* Set the mode bit for IMA cores. + For both MIV_RV32 v3.1 and v3.0 cores this is done by configurator. */ +#endif + csrw mtvec, t0 + +generic_reset_handling: +/* Copy sdata section first so that the gp is set and linker relaxation can be + used */ + la a4, __sdata_load + la a5, __sdata_start + la a6, __sdata_end + beq a4, a5, 1f /* Exit if source and dest are same */ + beq a5, a6, 1f /* Exit if section start and end addresses are same */ + call block_copy + +1: + /* initialize global pointer */ + la gp, __global_pointer$ + +.option pop + +/* Floating point support configuration */ +#ifdef __riscv_flen + csrr t0, mstatus + lui t1, 0xffffa + addi t1, t1, -1 + and t0, t0, t1 + lui t1, 0x4 + or t1, t0, t1 + csrw mstatus, t1 + + lui t0, 0x0 + fscsr t0 +#endif + call initializations + /* Initialize stack pointer */ + la sp, __stack_top + + /* Jump into C code */ + j _init + +/* Error: trap_entry is not at the expected address of reset_vector+mtvec offset + as configured in the MIV_RV32 core vectored mode */ +vector_address_not_matching: + ebreak + +initializations: +/* Initialize the .bss section */ + mv t0, ra /* Store ra for future use */ + la a5, __bss_start + la a6, __bss_end + beq a5, a6, 1f /* Section start and end address are the same */ + call zeroize_block + +1: +/* Initialize the .sbss section */ + la a5, __sbss_start + la a6, __sbss_end + beq a5, a6, 1f /* Section start and end address are the same */ + call zeroize_block + +/* Clear heap */ + la a5, __heap_start + la a6, __heap_end + beq a5, a6, 1f /* Section start and end address are the same */ + call zeroize_block + +1: +/* Copy data section */ + la a4, __data_load + la a5, __data_start + la a6, __data_end + beq a4, a5, 1f /* Exit early if source and dest are same */ + beq a5, a6, 1f /* Section start and end addresses are the same */ + call block_copy + +1: + mv ra, t0 /* Retrieve ra */ + ret + +zeroize_block: + bltu a6, a5, block_copy_error /* Error. End address is less than start */ + or a7, a6, a5 /* Check if start or end is unalined */ + andi a7, a7, 0x03u + bgtz a7, block_copy_error /* Unaligned addresses error*/ +zeroize_loop: + sw x0, 0(a5) + add a5, a5, __SIZEOF_POINTER__ + blt a5, a6, zeroize_loop + ret + +block_copy: + bltu a6, a5, block_copy_error /* Error. End address is less than start */ + or a7, a6, a5 /* Check if start or end is unalined */ + andi a7, a7, 0x03u + bgtz a7, block_copy_error /* Unaligned addresses error*/ +block_copy_loop: + lw a7, 0(a4) + sw a7, 0(a5) + addi a5, a5, 0x04 + addi a4, a4, 0x04 + blt a5, a6, block_copy_loop + j block_copy_exit + +block_copy_error: + j block_copy_error + +block_copy_exit: + ret + +#endif /*ENTRY_S*/ diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv_rv32_hal.c b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv_rv32_hal.c new file mode 100644 index 0000000..a112821 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv_rv32_hal.c @@ -0,0 +1,410 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_hal.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Implementation of Hardware Abstraction Layer for Mi-V soft processors + * + */ +#include +#include "miv_rv32_hal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SUCCESS 0U +#define ERROR 1U +#define MASK_32BIT 0xFFFFFFFFu + +/*------------------------------------------------------------------------------ + * Write in a sequence recommended by privileged spec to avoid spurious + * interrupts + + # New comparand is in a1:a0. + li t0, -1 + sw t0, mtimecmp # No smaller than old value. + sw a1, mtimecmp+4 # No smaller than new value. + sw a0, mtimecmp # New value. + */ +#ifndef MIV_RV32_EXT_TIMECMP +#define WRITE_MTIMECMP(value) MTIMECMPH = MASK_32BIT; \ + MTIMECMP = value & MASK_32BIT;\ + MTIMECMPH = (value >> 32u) & MASK_32BIT; +#else +#define WRITE_MTIMECMP(value) +#endif + +#ifndef MIV_RV32_EXT_TIMER +#define WRITE_MTIME(value) MTIME = value & MASK_32BIT;\ + MTIMEH = (value >> 32u) & MASK_32BIT; +#else +#define WRITE_MTIME(value) +#endif + +extern void Software_IRQHandler(void); + +#ifdef MIV_LEGACY_RV32 +#define MTIME_PRESCALER 100UL +/*------------------------------------------------------------------------------ + * + */ +uint8_t Invalid_IRQHandler(void); +uint8_t External_1_IRQHandler(void); +uint8_t External_2_IRQHandler(void); +uint8_t External_3_IRQHandler(void); +uint8_t External_4_IRQHandler(void); +uint8_t External_5_IRQHandler(void); +uint8_t External_6_IRQHandler(void); +uint8_t External_7_IRQHandler(void); +uint8_t External_8_IRQHandler(void); +uint8_t External_9_IRQHandler(void); +uint8_t External_10_IRQHandler(void); +uint8_t External_11_IRQHandler(void); +uint8_t External_12_IRQHandler(void); +uint8_t External_13_IRQHandler(void); +uint8_t External_14_IRQHandler(void); +uint8_t External_15_IRQHandler(void); +uint8_t External_16_IRQHandler(void); +uint8_t External_17_IRQHandler(void); +uint8_t External_18_IRQHandler(void); +uint8_t External_19_IRQHandler(void); +uint8_t External_20_IRQHandler(void); +uint8_t External_21_IRQHandler(void); +uint8_t External_22_IRQHandler(void); +uint8_t External_23_IRQHandler(void); +uint8_t External_24_IRQHandler(void); +uint8_t External_25_IRQHandler(void); +uint8_t External_26_IRQHandler(void); +uint8_t External_27_IRQHandler(void); +uint8_t External_28_IRQHandler(void); +uint8_t External_29_IRQHandler(void); +uint8_t External_30_IRQHandler(void); +uint8_t External_31_IRQHandler(void); + + +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for external interrupts. + */ +uint8_t (* const mrv_ext_irq_handler_table[32])(void) = +{ + + Invalid_IRQHandler, + External_1_IRQHandler, + External_2_IRQHandler, + External_3_IRQHandler, + External_4_IRQHandler, + External_5_IRQHandler, + External_6_IRQHandler, + External_7_IRQHandler, + External_8_IRQHandler, + External_9_IRQHandler, + External_10_IRQHandler, + External_11_IRQHandler, + External_12_IRQHandler, + External_13_IRQHandler, + External_14_IRQHandler, + External_15_IRQHandler, + External_16_IRQHandler, + External_17_IRQHandler, + External_18_IRQHandler, + External_19_IRQHandler, + External_20_IRQHandler, + External_21_IRQHandler, + External_22_IRQHandler, + External_23_IRQHandler, + External_24_IRQHandler, + External_25_IRQHandler, + External_26_IRQHandler, + External_27_IRQHandler, + External_28_IRQHandler, + External_29_IRQHandler, + External_30_IRQHandler, + External_31_IRQHandler +}; + +#else +/*------------------------------------------------------------------------------ + * Interrupt handlers as mapped into the MIE register of the MIV_RV32 + */ +extern void Reserved_IRQHandler(void); +extern void External_IRQHandler(void); +extern void MGEUI_IRQHandler(void); +extern void MGECI_IRQHandler(void); +extern void MSYS_EI0_IRQHandler(void); +extern void MSYS_EI1_IRQHandler(void); +extern void MSYS_EI2_IRQHandler(void); +extern void MSYS_EI3_IRQHandler(void); +extern void MSYS_EI4_IRQHandler(void); +extern void MSYS_EI5_IRQHandler(void); +extern void SUBSYS_IRQHandler(void); + +#ifndef MIV_RV32_V3_0 /*For MIV_RV32 v3.1*/ +extern void MSYS_EI6_IRQHandler(void); +extern void MSYS_EI7_IRQHandler(void); +extern void SUBSYSR_IRQHandler(void); // @suppress("Unused function declaration") +#endif /*MIV_RV32_V3_0*/ + +#endif /* MIV_LEGACY_RV32 */ + +/*------------------------------------------------------------------------------ + * Increment value for the mtimecmp register in order to achieve a system tick + * interrupt as specified through the MRV_systick_config() function. + */ +static uint64_t g_systick_increment = 0U; +static uint64_t g_systick_cmp_value = 0U; + +/*------------------------------------------------------------------------------ + * Configure the machine timer to generate an interrupt. + */ +uint32_t MRV_systick_config(uint64_t ticks) +{ + uint32_t ret_val = ERROR; + uint64_t remainder = ticks; + g_systick_increment = 0U; + g_systick_cmp_value = 0U; + + while (remainder >= MTIME_PRESCALER) + { + remainder -= MTIME_PRESCALER; + g_systick_increment++; + } + + g_systick_cmp_value = g_systick_increment + MRV_read_mtime(); + + if (g_systick_increment > 0U) + { + WRITE_MTIMECMP(g_systick_cmp_value); + set_csr(mie, MIP_MTIP); + MRV_enable_interrupts(); + ret_val = SUCCESS; + } + + return ret_val; +} + +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for machine timer interrupts. + */ +void handle_m_timer_interrupt(void) +{ + clear_csr(mie, MIP_MTIP); + + uint64_t mtime_at_irq = MRV_read_mtime(); + +#ifndef NDEBUG + static volatile uint32_t d_tick = 0u; +#endif + + while(g_systick_cmp_value < (mtime_at_irq + MTIME_DELTA)) { + g_systick_cmp_value = g_systick_cmp_value + g_systick_increment; + +#ifndef NDEBUG + d_tick += 1; +#endif + } +/***************************************************************************//** + /* + * Note: If d_tick > 1 it means, that a system timer interrupt has been + * missed. + * Please ensure that interrupt handlers are as short as possible to prevent + * them stopping other interrupts from being handled. For example, if a + * system timer interrupt occurs during a software interrupt, the system + * timer interrupt will not be handled until the software interrupt handling + * is complete. If the software interrupt handling time is more than one + * systick interval, it will result in d_tick > 1. + * If you are running the program using the debugger and halt the CPU at a + * breakpoint, MTIME will continue to increment and interrupts will be + * missed; resulting in d_tick > 1. + */ + + WRITE_MTIMECMP(g_systick_cmp_value); + + SysTick_Handler(); + + set_csr(mie, MIP_MTIP); +} + +void handle_m_soft_interrupt(void) +{ + Software_IRQHandler(); + MRV_clear_soft_irq(); +} +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for software interrupts. + */ +#ifdef MIV_LEGACY_RV32 +void handle_m_ext_interrupt(void) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; + uint8_t disable = EXT_IRQ_KEEP_ENABLED; + + if (0u !=int_num) + { + disable = mrv_ext_irq_handler_table[int_num](); + + PLIC->TARGET[hart_id].CLAIM_COMPLETE = int_num; + + if(EXT_IRQ_DISABLE == disable) + { + MRV_PLIC_disable_irq((IRQn_Type)int_num); + } + } +} +#else + +/*------------------------------------------------------------------------------ + * MSYS local interrupts table + */ +void (* const local_irq_handler_table[16])(void) = +{ +#ifndef MIV_RV32_V3_0 + MGEUI_IRQHandler, + MGECI_IRQHandler, + SUBSYS_IRQHandler, + SUBSYSR_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + MSYS_EI0_IRQHandler, + MSYS_EI1_IRQHandler, + MSYS_EI2_IRQHandler, + MSYS_EI3_IRQHandler, + MSYS_EI4_IRQHandler, + MSYS_EI5_IRQHandler, + MSYS_EI6_IRQHandler, + MSYS_EI7_IRQHandler +#else + MGEUI_IRQHandler, + MGECI_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + MSYS_EI0_IRQHandler, + MSYS_EI1_IRQHandler, + MSYS_EI2_IRQHandler, + MSYS_EI3_IRQHandler, + MSYS_EI4_IRQHandler, + MSYS_EI5_IRQHandler, + SUBSYS_IRQHandler, + Reserved_IRQHandler, +#endif +}; + +/*------------------------------------------------------------------------------ + * Jump to interrupt table containing local interrupts + */ +void handle_local_ei_interrupts(uint8_t irq_no) +{ + uint64_t mhart_id = read_csr(mhartid); + ASSERT(irq_no <= MIV_LOCAL_IRQ_MAX) + ASSERT(irq_no >= MIV_LOCAL_IRQ_MIN) + + uint8_t ei_no = (uint8_t)(irq_no - MIV_LOCAL_IRQ_MIN); + (*local_irq_handler_table[ei_no])(); +} +#endif /* MIV_LEGACY_RV32 */ + + +/*------------------------------------------------------------------------------ + * Trap handler. This function is invoked in the non-vectored mode. + */ +void handle_trap(uintptr_t mcause, uintptr_t mepc) +{ + uint64_t is_interrupt = mcause & MCAUSE_INT; + + if (is_interrupt) + { +#ifndef MIV_LEGACY_RV32 + if (((mcause & MCAUSE_CAUSE) >= MIV_LOCAL_IRQ_MIN) && ((mcause & MCAUSE_CAUSE) <= MIV_LOCAL_IRQ_MAX)) + { + handle_local_ei_interrupts((uint8_t)(mcause & MCAUSE_CAUSE)); + } + else if ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT) +#else + if ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT) +#endif + { +#ifndef MIV_LEGACY_RV32 + External_IRQHandler(); +#else + handle_m_ext_interrupt(); +#endif + } + else if ((mcause & MCAUSE_CAUSE) == IRQ_M_SOFT) + { + handle_m_soft_interrupt(); + } + else if ((mcause & MCAUSE_CAUSE) == IRQ_M_TIMER) + { + handle_m_timer_interrupt(); + } + } + else + { +#ifndef NDEBUG + /* + Arguments supplied to this function are mcause, mepc (exception PC) and + stack pointer. + Based on privileged-isa specification mcause values and meanings are: + + 0 Instruction address misaligned (mtval/mtval is the address) + 1 Instruction access fault (mtval/mtval is the address) + 2 Illegal instruction (mtval/mtval contains the + offending instruction opcode) + 3 Breakpoint + 4 Load address misaligned (mtval/mtval is the address) + 5 Load address fault (mtval/mtval is the address) + 6 Store/AMO address fault (mtval/mtval is the address) + 7 Store/AMO access fault (mtval/mtval is the address) + 8 Environment call from U-mode + 9 Environment call from S-mode + A Environment call from M-mode + B Instruction page fault + C Load page fault (mtval/mtval is the address) + E Store page fault (mtval/mtval is the address) + + # Please note: mtval is the newer name for register mbadaddr + # If you get a compile failure here, use the older name. + # At this point, both are supported in latest compiler, older compiler + # versions only support mbadaddr. + # See: https://github.com/riscv/riscv-gcc/issues/133 + */ + + /* interrupt pending */ + uintptr_t mip = read_csr(mip); + + /* additional info and meaning depends on mcause */ + uintptr_t mtval = read_csr(mtval); + + /* trap vector */ + uintptr_t mtvec = read_csr(mtvec); + + /* temporary, sometimes might hold temporary value of a0 */ + uintptr_t mscratch = read_csr(mscratch); + + /* status contains many smaller fields: */ + uintptr_t mstatus = read_csr(mstatus); + + /* PC value when the exception was taken*/ + uintptr_t mmepc = read_csr(mepc); + + /* breakpoint */ + __asm__("ebreak"); +#else + _exit(1 + mcause); +#endif /* NDEBUG */ + } +} + +#ifdef __cplusplus +} +#endif + diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv_rv32_hal.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv_rv32_hal.h new file mode 100644 index 0000000..9ce9ef6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv_rv32_hal.h @@ -0,0 +1,773 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_hal.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware Abstraction Layer functions for Mi-V soft processors + * + */ + +/*=========================================================================*//** + @mainpage MIV_RV32 Hardware Abstraction Layer + + ============================================================================== + Introduction + ============================================================================== + This document describes the Hardware Abstraction Layer (HAL) for the MIV_RV32 + Soft IP Core. This release of the HAL corresponds to the Soft IP core MIV_RV32 + v3.1 release. It also supports earlier versions of the MIV_RV32 as well as the + legacy RV32 IP cores. + The preprocessor macros provided with the MIV_RV32 HAL are used to customize + it to target the Soft Processor IP version being used in your project. + + The term "MIV_RV32" represents following two cores: + - MIV_RV32 v3.0 and later (the latest and greatest Mi-V soft processor) + - MIV_RV32IMC v2.1 (MIV_RV32 v3.0 is a drop in replacement for this core) + It is highly recommended to migrate your design to MIV_RV32 v3.1 + + The term, Legacy RV32 IP cores, represents following IP cores: + - MIV_RV32IMA_L1_AHB + - MIV_RV32IMA_L1_AXI + - MIV_RV32IMAF_L1_AHB + + These legacy RV32 IP cores are deprecated. It is highly recommended to migrate + your designs to MIV_RV32 v3.1 (and subsequent IP releases) for the latest + enhancements, bug fixes, and support. + + -------------------------------- + MIV_RV32 V3.1 + -------------------------------- + This is the latest release of the MIV_RV32 Soft IP core. For more details, + refer to the MIV_RV32 User [Guide](https://www.microchip.com/en-us/products/fpgas-and-plds/ip-core-tools/miv-rv32) + + The MIV_RV32 Core as well as this document use the terms defined below: + + -------------------------------- + - SUBSYS - Processor Subsystem for RISC-V + - OPSRV - Offload Processor Subsystem for RISC-V + - GPR - General Purpose Registers + - MGECIE - Machine GPR ECC Correctable Interrupt Enable + - MGEUIE - Machine GPR ECC Uncorrectable Interrupt Enable + - MTIE - Machine Timer Interrupt Enable + - MEIE - Machine External Interrupt Enable + - MSIE - Machine Software Interrupt Enable + - ISR - Interrupt Service Routine + + ============================================================================== + Customizing MIV_RV32 HAL + ============================================================================== + To use the HAL with older releases of MIV_RV32, preprocessor macros have been + provided. Using these macros, any of the IP version is targeted. + The HAL is used to target any of the mentioned platforms by adding the + following macros in the way : + Project Properties > C/C++ Build > Settings > Preprocessor in Assembler and + Compiler settings. + The table below shows the macros corresponding to the MIV Core being used in + your libero project. By default, the HAL targets v3.1 of the IP core and no + macros need to be set for this configutation. + + | Libero MI-V Soft IP Version | SoftConsole Macro | + |-----------------------------|-------------------| + | MIV_RV32 v3.1 | no macro required | + | MIV_RV32 v3.0 | MIV_CORE_V3_0 | + | Legacy RV32 Cores | MIV_LEGACY_RV32 | + + -------------------------------- + Interrupt Handling + -------------------------------- + The MIE Register is defined as a enum in the HAL, and the table below is used + as a reference when the vectored interrupts are enabled in the GUI core + configurator. + + The MIE register is a RISC-V Control and Status Register (CSR), which stands + for the Machine Interrupt Enable. This is used to enable the machine mode + interrupts in the MIV_RV32 hart. Refer to the RISC-V Priv spec for more details. + + The following table shows the trap entry addresses when an interrupt occurs and + the vectored interrupts are enabled in the GUI configurator. + + | MIE Register Bit | Interrupt Enable | Vector Address | + |-------------------|------------------|----------------| + | 31 | MSYS_IE7 | mtvec.BASE + 0x7C | + | 30 | MSYS_IE6 | mtvec.BASE + 0x78 | + | 29 | MSYS_IE5 | mtvec.BASE + 0x74 | + | 28 | MSYS_IE4 | mtvec.BASE + 0x70 | + | 27 | MSYS_IE3 | mtvec.BASE + 0x6C | + | 26 | MSYS_IE2 | mtvec.BASE + 0x68 | + | 25 | MSYS_IE1 | mtvec.BASE + 0x64 | + | 24 | MSYS_IE0 | mtvec.BASE + 0x60 | + | 23 | SUBSYS_EI | mtvec.BASE + 0x5C | + | 22 | SUBSYSR | mtvec.BASE + 0x58 | + | 17 | MGECIE | mtvec.BASE + 0x44 | + | 16 | MGEUIE | mtvec.BASE + 0x40 | + | 11 | MEIE | mtvec.BASE + 0x2C | + | 7 | MTIE | mtvec.BASE + 0x1C | + | 3 | MSIE | mtvec.BASE + 0x0C | + + + For changes in MIE register map, see the [MIE Register Map for MIV_RV32 v3.0] + (#mie-register-map-for-miv_rv32-v3.0) section. + + SUBSYSR is currently not being used by the core and is Reserved for future use. + + The mtvec.BASE field corresponds to the bits [31:2], where mtvec stands for + Machine Trap Vector, and all traps set the PC to the the value stored in the + mtvec.BASE field when in Non-Vectored mode. In this case, a generic trap + handler is as an interrupt service routine. + + When Vectored interrupts are enabled, use this formula to calculate the trap + address: (mtvec.BASE + 4*cause), where cause comes from the mcause CSR. The + mcause register is written with a code indicating the event that caused the trap. + For more details, see the RISC-V priv specification. + + The MIV_RV32 Soft IP core does not contain a Platfrom Level Interrup Controller + (PLIC). It is advised to use the PLIC contained within the MIV_ESS sub-system. + Connect the PLIC interrupt output of the MIV_ESS to the EXT_IRQ pin on the + MIV_RV32. + + The following table is the MIE register map for the MIV_RV32 Core V3.0. It only + highlights the differences between the V3.0 and V3.1 of the core. + + -------------------------------- + MIE Register Map for MIV_RV32 V3.0 + -------------------------------- + + | MIE Register Bit | Target Interrupt | Vector Address | + |-------------------|------------------|----------------| + | 31 | Not in use | top table | + | 30 | SUBSYS_EI | addr + 0x78 | + | 23 | Not in use | Not in use | + | 22 | Not in use | Not in use | + + Other interrupt bit postions like the MGEUIE and MSYS_IE5 to MSYS_IE0 remain + unchanged. + + -------------------------------- + Floating Point Interrupt Support + -------------------------------- + When an interrupt is taken and Floating Point instructions are used in the + ISR, the floating point register context must be saved to resume the application + correctly. To use this feature, enable the provided macro in the + Softconsole build settings. + This feature is turned off by default as it adds overhead which is not required + when the ISR does not used FP insturctions and saving the general purpose + register context is sufficient. + + | Macro Name | Definition | + |--------------------------|-------------------------------------------------| + | MIV_FP_CONTEXT_SAVE | Define to save the FP register file | + + + -------------------------------- + SUBSYS - SubSystem for RISC-V + -------------------------------- + SUBSYS stands for SubSystem for RISC-V. This was previously (MIV_RV32 v3.0) + known as OPSRV, which stands for "Offload Processor Subsystem + for RISC-V". See the earlier versions of the handbook for more details. + In the latest release of the MIV_RV32 IP core v3.1, OPSRV has been renamed to + SUBSYS. The MIV_RV32 HAL now uses SUBSYS instead of OPSRV. + + *//*=========================================================================*/ +#ifndef RISCV_HAL_H +#define RISCV_HAL_H + +#include "miv_rv32_regs.h" +#include "miv_rv32_plic.h" +#include "miv_rv32_assert.h" +#include "miv_rv32_subsys.h" + +#ifndef LEGACY_DIR_STRUCTURE +#include "fpga_design_config/fpga_design_config.h" +#else +#include "hw_platform.h" +#endif /*LEGACY_DIR_STRUCTURE*/ + +#ifdef __cplusplus +extern "C" { +#endif +/*-------------------------------------------------------------------------*//** + SUBSYS Backwards Compatibility + ======================================= + For application code using the older macro names and API functions, these macros + act as a compatibility layer and applications which use OPSRV API features work + due to these macro definitions. However, it is adviced to update your + application code to use the SUBSYS macros and API functions. + + | Macro Name | Now Called | + |-------------------------|--------------------------| + | OPSRV_TCM_ECC_CE_IRQ | SUBSYS_TCM_ECC_CE_IRQ | + | OPSRV_TCM_ECC_UCE_IRQ | SUBSYS_TCM_ECC_UCE_IRQ | + | OPSRV_AXI_WR_RESP_IRQ | SUBSYS_AXI_WR_RESP_IRQ | + | MRV32_MSYS_OPSRV_IRQn | MRV32_SUBSYS_IRQn | + | MRV32_opsrv_enable_irq | MRV32_subsys_enable_irq | + | MRV32_opsrv_disable_irq | MRV32_subsys_disable_irq | + | MRV32_opsrv_clear_irq | MRV32_subsys_clear_irq | + | OPSRV_IRQHandler | SUBSYS_IRQHandler | + */ + +/*-------------------------------------------------------------------------*//** + MTIME Timer Interrupt Constants + ======================================= + These values contain the register addresses for the registers used by the + machine timer interrupt + + MTIME_PRESCALER is not defined on the MIV_RV32IMC v2.0 and v2.1. By using this + definition the system crashes. For those core, use the following definition: + + #define MTIME_PRESCALER 100u + + MTIME and MTIMECMP + -------------------------------- + MIV_RV32 core offers flexibility in terms of generating MTIME and MTIMECMP + registers internal to the core or using external time reference. There four + possible combinations: + + - Internal MTIME and Internal MTIME IRQ enabled Generate the MTIME and MTIMECMP + registers internally. (The only combination available on legacy RV32 cores) + + - Internal MTIME enabled and Internal MTIME IRQ disabled Generate the MTIME + internally and have a timer interrupt input to the core as external pin. In + this case, 1 pin port will be available on MIV_RV32 for timer interrupt. + + - When the internal MTIME is disabled, and the Internal MTIME IRQ is enabled, the + system generates the time value externally and generates the mtimecmp and + interrupt internally (for example, a multiprocessor system with a shared time + between all cores). In this case, a 64-bit port is available on the MIV_RV32 + core as input. + + - Internal MTIME and Internal MTIME IRQ disabled Generate both the time and + timer interrupts externally. In this case a 64 bit port will be available on + the MIV_RV32 core as input, and a 1 pin port will be available for timer + interrupt. + + To handle all these combinations in the firmware, the following constants must + be defined in accordance with the configuration that you have made on your + MIV_RV32 core design. + + MIV_RV32_EXT_TIMER + -------------------------------- + When defined, it means that the MTIME register is not available internal to + the core. In this case, a 64 bit port will be available on the MIV_RV32 core as + input. When this macro is not defined, it means that the MTIME register is + available internally to the core. + + MIV_RV32_EXT_TIMECMP + -------------------------------- + When defined, it means the MTIMECMP register is not available internally to + the core and the Timer interrupt input to the core comes as an external pin. + When this macro is not defined it means the that MTIMECMP register exists + internal to the core and that the timer interrupt is generated internally. + +NOTE: All these macros must not be defined if you are using a MIV_RV32 core. + */ + +#define OPSRV_TCM_ECC_CE_IRQ SUBSYS_TCM_ECC_CE_IRQ +#define OPSRV_TCM_ECC_UCE_IRQ SUBSYS_TCM_ECC_UCE_IRQ +#define OPSRV_AXI_WR_RESP_IRQ SUBSYS_AXI_WR_RESP_IRQ +#define MRV32_MSYS_OPSRV_IRQn MRV32_SUBSYS_IRQn +#define MRV32_opsrv_enable_irq MRV32_subsys_enable_irq +#define MRV32_opsrv_disable_irq MRV32_subsys_disable_irq +#define MRV32_opsrv_clear_irq MRV32_subsys_clear_irq +#define OPSRV_IRQHandler SUBSYS_IRQHandler + +/*-------------------------------------------------------------------------*//** + External IRQ + ======================================= + Return value from External IRQ handler. This is used to disable the + External Interrupt. + + | Macro Name | Value | Description| + |-------------------|--------|----------------| + | EXT_IRQ_KEEP_ENABLED | 0 | Keep external interrupts enabled | + | EXT_IRQ_DISABLE | 1 | Disable external interrupts | + */ +#define EXT_IRQ_KEEP_ENABLED 0U +#define EXT_IRQ_DISABLE 1U + +#define MTIME_DELTA 5 +#ifdef MIV_LEGACY_RV32 +#define MSIP (*(uint32_t*)0x44000000UL) +#define MTIMECMP (*(uint32_t*)0x44004000UL) +#define MTIMECMPH (*(uint32_t*)0x44004004UL) +#define MTIME (*(uint32_t*)0x4400BFF8UL) +#define MTIMEH (*(uint32_t*)0x4400BFFCUL) + +/* To maintain backward compatibility with FreeRTOS config code */ +#define PRCI_BASE 0x44000000UL +#else /* MIV_LEGACY_RV32 */ + +/* To maintain backward compatibility with FreeRTOS config code */ +#define PRCI_BASE 0x02000000UL + +#ifndef MIV_RV32_EXT_TIMECMP +#define MTIMECMP (*(volatile uint32_t*)0x02004000UL) +#define MTIMECMPH (*(volatile uint32_t*)0x02004004UL) +#else +#define MTIMECMP (0u) +#define MTIMECMPH (0u) +#endif + +#define MTIME_PRESCALER (*(volatile uint32_t*)0x02005000UL) + +#ifndef MIV_RV32_EXT_TIMER +#define MTIME (*(volatile uint32_t*)0x0200BFF8UL) +#define MTIMEH (*(volatile uint32_t*)0x0200BFFCUL) + +/***************************************************************************//** + MIMPID Register + The MIMPID register is a RISC-V Control and Status Register In the v3.0 of + MIV_RV32, the value of `MIMPID = 0x000540AD`. In the v3.1 of MIV_RV32, the + value if `MIMPID = 0xE5010301` corresponding to (E)mbedded (5)ystem(01) core + version (03).(01) this terminology will be followed in the subsequent releases + of the core read the csr value and store it in a varible which may be used to + check the MIV_RV32 core version during runtime. + + Future releases of the core will increment the 03 and 01 as major and minor + releases respectively and the register can be read at runtime to find the + Soft IP core version. + + | Core Version | Register | Value | Notes | + |----------------|------------|---------|---------| + | MIV_RV32 V3.1 | mimpid | 0xE5010301 | implimentation ID | + | MIV_RV32 V3.0 | mimpid | 0x000540AD | implimentation ID | + */ +#define MIMPID read_csr(mimpid) + +/*Used as a mask to read and write to mte mtvec.BASE address*/ +#define MTVEC_BASE_ADDR_MASK 0xFFFFFFFC + +#else +#define MTIME (0u) +#define MTIMEH (0u) +#endif /*MIV_RV32_EXT_TIMER*/ + +/*-------------------------------------------------------------------------*//** + RISC-V Specification Interrupts + ======================================= + These definitions are provided for easy identification of the interrupt + in the MIE/MIP registers. + Apart from the standard software, timer, and external interrupts, the names + of the additional interrupts correspond to the names as used in the MIV_RV32 + handbook. Please refer the MIV_RV32 handbook for more details. + + All the interrups, provided by the MIV_RV32 core, follow the interrupt priority + order and register description as mentioned in the RISC-V spec. + + | Macro Name | Value | Description| + |-------------------|--------|----------------| + | MRV32_SOFT_IRQn | MIE_3_IRQn | Software interrupt enable | + | MRV32_TIMER_IRQn | MIE_7_IRQn | Timer interrupt enable | + | MRV32_EXT_IRQn | MIE_11_IRQn | External interrupt enable | + + */ +#define MRV32_SOFT_IRQn MIE_3_IRQn +#define MRV32_TIMER_IRQn MIE_7_IRQn +#define MRV32_EXT_IRQn MIE_11_IRQn + +/***************************************************************************//** + Interrupt numbers: + This enum represents the interrupt enable bits in the MIE register. + */ +enum +{ + MIE_0_IRQn = (0x01u), + MIE_1_IRQn = (0x01u<<1u), + MIE_2_IRQn = (0x01u<<2u), + MIE_3_IRQn = (0x01u<<3u), /*MSIE 0xC*/ + MIE_4_IRQn = (0x01u<<4u), + MIE_5_IRQn = (0x01u<<5u), + MIE_6_IRQn = (0x01u<<6u), + MIE_7_IRQn = (0x01u<<7u), /*MTIE 0x1C*/ + MIE_8_IRQn = (0x01u<<8u), + MIE_9_IRQn = (0x01u<<9u), + MIE_10_IRQn = (0x01u<<10u), + MIE_11_IRQn = (0x01u<<11u), /*MEIE 0x2C*/ + MIE_12_IRQn = (0x01u<<12u), + MIE_13_IRQn = (0x01u<<13u), + MIE_14_IRQn = (0x01u<<14u), + MIE_15_IRQn = (0x01u<<15u), + MIE_16_IRQn = (0x01u<<16u), /*MGEUIE ECC Uncorrectable 0x40*/ + MIE_17_IRQn = (0x01u<<17u), /*MGECIE ECC Correctable 0x44*/ + MIE_18_IRQn = (0x01u<<18u), + MIE_19_IRQn = (0x01u<<19u), + MIE_20_IRQn = (0x01u<<20u), + MIE_21_IRQn = (0x01u<<21u), + MIE_22_IRQn = (0x01u<<22u), /*SUBSYSR 0x58 (R)eserved*/ + MIE_23_IRQn = (0x01u<<23u), /*SUBSYS_IE 0x5C for MIV_RV32 v3.1*/ + MIE_24_IRQn = (0x01u<<24u), /*MSYS_IE0 0x60*/ + MIE_25_IRQn = (0x01u<<25u), /*MSYS_IE1 0x64*/ + MIE_26_IRQn = (0x01u<<26u), /*MSYS_IE2 0x68*/ + MIE_27_IRQn = (0x01u<<27u), /*MSYS_IE3 0x6C*/ + MIE_28_IRQn = (0x01u<<28u), /*MSYS_IE4 0x70*/ + MIE_29_IRQn = (0x01u<<29u), /*MSYS_IE5 0x74*/ + MIE_30_IRQn = (0x01u<<30u), /*MSYS_IE6 0x78, read comment below*/ + MIE_31_IRQn = (0x01u<<31u) /*MSYS_IE7 0x7C*/ +} MRV_LOCAL_IRQn_Type; + +#define MRV32_MGEUIE_IRQn MIE_16_IRQn +#define MRV32_MGECIE_IRQn MIE_17_IRQn +#define MRV32_MSYS_EIE0_IRQn MIE_24_IRQn +#define MRV32_MSYS_EIE1_IRQn MIE_25_IRQn +#define MRV32_MSYS_EIE2_IRQn MIE_26_IRQn +#define MRV32_MSYS_EIE3_IRQn MIE_27_IRQn +#define MRV32_MSYS_EIE4_IRQn MIE_28_IRQn +#define MRV32_MSYS_EIE5_IRQn MIE_29_IRQn +#ifndef MIV_RV32_V3_0 /*For MIV_RV32 v3.1*/ +#define MRV32_SUBSYSR_IRQn MIE_22_IRQn +#define MRV32_SUBSYS_IRQn MIE_23_IRQn +#define MRV32_MSYS_EIE6_IRQn MIE_30_IRQn +#define MRV32_MSYS_EIE7_IRQn MIE_31_IRQn +#else +#define MRV32_SUBSYS_IRQn MIE_30_IRQn +#endif /*MIV_RV32_V3_0*/ + +/*--------------------------------Public APIs---------------------------------*/ + +/***************************************************************************//** + The MRV32_clear_gpr_ecc_errors() function clears single bit ECC errors on the + GPRs. The ECC block does not write back corrected data to memory. Hence, when + ECC is enabled for the GPRs and if that data has a single bit error then the + data coming out of the ECC block is corrected and will not have the error, but + the data source will still have the error. Therefore, if data has a single bit + error, then the corrected data must be written back to prevent the single bit + error from becoming a double bit error. Clear the pending interrupt bit after + this using MRV32_mgeci_clear_irq() function to complete the ECC error handling. + + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline void MRV32_clear_gpr_ecc_errors(void) +{ + uint32_t temp; + + __asm__ __volatile__ ( + "sw x31, %0" + :"=m" (temp)); + + __asm__ volatile ( + "mv x31, x1;" + "mv x1, x31;" + + "mv x31, x2;" + "mv x2, x31;" + + "mv x31, x3;" + "mv x3, x31;" + + "mv x31, x4;" + "mv x4, x31;" + + "mv x31, x5;" + "mv x5, x31;" + + "mv x31, x6;" + "mv x6, x31;" + + "mv x31, x7;" + "mv x7, x31;" + + "mv x31, x8;" + "mv x8, x31;" + + "mv x31, x9;" + "mv x9, x31;" + + "mv x31, x10;" + "mv x10, x31;" + + "mv x31, x11;" + "mv x11, x31;" + + "mv x31, x12;" + "mv x12, x31;" + + "mv x31, x13;" + "mv x13, x31;" + + "mv x31, x14;" + "mv x14, x31;" + + "mv x31, x15;" + "mv x15, x31;" + + "mv x31, x16;" + "mv x16, x31;" + + "mv x31, x17;" + "mv x17, x31;" + + "mv x31, x18;" + "mv x18, x31;" + + "mv x31, x19;" + "mv x19, x31;" + + "mv x31, x20;" + "mv x20, x31;" + + "mv x31, x21;" + "mv x21, x31;" + + "mv x31, x22;" + "mv x22, x31;" + + "mv x31, x23;" + "mv x23, x31;" + + "mv x31, x24;" + "mv x24, x31;" + + "mv x31, x25;" + "mv x25, x31;" + + "mv x31, x26;" + "mv x26, x31;" + + "mv x31, x27;" + "mv x27, x31;" + + "mv x31, x28;" + "mv x28, x31;" + + "mv x31, x29;" + "mv x29, x31;" + + "mv x31, x30;" + "mv x30, x31;"); + + __asm__ __volatile__ ( + "lw x31, %0;" + : + :"m" (temp)); +} + + +/***************************************************************************//** + The MRV32_mgeui_clear_irq() function clears the GPR ECC Uncorrectable + Interrupt. MGEUI interrupt is available only when ECC is enabled in the MIV_RV32 + IP configurator. + + @return + This function does not return any value. + */ +static inline void MRV32_mgeui_clear_irq(void) +{ + clear_csr(mip, MRV32_MGEUIE_IRQn); +} + +/***************************************************************************//** + The MRV32_mgeci_clear_irq() function clears the GPR ECC Correctable Interrupt + MGECI interrupt is available only when ECC is enabled in the MIV_RV32 IP + configurator. + + @return + This function does not return any value. + */ +static inline void MRV32_mgeci_clear_irq(void) +{ + clear_csr(mip, MRV32_MGECIE_IRQn); +} + +/***************************************************************************//** + The MRV_enable_local_irq() function enables the local interrupts. It takes a + mask value as input. For each set bit in the mask value, the corresponding + interrupt bit in the MIE register is enabled. + + MRV_enable_local_irq( MRV32_SOFT_IRQn | MRV32_TIMER_IRQn | MRV32_EXT_IRQn | + MRV32_MSYS_EIE0_IRQn | + MRV32_MSYS_SUBSYS_IRQn); + */ +static inline void MRV_enable_local_irq(uint32_t mask) +{ + set_csr(mie, mask); +} + +/***************************************************************************//** + The MRV_disable_local_irq() function disables the local interrupts. It takes a + mask value as input. For each set bit in the mask value, the corresponding + interrupt bit in the MIE register is disabled. + + MRV_disable_local_irq( MRV32_SOFT_IRQn | MRV32_TIMER_IRQn | MRV32_EXT_IRQn | + MRV32_MSYS_EIE0_IRQn | + MRV32_MSYS_SUBSYS_IRQn); + */ +static inline void MRV_disable_local_irq(uint32_t mask) +{ + clear_csr(mie, mask); +} +#endif /* MIV_LEGACY_RV32 */ + +/***************************************************************************//** + The MRV_enable_interrupts() function enables all interrupts by setting the + machine mode interrupt enable bit in MSTATUS register. + + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline void MRV_enable_interrupts(void) +{ + set_csr(mstatus, MSTATUS_MIE); +} + +/***************************************************************************//** + The MRV_disable_interrupts() function disables all interrupts by clearing the + machine mode interrupt enable bit in MSTATUS register. + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline void MRV_disable_interrupts(void) +{ + clear_csr(mstatus, MSTATUS_MPIE); + clear_csr(mstatus, MSTATUS_MIE); +} + +/***************************************************************************//** + The MRV_read_mtvec_base() function reads the mtvec base value, which is the + addr used when an interrupt/trap occurs. In the mtvec register, [31:2] is the + BASE address. NOTE: The BASE address must be aligned on a 4B boundary. + + @param + The function does not take any parameters. + + @return + The function returns the value of the BASE field [31:2] as an unsigned 32-bit + value. + */ + +#ifndef MIV_LEGACY_RV32 +#ifndef MIV_RV32_v3_0 +static inline uint32_t MRV_read_mtvec_base (void) +{ + uint32_t mtvec_addr_base = read_csr(mtvec); + return mtvec_addr_base & MTVEC_BASE_ADDR_MASK; +} + +/***************************************************************************//** + The MRV_set_mtvec_base() function takes the mtvec_base address as a unsigned int + and writes the value into the BASE field [31:2] in the mtvec CSR, MODE[1:0] + is Read-only. BASE is 4B aligned, so the lowest 2 bits of mtvec_base are + ignored. + + @param mtvec_base + Any legal value is passed into the function, and it is used as the trap_entry + for interrupts. The PC jumps to this address provided when an interrupt occurs. + In case of vectored interrupts, the address value mentioned in the vector + table under the MIE Register Map is updated to the value passed to this + function parameter. + + @return + This function does not return any value. + */ +static inline void MRV_set_mtvec_base (uint32_t mtvec_base) +{ + mtvec_base = mtvec_base & MTVEC_BASE_ADDR_MASK; + write_csr(mtvec, mtvec_base); +} +#endif /*MIV_RV32_v3_0*/ +#endif /*MIV_LEGACY_RV32*/ + +/***************************************************************************//** + The MRV_read_mtime() function returns the current MTIME register value. + */ +static inline uint64_t MRV_read_mtime(void) +{ + volatile uint32_t hi = 0u; + volatile uint32_t lo = 0u; + + /* when mtime lower word is 0xFFFFFFFF, there will be rollover and + * returned value could be wrong. */ + do { + hi = MTIMEH; + lo = MTIME; + } while(hi != MTIMEH); + + return((((uint64_t)MTIMEH) << 32u) | lo); +} + +/***************************************************************************//** + The MRV_raise_soft_irq() function raises a synchronous software interrupt + by writing into the MSIP register. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV_raise_soft_irq(void) +{ + set_csr(mie, MIP_MSIP); /* Enable software interrupt bit */ + +#ifdef MIV_LEGACY_RV32 + /* You need to make sure that the global interrupt is enabled */ + MSIP = 0x01; /* raise soft interrupt */ +#else + /* Raise soft IRQ on MIV_RV32 processor */ + SUBSYS->soft_reg |= SUBSYS_SOFT_IRQ; +#endif +} + +/***************************************************************************//** + The MRV_clear_soft_irq() function clears a synchronous software interrupt + by clearing the MSIP register. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV_clear_soft_irq(void) +{ +#ifdef MIV_LEGACY_RV32 + MSIP = 0x00u; /* clear soft interrupt */ +#else + /* Clear soft IRQ on MIV_RV32 processor */ + SUBSYS->soft_reg &= ~SUBSYS_SOFT_IRQ; +#endif +} + +/***************************************************************************//** + System tick handler. This handler function gets called when the Machine + timer interrupt asserts. An implementation of this function must be provided + by the application to implement the application specific machine timer + interrupt handling. If application does not provide such implementation, the + weakly linked handler stub function implemented in riscv_hal_stubs.c gets + linked. + */ +void SysTick_Handler(void); + +/***************************************************************************//** + System timer tick configuration. + Configures the machine timer to generate a system tick interrupt at regular + intervals. Takes the number of system clock ticks between interrupts. + + Though this function can take any valid ticks value as parameter, we expect + that, for all practical purposes, a small tick value (to generate periodic + interrupts every few miliseconds) is passed. If you need to generate periodic + events in the range of seconds or more, you may use the SysTick_Handler() to + further count the number of interrupts and hence the larger time intervals. + + @param ticks + This is the number of ticks or clock cycles which are counted down from the + interrupt to be triggered. + + @return + Returns 0 if successful. + Returns 1 if the interrupt interval is not achieved. + */ +uint32_t MRV_systick_config(uint64_t ticks); + +#ifdef __cplusplus +} +#endif +#endif /* RISCV_HAL_H */ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv_rv32_hal_version.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv_rv32_hal_version.h new file mode 100644 index 0000000..4922bf2 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv_rv32_hal_version.h @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_hal_version.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware Abstraction Layer functions for Mi-V soft processors + * + */ + +#ifndef MIV_RV32_HAL_VERSION_H +#define MIV_RV32_HAL_VERSION_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MIV_RV32_HAL_VERSION_MAJOR 4 +#define MIV_RV32_HAL_VERSION_MINOR 2 +#define MIV_RV32_HAL_VERSION_PATCH 100 + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv_rv32_init.c b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv_rv32_init.c new file mode 100644 index 0000000..85f8aca --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv_rv32_init.c @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_init.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor memory section initializations and start-up code. + * + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern void main(void); + +void _init(void) +{ + /* This function is a placeholder for the case where some more hardware + * specific initializations are required before jumping into the application + * code. You can implement it here. */ + + /* Jump to the application code after all initializations are completed */ + main(); +} + +/* Function called after main() finishes */ +void +_fini(void) +{ +} + +#ifdef __cplusplus +} +#endif + diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv_rv32_plic.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv_rv32_plic.h new file mode 100644 index 0000000..3fd4103 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv_rv32_plic.h @@ -0,0 +1,214 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_plic.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V legacy RV32 soft processor PLIC access data structures and + * functions. + * Legacy RV32 soft processors are DEPRICATED. + * Migrate to MIV_RV32 v3.0 or later. + * + */ +#ifndef RISCV_PLIC_H +#define RISCV_PLIC_H + +#include +#include "miv_rv32_regs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================== + * Interrupt numbers: + */ +#ifdef MIV_LEGACY_RV32 +typedef enum +{ + MRV_NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + External_3_IRQn = 3, + External_4_IRQn = 4, + External_5_IRQn = 5, + External_6_IRQn = 6, + External_7_IRQn = 7, + External_8_IRQn = 8, + External_9_IRQn = 9, + External_10_IRQn = 10, + External_11_IRQn = 11, + External_12_IRQn = 12, + External_13_IRQn = 13, + External_14_IRQn = 14, + External_15_IRQn = 15, + External_16_IRQn = 16, + External_17_IRQn = 17, + External_18_IRQn = 18, + External_19_IRQn = 19, + External_20_IRQn = 20, + External_21_IRQn = 21, + External_22_IRQn = 22, + External_23_IRQn = 23, + External_24_IRQn = 24, + External_25_IRQn = 25, + External_26_IRQn = 26, + External_27_IRQn = 27, + External_28_IRQn = 28, + External_29_IRQn = 29, + External_30_IRQn = 30, + External_31_IRQn = 31 +} IRQn_Type; + +#define EXT_INTR_SOURCES 31 + +/*============================================================================== + * PLIC: Platform Level Interrupt Controller + */ +#define PLIC_BASE_ADDR 0x40000000UL + +typedef struct +{ + volatile uint32_t PRIORITY_THRESHOLD; + volatile uint32_t CLAIM_COMPLETE; + volatile uint32_t reserved[1022]; +} MRV_IRQ_Target_Type; + +typedef struct +{ + volatile uint32_t ENABLES[32]; +} MRV_Target_Enables_Type; + +typedef struct +{ + /*-------------------- Source Priority --------------------*/ + volatile uint32_t SOURCE_PRIORITY[1024]; + + /*-------------------- Pending array --------------------*/ + volatile const uint32_t PENDING_ARRAY[32]; + volatile uint32_t RESERVED1[992]; + + /*-------------------- Target enables --------------------*/ + volatile MRV_Target_Enables_Type TARGET_ENABLES[15808]; + + volatile uint32_t RESERVED2[16384]; + + /*--- Target Priority threshold and claim/complete---------*/ + MRV_IRQ_Target_Type TARGET[15872]; + +} PLIC_Type; + +#define PLIC ((PLIC_Type *)PLIC_BASE_ADDR) + +/*============================================================================== + * The function MRV_PLIC_init() initializes the PLIC controller and enables + * the global external interrupt bit. + */ +static inline void MRV_PLIC_init(void) +{ + uint32_t inc; + unsigned long hart_id = read_csr(mhartid); + + /* Disable all interrupts for the current hart. */ + for(inc = 0; inc < ((EXT_INTR_SOURCES + 32u) / 32u); ++inc) + { + PLIC->TARGET_ENABLES[hart_id].ENABLES[inc] = 0; + } + + /* Set priorities to zero. */ + for(inc = 0; inc < EXT_INTR_SOURCES; ++inc) + { + PLIC->SOURCE_PRIORITY[inc] = 0; + } + + /* Set the threshold to zero. */ + PLIC->TARGET[hart_id].PRIORITY_THRESHOLD = 0; + + /* Enable machine external interrupts. */ + set_csr(mie, MIP_MEIP); +} + +/*============================================================================== + * The function MRV_PLIC_enable_irq() enables the external interrupt for the + * interrupt number indicated by the parameter IRQn. + */ +static inline void MRV_PLIC_enable_irq(IRQn_Type IRQn) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t current = PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32]; + current |= (uint32_t)1 << (IRQn % 32); + PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32] = current; +} + +/*============================================================================== + * The function MRV_PLIC_disable_irq() disables the external interrupt for + * the interrupt number indicated by the parameter IRQn. + + * NOTE: + * This function can be used to disable the external interrupt from outside + * external interrupt handler function. + * This function MUST NOT be used from within the External Interrupt handler. + * If you wish to disable the external interrupt while the interrupt handler + * for that external interrupt is executing then you must use the return value + * EXT_IRQ_DISABLE to return from the extern interrupt handler. + */ +static inline void MRV_PLIC_disable_irq(IRQn_Type IRQn) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t current = PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32]; + + current &= ~((uint32_t)1 << (IRQn % 32)); + + PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32] = current; +} + +/*============================================================================== + * The function MRV_PLIC_set_priority() sets the priority for the external + * interrupt for the interrupt number indicated by the parameter IRQn. + */ +static inline void MRV_PLIC_set_priority(IRQn_Type IRQn, uint32_t priority) +{ + PLIC->SOURCE_PRIORITY[IRQn] = priority; +} + +/*============================================================================== + * The function MRV_PLIC_get_priority() returns the priority for the external + * interrupt for the interrupt number indicated by the parameter IRQn. + */ +static inline uint32_t MRV_PLIC_get_priority(IRQn_Type IRQn) +{ + return PLIC->SOURCE_PRIORITY[IRQn]; +} + +/***************************************************************************//** + * MRV_PLIC_clear_pending_irq(void) + * This is only called by the startup hart and only once + * Clears any pending interrupts as PLIC can be in unknown state on startup + */ +static inline void MRV_PLIC_clear_pending_irq(void) +{ + unsigned long hart_id = read_csr(mhartid); + volatile uint32_t int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; + volatile int32_t wait_possible_int; + + while (MRV_NoInterrupt_IRQn != int_num) + { + PLIC->TARGET[hart_id].CLAIM_COMPLETE = int_num; + wait_possible_int = 0xFU; + while (wait_possible_int) + { + wait_possible_int--; + } + + int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; + } +} + +#endif /* MIV_LEGACY_RV32 */ + +#ifdef __cplusplus +} +#endif + +#endif /* RISCV_PLIC_H */ diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv_rv32_regs.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv_rv32_regs.h new file mode 100644 index 0000000..07d58e7 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv_rv32_regs.h @@ -0,0 +1,520 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor register bit mask and shift constants encodings. + * + */ +#ifndef MIV_RV32_REGS_H +#define MIV_RV32_REGS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MSTATUS_UIE 0x00000001UL +#define MSTATUS_SIE 0x00000002UL +#define MSTATUS_HIE 0x00000004UL +#define MSTATUS_MIE 0x00000008UL +#define MSTATUS_UPIE 0x00000010UL +#define MSTATUS_SPIE 0x00000020UL +#define MSTATUS_HPIE 0x00000040UL +#define MSTATUS_MPIE 0x00000080UL +#define MSTATUS_SPP 0x00000100UL +#define MSTATUS_HPP 0x00000600UL +#define MSTATUS_MPP 0x00001800UL +#define MSTATUS_FS 0x00006000UL +#define MSTATUS_XS 0x00018000UL +#define MSTATUS_MPRV 0x00020000UL +#define MSTATUS_SUM 0x00040000UL +#define MSTATUS_MXR 0x00080000UL +#define MSTATUS_TVM 0x00100000UL +#define MSTATUS_TW 0x00200000UL +#define MSTATUS_TSR 0x00400000UL +#define MSTATUS_RES 0x7F800000UL +#define MSTATUS32_SD 0x80000000UL +#define MSTATUS64_SD 0x8000000000000000UL + +#define MCAUSE32_CAUSE 0x7FFFFFFFUL +#define MCAUSE64_CAUSE 0x7FFFFFFFFFFFFFFFUL +#define MCAUSE32_INT 0x80000000UL +#define MCAUSE64_INT 0x8000000000000000UL + +#define MIP_SSIP (1u << IRQ_S_SOFT) +#define MIP_HSIP (1u << IRQ_H_SOFT) +#define MIP_MSIP (1u << IRQ_M_SOFT) +#define MIP_STIP (1u << IRQ_S_TIMER) +#define MIP_HTIP (1u << IRQ_H_TIMER) +#define MIP_MTIP (1u << IRQ_M_TIMER) +#define MIP_SEIP (1u << IRQ_S_EXT) +#define MIP_HEIP (1u << IRQ_H_EXT) +#define MIP_MEIP (1u << IRQ_M_EXT) + +#define PRV_M 3U + +#define VM_MBARE 0U +#define VM_MBB 1U +#define VM_MBBID 2U +#define VM_SV32 8U +#define VM_SV39 9U +#define VM_SV48 10U + +#define IRQ_S_SOFT 1U +#define IRQ_H_SOFT 2U +#define IRQ_M_SOFT 3U +#define IRQ_S_TIMER 5U +#define IRQ_H_TIMER 6U +#define IRQ_M_TIMER 7U +#define IRQ_S_EXT 9U +#define IRQ_H_EXT 10U +#define IRQ_M_EXT 11U + +#define DEFAULT_RSTVEC 0x00001000 +#define DEFAULT_NMIVEC 0x00001004 +#define DEFAULT_MTVEC 0x00001010 +#define CONFIG_STRING_ADDR 0x0000100C +#define EXT_IO_BASE 0x40000000 +#define DRAM_BASE 0x80000000 + +#ifdef __riscv + +#if __riscv_xlen == 64 +# define MSTATUS_SD MSTATUS64_SD +# define SSTATUS_SD SSTATUS64_SD +# define MCAUSE_INT MCAUSE64_INT +# define MCAUSE_CAUSE MCAUSE64_CAUSE +# define RISCV_PGLEVEL_BITS 9 +#else +# define MSTATUS_SD MSTATUS32_SD +# define SSTATUS_SD SSTATUS32_SD +# define RISCV_PGLEVEL_BITS 10 +# define MCAUSE_INT MCAUSE32_INT +# define MCAUSE_CAUSE MCAUSE32_CAUSE +#endif + +#define RISCV_PGSHIFT 12U +#define RISCV_PGSIZE (1U << RISCV_PGSHIFT) + +#ifndef __ASSEMBLER__ + +#ifdef __GNUC__ + +#define read_csr(reg) ({ unsigned long __tmp; \ + __asm__ volatile ("csrr %0, " #reg : "=r"(__tmp)); \ + __tmp; }) + +#define write_csr(reg, val) ({ \ + __asm__ volatile ("csrw " #reg ", %0" :: "rK"(val)); }) + +#define swap_csr(reg, val) ({ unsigned long __tmp; \ + __asm__ volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "rK"(val)); \ + __tmp; }) + +#define set_csr(reg, bit) ({ unsigned long __tmp; \ + __asm__ volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ + __tmp; }) + +#define clear_csr(reg, bit) ({ unsigned long __tmp; \ + __asm__ volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ + __tmp; }) + +#ifdef __riscv_atomic + +#define MASK(nr) (1UL << nr) +#define MASK_NOT(nr) (~(1UL << nr)) + +/** + * atomic_read - read atomic variable + * @v: pointer of type int + * + * Atomically reads the value of @v. + */ +static inline int atomic_read(const int *v) +{ + return *((volatile int *)(v)); +} + +/** + * atomic_set - set atomic variable + * @v: pointer of type int + * @i: required value + * + * Atomically sets the value of @v to @i. + */ +static inline void atomic_set(int *v, int i) +{ + *v = i; +} + +/** + * atomic_add - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v. + */ +static inline void atomic_add(int i, int *v) +{ + __asm__ __volatile__ ( + "amoadd.w zero, %1, %0" + : "+A" (*v) + : "r" (i)); +} + +static inline int atomic_fetch_add(unsigned int mask, int *v) +{ + int out; + + __asm__ __volatile__ ( + "amoadd.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_sub - subtract integer from atomic variable + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v. + */ +static inline void atomic_sub(int i, int *v) +{ + atomic_add(-i, v); +} + +static inline int atomic_fetch_sub(unsigned int mask, int *v) +{ + int out; + + __asm__ __volatile__ ( + "amosub.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_add_return - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v and returns the result + */ +static inline int atomic_add_return(int i, int *v) +{ + register int c; + __asm__ __volatile__ ( + "amoadd.w %0, %2, %1" + : "=r" (c), "+A" (*v) + : "r" (i)); + return (c + i); +} + +/** + * atomic_sub_return - subtract integer from atomic variable + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v and returns the result + */ +static inline int atomic_sub_return(int i, int *v) +{ + return atomic_add_return(-i, v); +} + +/** + * atomic_inc - increment atomic variable + * @v: pointer of type int + * + * Atomically increments @v by 1. + */ +static inline void atomic_inc(int *v) +{ + atomic_add(1, v); +} + +/** + * atomic_dec - decrement atomic variable + * @v: pointer of type int + * + * Atomically decrements @v by 1. + */ +static inline void atomic_dec(int *v) +{ + atomic_add(-1, v); +} + +static inline int atomic_inc_return(int *v) +{ + return atomic_add_return(1, v); +} + +static inline int atomic_dec_return(int *v) +{ + return atomic_sub_return(1, v); +} + +/** + * atomic_sub_and_test - subtract value from variable and test result + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v and returns + * true if the result is zero, or false for all + * other cases. + */ +static inline int atomic_sub_and_test(int i, int *v) +{ + return (atomic_sub_return(i, v) == 0); +} + +/** + * atomic_inc_and_test - increment and test + * @v: pointer of type int + * + * Atomically increments @v by 1 + * and returns true if the result is zero, or false for all + * other cases. + */ +static inline int atomic_inc_and_test(int *v) +{ + return (atomic_inc_return(v) == 0); +} + +/** + * atomic_dec_and_test - decrement and test + * @v: pointer of type int + * + * Atomically decrements @v by 1 and + * returns true if the result is 0, or false for all other + * cases. + */ +static inline int atomic_dec_and_test(int *v) +{ + return (atomic_dec_return(v) == 0); +} + +/** + * atomic_add_negative - add and test if negative + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v and returns true + * if the result is negative, or false when + * result is greater than or equal to zero. + */ +static inline int atomic_add_negative(int i, int *v) +{ + return (atomic_add_return(i, v) < 0); +} + +static inline int atomic_xchg(int *v, int n) +{ + register int c; + __asm__ __volatile__ ( + "amoswap.w %0, %2, %1" + : "=r" (c), "+A" (*v) + : "r" (n)); + return c; +} + +/** + * atomic_and - Atomically clear bits in atomic variable + * @mask: Mask of the bits to be retained + * @v: pointer of type int + * + * Atomically retains the bits set in @mask from @v + */ +static inline void atomic_and(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoand.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_and(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoand.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_or - Atomically set bits in atomic variable + * @mask: Mask of the bits to be set + * @v: pointer of type int + * + * Atomically sets the bits set in @mask in @v + */ +static inline void atomic_or(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoor.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_or(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoor.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_xor - Atomically flips bits in atomic variable + * @mask: Mask of the bits to be flipped + * @v: pointer of type int + * + * Atomically flips the bits set in @mask in @v + */ +static inline void atomic_xor(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoxor.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_xor(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoxor.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * test_and_set_bit - Set a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_set_bit(int nr, volatile unsigned long *addr) +{ + unsigned long __res, __mask; + __mask = MASK(nr); + __asm__ __volatile__ ( \ + "amoor.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to clear + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_clear_bit(int nr, volatile unsigned long *addr) +{ + unsigned long __res, __mask; + __mask = MASK_NOT(nr); + __asm__ __volatile__ ( \ + "amoand.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * test_and_change_bit - Change a bit and return its old value + * @nr: Bit to change + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_change_bit(int nr, volatile unsigned long *addr) +{ + + unsigned long __res, __mask; + __mask = MASK(nr); + __asm__ __volatile__ ( \ + "amoxor.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * set_bit - Atomically set a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * This function is atomic and may not be reordered. + */ + +static inline void set_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOOR.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK(nr))); +} + +/** + * clear_bit - Clears a bit in memory + * @nr: Bit to clear + * @addr: Address to start counting from + * + * clear_bit() is atomic and may not be reordered. + */ +static inline void clear_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOAND.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK_NOT(nr))); +} + +/** + * change_bit - Toggle a bit in memory + * @nr: Bit to change + * @addr: Address to start counting from + * + * change_bit() is atomic and may not be reordered. + */ +static inline void change_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOXOR.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK(nr))); +} + +#endif /* __riscv_atomic */ + +#endif /* __GNUC__ */ + +#endif /* __ASSEMBLER__ */ + +#endif /* __riscv */ + +#ifdef __cplusplus +} +#endif + +#endif /* RISCV_REGS_H */ diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv_rv32_stubs.c b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv_rv32_stubs.c new file mode 100644 index 0000000..e26ecfc --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv_rv32_stubs.c @@ -0,0 +1,243 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_stubs.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Stubs for the Mi-V soft processor Interrupt handler. + * + * The functions below will only be linked with the application code if the user + * does not provide an implementation for these functions. These functions are + * defined with weak linking so that they can be overridden by a function with + * same prototype in the user's application code. + * + */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +__attribute__((weak)) void Software_IRQHandler(void) +{ + _exit(10); +} + +__attribute__((weak)) void SysTick_Handler(void) +{ + /* Default handler */ +} + +#ifdef MIV_LEGACY_RV32 +__attribute__((weak)) uint8_t Invalid_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_1_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_2_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_3_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_4_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_5_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_6_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_7_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_8_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_9_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_10_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_11_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_12_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_13_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_14_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_15_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_16_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_17_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_18_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_19_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_20_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_21_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_22_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_23_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_24_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_25_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_26_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_27_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_28_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_29_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_30_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_31_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +#else +__attribute__((weak)) void External_IRQHandler(void) +{ +} +__attribute__((weak)) void MGECI_IRQHandler(void) +{ +} +__attribute__((weak)) void MGEUI_IRQHandler(void) +{ +} +__attribute__((weak)) void SUBSYS_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI0_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI1_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI2_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI3_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI4_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI5_IRQHandler(void) +{ +} +__attribute__((weak)) void Reserved_IRQHandler(void) +{ + _exit(10); +} +#ifndef MIV_RV32_V3_0 /* For MIV_RV32 v3.0 */ +__attribute__((weak)) void MSYS_EI6_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI7_IRQHandler(void) +{ +} +__attribute__((weak)) void SUBSYSR_IRQHandler(void) +{ +} +#endif /* MIV_RV32_V3_0 */ +#endif /* MIV_LEGACY_RV32 */ + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv_rv32_subsys.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv_rv32_subsys.h new file mode 100644 index 0000000..509f13b --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv_rv32_subsys.h @@ -0,0 +1,293 @@ +/******************************************************************************* + * Copyright 2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_subsys.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor SUBSYS regsiter description and API fuctions. + * + */ +#ifndef MIV_RV32_SUBSYS_H +#define MIV_RV32_SUBSYS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef MIV_LEGACY_RV32 +#define MGEUI 16U +#define MGECI 17U +#define MSYS_EI0 24U +#define MSYS_EI1 25U +#define MSYS_EI2 26U +#define MSYS_EI3 27U +#define MSYS_EI4 28U +#define MSYS_EI5 29U + +#define MGEUI_MEIP (1u << MGEUI) +#define MGECI_MEIP (1u << MGECI) +#define MSYS_EI0IP (1u << MSYS_EI0) +#define MSYS_EI1IP (1u << MSYS_EI1) +#define MSYS_EI2IP (1u << MSYS_EI2) +#define MSYS_EI3IP (1u << MSYS_EI3) +#define MSYS_EI4IP (1u << MSYS_EI4) +#define MSYS_EI5IP (1u << MSYS_EI5) + +#define MIV_LOCAL_IRQ_MIN 16 +#ifndef MIV_RV32_V3_0 /*For MIV_RV32 v3.1*/ +#define SUBSYSR 22U +#define SUBSYS_EI 23U +#define MSYS_EI6 30U +#define MSYS_EI7 31U +#define MIV_SUBSYSR (1u << SUBSYSR) +#define MIV_SUBSYS (1u << SUBSYS_EI) +#define MSYS_EI6IP (1u << MSYS_EI6) +#define MSYS_EI7IP (1u << MSYS_EI7) +#define MIV_LOCAL_IRQ_MAX 31 + +#else /* MIV_RV32_V3_0 */ +#define MIV_LOCAL_IRQ_MAX 29 +#define SUBSYS_EI 30U +#define MIP_SUBSYS_REG (1u << SUBSYS_EI) + +#endif /* MIV_RV32_V3_0 */ +#endif /* MIV_LEGACY_RV32 */ + +#ifdef MIV_LEGACY_RV32 +#define MIV_LOCAL_IRQ_MAX 0U +#define MIV_LOCAL_IRQ_MIN 0U +#endif /* MIV_LEGACY_RV32 */ + +#ifdef __cplusplus +} +#endif + +/*-------------------------------------------------------------------------*//** + SUBSYS Register Configuration + ======================================= + For the SUBSYS registers configutation, the following definitions are used in + the SUBSUS API functions. For example, to raise soft interrupts, enable parity + checks, soft reset, and so on. + + | Configuration | Value | Description | + |--------------------------|-------|------------------------------------------------| + | SUBSYS_SOFT_REG_GRP_DED | 0x04 | Mask for the Core GPR DED Reset Register | + | SUBSYS_CFG_PARITY_CHECK | 0x01 | Use to set or clear the parity check on the TCM | + | SUBSYS_SOFT_RESET | 0x01 | Use the SUBSYS soft reset the MIV_RV32 IP core | + | SUBSYS_SOFT_IRQ | 0x02 | Use to raise a software interrupt through SUBSYS| + */ +/*Mask for the Core GPR DED Reset Register*/ +#define SUBSYS_SOFT_REG_GRP_DED 0x04U + +/*Use to set or clear the parity check on the TCM*/ +#define SUBSYS_CFG_PARITY_CHECK 0x01U + +/*Use the SUBSYS soft reset the MIV_RV32 IP core*/ +#define SUBSYS_SOFT_RESET 0x01U + +/*Use to raise a software interrupt through SUBSYS*/ +#define SUBSYS_SOFT_IRQ 0x02U + +/*-------------------------------------------------------------------------*//** + SUBSYS Interrupt Request Masks + ======================================= + The following values correspond to the bit value of the SUBSYS interrupt + enable and interrupt pending register. + + | Interrupt Mask | Value | Description | + |----------------------------|---------|-------------------------------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | TCM ECC controllable error irq enable | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | TCM ECC uncontrollable error irq enable | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | AXI write response error irq enable | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | Icache ECC Correctable error irq | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | Icache ECC Uncorrectable error irq | + | SUBSYS_BASE_ADDR | 0x6000u | Base address of the SUBSYS | + */ +/* TCM ECC correctable error irq enable mask value */ +#define SUBSYS_TCM_ECC_CE_IRQ 0x01u + +/* TCMECC uncorrectable error irq enable */ +#define SUBSYS_TCM_ECC_UCE_IRQ 0x02u + +/* AXI write response error irq enable */ +#define SUBSYS_AXI_WR_RESP_IRQ 0x10u + +/*Icache ECC Correctable error irq*/ +#define SUBSYS_ICACHE_ECC_CE_IRQ 0x40u + +/*Icache ECC Uncorrectable error irq*/ +#define SUBSYS_ICACHE_ECC_UCE_IRQ 0x80u + +/*Base address of the SUBSYS*/ +#define SUBSYS_BASE_ADDR 0x00006000UL + +/***************************************************************************//** + Subsys contains interrupt enable, interrupt pending and Subsys registers + which can be used to enable SUBSYS specific features such as ECC for vaious + memories. For more available features refer to the MIV_RV32 User Guide +*/ +typedef struct +{ + volatile uint32_t cfg; /*Parity is not supported by MIV_RV32 v3.1 and MIV_RV32 v3.0.100*/ + volatile uint32_t reserved0[3]; + volatile uint32_t irq_en; /*offset 0x10*/ + volatile uint32_t irq_pend; + volatile uint32_t reserved1[2]; + volatile uint32_t soft_reg; /*offset 0x20*/ +} SUBSYS_Type; + +#define SUBSYS ((SUBSYS_Type *)SUBSYS_BASE_ADDR) + +/***************************************************************************//** + The MRV32_subsys_enable_irq() function initializes the SUBSYS interrupts. It + takes the logical OR of the following defined IRQ masks as a parameter. + + @param irq_mask + | irq_mask | Value | + |------------------------|------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | + Use logical OR values of one or more interrupts to enable them in the SUBSYS + @return + This function does not return any value. + */ +static inline void MRV32_subsys_enable_irq(uint32_t irq_mask) +{ + SUBSYS->irq_en |= irq_mask; +} + +/***************************************************************************//** + The MRV32_subsys_disable_irq() function disables the SUBSYS interrupts. It + takes the logical OR of the following defined IRQ masks as a parameter. + + @param irq_mask + | irq_mask | Value | + |------------------------|------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | + Use logical OR values of one or more interrupts to disable them in the SUBSYS + @return + This function does not return any value. + */ +static inline void MRV32_subsys_disable_irq(uint32_t irq_mask) +{ + SUBSYS->irq_en &= ~irq_mask; +} + +/***************************************************************************//** + The MRV32_subsys_clear_irq() function clears the SUBSYS interrupts, which was + triggered. It takes the logical OR of the following defined IRQ masks as a + parameter. + @param irq_mask + | irq_mask | Value | + |------------------------|------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | + Use logical OR values of one or more interrupts to disable them in the SUBSYS + @return + This function does not return any value. + */ +static inline void MRV32_subsys_clear_irq(uint32_t irq_mask) +{ + SUBSYS->irq_pend |= irq_mask; +} + +/***************************************************************************//** + The MRV32_subsys_irq_cause() function returns the irq_pend register value which + is present in the SUBSYS. This is be used to check which irq_mask value + caused the SUBSYS interrupt to occur. + @param + This function does not take any parameters + + @return + This function returns the irq_pend regsiter value. +*/ +static inline uint32_t MRV32_subsys_irq_cause() +{ + return SUBSYS->irq_pend; +} + +/***************************************************************************//** + The MRV32_is_gpr_ded() function returns the core_gpr_ded_reset_reg bit value. + When ECC is enabled, the core_gpr_ded_reset_reg is set when the core was + reset due to GPR DED error. + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline uint32_t MRV32_is_gpr_ded(void) +{ + return((SUBSYS->soft_reg & SUBSYS_SOFT_REG_GRP_DED) >> 0x02u); +} + +/***************************************************************************//** + The MRV32_clear_gpr_ded() function must be used to clear the + core_gpr_ded_reset_reg bit. When ECC is enabled, the core_gpr_ded_reset_reg is + set when the core was previously reset due to GPR DED error. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV32_clear_gpr_ded(void) +{ + SUBSYS->soft_reg &= ~SUBSYS_SOFT_REG_GRP_DED; +} + +/***************************************************************************//** + The MRV32_enable_parity_check() function is used to enable parity check on + the TCM and it's interface transactions. This feature is not available on + MIV_RV32 v3.1 and MIV_RV32 v3.0.100 + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV32_enable_parity_check(void) +{ + SUBSYS->cfg |= SUBSYS_CFG_PARITY_CHECK; +} + +/***************************************************************************//** + The MRV32_disable_parity_check() function is used to disable parity check on + the TCM and it's interface transactions. + @param + This function does not take any parameters + + @return + This function does not return any value. + + */ +static inline void MRV32_disable_parity_check(void) +{ + SUBSYS->cfg &= ~SUBSYS_CFG_PARITY_CHECK; +} + +/***************************************************************************//** + The MRV32_cpu_soft_reset() function is used to cause a soft cpu reset on + the MIV_RV32 soft processor core. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV32_cpu_soft_reset(void) +{ + SUBSYS->soft_reg |= SUBSYS_SOFT_RESET; +} +#endif /* MIV_RV32_SUBSYS_H */ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv_rv32_syscall.c b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv_rv32_syscall.c new file mode 100644 index 0000000..bd2f881 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/miv_rv32_syscall.c @@ -0,0 +1,364 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_syscall.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Stubs for system calls. + * + */ +#include +#include +#include +#include +#include "miv_rv32_hal.h" + +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +#include + +#ifndef LEGACY_DIR_STRUCTURE +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" +#else +#include "core_uart_apb.h" +#endif + +#endif /*MSCC_STDIO_THRU_CORE_UART_APB*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + +/*------------------------------------------------------------------------------ + * CoreUARTapb instance data for the CoreUARTapb instance used for standard + * output. + */ +static UART_instance_t g_stdio_uart; + +/*============================================================================== + * Flag used to indicate if the UART driver needs to be initialized. + */ +static int g_stdio_uart_init_done = 0; + +/* + * Disable semihosting apis + */ +#pragma import(__use_no_semihosting_swi) + +/*============================================================================== + * sendchar() + */ +int sendchar(int ch) +{ + /*-------------------------------------------------------------------------- + * Initialize the UART driver if it is the first time this function is + * called. + */ + if ( !g_stdio_uart_init_done ) + { + /****************************************************************************** + * Baud value: + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + UART_init( &g_stdio_uart, + MSCC_STDIO_UART_BASE_ADDR, + ((SYS_CLK_FREQ/(16 * MSCC_STDIO_BAUD_VALUE))-1), + (DATA_8_BITS | NO_PARITY)); + + g_stdio_uart_init_done = 1; + } + + /*-------------------------------------------------------------------------- + * Output text to the UART. + */ + UART_send( &g_stdio_uart, (uint8_t *)&ch, 1 ); + + return (ch); +} + +/*============================================================================== + * getachar() + */ +int getachar(void) +{ + uint8_t rx_size; + uint8_t rx_byte; + + if ( !g_stdio_uart_init_done ) + { + /****************************************************************************** + * Baud value: + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + UART_init( &g_stdio_uart, + MSCC_STDIO_UART_BASE_ADDR, + ((SYS_CLK_FREQ/(16 * MSCC_STDIO_BAUD_VALUE))-1), + (DATA_8_BITS | NO_PARITY)); + + g_stdio_uart_init_done = 1; + } + + do + { + rx_size = UART_get_rx(&g_stdio_uart, &rx_byte, 1); + } while(0u == rx_size); + + return rx_byte; +} + +#endif /*MSCC_STDIO_THRU_CORE_UART_APB*/ + +#undef errno +static int errno; + +static char *__env[1] = { 0 }; +char **environ = __env; + +void write_hex(int fd, uint32_t hex) +{ + char towrite; + + write( fd , "0x", 2U ); + + for (uint32_t ii = 8U ; ii > 0U; ii--) + { + uint32_t jj = ii-1U; + uint8_t digit = ((hex & (0xFU << (jj*4U))) >> (jj*4U)); + towrite = digit < 0xAU ? (0x48U + digit) : (0x65U + (digit - 0xAU)); + write( fd, &towrite, 1U); + } +} + + +#ifdef GDB_TESTING +void __attribute__((optimize("O0"))) _exit(int code) +#else +void _exit(int code) +#endif +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + const char * message = "\nProgam has exited with code:"; + + write(STDERR_FILENO, message, strlen(message)); + write_hex(STDERR_FILENO, code); +#endif + + while (1){}; +} + +void *_sbrk(ptrdiff_t incr) +{ + extern char _end; + extern char _heap_end; + extern char __heap_start; + extern char __heap_end; + static char *curbrk = &_end; + void * ret = NULL; + + /* + * Did we allocated memory for the heap in the linker script? + * You need to set HEAP_SIZE to a non-zero value in your linker script if + * the following assertion fires. + */ + ASSERT(&__heap_end > &__heap_start); + + if (((curbrk + incr) < &_end) || ((curbrk + incr) > &_heap_end)) + { + errno = ENOMEM; + ret = ((char *) - 1); + } + else + { + curbrk += incr; + ret = curbrk - incr; + } + + /* + * Did we run out of heap? + * You need to increase the heap size in the linker script if the following + * assertion fires. + * */ + ASSERT(curbrk <= &__heap_end); + + return(ret); +} + +int _isatty(int fd) +{ + int ret = 0; + + if (fd <= 2) /* one of stdin, stdout, stderr */ + { + ret = 1; + } + else + { + errno = EBADF; + ret = 0; + } + + return(ret); +} + +static int stub(int err) +{ + errno = err; + return -1; +} + +int _open(const char* name, int flags, int mode) +{ + return stub(ENOENT); +} + +int _openat(int dirfd, const char* name, int flags, int mode) +{ + return stub(ENOENT); +} + +int _close(int fd) +{ + return stub(EBADF); +} + +int _execve(const char* name, char* const argv[], char* const env[]) +{ + return stub(ENOMEM); +} + +int _fork(void) +{ + return stub(EAGAIN); +} + +int _fstat(int fd, struct stat *st) +{ + int ret = 0; + + if (isatty(fd)) + { + st->st_mode = S_IFCHR; + ret = 0; + } + else + { + ret = stub(EBADF); + } + + return ret; +} + +int _getpid(void) +{ + return 1; +} + +int _kill(int pid, int sig) +{ + return stub(EINVAL); +} + +int _link(const char *old_name, const char *new_name) +{ + return stub(EMLINK); +} + +off_t _lseek(int fd, off_t ptr, int dir) +{ + off_t ret = 0; + if (_isatty(fd)) + { + ret = 0; + } + else + { + ret = stub(EBADF); + } + + return ret; +} + +ssize_t _read(int fd, void* ptr, size_t len) +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + + char* ptr1 = (char*)ptr; + + if (_isatty(fd)) + { + int count; + + for (count = 0; count < len; count++) + { + ptr1[count] = getachar(); + sendchar(ptr1[count]); + + /* Return partial buffer if we get EOL */ + if (('\r' == ptr1[count])||('\n' == ptr1[count])) + { + ptr1[count] = '\n'; + return count; + } + } + + return count; /* Filled the buffer */ + } +#endif + + return stub(EBADF); +} + +int _stat(const char* file, struct stat* st) +{ + return stub(EACCES); +} + +clock_t _times(struct tms* buf) +{ + return stub(EACCES); +} + +int _unlink(const char* name) +{ + return stub(ENOENT); +} + +int _wait(int* status) +{ + return stub(ECHILD); +} + +ssize_t _write(int fd, const void* ptr, size_t len) +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + int count_out; + char* ptr1 = (char*)ptr; + + /*-------------------------------------------------------------------------- + * Output text to the UART. + */ + count_out = 0; + while(len--) + { + sendchar(ptr1[count_out]); + count_out++; + } + + errno = 0; + return count_out; + +#else /* MSCC_STDIO_THRU_CORE_UART_APB */ + + return stub(EBADF); + +#endif /* MSCC_STDIO_THRU_CORE_UART_APB */ + +} + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/sample_fpga_design_config.h b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/sample_fpga_design_config.h new file mode 100644 index 0000000..a380d96 --- /dev/null +++ b/applications/user-crypto/miv-rv32-aes-cryptography/src/platform/miv_rv32_hal/sample_fpga_design_config.h @@ -0,0 +1,167 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file sample_fpga_design_config.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Sample design configuration settings + * + */ + /*========================================================================*//** + @mainpage + Example file detailing how the fpga_design_config.h should be constructed + for the SoftConsole project targeted for Mi-V processors. + + @section intro_sec Introduction + The SoftConsole project targeted for Mi-V processors now have an improved + folder structure. Detailed description of the folder structure is available + at https://github.com/Mi-V-Soft-RISC-V/miv-rv32-documentation. + + The fpga_design_config.h must be stored as shown below + /boards//fpga_design_config.h + + Currently this file must be hand crafted when using the Mi-V Soft Processor. + In future, all the design and soft IP configurations will be automatically + generated from the Libero design description data. + + You can use this sample file as an example. + Rename this file from sample_fpga_design_config.h to fpga_design_config.h + and then customize it per your hardware design. + + @section Project configuration Instructions + 1. Change SYS_CLK_FREQ define to frequency of Mi-V Soft processor clock + 2 Add all the soft IP core BASE addresses + 3. Add the peripheral Core Interrupts to Mi-V Soft processor IRQ number + mappings + 4. Define MSCC_STDIO_UART_BASE_ADDR if you want a CoreUARTapb mapped to + STDIO + + **NOTE** + In the legacy folder structures, the file hw_config.h as was used at the + root of the project folder. This file is now depricated. + +*//*=========================================================================*/ + +#ifndef FPGA_DESIGN_CONFIG_H_ +#define FPGA_DESIGN_CONFIG_H_ + +/***************************************************************************//** + * Soft-processor clock definition + * This is the only clock brought over from the Mi-V Libero design. + */ +#ifndef SYS_CLK_FREQ +#define SYS_CLK_FREQ 50000000UL +#endif + +/***************************************************************************//** + * Peripheral base addresses. + * Format of define is: + * __BASE_ADDR + * The field is optional if there is only one instance of the core + * in the design + * MIV_ESS is an extended peripheral subsystem IP core with peripherals + * connections as defined below. + * The system can be further extended by attaching APB peripherals to the + * empty APB slots. + */ +#define MIV_ESS_PLIC_BASE_ADDR 0x70000000UL +#define COREUARTAPB0_BASE_ADDR 0x71000000UL +#define MIV_MTIMER_BASE_ADDR 0x72000000UL +#define MIV_ESS_APBSLOT3_BASE_ADDR 0x73000000UL +#define MIV_ESS_APBSLOT4_BASE_ADDR 0x74000000UL +#define COREGPIO_OUT_BASE_ADDR 0x75000000UL +#define CORESPI_BASE_ADDR 0x76000000UL +#define MIV_ESS_uDMA_BASE_ADDR 0x78000000UL +#define MIV_ESS_WDOG_BASE_ADDR 0x79000000UL +#define MIV_ESS_I2C_BASE_ADDR 0x7A000000UL +#define MIV_ESS_APBSLOTB_BASE_ADDR 0x7B000000UL +#define MIV_ESS_APBSLOTC_BASE_ADDR 0x7C000000UL +#define MIV_ESS_APBSLOTD_BASE_ADDR 0x7D000000UL +#define MIV_ESS_APBSLOTE_BASE_ADDR 0x7E000000UL +#define MIV_ESS_APBSLOTF_BASE_ADDR 0x7F000000UL + +/***************************************************************************//** + * Peripheral Interrupts are mapped to the corresponding Mi-V Soft processor + * interrupt in the Libero design. + * + * On the legacy RV32 cores, there can be up to 31 external interrupts (IRQ[30:0] + * pins). The legacy RV32 Soft processor external interrupts are defined in the + miv_rv32_plic.h + * + * These are of the form + * typedef enum +{ + NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + . + . + . + External_31_IRQn = 31 +} IRQn_Type; + + On the legacy RV32 processors, the PLIC identifies the interrupt and passes it + on to the processor core. The interrupt 0 is not used. The pin IRQ[0] should + map to External_1_IRQn likewise IRQ[30] should map to External_31_IRQn + +e.g + +#define TIMER0_IRQn External_30_IRQn +#define TIMER1_IRQn External_31_IRQn + + The MIV_RV32 soft processor has up to six optional system interrupts, MSYS_EI[n] + in addition to one EXT_IRQ. + The MIV_RV32 does not have an inbuilt PLIC and all the interrupts are directly + delivered to the processor core, hence unlike legacy RV32 cores, no interrupt + number mapping is necessary on MIV_RV32 core. + */ + +/**************************************************************************** + * Baud value to achieve a 115200 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ +#define BAUD_VALUE_115200 ((SYS_CLK_FREQ / (16 * 115200)) - 1) + +/****************************************************************************** + * Baud value to achieve a 57600 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + #define BAUD_VALUE_57600 ((SYS_CLK_FREQ / (16 * 57600)) - 1) + +/***************************************************************************//** + * Define MSCC_STDIO_THRU_CORE_UART_APB in the project settings if you want the + * standard IOs to be redirected to a terminal via UART. + */ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +/* + * A base address mapping for the STDIO printf/scanf mapping to CortUARTapb + * must be provided if it is being used + * + * e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR + */ +#define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB0_BASE_ADDR + +#ifndef MSCC_STDIO_UART_BASE_ADDR +#error MSCC_STDIO_UART_BASE_ADDR not defined- e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR +#endif + +#ifndef MSCC_STDIO_BAUD_VALUE +/* + * The MSCC_STDIO_BAUD_VALUE define should be set in your project's settings to + * specify the baud value used by the standard output CoreUARTapb instance for + * generating the UART's baud rate if you want a different baud rate from the + * default of 115200 baud + */ +#define MSCC_STDIO_BAUD_VALUE 115200 +#endif /*MSCC_STDIO_BAUD_VALUE*/ + +#endif /* end of MSCC_STDIO_THRU_CORE_UART_APB */ +/******************************************************************************* + * End of user edit section + */ +#endif /* FPGA_DESIGN_CONFIG_H_ */ diff --git a/applications/user-crypto/miv-rv32-ccm-services/.cproject b/applications/user-crypto/miv-rv32-ccm-services/.cproject new file mode 100644 index 0000000..3465f7a --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/.cproject @@ -0,0 +1,332 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-ccm-services/.gitignore b/applications/user-crypto/miv-rv32-ccm-services/.gitignore new file mode 100644 index 0000000..f1b6b72 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/.gitignore @@ -0,0 +1,3 @@ +/.settings/ +/*miv-rv32-imc-debug*/ +/*miv-rv32-imc-release*/ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-ccm-services/.project b/applications/user-crypto/miv-rv32-ccm-services/.project new file mode 100644 index 0000000..8e23413 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/.project @@ -0,0 +1,26 @@ + + + miv-rv32-ccm-services + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/applications/user-crypto/miv-rv32-ccm-services/README.md b/applications/user-crypto/miv-rv32-ccm-services/README.md new file mode 100644 index 0000000..c2a0798 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/README.md @@ -0,0 +1,186 @@ +PolarFire User Crypto CCM Services example +================================================================================ +This example project demonstrates the use of the following User Crypto Services +for demonstrating CBC Counter Mode (CCM) + + - CALSymEncAuthDMA() + - CALMAC() + +CCM is used to provide assurance of the confidentiality and the authenticity +of computer data by combining the techniques of the Counter (CTR) mode and the +Cipher Block Chaining-Message Authentication Code (CBC-MAC) algorithm. + +The example project demonstrates CCM functionality using the existing CTR-AES +and CMAC-AES modes, which are supported by the TeraFire core and CAL software. +The two supported TeraFire functions, namely CTR-AES and CMAC-AES can be used +to construct CCM along with some additional minor application code, to perform +the CCM padding requirements. The example project demonstrates how to pre-process +the message data (e.g., any required padding), call the appropriate TeraFire +C-API functions, and do any post-processing required to perform NIST standard +compliant CCM. + +There are two different build configurations provided with this project which +configure this SoftConsole project for RISC-V IMC instruction extension. +The following configurations are provided with the example: + + - miv-rv32-imc-debug + - miv-rv32-imc-release + +Mi-V Soft Processor +-------------------------------------------------------------------------------- +This example uses Mi-V SoftProcessor MiV_RV32.The design is built for debugging +MiV_RV32 through the PolarFire FPGA programming JTAG port using a FlashPro5. +To achieve this the CoreJTAGDebug IP is used to connect to the JTAG port of the +MiV_RV32. + +All the platform/design specific definitions such as peripheral base addresses, +system clock frequency etc. are included in fpga_design_config.h. The +fpga_design_config.h is located at the root folder of this project. + +The Mi-V Soft Processor MiV_RV32 firmware projects needs the miv_rv32_hal and +the hal firmware(RISC-V HAL). + +The RISC-V HAL is available at GitHub [Mi-V-Soft-RISC-V](https://mi-v-ecosystem.github.io/redirects/platform). + +How to use this example +-------------------------------------------------------------------------------- +This example project is targeted at a MIV_RV32 design running on a PolarFire-Eval-Kit +connected via a USB-UART serial cable to a host PC running a terminal emulator +such as TeraTerm or Putty configured as follows: + + - 115200 baud + - 8 data bits + - 1 stop bit + - no parity + - no flow control. + +Run the example project using a debugger. A greeting message will appear over the +UART terminal followed by a menu system and instructions. + +This program displays the return data from User Crypto processor for digital +signature generation and verification services. + +fpga_design_config (formerly known as hw_config.h) +-------------------------------------------------------------------------------- +The SoftConsole project targeted for Mi-V processors now use an improved +directory structure. The fpga_design_config.h must be stored as shown below + +` + /boards//fpga_design_config/fpga_design_config.h +` + +Currently, this file must be hand crafted when using the Mi-V Soft Processor. +In future, all the design and soft IP configurations will be automatically +generated from the Libero design description data. + +You can use the sample file provided with MIV_RV32 HAL as an example. Rename it +from sample_fpga_design_config.h to fpga_design_config.h and then customize it +per your hardware design such as SYS_CLK_FREQ, peripheral BASE addresses, +interrupt numbers, definition of MSCC_STDIO_UART_BASE_ADDR if you want a +CoreUARTapb mapped to STDIO, etc. + +### Data Authenticated Encryption Using AES 128-bit key + +Select option '1' to perform authenticated encryption using Counter with CBC-MAC +(CCM) algorithm. This example project reads the 128 bit key, 16 bytes of Nonce, +64 bytes of plain text(P), and 16 bytes of additional authentication data (AAD) +from UART terminal. The example project stores the keys in SNVM region using +system controller SNVM service. After reading all the required data from UART +terminal, the example project call **MACCcmEnrypt()** function to perform CCM +encryption. + +The CCM algorithm compute the authentication field and encrypt the message data +using Counter (CTR) mode. This CCM algorithm performs authenticated encryption +with associated data for confidentiality and integrity. The plain text is both +encrypted and used in computation of message authentication code according to +the SATSYMTYPE_AES128 encryption algorithm and CCM mode. Both the encrypted data +and tag are displayed on UART terminal. + +### Data Authenticated Decryption Using AES 128-bit key + +Select option '2' to perform authenticated decryption using Counter with CBC-MAC +(CCM) algorithm. This example project reads the 128 bit key, 16 bytes of Nonce, +64 bytes of cipher text(P), and 16 bytes of additional authentication data (AAD) +from UART terminal. The example project stores the keys in SNVM region using +system controller SNVM service. After reading all the required data from UART +terminal, the example project call **MACCcmDecrypt()** function to perform CCM +decryption. The CCM algorithm decrypt the encrypted message data using Counter +(CTR) mode. The decrypted data contain the plain text message and the message +authentication code and are displayed on UART terminal. + +**NOTE:** + You can calculate the MAC using CBC MAC function based on the decrypted plain + text message and compare the decrypted MAC and compute MAC value are equal + or not in order to authenticate the data. + +### Configurations + +The CAL library needs a config_user.h containing the configuration data. +This application provides following settings as per CAL requirement + 1. A variable which provides the base address of the User Crypto hardware block + is defined in main.c + + `uint32_t g_user_crypto_base_addr = 0x62000000UL;` + + 2. A symbol INC_STDINT_H is defined in project preprocessor setting. + For more detail, please refer to caltypes.h file present in CAL folder. + +**NOTE:** + 1. If you try to enter data values other than 0 - 9, a - f, A - F, an error + message will be displayed on the serial terminal. + 2. You must enter all input data as whole bytes. If you enter the 128-bit + key {1230...0} as 0x12 0x3 and press return, this will be treated as + byte0 = 0x12, byte1 = 0x30, byte2-127 = 0x00. + +### Test script + +A test script is provided with this example which automatically enters the NIST +vectors and associated data to verify the functionality.You can use +the RV32_CCM_msg_auth.ttl Tera Term Macro script present in project directory +for testing Data Authenticated Encryption/Decryption Services. + +**NOTE:** +1. Tera Term Macros don’t work with Windows 10 build 14393.0. You should update + to Windows 10 build 14393.0.105 or [later.](https://osdn.net/ticket/browse.php?group_id=1412&tid=36526) +2. Before running Tera Term Macro script, set language as English + (Setup->General->Language). Also setup transmit delay in (Setup->Serial port) + to 5msec/char and 5msec/line. +3. By default, Tera Term log will be stored in Tera Term installation Directory. + +## Target hardware + +This project was tested on PolarFire-Eval-Kit with CFG4 configuration of the +MIV_RV32 design available [here](https://github.com/Mi-V-Soft-RISC-V/PolarFire-Eval-Kit/tree/main/Libero_Projects) + +All the design specific definitions such as peripheral base addresses, system +clock frequency etc. are included in fpga_design_config.h. + +The firmware projects needs the HAL and the MIV_RV32 HAL firmware components. + +This example project can be used with another design using a different hardware +configurations. This can be achieved by overwriting the content of this example +project's "fpga_design_config.h" file with the correct data per your Libero design. + +### Booting the system + +Currently the example project is configured to use FlashPro debugger to execute +from LSRAM in both Debug and Release mode. + +In the release mode build configuration, following setting is used +`--change-section-lma *-0x80000000` under +Tool Settings > Cross RISCV GNU Create Flash Image > General > Other flags. + +This will allow you to attach the release mode executable as the memory +initialization client in Libero when you want to execute it from non-volatile memory. + +## Silicon revision dependencies + +This example is tested on PolarFire MPF300TS device. + +### CAL library src + +To obtain the CAL source code and a SoftConsole project to generate the CAL +library archive file (*.a) refer [SoftConsole Documentation](https://mi-v-ecosystem.github.io/SoftConsole-Documentation/SoftConsole-v2021.3/using_softconsole/other.html#crypto-application-library). +The CAL source code is bound by license agreement and it will be available as +part of the SoftConsole installation if the CAL specific license was agreed +while installing it. diff --git a/applications/user-crypto/miv-rv32-ccm-services/RV32_CCM_msg_auth.ttl b/applications/user-crypto/miv-rv32-ccm-services/RV32_CCM_msg_auth.ttl new file mode 100644 index 0000000..d8cef0b --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/RV32_CCM_msg_auth.ttl @@ -0,0 +1,421 @@ +; Tera Term Setting: +; 1. Before running Tera Term Macro script, you should set language as English +; and transmit delay in Serial port setup to 5msec/char and 5msec/line. +; 2. By default, Tera Term log will be stored in Tera Term installation Directory. + +changedir '.' +logopen "MAC_ccm_msg_auth.log" 0 0 0 1 + +settitle 'PolarFire User Crypto CCM service' + +setsync 1 + +; Set baud rate to 115200 +setbaud 115200 + +; local echo off +setecho 0 + +;press any key +send '5' +pause 1 + +; ------------------------------------------------------------------------------- +; Test Case 1 +; Inputs +; 8, 3, 44, 20, +; AES key +; 40414243 44454647 48494A4B 4C4D4E4F +; NONCE +; 10111213 14151617 18191A1B +; AAD +; 00010203 04050607 08090A0B 0C0D0E0F 10111213 +; Message P +; 20212223 24252627 28292A2B 2C2D2E2F 30313233 34353637 + +; Output - Encrypted Data +; E3B201A9 F5B71A7A 9B1CEAEC CD97E70B 6176AAD9 A4428AA5 484392FB C1B09951 +; ----------------------------------------------------------------------------- +send '1' +pause 2 + +;Key +send '404142434445464748494a4b4c4d4e4f' +pause 1 + +;Nonce +send '101112131415161718191a1b' +pause 1 +send 13 +pause 1 + +;AAD +send '000102030405060708090a0b0c0d0e0f10111213' +pause 1 +send 13 +pause 1 + +;MSG +send '202122232425262728292A2B2C2D2E2F3031323334353637' +pause 1 +send 13 +pause 1 + +;M +send '2' +pause 5 + +;Send dummy +send '5' +pause 2 + +; ------------------------------------------------------------------------------- +; Test Case 2 +; Inputs +; 8, 2, 32, 8 +; AES key +; C0C1C2C3 C4C5C6C7 C8C9CACB CCCDCECF +; NONCE +; 00000004 030201A0 A1A2A3A4 A5 +; AAD +; 00010203 04050607 +; Message P +; 08090A0B 0C0D0E0F 10111213 14151617 18191A1B 1C1D1E1F + +; Output - Encrypted Data +; 72C91A36 E135F8CF 291CA894 085C87E3 CC15C439 C9E43A3B A091D56E 10400916 +; ----------------------------------------------------------------------------- + +send '1' +pause 2 + +;Key +send 'C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF' +pause 1 + +;Nonce +send '00000004030201A0A1A2A3A4A5' +pause 1 +send 13 +pause 1 + +;AAD +send '0001020304050607' +pause 1 +send 13 +pause 1 + +;MSG +send '08090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F' +pause 1 +send 13 +pause 1 + +;M +send '2' +pause 5 + +;Send dummy +send '5' +pause 2 + +; ------------------------------------------------------------------------------- +; Test Case 3 +; Inputs +; 4, 8, 12, 8, +; AES key +; C0C1C2C3 C4C5C6C7 C8C9CACB CCCDCECF +; NONCE +; 10111213 141516 +; AAD +; 00010203 04050607 +; Message P +; 20212223 + +; Output - Encrypted Data +; 7162015B 4DAC255D +; ----------------------------------------------------------------------------- + +send '1' +pause 2 + +;Key +send '404142434445464748494A4B4C4D4E4F' +pause 1 + +;Nonce +send '10111213141516' +pause 1 +send 13 +pause 1 + +;AAD +send '0001020304050607' +pause 1 +send 13 +pause 1 + +;MSG +send '20212223' +pause 1 +send 13 +pause 1 + +;M +send '1' +pause 5 + +;Send dummy +send '5' +pause 2 + +; ------------------------------------------------------------------------------- +; Test Case 4 Decryption +; Inputs +; 8, 3, 44, 20, +; AES KEY +; 40414243 44454647 48494A4B 4C4D4E4F +; NONCE +; 10111213 14151617 18191A1B +; AAD +; 00010203 04050607 08090A0B 0C0D0E0F 10111213 +; Encrypted Data +; E3B201A9 F5B71A7A 9B1CEAEC CD97E70B 6176AAD9 A4428AA5 484392FB C1B09951 + +; Output - +; P +; 20212223 24252627 28292A2B 2C2D2E2F 30313233 34353637 +; MAC +; 67C99240 C7D51048 +; ----------------------------------------------------------------------------- +send '2' +pause 2 + +;Key +send '404142434445464748494a4b4c4d4e4f' +pause 1 + +;Nonce +send '101112131415161718191a1b' +pause 1 +send 13 +pause 1 + +;AAD +send '000102030405060708090a0b0c0d0e0f10111213' +pause 1 +send 13 +pause 1 + +;Encrypted data +send 'E3B201A9F5B71A7A9B1CEAECCD97E70B6176AAD9A4428AA5484392FBC1B09951' +pause 1 +send 13 +pause 1 + +;M +send '2' +pause 5 + +;Send dummy +send '5' +pause 2 + + +; ------------------------------------------------------------------------------- +; Test Case 5 Decryption +; Inputs +; 8, 2, 32, 8, +; AES KEY +; C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF +; NONCE +; 00000004030201A0A1A2A3A4A5 +; AAD +; 0001020304050607 +; Encrypted Data +; 72C91A36E135F8CF291CA894085C87E3CC15C439C9E43A3BA091D56E10400916 + +; Output - +: P +; 08090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F +; MAC +; F7B9056A 86926CF3 +; ----------------------------------------------------------------------------- +send '2' +pause 2 + +;Key +send 'C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF' +pause 1 + +;Nonce +send '00000004030201A0A1A2A3A4A5' +pause 1 +send 13 +pause 1 + +;AAD +send '0001020304050607' +pause 1 +send 13 +pause 1 + +;Encrypted data +send '72C91A36E135F8CF291CA894085C87E3CC15C439C9E43A3BA091D56E10400916' +pause 1 +send 13 +pause 1 + +;M +send '2' +pause 5 + +;Send dummy +send '5' +pause 2 + +; ------------------------------------------------------------------------------- +; Test Case 6 Decryption +; Inputs +; 4, 8, 12, 8, +; AES KEY +; 40414243 44454647 48494A4B 4C4D4E4F +; NONCE +; 10111213 141516 +; AAD +; 00010203 04050607 +; Encrypted Data +; 7162015B 4DAC255D + +; Output +; P +; 20212223 +; MAC +; 6084341B +; ----------------------------------------------------------------------------- +send '2' +pause 2 + +;Key +send '404142434445464748494A4B4C4D4E4F' +pause 1 + +;Nonce +send '10111213141516' +pause 1 +send 13 +pause 1 + +;AAD +send '0001020304050607' +pause 1 +send 13 +pause 1 + +;Encrypted data +send '7162015B4DAC255D' +pause 1 +send 13 +pause 1 + +;M +send '1' +pause 5 + +;Send dummy +send '5' +pause 2 + +; ------------------------------------------------------------------------------- +; Test Case 7 +; Inputs +; [Tlen = 4] +; Key = 43b1a6bc8d0d22d6d1ca95c18593cca5 +; Nonce = 9882578e750b9682c6ca7f8f86 +; Count = 0 +; Adata = 2084f3861c9ad0ccee7c63a7e05aece5db8b34bd8724cc06b4ca99a7f9c4914f +; Payload = a2b381c7d1545c408fe29817a21dc435a154c87256346b05 + +; Output +; CT = cc69ed76985e0ed4c8365a72775e5a19bfccc71aeb116c85a8c74677 + +; ----------------------------------------------------------------------------- +send '1' +pause 2 + +;Key +send '43b1a6bc8d0d22d6d1ca95c18593cca5' +pause 1 + +;Nonce +send '9882578e750b9682c6ca7f8f86' +pause 1 +send 13 +pause 1 + +;AAD +send '2084f3861c9ad0ccee7c63a7e05aece5db8b34bd8724cc06b4ca99a7f9c4914f' +pause 1 + +;MSG +send 'a2b381c7d1545c408fe29817a21dc435a154c87256346b05' +pause 1 +send 13 +pause 1 + +;M +send '1' +pause 5 + +;Send dummy +send '5' +pause 2 + + +; ------------------------------------------------------------------------------- +; Test Case 8 Decryption +; Inputs +; [Tlen = 4] +; Key = 43b1a6bc8d0d22d6d1ca95c18593cca5 +; Nonce = 9882578e750b9682c6ca7f8f86 +; Count = 0 +; Adata = 2084f3861c9ad0ccee7c63a7e05aece5db8b34bd8724cc06b4ca99a7f9c4914f +; CT = cc69ed76985e0ed4c8365a72775e5a19bfccc71aeb116c85a8c74677 + +; Output +; Payload = a2b381c7d1545c408fe29817a21dc435a154c87256346b05 +; MAC = 95DA703C +; ----------------------------------------------------------------------------- +send '2' +pause 2 + +;Key +send '43b1a6bc8d0d22d6d1ca95c18593cca5' +pause 1 + +;Nonce +send '9882578e750b9682c6ca7f8f86' +pause 1 +send 13 +pause 1 + +;AAD +send '2084f3861c9ad0ccee7c63a7e05aece5db8b34bd8724cc06b4ca99a7f9c4914f' +pause 1 + +;Encrypted data +send 'cc69ed76985e0ed4c8365a72775e5a19bfccc71aeb116c85a8c74677' +pause 1 +send 13 +pause 1 + +;M +send '1' +pause 5 + +;Send dummy +send '5' +pause 2 + +pause 5 +logclose \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-ccm-services/miv-rv32-ccm-services hw Debug.launch b/applications/user-crypto/miv-rv32-ccm-services/miv-rv32-ccm-services hw Debug.launch new file mode 100644 index 0000000..1175fc7 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/miv-rv32-ccm-services hw Debug.launch @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/user-crypto/miv-rv32-ccm-services/miv-rv32-ccm-services hw attach.launch b/applications/user-crypto/miv-rv32-ccm-services/miv-rv32-ccm-services hw attach.launch new file mode 100644 index 0000000..460e8d3 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/miv-rv32-ccm-services hw attach.launch @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/application/ccm.c b/applications/user-crypto/miv-rv32-ccm-services/src/application/ccm.c new file mode 100644 index 0000000..be3d28b --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/application/ccm.c @@ -0,0 +1,456 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file ccm.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief PolarFire User crypto MAC-CCM algorithm implementation. See file "ccm.h" + * for description of the functions implemented in this file. + * + */ +#include +#include +#include +#include +#include +#include "hal/hal.h" +#include "cal/calpolicy.h" +#include "cal/pk.h" +#include "cal/pkx.h" +#include "cal/pkxlib.h" +#include "cal/calini.h" +#include "cal/utils.h" +#include "cal/hash.h" +#include "cal/drbgf5200.h" +#include "cal/drbg.h" +#include "cal/nrbg.h" +#include "cal/sym.h" +#include "cal/shaf5200.h" +#include "cal/calenum.h" +#include "ccm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +__attribute__ ((section (".crypto_data")))static uint8_t g_mac[100]; +__attribute__ ((section (".crypto_data"))) uint8_t A[100] = {0x00}; /* A_i blocks for encryption input */ +__attribute__ ((section (".crypto_data"))) static uint8_t S[100]; /* S_i = encrypted A_i blocks */ +static uint8_t __attribute__ ((section (".crypto_data")))B[100] = {0x00};/* B_i blocks for CBC-MAC input */ + +extern SATR CCMMAC(SATMACTYPE eMACType, const SATUINT32_t *pKey, SATUINT32_t uiKeyLen, + const void *pMsg, SATUINT32_t uiMsgLen, void *pMAC); + +/*============================================================================== + Clear CCM global variable. + */ +void clear_ccm_var(void) +{ + uint16_t var = 0; + + for(var = 0; var < 100; var++) + { + g_mac[var] = 0; + A[var] = 0; + S[var] = 0; + B[var] = 0; + } +} + +static inline int int_to_uint16(uint8_t *field, uint16_t value) +{ + field[0] = (value >> 8) & 0xff; + field[1] = value & 0xff; + return 2; +} + +static inline int int_to_uint32(uint8_t *field, uint32_t value) +{ + field[0] = (value >> 24) & 0xff; + field[1] = (value >> 16) & 0xff; + field[2] = (value >> 8) & 0xff; + field[3] = value & 0xff; + return 4; +} + +static inline int int_to_uint64(unsigned char *field, uint64_t value) +{ + field[0] = (value >> 56) & 0xff; + field[1] = (value >> 48) & 0xff; + field[2] = (value >> 40) & 0xff; + field[3] = (value >> 32) & 0xff; + field[4] = (value >> 24) & 0xff; + field[5] = (value >> 16) & 0xff; + field[6] = (value >> 8) & 0xff; + field[7] = value & 0xff; + return 8; +} +static void set_counter(uint8_t A[CCM_BLOCKSIZE],uint16_t L,uint16_t cnt,uint16_t C) +{ + uint8_t i_; + volatile uint16_t temp = 0; + memset((A) + CCM_BLOCKSIZE - (L), 0, (L)); + + temp = (((uint16_t)1 << (8 * L)) - 1); + + (C) = (cnt) & 0xFFFFFFFF; + + for (i_ = CCM_BLOCKSIZE - 1; (C) && (i_ > (L)); --i_, (C) >>= 8) + { + (A)[i_] |= (C) & 0xFF; + } +} + +static uint8_t roundUp(uint8_t numToRound, uint8_t multiple) +{ + return ((numToRound + multiple - 1) / multiple) * multiple; +} + +static inline void +block0(size_t M, /* number of auth bytes */ + size_t L, /* number of bytes to encode message length */ + size_t la, /* l(a) octets additional authenticated data */ + size_t lm, /* l(m) message length */ + uint8_t nonce[CCM_BLOCKSIZE], + uint8_t *result) +{ + uint8_t i; + + result[0] = CCM_FLAGS(la, M, L); + + /* copy the nonce */ + memcpy(result + 1, nonce, CCM_BLOCKSIZE - L - 1); + + for (i = 0; i < L; i++) + { + result[15-i] = lm & 0xff; + lm >>= 8; + } +} + +/*============================================================================== + Form input block B1.. Bn for Authentication. + */ +static uint8_t +add_auth_data(const uint8_t *msg, size_t la, uint8_t *B1) +{ + size_t i,j; + uint8_t status = 0u; + uint8_t len = 0; + + memset(B1, 0, CCM_BLOCKSIZE); + + if (!la) + { + return 0; + } + + if (la < 0xFF00) + { + j = 2; + int_to_uint16(B1, la); + } + else if (la <= UINT32_MAX) + { + j = 6; + int_to_uint16(B1, 0xFFFE); + int_to_uint32(B1+2, la); + } + else + { + j = 10; + int_to_uint16(B1, 0xFFFF); + int_to_uint64(B1+2, la); + } + + i = min(CCM_BLOCKSIZE - j, la); + memcpy(B1 + j, msg, i); + la -= i; + msg += i; + len = i+j; + B1 += len; + + while (la > CCM_BLOCKSIZE) + { + for (i = 0; i < CCM_BLOCKSIZE; ++i) + { + *B1++ = *msg++; + } + la -= CCM_BLOCKSIZE; + len += CCM_BLOCKSIZE; + } + + if (la) + { + memcpy(B1, msg, la); + len += CCM_BLOCKSIZE; + } + + return len; +} + +/*============================================================================== + Encryption using AES-128 + */ +static inline void +ccm_aes_encrypt(size_t L, uint16_t counter, + uint8_t *msg, size_t len, + uint8_t A[CCM_BLOCKSIZE], + uint8_t S[CCM_BLOCKSIZE], + uint8_t* key, + uint8_t *pDest) +{ + static uint16_t counter_tmp; + uint8_t status = 0u; + + set_counter(A, L, counter, counter_tmp); + + status = CALSymEncryptDMA(SATSYMTYPE_AES128, (uint32_t *)key, + SATSYMMODE_CTR, A, SAT_TRUE, msg, + pDest, 16, X52CCR_DEFAULT); + + CALPKTrfRes(SAT_TRUE); + +} + +/*============================================================================== + Input Block B calculation for MAC + */ +uint16_t +ccm_mac_block(size_t M, size_t L, uint8_t *nonce, + uint8_t *msg, size_t lm, + const uint8_t *aad, size_t la) +{ + volatile uint8_t *b_ptr = (uint8_t *)&B; + uint8_t return_len = 0; + uint8_t len = 0; + uint8_t i = 0; + + /* + * Clear B array. + */ + for(i = 0; i < sizeof(B); i++) + { + B[i] = 0; + } + + /* Create the initial authentication block B0 i.e. define a sequence of + * blocks B0 + */ + block0(M, L, la, lm, nonce, B); + b_ptr += CCM_BLOCKSIZE; + return_len = CCM_BLOCKSIZE; + + /* Input Block B1 ... Bn */ + len = add_auth_data( aad, la, (uint8_t *)b_ptr); + len = roundUp(len, 16); + b_ptr += len; + return_len += len; + + /* Last Block calculation. */ + memcpy((uint8_t *)b_ptr, msg, lm); + len = roundUp(lm, 16); + return_len += len; + + return return_len; +} + +/*============================================================================== + Form Input block and perform CCM Encryption + */ +uint16_t +ccm_encrypt_message(size_t M, size_t L, uint8_t nonce[CCM_BLOCKSIZE], + uint8_t *msg, size_t lm, uint8_t *key, uint8_t *pDest) +{ + uint8_t status = 0u; + uint16_t msg_len = 0; + size_t i,j; + size_t len; + uint16_t counter_tmp; + uint16_t counter = 1; + + /* Save original length */ + len = lm; + + /* Initialize block template */ + A[0] = L-1; + + /* Copy the nonce */ + memcpy(A + 1, nonce, CCM_BLOCKSIZE - L - 1); + + while (lm >= CCM_BLOCKSIZE) + { + /* Encrypt */ + ccm_aes_encrypt( L, counter, msg, CCM_BLOCKSIZE, A, S, key, pDest); + + /* Update local pointers */ + lm -= CCM_BLOCKSIZE; + msg += CCM_BLOCKSIZE; + pDest += CCM_BLOCKSIZE; + counter++; + msg_len += CCM_BLOCKSIZE; + } + + if (lm) + { + /* Encrypt */ + ccm_aes_encrypt( L, counter, msg, lm, A, S, key, pDest); + + /* Update local pointers */ + msg += lm; + msg_len += lm; + pDest += lm; + } + + /* Calculate S_0 */ + set_counter(A, L, 0, counter_tmp); + + status = CALSymEncryptDMA(SATSYMTYPE_AES128, (uint32_t *)key, + SATSYMMODE_CTR, A, SAT_TRUE, msg, + S , 16, X52CCR_DEFAULT); + + CALPKTrfRes(SAT_TRUE); + + return msg_len; +} + +/*============================================================================== + CCM Decryption + */ +uint16_t +ccm_decrypt_message(size_t M, size_t L, + uint8_t nonce[CCM_BLOCKSIZE], + uint8_t *msg, size_t lm, + uint8_t *key, + uint8_t *pDest) +{ + uint16_t counter_tmp = 0; + uint16_t counter = 1; + uint16_t i = 0; + uint16_t error, n = 0; + uint8_t status = 0; + + for(i = 0; i < 80; i++) + { + A[i] = 0; + } + + if (lm < M) + goto error; + + /* save original length */ + lm -= M; + + /* Initialize block template */ + A[0] = L-1; + + /* Copy the nonce */ + memcpy(A + 1, nonce, CCM_BLOCKSIZE - L - 1); + + while (lm >= CCM_BLOCKSIZE) + { + /* Decrypt */ + ccm_aes_encrypt( L, counter, msg, CCM_BLOCKSIZE, A, S, key, pDest); + + for(i = 0; i < CCM_BLOCKSIZE; i++) + { + S[i] = pDest[i]; + } + + /* Update local pointers */ + lm -= CCM_BLOCKSIZE; + msg += CCM_BLOCKSIZE; + pDest += CCM_BLOCKSIZE; + counter++; + } + + if (lm) + { + /* Decrypt */ + ccm_aes_encrypt( L, counter, msg, lm, A, S, key, pDest); + + /* update local pointers */ + msg += lm; + pDest += lm; + + } + + /* Calculate S_0 */ + set_counter(A, L, 0, counter_tmp); + CALSymEncryptDMA(SATSYMTYPE_AES128, (uint32_t *)key, + SATSYMMODE_CTR, A, SAT_TRUE, msg, + S , 16, X52CCR_DEFAULT); + + CALPKTrfRes(SAT_TRUE); + + return 0; + + error: + return -1; +} + +/*============================================================================== + CCM Encryption + */ +void +MACCcmEnrypt(size_t M, size_t L, uint8_t *pNonce, uint8_t *pSrc, size_t lm, + const uint8_t *pAad, size_t la, uint16_t *pKey, void *pDest) +{ + uint8_t i = 0; + uint32_t len = 0; + uint8_t *p_msg = pDest; + uint8_t status = 0; + + /* Initializes the Athena Processor. */ + CALIni(); + + /* Calculate MAC input block. */ + len = ccm_mac_block(M, L, pNonce, pSrc, lm, pAad, la); + + /* Calculate MAC. */ + status = CCMMAC(SATMACTYPE_AESCMAC128, (uint32_t *)pKey, 16, B, len, g_mac); + + /* Encrypt the message. */ + len = ccm_encrypt_message(M, L, pNonce, pSrc, lm, (uint8_t *)pKey, pDest); + p_msg += len; + + /* The authentication value U is computed by encrypting T with the key + * stream block S_0 and truncating it to the desired length. + * U := T XOR first-M-bytes( S_0 ) + */ + for (i = 0; i < M; ++i) + { + *p_msg++ = S[i] ^ g_mac[i]; + } +} + +/*============================================================================== + Perform CCM decryption and calculate MAC value of decrypted data for + verification. + */ +void +MACCcmDecrypt(size_t M, size_t L, uint8_t *pNonce, uint8_t *pEncMsg, size_t lm, + const uint8_t *pAad, size_t la, uint16_t *pKey, uint8_t *pDest, + uint8_t *pMAC) +{ + uint8_t status = 0; + uint8_t i = 0; + + /* Initializes the Athena Processor. */ + CALIni(); + + /* Decrypt the encrypted message.*/ + ccm_decrypt_message(M, L, pNonce, pEncMsg, lm, (uint8_t *)pKey, pDest); + + for(i = 0; i < M; i++) + { + pMAC[i] = S[i]; + } + +} + + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/application/ccm.h b/applications/user-crypto/miv-rv32-ccm-services/src/application/ccm.h new file mode 100644 index 0000000..d528701 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/application/ccm.h @@ -0,0 +1,196 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file ccm.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief This file contains the application programming interface for the + * PolarFire User Crypto MAC using CCM service. + * + */ +/*=========================================================================*//** + @mainpage PolarFire User Crypto CCM Bare Metal Driver. + *//*=========================================================================*/ +/*=========================================================================*//** + @mainpage CCM MAC Algorithm implementation. + CCM(Counter with CBC-MAC) is used to provide assurance of the confidentiality + and the authenticity of computer data by combining the techniques of the + Counter (CTR) mode and the Cipher Block Chaining-Message Authentication Code + (CBC-MAC) algorithm. The TeraFire functions, namely CTR-AES is used to + construct CCM along with some additional minor application code, to perform + the CCM padding requirements. + + Initialization and Configuration + The CAL library driver is initialized through a call to the CALIni() + function. The CALIni() function must be called before any other + CAL Library driver or CCM functions is called. + + CCM services. + The CCM driver can ebe used to execute Authentication encryption and + decryption services using the following function. + • MACCcmEnrypt () + • MACCcmDecrypt () + + *//*=========================================================================*/ + +#ifndef __CCM_H +#define __CCM_H 1 + +#include "hal/hal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + * Macro definitation. + */ +#define CCM_BLOCKSIZE 16 +#define min(a,b) ((a) < (b) ? (a) : (b)) +#define CCM_FLAGS(A,M,L) (((A > 0) << 6) | (((M - 2)/2) << 3) | (L - 1)) +#define MASK_L(_L) ((1 << 8 * _L) - 1) + + /***************************************************************************//** + * Global Structure. + */ +struct test_vector { + size_t M, L; /* M - Number of Authenticate bytes. + L - Number of bytes to encode message length. */ + size_t lm; /* overall message length*/ + size_t la; /* number of bytes additional data */ + uint8_t key[CCM_BLOCKSIZE]; + uint8_t nonce[CCM_BLOCKSIZE]; + uint8_t msg[128]; + uint8_t aad[128]; + uint8_t output[128]; + uint8_t dec_mac[128]; +}; + + /***************************************************************************//** + * Global Functions. + */ + /***************************************************************************//** + * The function MACCcmEnrypt() performs authenticated encryption with associated + * data, for confidentiality and integrity. The associated data, pointed at by + * pAad, with byte length la, is used in the computation of the message + * authentication code and but not encrypted and is not included in the output + * of CCM mode. AAD can be used to authenticate plaintext packet headers, or + * contextual information that affects the interpretation of the message. Users + * who do not wish to authenticate additional data can provide a string of + * length zero. The data pointed at by pSrc, is encrypted and used in the + * computation of the message authentication code according to the + * SATSYMTYPE_AES128 encryption algorithm, and SATSYMMODE_CTR mode. The length of + * the data pointed by pSrc is specified by lm. The final result consists of the + * encrypted message followed by the encrypted authentication value. And will be + * stored at the location pointed at by pDest. The byte length of the message + * authentication code is specified by M. The data will be encrypted using the + * key pointed at by pKey. The Nonce is pointed at by pNonce. + + * @param M The M parameter specifies the the size of authentication + * field. + * + * @param L The L parameter specifies the number of octets in length + * field. + * + * @param pNonce The pNonce parameter is a pointer to the buffer where the + * nonce value will be stored. + * + * @param pSrc The pSrc parameter is pointer to the plaintext/authenticate + * data buffer. + * + * @param lm The lm parameter specifies the length of the plaintext in + * bytes the encrypt/authenticate. + * + * @param pAad The aad parameter is pointer the Additional authenticated + * data buffer. + * + * @param la The la parameter specifies the length of Additional + * authenticated data buffer. + * + * @param pKey The pKey parameter is pointer to key. + * + * @param pDest The pDest parameter is a pointer to ciphertext data + * buffer. + * + * @return This function does not return any value. + * + * Example: + * @code + * /* CCM Encryption *//* + * MACCcmEnrypt(data.M, + * data.L, + * data.nonce, + * data.msg, + * data.lm, + * data.aad, + * data.la, + * data.key, + * data.output); + * @endcode + */ +void +MACCcmEnrypt(size_t M, size_t L, uint8_t *pNonce, uint8_t *pSrc, size_t lm, + const uint8_t *pAad, size_t la, uint16_t *pKey, void *pDest); + +/***************************************************************************//** + * The MACCcmDecrypt() function performs authenticated decryption with + * additional authenticated data, for confidentiality and integrity. The + * additional authenticated data data, pointed at by pAad, with byte length la, + * is used in the computation of the message authentication code, but is not + * decrypted. The data pointed at by pEncMsg, with byte length lm, is both + * decrypted and used in the computation of the message authentication code + * according to the selected decryption algorithm, based on SATSYMTYPE_AES128 + * encryption algorithm, and SATSYMMODE_CTR mode. + * The decrypted data will be stored at the location pointed at by pDest, and + * the message authentication code will be compared to the value stored at the + * location pointed at by pMAC; The byte length of the message authentication + * code is specified by la. The data will be decrypted using the key pointed at + * by pKey variable. The Nonce value is pointed at by pNonce. + + * @param M The M parameter specifies the length of the message + * authentication code in bytes. + * + * @param L The L parameter specifies the number of octets in length + * field. + * + * @param pNonce The pNonce parameter is a pointer to the buffer where the + * nonce value will be stored. + * + * @param pEncMsg The pEncMsg parameter is pointer to the ciphertext/verify + * data buffer. + * + * @param lm The lm parameter specifies the length of the plaintext in + * bytes the encrypt/authenticate. + * + * @param pAad The pAad parameter is pointer the Additional + * authenticated data buffer.i.e. verify-only data buffer. + * + * @param la The la parameter specifies the length of Additional + * authenticated data buffer.i.e. verify-only data buffer. + * + * @param pKey The pKey parameter is pointer to key. + * + * @param pDest The pDest parameter is a pointer to plaintext data + * buffer. + * + * @param pMAC The pMAC parameter is a pointer to the message + * authentication code. + * + * + * @return This function does not return any value. + * + * Example: + * @code + * @endcode + */ +void +MACCcmDecrypt(size_t M, size_t L, uint8_t *pNonce, uint8_t *pEncMsg, size_t lm, + const uint8_t *pAad, size_t la, uint16_t *pKey, uint8_t *pDest, + uint8_t *pMAC); + +#ifdef __cplusplus +} +#endif + +#endif /* __CCM_H */ diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/application/ccm_mac.c b/applications/user-crypto/miv-rv32-ccm-services/src/application/ccm_mac.c new file mode 100644 index 0000000..145c513 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/application/ccm_mac.c @@ -0,0 +1,246 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file ccm_mac.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief PolarFire user crypto MAC-CCM algorithm- MAC implementation. + * + */ +#include "cal/calpolicy.h" +#include "cal/caltypes.h" +#include "cal/calenum.h" +#include "cal/utils.h" +#include "cal/hash.h" +#include "cal/calcontext.h" +#include "cal/shaf5200.h" +#include "cal/sym.h" +#include "cal/aesf5200.h" + +static __attribute__ ((section (".crypto_data")))SATMACTYPE CurMAC=SATMACTYPE_NULL; +static __attribute__ ((section (".crypto_data")))SATSYMTYPE CurSym=SATSYMTYPE_NULL; +static __attribute__ ((section (".crypto_data")))SATUINT32_t uiIV[4]; +static __attribute__ ((section (".crypto_data")))SATUINT32_t uiCMACK[4]; +static __attribute__ ((section (".crypto_data")))SATUINT32_t uiSymMsgLen; + +static SATR AES_MAC_Write(const void *pBuffer, SATUINT32_t uiBufLen) +{ + SATR rReturn; + + SATUINT32_t uiBytesCBC,i; + SATUINT8_t *pui8Buffer, *pui8IV, *pui8K; + pui8Buffer=(SATUINT8_t *)pBuffer; + + /* Validate length */ + if(uiBufLen > uiSymMsgLen) + { + return SATR_BADLEN; + } + + /* Calculate number of CBC bytes to process before final block */ + if((uiSymMsgLen - uiBufLen) > 0) + { + uiBytesCBC = uiBufLen; + } + else + { + if(uiBufLen > 16) + { + if((uiBufLen % 16) != 0) + { + uiBytesCBC = uiBufLen - (uiBufLen % 16); + } + else + { + uiBytesCBC = uiBufLen - 16; + } + } + else + { + uiBytesCBC = 0; + } + } + + /* Update message length state */ + uiSymMsgLen -= uiBufLen; + + /* Process all message blocks except last */ + if (uiBytesCBC >= 16) + { + aesf5200aes (CurSym, SATSYMMODE_CBC, uiIV, SAT_TRUE, pui8Buffer, + SAT_NULL, uiBytesCBC, SAT_FALSE); + + rReturn = CALSymTrfRes(SAT_TRUE); + + pui8Buffer += uiBytesCBC; + } + + /* XOR final message with subkey */ + if(uiSymMsgLen == 0) + { + /* Calculate size of final block */ + pui8IV = (SATUINT8_t*)uiIV; + pui8K = (SATUINT8_t*)uiCMACK; + for (i = 0; i < (uiBufLen - uiBytesCBC); i++) + { + *pui8IV = *pui8IV ^ *pui8Buffer; + pui8IV++; + pui8Buffer++; + } + if (i<16) + { + *pui8IV = *pui8IV ^ 0x80; + pui8IV++; + i++; + } + for (; i < 16; i++) + { + pui8IV++; + } + + /* Encrypt final block */ + rReturn = aesf5200aes(CurSym, SATSYMMODE_ECB, SAT_NULL, SAT_FALSE, + uiIV, uiIV, 16, SAT_FALSE); + if(rReturn != SATR_SUCCESS) + { + return rReturn; + } + + rReturn = CALSymTrfRes(SAT_TRUE); + if(rReturn != SATR_SUCCESS) + { + return rReturn; + } + } + + return rReturn; +} + +SATR MACWrite(const void *pBuffer, SATUINT32_t uiBufLen) +{ + SATR rRet; + + if(CurMAC == SATMACTYPE_NULL) + { + return SATR_BADMACTYPE; + } + + if(pBuffer == SAT_NULL) + { + return SATR_BADPARAM; + } + + if(CurMAC >= SATMACTYPE_AESCMAC128 && CurMAC <= SATMACTYPE_AESCMAC256) + { + rRet = AES_MAC_Write(pBuffer, uiBufLen); + } + /* No default else statement - CALMACIni checks type and sets it to SAT_NULL + if it's invalid. Then this function checks & returns if type ==SAT_NULL */ + return rRet; +} + +static void macsubkey(const void *pSubKeyIn, void *pSubKeyOut) +{ + SATUINT8_t uiC,uiCNew; + SATUINT8_t *pui8In,*pui8Out; + SATINT8_t i; + uiC = 0; + + pui8In = ((SATUINT8_t *)pSubKeyIn) + 15; + pui8Out = ((SATUINT8_t *)pSubKeyOut) + 15; + for( i = 15; i >= 0; i--) + { + uiCNew = (*pui8In & 0x80) >> 7; + *pui8Out = *pui8In << 1 | uiC; + pui8Out--; + pui8In--; + uiC = uiCNew; + } + pui8In = ((SATUINT8_t *)pSubKeyIn) + 15; + pui8Out = ((SATUINT8_t *)pSubKeyOut) + 15; + if (uiC) + { + *pui8Out = *pui8In ^ 0x87; + } +} + +SATR MACIni(SATMACTYPE eMACType, const SATUINT32_t *pKey, SATUINT32_t uiKeyLen, + SATUINT32_t uiMsgLen) +{ + SATUINT32_t i; + SATR rReturn = SATR_BADMACTYPE; + + if (pKey == SAT_NULL) + { + return SATR_BADPARAM; + } + + for( i = 0; i < 4; i++) + { + uiIV[i] = 0; + } + + CurMAC = eMACType; + uiSymMsgLen = uiMsgLen; + CurSym = SATSYMTYPE_AES128; + CALSymEncrypt(CurSym, pKey, SATSYMMODE_ECB, SAT_NULL, SAT_FALSE, uiIV, uiCMACK, 128/8); + + CALSymTrfRes(SAT_TRUE); + macsubkey(uiCMACK,uiCMACK); + + if ((uiMsgLen & 0xf) || (uiMsgLen == 0)) + { + macsubkey(uiCMACK,uiCMACK); + } + + return SATR_SUCCESS; +} + +SATR MACRead(void *pMAC) +{ + SATR rReturn = SATR_SUCCESS; + + if(CurMAC == SATMACTYPE_NULL) + { + return SATR_BADMACTYPE; + } + else if(CurMAC >= SATMACTYPE_AESCMAC128 && CurMAC <= SATMACTYPE_AESCMAC256) + { + CALMemCopy(pMAC, uiIV, 16 ); + CALMemClear(uiIV, 16); + rReturn = SATR_SUCCESS; + } + else + { + return SATR_BADMACTYPE; + } + + /* Clear eCurMAC as data has been read */ + CurMAC = SATMACTYPE_NULL; + return rReturn; +} + +SATR CCMMAC(SATMACTYPE eMACType, const SATUINT32_t *pKey, SATUINT32_t uiKeyLen, + const void *pMsg, SATUINT32_t uiMsgLen, void *pMAC) +{ + SATR rReturn; + + /* Initialize MAC operation */ + rReturn = MACIni(eMACType, pKey, uiKeyLen, uiMsgLen); + if (rReturn != SATR_SUCCESS) + { + return rReturn; + } + + /* Write message */ + rReturn = MACWrite(pMsg, uiMsgLen); + if (rReturn != SATR_SUCCESS) + { + return rReturn; + } + + /* Read resulting MAC */ + rReturn = MACRead(pMAC); + return rReturn; +} diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/application/helper.c b/applications/user-crypto/miv-rv32-ccm-services/src/application/helper.c new file mode 100644 index 0000000..914f872 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/application/helper.c @@ -0,0 +1,278 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file helper.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Helper function for PolarFire User Crypto- Cryptography service example. + * + */ +#include +#include +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" +#include "helper.h" + +static const uint8_t g_separator[] = +"\r\n\ +------------------------------------------------------------------------------"; +static const uint8_t hex_chars[16] = { '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + +/*============================================================================== + Function to clear local variable and array. + */ +static void clear_variable(uint8_t *p_var, uint16_t size) +{ + uint16_t inc; + + for(inc = 0; inc < size; inc++) + { + *p_var = 0x00; + p_var++; + } +} + +/*============================================================================== + Function to get the input data from user. + */ +uint16_t get_input_data +( + uint8_t* location, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +) +{ + uint16_t count = 0u; + + /* Clear the memory location. */ + clear_variable(location, size); + + /* Read data from UART terminal. */ + count = get_data_from_uart(location, size, msg, msg_size); + + return count; +} + +/*============================================================================== + Function to get the key from user. + */ +void get_key +( + uint8_t key_type, + uint8_t* location, + uint8_t size, + const uint8_t* msg, + uint8_t msg_size +) +{ + uint8_t status = 0u; + const uint8_t invalid_ms[] = "\r\n Invalid key type. "; + + if(status == VALID) + { + /* Read the 16 bytes of input data from UART terminal. */ + get_input_data(location, size, msg, msg_size); + } + else + { + UART_send(&g_uart, invalid_ms, sizeof( invalid_ms)); + } +} + +/*============================================================================== + Convert ASCII value to hex value. + */ +uint8_t convert_ascii_to_hex(uint8_t* dest, const uint8_t* src) +{ + uint8_t error_flag = 0u; + + if((*src >= '0') && (*src <= '9')) + { + *dest = (*src - '0'); + } + else if((*src >= 'a') && (*src <= 'f')) + { + *dest = (*src - 'a') + 10u; + } + else if((*src >= 'A') && (*src <= 'F')) + { + *dest = (*src - 'A') + 10u; + } + else if(*src != 0x00u) + { + UART_send(&g_uart, (const uint8_t *)"\r\n Invalid data.", sizeof("\r\n Invalid data.")); + error_flag = 1u; + } + return error_flag; +} + +/*============================================================================== + Validate the input hex value . + */ +uint8_t validate_input(uint8_t ascii_input) +{ + uint8_t valid_key = 0u; + + if(((ascii_input >= 'A') && (ascii_input <= 'F')) || \ + ((ascii_input >= 'a') && (ascii_input <= 'f')) || \ + ((ascii_input >= '0') && (ascii_input <= '9'))) + { + valid_key = 1u; + } + else + { + valid_key = 0u; + } + return valid_key; +} + +/*============================================================================== + Display content of buffer passed as parameter as hex values. + */ +void display_output +( + uint8_t* in_buffer, + uint32_t byte_length +) +{ + uint32_t inc; + uint8_t byte = 0; + + UART_send(&g_uart, (const uint8_t*)" ", sizeof(" ")); + for(inc = 0; inc < byte_length; ++inc) + { + if((inc > 1u) &&(0u == (inc % 16u))) + { + UART_send(&g_uart, (const uint8_t*)"\r\n ", sizeof("\r\n ")); + } + + byte = in_buffer[inc]; + UART_send(&g_uart, &hex_chars[((byte & 0xF0) >> 4) ], 1); + UART_send(&g_uart, &hex_chars[(byte & 0x0F)], 1); + } + +} + +/*============================================================================== + Function to read data from UART terminal and stored it. + */ +uint16_t get_data_from_uart +( + uint8_t* src_ptr, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +) +{ + uint8_t complete = 0u; + uint8_t rx_buff[1]; + uint8_t rx_size = 0u; + uint16_t count = 0u; + uint16_t ret_size = 0u; + uint8_t first = 0u; + uint16_t src_ind = 0u; + uint8_t prev = 0; + uint8_t curr = 0; + uint8_t temp = 0; + uint8_t next_byte = 0; + uint16_t read_data_size = 0; + + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, msg, msg_size); + + if(size != 1) + { + read_data_size = size * 2; + } + else + { + read_data_size = size; + } + + /* Read the key size sent by user and store it. */ + count = 0u; + while(!complete) + { + rx_size = UART_get_rx(&g_uart, rx_buff, sizeof(rx_buff)); + if(rx_size > 0u) + { + /* Is it to terminate from the loop */ + if(ENTER == rx_buff[0]) + { + complete = 1u; + } + /* Is entered key valid */ + else if(validate_input(rx_buff[0]) != 1u) + { + UART_send(&g_uart, rx_buff, sizeof(rx_buff)); + UART_send(&g_uart, (const uint8_t *)"\r\n Invalid input.", + sizeof("\r\n Invalid input.")); + UART_send(&g_uart, msg, msg_size); + complete = 0u; + count = 0u; + first = 0u; + } + else + { + if(next_byte == 0) + { + convert_ascii_to_hex(&src_ptr[src_ind], &rx_buff[0]); + prev = src_ptr[src_ind]; + next_byte = 1; + } + else + { + convert_ascii_to_hex(&curr, &rx_buff[0]); + temp = ((prev << 4) & 0xF0); + src_ptr[src_ind] = (temp | curr); + next_byte = 0; + src_ind++; + } + + + /* Switching to next line after every 8 bytes */ + if(((count % 32u) == 0x00u) && (count > 0x00u) && (complete != 0x01u)) + { + UART_send(&g_uart, (const uint8_t *)"\n\r", sizeof("\n\r")); + first = 0u; + } + + if(first == 0u) + { + UART_send(&g_uart, (const uint8_t *)" ", sizeof(" ")); + first++; + } + UART_send(&g_uart, rx_buff, sizeof(rx_buff)); + count++; + if(read_data_size == count) + { + complete = 1u; + } + } + } + } + + if((count % 2) == 0) + { + ret_size = count / 2; + } + else + { + if(size != 1) + { + temp = src_ptr[src_ind]; + src_ptr[src_ind] = ((temp << 4) & 0xF0); + + ret_size = (count / 2) + 1; + } + else + { + ret_size = 1; + } + } + + return ret_size; +} + diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/application/helper.h b/applications/user-crypto/miv-rv32-ccm-services/src/application/helper.h new file mode 100644 index 0000000..242514d --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/application/helper.h @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file helper.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Helper function public API. + * + */ +#ifndef __HELPER_H_ +#define __HELPER_H_ 1 + +/****************************************************************************** + * Maximum buffer size. + *****************************************************************************/ +#define MAX_RX_DATA_SIZE 256 +#define MASTER_TX_BUFFER 10 +#define DATA_LENGTH_32_BYTES 32 + +/*============================================================================== + Macro + */ +#define VALID 0U +#define INVALID 1U +#define ENTER 13u + +/****************************************************************************** + * CoreUARTapb instance data. + *****************************************************************************/ +extern UART_instance_t g_uart; + +uint16_t get_input_data +( + uint8_t* location, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +); +void get_key +( + uint8_t key_type, + uint8_t* location, + uint8_t size, + const uint8_t* msg, + uint8_t msg_size +); +uint16_t get_data_from_uart +( + uint8_t* src_ptr, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +); +void display_output +( + uint8_t* in_buffer, + uint32_t byte_length +); +#endif /* __HELPER_H_ */ diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/application/main.c b/applications/user-crypto/miv-rv32-ccm-services/src/application/main.c new file mode 100644 index 0000000..7938803 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/application/main.c @@ -0,0 +1,314 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file main.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Application demonstrating the CCM cryptography service. Please see the + * Readme.md for more details. + * + */ +#include "cal/calini.h" +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" +#include "fpga_design_config/fpga_design_config.h" +#include "miv_rv32_hal/miv_rv32_hal.h" +#include "helper.h" +#include "ccm.h" + +/****************************************************************************** + * User Crypto base address. This will be used in config_user.h in CAL. + *****************************************************************************/ +uint32_t g_user_crypto_base_addr = 0x62000000UL; + +/****************************************************************************** + * CoreUARTapb instance data. + *****************************************************************************/ +UART_instance_t g_uart; + +/*============================================================================== + Messages displayed over the UART. + */ +const uint8_t g_greeting_msg[] = +"\r\n\r\n\ +******************************************************************************\r\n\ +************* PolarFire User Crypto CCM Example Project **********************\r\n\ +******************************************************************************\r\n\ + This example project demonstrates the use of the PolarFire User Crypto \r\n\ + CCM service using AES cipher Services. The following CCM services \r\n\ + are demonstrated:\r\n\ + 1 - Encryption and authenticated.\r\n\ + 2 - Decryption and authenticated.\r\n"; + +const uint8_t g_select_operation_msg[] = +"\r\n\ +------------------------------------------------------------------------------\r\n\ + Select the CCM operation to perform:\r\n\ + Press key '1' to perform Encryption and Authenticated \r\n\ + Press key '2' to perform Decryption and Authenticated \r\n\ +------------------------------------------------------------------------------\r\n"; + +static const uint8_t aes_encrypt_select_msg[] = +"\r\n Selected Encryption and Authenticated using CCM. \r\n"; + +static const uint8_t aes_decrypt_select_msg[] = +"\r\n Selected Decryption and Authenticated using CCM. \r\n"; + +static const uint8_t g_separator[] = +"\r\n\ +------------------------------------------------------------------------------"; + +static const uint8_t read_key_msg[] = +"\r\n Enter the 128-bit/16-byte key: \r\n"; + +static const uint8_t read_nonce[] = +"\r\n Enter the Nonce (max : 16 Bytes): \r\n"; + +static const uint8_t read_aad[] = +"\r\n Enter the Additional authenticated data (max : 32 Bytes): \r\n"; + +static const uint8_t read_msg[] = +"\r\n Enter the input data to encrypt and authenticate (max : 64 bytes):\r\n"; + +static const uint8_t read_MAC_len[] = +"\r\n Enter the Number of octets in authentication field: \r\n\ + Press key '1' for 4 bytes \r\n\ + Press key '2' for 8 bytes \r\n\ + Press key '3' for 12 bytes \r\n\ + Press key '4' for 16 bytes \r\n"; + +static const uint8_t read_dec_msg[] = +"\r\n Enter the encrypted and authenticated message (max : 64 bytes):\r\n"; + +volatile __attribute__ ((section (".crypto_data"))) struct test_vector data = { 0x00 }; + +static void clear_ccm_var(void) +{ + uint16_t var = 0; + + data.M = 0; + data.L = 0; + data.lm = 0; + data.la = 0; + + for(var = 0; var < CCM_BLOCKSIZE; var++) + { + data.key[var] = 0; + data.nonce[var] = 0; + } + + for(var = 0; var < 100; var++) + { + data.msg[var] = 0; + data.output[var] = 0; + data.dec_mac[var] = 0; + } +} + +/*============================================================================== + Display greeting message when application is started. + */ +static void display_greeting(void) +{ + UART_send(&g_uart, g_greeting_msg,sizeof(g_greeting_msg)); +} + +/*============================================================================== + Display the choice of cryptographic operation to perform. + */ +static void display_operation_choices(void) +{ + UART_send(&g_uart, g_select_operation_msg, sizeof(g_select_operation_msg)); +} + +/*============================================================================== + Display the Option to continue. + */ +static void display_option(void) +{ + uint8_t rx_size; + uint8_t rx_buff[1]; + + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, (const uint8_t*)"\r\n Press any key to continue.\r\n", + sizeof("\r\n Press any key to continue.\r\n")); + do + { + rx_size = UART_get_rx(&g_uart, rx_buff, sizeof(rx_buff)); + } while(0u == rx_size); +} + +/*============================================================================== + Perform CCM encryption. + */ +void perform_ccm_encrypt( void ) +{ + uint16_t len = 0; + uint8_t addr = 0x4; + uint8_t i = 0x4; + uint8_t status = 0; + uint8_t text[256] = {0x00}; + uint8_t admin[4] = {0x00}; + uint8_t input_text[256] = {0x00}; + uint8_t user_key[12] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x10, 0x11}; + + + /* Clear input and output variables */ + clear_ccm_var(); + + /* Get key. */ + get_input_data((uint8_t*)&data.key, 16u, read_key_msg, sizeof(read_key_msg)); + + /* Nonce N */ + len = get_input_data((uint8_t*)&data.nonce, 16u, read_nonce, sizeof(read_nonce)); + data.L = 15 - len; + + /* Additional authenticated data a */ + data.la = get_input_data((uint8_t*)&data.aad, 32u, read_aad, sizeof(read_aad)); + + /* Message m */ + data.lm = get_input_data((uint8_t*)data.msg, 64u, read_msg, sizeof(read_msg)); + + /* Read MAC length */ + get_input_data((uint8_t*)&data.M, 1u, read_MAC_len, sizeof(read_MAC_len)); + data.M *= 4; + + /* CCM Encryption */ + MACCcmEnrypt(data.M, + data.L, + (uint8_t*)data.nonce, + (uint8_t*)data.msg, + data.lm, + (uint8_t*)data.aad, + data.la, + (uint16_t*)data.key, + (uint8_t *)data.output); + + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, (const uint8_t *)"\r\n Encrypted and Authentication data:\r\n", + sizeof("\r\n Encrypted and Authentication data:\r\n")); + display_output((uint8_t* )data.output, data.lm + data.M); +} + +/*============================================================================== + Perform CCM decryption. + */ +void perform_ccm_decrypt( void ) +{ + uint16_t len = 0; + uint8_t addr = 0x4; + uint8_t i = 0x4; + uint8_t status = 0; + uint8_t text[256] = {0x00}; + uint8_t admin[4] = {0x00}; + uint8_t input_text[256] = {0x00}; + uint8_t user_key[12] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, \ + 0x09, 0x0a, 0xb, 0x0c}; + + /* Clear input and output variables */ + clear_ccm_var(); + + /* Get key. */ + get_input_data((uint8_t*)&data.key, 16u, read_key_msg, sizeof(read_key_msg)); + + /* Nonce N */ + len = get_input_data((uint8_t*)&data.nonce, 16u, read_nonce, + sizeof(read_nonce)); + + data.L = 15 - len; + + /* Additional authenticated data a */ + data.la = get_input_data((uint8_t*)&data.aad, 32u, read_aad, + sizeof(read_aad)); + + /* Encrypted and authenticated message c */ + data.lm = get_input_data((uint8_t*)data.msg, 64u, read_dec_msg, + sizeof(read_dec_msg)); + + /* Read MAC length */ + get_input_data((uint8_t*)&data.M, 1u, read_MAC_len, sizeof(read_MAC_len)); + data.M *= 4; + + /* Decrypt and Authenticate the input data.*/ + MACCcmDecrypt( data.M, + data.L, + (uint8_t*)data.nonce, + (uint8_t*)data.msg, + data.lm, + (uint8_t*)data.aad, + data.la, + (uint16_t*)&data.key, + (uint8_t *)&data.output, + (uint8_t *)&data.dec_mac); + + /* Display decrypted data and MAC value. */ + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, (const uint8_t *)"\r\n Decrypted data:\r\n", + sizeof("\r\n Decrypted data:\r\n")); + display_output((uint8_t*)(data.output), data.lm - data.M); + + UART_send(&g_uart, (const uint8_t *)"\r\n Authenticated data (MAC):\r\n", + sizeof("\r\n Authenticated data (MAC):\r\n")); + display_output((uint8_t*)(data.dec_mac), data.M); +} + +/****************************************************************************** + * main function. + *****************************************************************************/ +int main( void ) +{ + uint8_t rx_buff[1]; + size_t rx_size = 0; + + /* Initialize CoreUARTapb with its base address, baud value. */ + UART_init(&g_uart, COREUARTAPB0_BASE_ADDR, BAUD_VALUE_115200, + (DATA_8_BITS | NO_PARITY)); + /* Initializes the Athena Processor */ + CALIni(); + + /* Display greeting message. */ + display_greeting(); + + /* Select CCM operation */ + display_operation_choices(); + + for(;;) + { + /* Read input from UART terminal. */ + rx_size = UART_get_rx(&g_uart, rx_buff, sizeof(rx_buff)); + if(rx_size > 0) + { + switch(rx_buff[0]) + { + case '1': + /* Perform Encryption using AES-128.*/ + UART_send(&g_uart, aes_encrypt_select_msg, + sizeof(aes_encrypt_select_msg)); + + /* Authenticate and encrypt the input data.*/ + perform_ccm_encrypt(); + + display_option(); + display_operation_choices(); + break; + + case '2': + /* Perform decryption using AES-128 */ + UART_send(&g_uart, aes_decrypt_select_msg, + sizeof(aes_decrypt_select_msg)); + + /* Authenticate and decrypt the input data.*/ + perform_ccm_decrypt(); + + display_option(); + display_operation_choices(); + break; + + default: + break; + } + } + } +} + diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h b/applications/user-crypto/miv-rv32-ccm-services/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h new file mode 100644 index 0000000..3fd1438 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h @@ -0,0 +1,156 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file fpga_design_config.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Sample design configuration settings. + * + */ + /*========================================================================*//** + @mainpage + Example file detailing how the fpga_design_config.h should be constructed + for the SoftConsole project targeted for Mi-V processors. + + @section intro_sec Introduction + The SoftConsole project targeted for Mi-V processors now have an improved + folder structure. Detailed description of the folder structure is available + at https://github.com/Mi-V-Soft-RISC-V/miv-rv32-documentation. + + The fpga_design_config.h must be stored as shown below + /boards//fpga_design_config.h + + Currently this file must be hand crafted when using the Mi-V Soft Processor. + In future, all the design and soft IP configurations will be automatically + generated from the Libero design description data. + + You can use this sample file as an example. + Rename this file from sample_fpga_design_config.h to fpga_design_config.h + and then customize it per your hardware design. + + @section Project configuration Instructions + 1. Change SYS_CLK_FREQ define to frequency of Mi-V Soft processor clock + 2 Add all the soft IP core BASE addresses + 3. Add the peripheral Core Interrupts to Mi-V Soft processor IRQ number + mappings + 4. Define MSCC_STDIO_UART_BASE_ADDR if you want a CoreUARTapb mapped to + STDIO + + **NOTE** + In the legacy folder structures, the file hw_config.h as was used at the + root of the project folder. This file is now depricated. + +*//*=========================================================================*/ + +#ifndef FPGA_DESIGN_CONFIG_H_ +#define FPGA_DESIGN_CONFIG_H_ + +/***************************************************************************//** + * Soft-processor clock definition + * This is the only clock brought over from the Mi-V Libero design. + */ +#ifndef SYS_CLK_FREQ +#define SYS_CLK_FREQ 83000000UL +#endif + +/***************************************************************************//** + * Peripheral base addresses. + * Format of define is: + * __BASE_ADDR + * The field is optional if there is only one instance of the core + * in the design + * MIV_ESS is an extended peripheral subsystem IP core with peripherals + * connections as defined below. + * The system can be further extended by attaching APB peripherals to the + * empty APB slots. + */ +#define COREUARTAPB0_BASE_ADDR 0x70000000UL +#define COREGPIO_OUT_BASE_ADDR 0x70001000UL +#define CORESPI_BASE_ADDR 0x70002000UL +#define CORESYS_SERV_BASE_ADDR 0x70003000UL + +/***************************************************************************//** + * Peripheral Interrupts are mapped to the corresponding Mi-V Soft processor + * interrupt in the Libero design. + * + * On the legacy RV32 cores, there can be up to 31 external interrupts (IRQ[30:0] + * pins). The legacy RV32 Soft processor external interrupts are defined in the + miv_rv32_plic.h + * + * These are of the form + * typedef enum +{ + NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + . + . + . + External_31_IRQn = 31 +} IRQn_Type; + + On the legacy RV32 processors, the PLIC identifies the interrupt and passes it + on to the processor core. The interrupt 0 is not used. The pin IRQ[0] should + map to External_1_IRQn likewise IRQ[30] should map to External_31_IRQn + +e.g + +#define TIMER0_IRQn External_30_IRQn +#define TIMER1_IRQn External_31_IRQn + + The MIV_RV32 soft processor has up to six optional system interrupts, MSYS_EI[n] + in addition to one EXT_IRQ. + The MIV_RV32 does not have an inbuilt PLIC and all the interrupts are directly + delivered to the processor core, hence unlike legacy RV32 cores, no interrupt + number mapping is necessary on MIV_RV32 core. + */ + +/**************************************************************************** + * Baud value to achieve a 115200 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ +#define BAUD_VALUE_115200 ((SYS_CLK_FREQ / (16 * 115200)) - 1) + +/****************************************************************************** + * Baud value to achieve a 57600 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + #define BAUD_VALUE_57600 ((SYS_CLK_FREQ / (16 * 57600)) - 1) + +/***************************************************************************//** + * Define MSCC_STDIO_THRU_CORE_UART_APB in the project settings if you want the + * standard IOs to be redirected to a terminal via UART. + */ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +/* + * A base address mapping for the STDIO printf/scanf mapping to CortUARTapb + * must be provided if it is being used + * + * e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR + */ +#define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB0_BASE_ADDR + +#ifndef MSCC_STDIO_UART_BASE_ADDR +#error MSCC_STDIO_UART_BASE_ADDR not defined- e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR +#endif + +#ifndef MSCC_STDIO_BAUD_VALUE +/* + * The MSCC_STDIO_BAUD_VALUE define should be set in your project's settings to + * specify the baud value used by the standard output CoreUARTapb instance for + * generating the UART's baud rate if you want a different baud rate from the + * default of 115200 baud + */ +#define MSCC_STDIO_BAUD_VALUE 115200 +#endif /*MSCC_STDIO_BAUD_VALUE*/ + +#endif /* end of MSCC_STDIO_THRU_CORE_UART_APB */ +/******************************************************************************* + * End of user edit section + */ +#endif /* FPGA_DESIGN_CONFIG_H_ */ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld b/applications/user-crypto/miv-rv32-ccm-services/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld new file mode 100644 index 0000000..8541db6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld @@ -0,0 +1,160 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-ram.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * debug image executing in SRAM. + * + * This linker script assumes that a RAM is connected at on Mi-V soft processor + * memory space pointed by the reset vector address. + * + * NOTE : Modify the memory section address and the size according to your + * Libero design. + * For example: + * 1) If you want to download and step debug at a different RAM memory address in + * your design (For example TCM base address) than the one provided in this file. + * 2) The MIV_RV32, when used with MIV_ESS IP, provides ways to copy the executable + * HEX file from external Non-Volatile memory into the TCM at reset. In this + * case your executable must be linked to the TCM address. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +MEMORY +{ + ram (rwx) : ORIGIN = 0x80000000, LENGTH = 64k + crypto_ram (rw) : ORIGIN = 0x61000000, LENGTH = 32k +} + +RAM_START_ADDRESS = 0x80000000; /* Must be the same value MEMORY region ram ORIGIN above. */ +RAM_SIZE = 64k; /* Must be the same value MEMORY region ram LENGTH above. */ +STACK_SIZE = 2k; /* needs to be calculated for your application */ +HEAP_SIZE = 0k; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > ram + + .text : ALIGN(0x10) + { + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } > ram + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } > ram + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } > ram + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram + + . = 0x61000000; + .crypto_data : ALIGN(0x10) + { + . = ALIGN(0x10); + *(.crypto_data) + } > crypto_ram +} + diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/aesf5200.h b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/aesf5200.h new file mode 100644 index 0000000..889dddd --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/aesf5200.h @@ -0,0 +1,104 @@ +/* ------------------------------------------------------------------- + $Rev: 1293 $ $Date: 2017-07-27 14:09:14 -0400 (Thu, 27 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for F5200 AES function hardware implementation for + CAL. + ------------------------------------------------------------------- */ + +#ifndef AESF5200_H +#define AESF5200_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef AESF5200_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATR aesf5200aes (SATSYMTYPE eSymType, SATSYMMODE eMode, + void *pIV, SATBOOL bLoadIV, const void *pSrc, void *pDest, SATUINT32_t uiLen, + SATBOOL bDecrypt); + +extern SATR aesf5200aesk (SATSYMTYPE eSymType, const SATUINT32_t *puiKey); + +extern SATR aesf5200gcm (SATSYMTYPE eSymType, SATSYMMODE eMode, void *pIV, + const void *pSrc, void *pDest, SATUINT32_t uiEncLen, + const void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, SATUINT32_t uiMACLen, + SATBOOL bDecrypt); + +extern SATR aesf5200gcmdma(SATSYMTYPE eSymType, SATSYMMODE eMode, void *pIV, + const void *pSrc, void *pDest, SATUINT32_t uiEncLen, const void *pAuth, + SATUINT32_t uiAuthLen, void *pMAC, SATUINT32_t uiMACLen, SATBOOL bDecrypt, + SATUINT32_t uiDMAChConfig); + +extern SATR aesf5200kw(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR aesf5200kwp(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR aesf5200kr(SATSYMTYPE eSymType, SATSYMMODE eMode, + const SATUINT32_t *puiKey, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKrf, SATBOOL bDecrypt); + +extern SATR aesf5200dma(SATSYMTYPE eSymType, SATSYMMODE eMode, void *pIV, + SATBOOL bLoadIV, const void *pExtSrc, void *pExtDest, SATUINT32_t uiLen, + SATUINT32_t uiDMAChConfig, SATBOOL bDecrypt); + +extern SATR aesf5200krdma(SATSYMTYPE eSymType, SATSYMMODE eMode, + const SATUINT32_t *puiKey, void *pIV, SATBOOL bLoadIV, const void *pExtSrc, + void *pExtDest, SATUINT32_t uiLen, SATUINT32_t uiKrf, + SATUINT32_t uiDMAChConfig, SATBOOL bDecrypt); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/calcontext.h b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/calcontext.h new file mode 100644 index 0000000..fc408c2 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/calcontext.h @@ -0,0 +1,88 @@ +/* ------------------------------------------------------------------- + $Rev: 1298 $ $Date: 2017-08-04 13:04:19 -0400 (Fri, 04 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL context management functions. + ------------------------------------------------------------------- */ + +#ifndef CALCONTEXT_H +#define CALCONTEXT_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* Function resource handle. */ +/* ----- ------ ------- ---- */ +#define SATRES_DEFAULT (SATRESHANDLE)0U +#define SATRES_CALSW (SATRESHANDLE)1U + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ +typedef struct{ + SATUINT32_t uiBase; + SATRESCONTEXTPTR pContext; + }SATRESHANDLESTRUCT; + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALCONTEXT_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATRESCONTEXTPTR CALContextCurrent(const SATRESHANDLE hResource); + +extern SATR CALContextLoad(const SATRESHANDLE hResource, + const SATRESCONTEXTPTR pContext); + +extern SATR CALContextRemove(const SATRESHANDLE hResource); + +extern SATR CALContextUnload(const SATRESHANDLE hResource); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern void init_reshandles(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/calenum.h b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/calenum.h new file mode 100644 index 0000000..6281f3f --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/calenum.h @@ -0,0 +1,289 @@ +/* ------------------------------------------------------------------- + $Rev: 1566 $ $Date: 2018-09-14 11:04:30 -0400 (Fri, 14 Sep 2018) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + This file defines common types in the CAL. + + Most CAL types and constants are defined with the "SAT" prefix to + reduce the chance of name space collisions with other users. + ------------------------------------------------------------------- */ + +#ifndef CALENUM_H +#define CALENUM_H + +/* -------- */ +/* Includes */ +/* -------- */ + +/* CAL base types. */ +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ +/* NULL definitions. */ +#define SAT_NULL 0 + +/* Boolean definitions. */ +#define SAT_TRUE ((SATBOOL)1) +#define SAT_FALSE ((SATBOOL)0) + + +/* Major cipher key/SSP type. */ +/* ----- ------ ------- ----- */ +#define SATSSPTYPE_NULL (SATSSPTYPE)0 +#define SATSSPTYPE_SYMKEY (SATSSPTYPE)1 +#define SATSSPTYPE_ASYMKEY (SATSSPTYPE)2 +/* Special marker for end of list. */ +#define SATSSPTYPE_LAST (SATSSPTYPE)3 + + +/* Asymmetric Ciphers */ +/* ---------- ------- */ +#define SATASYMTYPE_NULL (SATASYMTYPE)0U +#define SATASYMTYPE_DSA_SIGN (SATASYMTYPE)1U +#define SATASYMTYPE_DSA_VERIFY (SATASYMTYPE)2U +#define SATASYMTYPE_RSA_ENCRYPT (SATASYMTYPE)3U +#define SATASYMTYPE_RSA_DECRYPT (SATASYMTYPE)4U +#define SATASYMTYPE_DH (SATASYMTYPE)5U +#define SATASYMTYPE_ECDSA_SIGN (SATASYMTYPE)6U +#define SATASYMTYPE_ECDSA_VERIFY (SATASYMTYPE)7U +#define SATASYMTYPE_ECDH (SATASYMTYPE)8U +#define SATASYMTYPE_RSA_SIGN (SATASYMTYPE)9U +#define SATASYMTYPE_RSA_VERIFY (SATASYMTYPE)10U +/* Special marker for end of list. */ +#define SATASYMTYPE_LAST (SATASYMTYPE)11U + + +/* Encoding Types */ +/* -------- ----- */ +#define SATRSAENCTYPE_NULL (SATRSAENCTYPE)0U +#define SATRSAENCTYPE_PKCS (SATRSAENCTYPE)1U +#define SATRSAENCTYPE_ANSI (SATRSAENCTYPE)2U +#define SATRSAENCTYPE_PSS (SATRSAENCTYPE)3U +/* Special marker for end of list. */ +#define SATRSAENCTYPE_LAST (SATRSAENCTYPE)4U + + +/* Symmetric Ciphers */ +/* --------- ------- */ + +/* Cipher Type. */ +#define SATSYMTYPE_NULL (SATSYMTYPE)0U +#define SATSYMTYPE_AES128 (SATSYMTYPE)1U +#define SATSYMTYPE_AES192 (SATSYMTYPE)2U +#define SATSYMTYPE_AES256 (SATSYMTYPE)3U +#define SATSYMTYPE_AESKS128 (SATSYMTYPE)4U +#define SATSYMTYPE_AESKS192 (SATSYMTYPE)5U +#define SATSYMTYPE_AESKS256 (SATSYMTYPE)6U +/* Special marker for end of list. */ +#define SATSYMTYPE_LAST (SATSYMTYPE)7U + +/* Names for common cipher key lengths, in bits. */ +#define SATSYMKEYSIZE_AES128 (SATSYMKEYSIZE)128U +#define SATSYMKEYSIZE_AES192 (SATSYMKEYSIZE)192U +#define SATSYMKEYSIZE_AES256 (SATSYMKEYSIZE)256U +#define SATSYMKEYSIZE_AESKS128 (SATSYMKEYSIZE)256U +#define SATSYMKEYSIZE_AESKS192 (SATSYMKEYSIZE)384U +#define SATSYMKEYSIZE_AESKS256 (SATSYMKEYSIZE)512U + +/* Cipher Mode. */ +#define SATSYMMODE_NULL (SATSYMMODE)0U +#define SATSYMMODE_ECB (SATSYMMODE)1U +#define SATSYMMODE_CBC (SATSYMMODE)2U +#define SATSYMMODE_CFB (SATSYMMODE)3U +#define SATSYMMODE_OFB (SATSYMMODE)4U +#define SATSYMMODE_CTR (SATSYMMODE)5U +#define SATSYMMODE_GCM (SATSYMMODE)6U +#define SATSYMMODE_GHASH (SATSYMMODE)8U +/* Special marker for end of list. */ +#define SATSYMMODE_LAST (SATSYMMODE)9U + + +/* Hashes */ +/* ------ */ +#define SATHASHTYPE_NULL (SATHASHTYPE)0U +#define SATHASHTYPE_SHA1 (SATHASHTYPE)1U +#define SATHASHTYPE_SHA224 (SATHASHTYPE)2U +#define SATHASHTYPE_SHA256 (SATHASHTYPE)3U +#define SATHASHTYPE_SHA384 (SATHASHTYPE)4U +#define SATHASHTYPE_SHA512 (SATHASHTYPE)5U +#define SATHASHTYPE_SHA512_224 (SATHASHTYPE)6U +#define SATHASHTYPE_SHA512_256 (SATHASHTYPE)7U +/* Special marker for end of list. */ +#define SATHASHTYPE_LAST (SATHASHTYPE)8U + +/* Hash sizes defined in bits */ +#define SATHASHSIZE_NULL (SATHASHSIZE)0U +#define SATHASHSIZE_SHA1 (SATHASHSIZE)160U +#define SATHASHSIZE_SHA224 (SATHASHSIZE)224U +#define SATHASHSIZE_SHA256 (SATHASHSIZE)256U +#define SATHASHSIZE_SHA384 (SATHASHSIZE)384U +#define SATHASHSIZE_SHA512 (SATHASHSIZE)512U +#define SATHASHSIZE_SHA512_224 (SATHASHSIZE)224U +#define SATHASHSIZE_SHA512_256 (SATHASHSIZE)256U + +#define SATHASHSIZE_HASH160 (SATHASHSIZE)160U +#define SATHASHSIZE_HASH192 (SATHASHSIZE)192U +#define SATHASHSIZE_HASH224 (SATHASHSIZE)224U +#define SATHASHSIZE_HASH256 (SATHASHSIZE)256U +#define SATHASHSIZE_HASH320 (SATHASHSIZE)320U +#define SATHASHSIZE_HASH384 (SATHASHSIZE)384U +#define SATHASHSIZE_HASH512 (SATHASHSIZE)512U +#define SATHASHSIZE_HASH521 (SATHASHSIZE)521U + + +/* Message Authentication Codes */ +/* ------- -------------- ----- */ + +/* Message Authentication Types */ +#define SATMACTYPE_NULL (SATMACTYPE)0U +#define SATMACTYPE_SHA1 (SATMACTYPE)1U +#define SATMACTYPE_SHA224 (SATMACTYPE)2U +#define SATMACTYPE_SHA256 (SATMACTYPE)3U +#define SATMACTYPE_SHA384 (SATMACTYPE)4U +#define SATMACTYPE_SHA512 (SATMACTYPE)5U +#define SATMACTYPE_SHA512_224 (SATMACTYPE)6U +#define SATMACTYPE_SHA512_256 (SATMACTYPE)7U +#define SATMACTYPE_AESCMAC128 (SATMACTYPE)10U +#define SATMACTYPE_AESCMAC192 (SATMACTYPE)11U +#define SATMACTYPE_AESCMAC256 (SATMACTYPE)12U +#define SATMACTYPE_AESGMAC (SATMACTYPE)13U +/* Special marker for end of list. */ +#define SATMACTYPE_LAST (SATMACTYPE)14U + + +/* Message Authentication Flags */ +#define SATMACFLAG_OP (SATMACTYPEFLAG)0U +#define SATMACFLAG_FIRSTPASS (SATMACTYPEFLAG)1U +#define SATMACFLAG_FINALPASS (SATMACTYPEFLAG)2U +#define SATMACFLAG_IKEYFINAL (SATMACTYPEFLAG)4U +#define SATMACFLAG_OKEYFINAL (SATMACTYPEFLAG)8U + + +/* Non-deterministic Random Bit Generator */ +/* ------- -------------- ----- */ + +/* NRBG register write enables */ +#define SATNRBGCONFIG_NONE 0x0 +#define SATNRBGCONFIG_RNG_CSR 0x1 +#define SATNRBGCONFIG_RNG_CNTLIM 0x2 +#define SATNRBGCONFIG_RNG_VOTIMER 0X4 +#define SATNRBGCONFIG_RNG_FMSK 0X8 + +/* RNG_CSR access defines */ +#define SATNRBGCONFIG_CSR_RODIS 0x0 +#define SATNRBGCONFIG_CSR_ROEN 0x1 +#define SATNRBGCONFIG_CSR_ROFATAL 0x2 +#define SATNRBGCONFIG_CSR_ROFATALCLR 0X4 + +/* RNG_FMSK mask values */ +#define SATNRBGCONFIG_FMSK_ROOSCF 0xFF +#define SATNRBGCONFIG_FMSK_MONOBITF 0x10000 +#define SATNRBGCONFIG_FMSK_POKERF 0x20000 +#define SATNRBGCONFIG_FMSK_RUNSF 0x40000 +#define SATNRBGCONFIG_FMSK_LRUNSF 0x80000 +#define SATNRBGCONFIG_FMSK_F1401 0xF0000 +#define SATNRBGCONFIG_FMSK_REPCNTF 0x100000 +#define SATNRBGCONFIG_FMSK_APROPF 0x200000 +#define SATNRBGCONFIG_FMSK_SP800 0x300000 + +/* RNG_ROHEALTH mask values */ +#define SATNRBGCONFIG_HLTH_ROOSCF 0x3FC0 +#define SATNRBGCONFIG_HLTH_APROPF 0x20 +#define SATNRBGCONFIG_HLTH_REPCNTF 0x10 +#define SATNRBGCONFIG_HLTH_LRUNSF 0x8 +#define SATNRBGCONFIG_HLTH_RUNSF 0x4 +#define SATNRBGCONFIG_HLTH_POKERF 0x2 +#define SATNRBGCONFIG_HLTH_MONOBITF 0x1 + + +/* Return Codes */ +/* ------ ----- */ +#define SATR_SUCCESS (SATR)0U +#define SATR_FAIL (SATR)1U +#define SATR_BADPARAM (SATR)2U +#define SATR_VERIFYFAIL (SATR)3U +#define SATR_KEYSFULL (SATR)4U +#define SATR_BUSY (SATR)5U +#define SATR_ROFATAL (SATR)6U +#define SATR_PARITYFLUSH (SATR)7U +#define SATR_SIGNFAIL (SATR)8U +#define SATR_VALIDATEFAIL (SATR)9U +#define SATR_PAF (SATR)10U +#define SATR_VALPARMX (SATR)11U +#define SATR_VALPARMY (SATR)12U +#define SATR_VALPARMB (SATR)13U +#define SATR_DCMPPARMX (SATR)14U +#define SATR_DCMPPARMB (SATR)15U +#define SATR_DCMPPARMP (SATR)16U +#define SATR_SIGNPARMD (SATR)17U +#define SATR_SIGNPARMK (SATR)18U +#define SATR_VERPARMR (SATR)19U +#define SATR_VERPARMS (SATR)20U +#define SATR_MSBICV1 (SATR)21U +#define SATR_MSBICV2 (SATR)22U +#define SATR_PADLEN (SATR)23U +#define SATR_LSB0PAD (SATR)24U +#define SATR_BADLEN (SATR)25U +#define SATR_BADHASHTYPE (SATR)26U +#define SATR_BADTYPE (SATR)27U +#define SATR_BADMODE (SATR)28U +#define SATR_BADCONTEXT (SATR)29U +#define SATR_BADHASHLEN (SATR)30U +#define SATR_BADMACTYPE (SATR)31U +#define SATR_BADMACLEN (SATR)32U +#define SATR_BADHANDLE (SATR)33U +#define SATR_FNP (SATR)34U +#define SATR_HFAULT (SATR)35U +#define SATR_NOPEND (SATR)36U +#define SATR_BADRSAENC (SATR)37U +#define SATR_BADMOD (SATR)38U +/* Special marker for end of list. */ +#define SATR_LAST (SATR)39U + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* See caltypes.h for type definitions associated with defines above. */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALENUM_C +#ifdef __cplusplus +extern "C" { +#endif + +/* NOTE: this header file does not have an associated C file. */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/calini.h b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/calini.h new file mode 100644 index 0000000..62461d1 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/calini.h @@ -0,0 +1,69 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL initialization + ------------------------------------------------------------------- */ + +#ifndef CALINI_H +#define CALINI_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALINI_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALIni(void); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/calpolicy.h b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/calpolicy.h new file mode 100644 index 0000000..2a43445 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/calpolicy.h @@ -0,0 +1,183 @@ +/* ------------------------------------------------------------------- + $Rev: 1293 $ $Date: 2017-07-27 14:09:14 -0400 (Thu, 27 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file defining CAL policy for endianess, HW/SW, etc. + ------------------------------------------------------------------- */ + +#ifndef CALPOLICY_H +#define CALPOLICY_H + +/* -------- */ +/* Includes */ +/* -------- */ + +/* The following include provides a custom configuration header file when + CALCONFIGH is defined +*/ +#ifdef CALCONFIGH +# include CALCONFIGH +#else +# error "CALCONFIGH not defined. CAL requires a custom configuration header \ +defined by CALCONFIGH. Review CAL README." +#endif + +/* ------- */ +/* Defines */ +/* ------- */ + +/* Context switching */ +#ifndef MAXRESHANDLES +# define MAXRESHANDLES 1 +#endif + +/* Little Endian (default) / Big Endian */ +#ifndef SAT_LITTLE_ENDIAN +# define SAT_LITTLE_ENDIAN 1 +#endif + +/* PK SW Point Validate Checking */ +#ifndef PKSWCHKVALPT +# define PKSWCHKVALPT 1 +#endif + +/* DMA */ +#ifndef USE_X52EXEC_DMA +# define USE_X52EXEC_DMA 0 +#endif + +/* SHA */ +#define MAXHASHLEN 512 +#define MAXHMACKEYLEN 512 + +/* RNG */ +#define NRBGSIMNUMRO 16 +#define ENTROPYMEMBLOCKS 7 +#define BUFMEMBLOCKS 3 +#ifndef RNXBLKLEN +#define RNXBLKLEN 32 +#endif +#ifndef RNXBLKOUTLEN +#define RNXBLKOUTLEN 4 +#endif + +#ifndef USENRBGSW +# define USENRBGSW 0 +#endif + +/* PK */ +#ifndef PKX0_BASE +# define PKX0_BASE 0xE0000000u +#endif + +#if USEPKSW +# ifndef MAXMODSIZE +# define MAXMODSIZE 8192 +# endif +# ifndef PKSWBUFSIZE +# define PKSWBUFSIZE 15*(MAXMODSIZE/32) +# endif +#else +# define USEPKSW 0 +#endif + +/* Set default values for X52 configuration defines. */ +#ifndef X52_CFG_OPT +# define X52_CFG_OPT 0 +#endif +#ifndef X52_LIR_LEN +# define X52_LIR_LEN 0x800 +#endif +#ifndef X52_BER_LEN +# define X52_BER_LEN 0x400 +#endif +#ifndef X52_MMR_LEN +# define X52_MMR_LEN 0x400 +#endif +#ifndef X52_TSR_LEN +# define X52_TSR_LEN 0x400 +#endif +#ifndef X52_FPR_LEN +# define X52_FPR_LEN 0x400 +#endif +#if X52_LIR_ROM_LEN>0 && X52_LIR_LEN>X52_LIR_ROM_LEN +# define PKX_OFFSET 2048 +#else +# define PKX_OFFSET 0 +#endif + +/* X52 Configuration Options */ +#define AESPKX (X52_CFG_OPT&0x00000001u) +#define AESPKXGCM (X52_CFG_OPT&0x00000008u) +#define AESPKXFASTKEY (X52_CFG_OPT&0x01000000u) +#define SHAPKXOPT1 (X52_CFG_OPT&0x00000020u) +#define SHAPKXOPT224 (X52_CFG_OPT&0x00000040u) +#define SHAPKXOPT256 (X52_CFG_OPT&0x00000080u) +#define SHAPKXOPT384 (X52_CFG_OPT&0x00000100u) +#define SHAPKXOPT512 (X52_CFG_OPT&0x00000200u) +#define SHAPKXOPT5124 (X52_CFG_OPT&0x00400000u) +#define SHAPKXOPT5126 (X52_CFG_OPT&0x00800000u) + +/* Define the maximum number of return values that may be handled using + CAL*TrfRes() function(s). +*/ +#define CAL_MAXTRFS 4 + +/* Volatile pointer operations */ +/* These access macros are designed so that they may be redefined by a + user compiling CAL. +*/ +#ifndef CALREAD32 +# define CALREAD32(ptr) ( *(ptr) ) +#endif +#ifndef CALWRITE32 +# define CALWRITE32(ptr, val) ( *(ptr)=val ) +#endif +#ifndef CALPOLL32 +# define CALPOLL32(ptr, val, mask) while ((*(ptr) & (mask)) != (val)); +#endif + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +#ifndef CALPOLICY_C +#ifdef __cplusplus +extern "C" { +#endif + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +/* NOTE: this header file does not have an associated C file. */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/caltypes.h b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/caltypes.h new file mode 100644 index 0000000..3b2fe0b --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/caltypes.h @@ -0,0 +1,328 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + This file defines common types in the CAL. + + Since support for the C99 stdint.h integer types is not universal, + these are defined herein and may require customization from compiler + to compiler, or use of the stdint.h header, if present (recommended). + + C99 supports 64-bit types; however, support in older compilers is + spotty. For those that do not support it, the macro NO64BITINT may be + defined by the user to prevent defintion of 64-bit types. This is + generally safe with CAL-PK and CAL-SYM; however, this is incompatible + with CAL-SW. + + Most CAL types and constants are defined with the "SAT" prefix to + reduce the chance of name space collisions with other users. + ------------------------------------------------------------------- */ + +#ifndef CALTYPES_H +#define CALTYPES_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* Base Types */ +/* ---- ----- */ + +/* The user may compile using stdint.h instead of the definitions below + by defining the macro INC_STDINT_H. */ +#ifdef INC_STDINT_H +#include +#endif + +/* Integer type abstraction layer. */ +#ifndef INC_STDINT_H + +typedef unsigned char uint8_t; +typedef signed char int8_t; + +typedef unsigned short uint16_t; +typedef signed short int16_t; + +typedef unsigned int uint32_t; +typedef int int32_t; + +/* stdint.h is a C99 feature, and C99 supports 64-bit ints, so this is + immune to the macro used to disable 64-bit int support. +*/ +typedef unsigned long long uint64_t; +typedef long long int64_t; + +typedef long uintptr_t; + +#endif + +/* Boolean type. */ +typedef uint8_t SATBOOL; + +/* Unsigned integer type */ +typedef uint8_t SATUINT8_t; +typedef uint16_t SATUINT16_t; +typedef uint32_t SATUINT32_t; +#ifdef INC_STDINT_H +typedef uint64_t SATUINT64_t; +#else +#ifndef NO64BITINT +typedef uint64_t SATUINT64_t; +#endif +#endif + +/* Integer type */ +typedef int8_t SATINT8_t; +typedef int16_t SATINT16_t; +typedef int32_t SATINT32_t; +#ifdef INC_STDINT_H +typedef int64_t SATINT64_t; +#else +#ifndef NO64BITINT +typedef int64_t SATINT64_t; +#endif +#endif + +typedef uintptr_t SATUINTPTR_t; + +/* Major cipher key/SSP type. */ +/* ----- ------ ------- ----- */ +typedef uint8_t SATSSPTYPE; +typedef SATSSPTYPE * SATSSPTYPEPTR; + + +/* Asymmetric Ciphers */ +/* ---------- ------- */ + +/* Cipher type. */ +typedef uint8_t SATASYMTYPE; +typedef SATASYMTYPE * SATASYMTYPEPTR; + +/* Cipher size type. */ +typedef uint16_t SATASYMSIZE; +typedef SATASYMSIZE * SATASYMSIZEPTR; + +/* Cipher encoding */ +typedef uint8_t SATRSAENCTYPE; +typedef SATRSAENCTYPE * SATRSAENCTYPEPTR; + +/* DSA public/private key. */ +typedef struct { + uint16_t ui16PLen; /* Length of modulus p. */ + uint16_t ui16QLen; /* Length of prime divisor q. */ + uint32_t *pui32P; /* Prime modulus p. */ + uint32_t *pui32Q; /* Prime divisor q. */ + uint32_t *pui32G; /* Generator g, length==p. */ + uint32_t *pui32X; /* Private key x, length==p. */ + uint32_t *pui32Y; /* Private key y, length==q. */ +} SATASYMDSADOMAIN; +typedef SATASYMDSADOMAIN * SATASYMDSADOMAINPTR; + + +/* Symmetric Ciphers */ +/* --------- ------- */ + +/* Cipher type. */ +typedef uint8_t SATSYMTYPE; +typedef SATSYMTYPE * SATSYMTYPEPTR; + +/* Cipher key size type (in bits). */ +typedef uint16_t SATSYMKEYSIZE; +typedef SATSYMKEYSIZE * SATSYMKEYSIZEPTR; + +/* Cipher mode type. */ +typedef uint8_t SATSYMMODE; +typedef SATSYMMODE * SATSYMMODEPTR; + +/* Cipher key object. */ +/* Other fields are only valid when sstCipher!=SATSYMTYPE_NULL. */ +typedef struct { + SATSYMTYPE sstCipher; + SATSYMKEYSIZE ssksKeyLen; + uint32_t *pui32Key; +} SATSYMKEY; +typedef SATSYMKEY * SATSYMKEYPTR; + + +/* Hashes */ +/* ------ */ + +/* Hash type. */ +typedef uint8_t SATHASHTYPE; +typedef SATHASHTYPE * SATHASHTYPEPTR; + +/* Hash size type (in bits). */ +typedef uint16_t SATHASHSIZE; +typedef SATHASHSIZE * SATHASHSIZEPTR; + + +/* Context switching. */ +/* ----- ------ ------- ----- */ + +typedef uint32_t SATRESHANDLE; +typedef SATRESHANDLE * SATRESHANDLEPTR; + +typedef struct { + SATHASHTYPE sshashtype; + uint32_t uiRunLen; + uint32_t uiHash[MAXHASHLEN/32]; /* holds intermed hash */ +} SHACTX; + +typedef struct { + SATHASHTYPE sshashtype; + uint32_t uiRunLen; + uint32_t uiKeyLen; + uint32_t uiHash[MAXHASHLEN/32]; /* holds intermed hash */ + uint32_t uiKey[MAXHMACKEYLEN/32]; /* holds intermed key */ +} SHAHMACCTX; + +typedef struct { + uint8_t uiContextType; + union{ + SHACTX ctxSHA; + SHAHMACCTX ctxMAC; + }CTXUNION; +} SATRESCONTEXT; +typedef SATRESCONTEXT * SATRESCONTEXTPTR; + + +/* Message Authentication Codes */ +/* ------- -------------- ----- */ + +/* MAC type. */ +typedef uint8_t SATMACTYPE; +typedef SATMACTYPE * SATMACTYPEPTR; +typedef uint8_t SATMACTYPEFLAG; + + +/* Random Number Generator */ +/* ------ ------ --------- */ +typedef union { + uint32_t u32[4]; + uint8_t u8[16]; +} uint128_t; + +typedef struct { + uint128_t ui128V; + uint128_t ui128K[2]; + uint32_t uiReseedCnt; + uint32_t uiReseedLim; + uint32_t uiEntropyFactor; + SATSYMKEYSIZE eStrength; + SATBOOL bTesting; + +} DRBGCTX; + +typedef DRBGCTX * DRBGCTXPTR; + + +/* Function Return Code */ +/* -------- ------ ---- */ +typedef uint16_t SATR ; +typedef SATR * SATRPTR ; + + +/* Transfer Results */ +/* -------- ------- */ +typedef struct { + SATUINT32_t uiLen; + volatile SATUINT32_t* vpuiSrc; + void* pDest; +} SATDATATRF; + +typedef struct { + SATUINT32_t uiResType; + SATUINT32_t uiNumDataTrf; + SATDATATRF dtrfArray[CAL_MAXTRFS]; +} SATRESULT; + + +/* EC Ultra Structs */ +/* -- ----- ------- */ +typedef uint32_t SATECTYPE; + +typedef struct { + SATUINT32_t uiLen; + SATUINT32_t* puiX; + SATUINT32_t* puiY; +} SATECPOINT; + +typedef struct { + SATUINT32_t uiLen; + SATUINT32_t* puiMod; + SATUINT32_t* puiMontPrecompute; + SATUINT32_t* puiRSqd; +} SATECMONTMOD; + +typedef struct { + SATUINT32_t uiCurveSize; + SATECTYPE eCurveType; + SATECPOINT* pBasePoint; + SATECMONTMOD* pModP; + SATECMONTMOD* pModN; + SATUINT32_t* puiA; + SATUINT32_t* puiB; +} SATECCURVE; + +typedef struct { + SATUINT32_t uiLen; + SATUINT32_t* puiSigR; + SATUINT32_t* puiSigS; + SATUINT32_t* puiSigX; + SATUINT32_t* puiSigY; +} SATECDSASIG; + +typedef struct { + SATHASHSIZE sHashLen; + SATUINT32_t* puiHash; +} SATHASH; + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALTYPES_C +#ifdef __cplusplus +extern "C" { +#endif + +/* NOTE: this header file does not have an associated C file. */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/config_user.h b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/config_user.h new file mode 100644 index 0000000..3728565 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/config_user.h @@ -0,0 +1,44 @@ +/* ------------------------------------------------------------------- + $Rev: 727 $ $Date: 2017-10-20 16:50:53 -0400 (Fri, 20 Oct 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + + User configuration file to include/exclude CAL components. + ------------------------------------------------------------------- */ + +#ifndef CALCONFIG_F5200_H +#define CALCONFIG_F5200_H + +#include "x52cfg_user.h" +#include + +extern uint32_t g_user_crypto_base_addr; + +#define SAT_LITTLE_ENDIAN 1 +#define PKX0_BASE (g_user_crypto_base_addr) +#define USEPKX 1 +#define USEAESPKX 1 +#define USESHAPKX 1 +#define USEDRBGPKX 1 +#define USENRBGPKX 1 +#define USECALCTX 1 + +#endif diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/drbg.h b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/drbg.h new file mode 100644 index 0000000..dba16f7 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/drbg.h @@ -0,0 +1,91 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for DRBG functions for CAL + ------------------------------------------------------------------- */ + +#ifndef DRBG_H +#define DRBG_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ +#define CALDRBGENTROPYFACTOR 2 + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef DRBG_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALDRBGInstantiate(const SATUINT32_t *puiNonce, + SATUINT32_t uiNonceLen, const SATUINT32_t *puiPzStr, + SATUINT32_t uiPzStrLen, SATSYMKEYSIZE eStrength, + SATUINT32_t uiEntropyFactor, SATUINT32_t uiReseedLim, SATBOOL bTesting); + +extern SATR CALDRBGReseed(const SATUINT32_t *puiAddIn, SATUINT32_t uiAddInLen); + +extern SATR CALDRBGGenerate(const SATUINT32_t *puiAddIn, SATUINT32_t uiAddInLen, + SATBOOL bPredResist, SATUINT32_t *puiOut, SATUINT32_t uiOutBlocks); + +extern SATR CALDRBGUninstantiate(void); + +extern SATR CALDRBGGetCtx(DRBGCTXPTR drbgCtxExt); + +extern SATR CALDRBGLoadCtx(DRBGCTXPTR drbgCtxExt); + +extern SATR CALDRBGGetbInst(void); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +extern SATR CALDrbgTrfRes(SATBOOL bBlock); + +extern void CALDrbgIni(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/drbgf5200.h b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/drbgf5200.h new file mode 100644 index 0000000..d7f6c4c --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/drbgf5200.h @@ -0,0 +1,120 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for F5200 DRBG function hardware implementations + in CAL. + ------------------------------------------------------------------- */ + +#ifndef DRBGF5200_H +#define DRBGF5200_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ +#define RNXEFACTOR (X52BER+2) +#define RNXIRLEN (X52BER+2) +#define RNXKEYORD (X52BER+3) +#define RNXRESPRED (X52BER+4) +#define RNXTESTSEL (X52BER+5) +#define RNXBADDIN (X52BER+6) +#define RNXPPSTR (X52BER+7) +#define RNXPCTX (X52BER+8) +#define RNXPRENT (X52BER+13) +#define RNXITMP3 (X52BER+20) +#define RNXPCTX2 (X52BER+22) +/* These use same locs as tb generator, but can change */ +#define RNXRDATA (X52BER_ENDIAN+0x24) +#define RNXAIDATAOFF 0x0062 +#define RNXAIDATA (X52BER_ENDIAN+RNXAIDATAOFF) +#define RNXCTXOFF 0x0094 +#define RNXCTX (X52FPR+RNXCTXOFF) +#define RNXCTXV (X52FPR_ENDIAN+RNXCTXOFF+6) +#define RNXCTXVMMR (X52MMR_ENDIAN+RNXCTXOFF+6) +#define RNXTESTENT (X52TSR_ENDIAN+8) + +#define RNXCTXWORDS 18 +#define RNXBLENLOC (RNXCTX+RNXCTXWORDS) +#define RNXBOUTLENLOC (RNXCTX+RNXCTXWORDS+1) + +#define RNXMAXTESTENT32 512 +#define CALDRBGMAXADDINLEN X52_BER_LEN-RNXAIDATAOFF-4 +#define CALDRBGMAXPSNONCELEN X52_BER_LEN-RNXAIDATAOFF-4 + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef DRBGF5200_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATR drbgf5200Ini(void); + +extern SATR drbgf5200TrfRes(SATBOOL bBlock); + +extern SATR drbgf5200instantiate(const SATUINT32_t *puiNonce, + SATUINT32_t uiNonceLen, const SATUINT32_t *puiPzStr, SATUINT32_t uiPzStrLen, + SATSYMKEYSIZE eStrength, SATUINT32_t uiEntropyFactor, + SATUINT32_t uiReseedLim, SATBOOL bTesting); + +extern SATR drbgf5200reseed(const SATUINT32_t *puiAddIn, + SATUINT32_t uiAddInLen); + +extern SATR drbgf5200generate(const SATUINT32_t *puiAddIn, + SATUINT32_t uiAddInLen, SATBOOL bPredResist, SATUINT32_t uiReqLen, + SATUINT32_t *puiOut); + +extern SATR drbgf5200uninstantiate(void); + +extern SATR drbgf5200getctx(DRBGCTXPTR drbgCtxExt); + +extern SATR drbgf5200loadctx(DRBGCTXPTR drbgCtxExt); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/hash.h b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/hash.h new file mode 100644 index 0000000..f3fd6d4 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/hash.h @@ -0,0 +1,102 @@ +/* ------------------------------------------------------------------- + $Rev: 1293 $ $Date: 2017-07-27 14:09:14 -0400 (Thu, 27 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL hash functions. + ------------------------------------------------------------------- */ + +#ifndef HASH_H +#define HASH_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ +extern const SATHASHSIZE uiHashWordLen[SATHASHTYPE_LAST]; + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef HASH_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALHash(SATHASHTYPE eHashType, const void *pMsg, + SATUINT32_t uiMsgLen, void *pHash); + +extern SATR CALHashDMA(SATHASHTYPE eHashType, const void *pMsg, + SATUINT32_t uiMsgLen, void *pHash, SATUINT32_t uiDMAChConfig); + +extern SATR CALHashCtx(const SATRESHANDLE hResource, + const SATRESCONTEXTPTR pContext, const void *pMsg, SATUINT32_t uiMsgLen, + void *pHash, const SATBOOL bFinal); + +extern SATR CALHashCtxIni(const SATRESCONTEXTPTR pContext, + const SATHASHTYPE eHashType); + +extern SATR CALHashIni(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen); + +extern SATR CALHashWrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR CALHashRead(void *pHash); + +extern SATR CALKeyTree(SATBOOL bPathSizeSel, const SATUINT32_t* puiKey, + SATUINT8_t uiOpType, const SATUINT32_t* puiPath, SATUINT32_t* puiKeyOut); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATUINT32_t iGetHashLen(SATHASHTYPE eHashType); + +extern SATUINT32_t iGetBlockLen(SATHASHTYPE eHashType); + +extern SATR CALHashCtxLoad(const SATRESHANDLE hResource, + SATRESCONTEXTPTR const pContext, SATUINT32_t uiRunLen); + +extern SATUINT32_t iGetRunLen(SATRESCONTEXTPTR const pContext); + +extern SATR CALHashTypeIni(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/mac.h b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/mac.h new file mode 100644 index 0000000..acdc767 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/mac.h @@ -0,0 +1,95 @@ +/* ------------------------------------------------------------------- + $Rev: 1296 $ $Date: 2017-08-01 13:54:48 -0400 (Tue, 01 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL MAC functions. + ------------------------------------------------------------------- */ + +#ifndef MAC_H +#define MAC_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef MAC_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALMAC(SATMACTYPE eMACType, const SATUINT32_t *pKey, SATUINT32_t uiKeyLen, + const void *pMsg, SATUINT32_t uiMsgLen, void *pMAC); + +extern SATR CALMACDMA(SATMACTYPE eMACType, const SATUINT32_t *pKey, + SATUINT32_t uiKeyLen, const void *pMsg, SATUINT32_t uiMsgLen, + const void *pMAC, SATUINT32_t uiDMAChConfig); + +extern SATR CALMACIni(SATMACTYPE eMACType, const SATUINT32_t *pKey, + SATUINT32_t uiKeyLen, SATUINT32_t uiMsgLen); + +extern SATR CALMACCtx(const SATRESHANDLE hResource, + const SATRESCONTEXTPTR pContext, const void *pMsg, SATUINT32_t uiMsgLen, + void *pHash, const SATUINT8_t uiFlag); + +extern SATR CALMACCtxIni(const SATRESCONTEXTPTR pContext, const SATHASHTYPE eHashType, + const SATUINT32_t *pKey, SATUINT32_t uiKeyLen); + +extern SATR CALMACWrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR CALMACRead(void *pMAC); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATUINT32_t iGetMACKeyLen(SATMACTYPE eMACType); + +extern SATR CALMACCtxLoad(const SATRESHANDLE hResource, + SATRESCONTEXTPTR const pContext, SATUINT32_t uiRunLen); + +extern SATUINT32_t iGetMACRunLen(SATRESCONTEXTPTR const pContext); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/miv-rv32i-user-crypto-lib.a b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/miv-rv32i-user-crypto-lib.a new file mode 100644 index 0000000..5fda638 Binary files /dev/null and b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/miv-rv32i-user-crypto-lib.a differ diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/miv-rv32imc-user-crypto-lib.a b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/miv-rv32imc-user-crypto-lib.a new file mode 100644 index 0000000..ee7bcf4 Binary files /dev/null and b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/miv-rv32imc-user-crypto-lib.a differ diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/nrbg.h b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/nrbg.h new file mode 100644 index 0000000..d517065 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/nrbg.h @@ -0,0 +1,83 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for NRBG functions for CAL. + ------------------------------------------------------------------- */ + +#ifndef NRBG_H +#define NRBG_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef NRBG_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALNRBGSetTestEntropy(SATUINT32_t * puiEntropy, + SATUINT32_t uiEntLen32); + +extern SATR CALNRBGGetEntropy(SATUINT32_t * puiEntropy, SATUINT32_t uiEntLen32, + SATBOOL bTesting); + +extern SATR CALNRBGConfig(SATUINT32_t uiWriteEn, SATUINT32_t uiCSR, + SATUINT32_t uiCntLim, SATUINT32_t uiVoTimer, SATUINT32_t uiFMsk, + SATUINT32_t* puiStatus); + +extern SATUINT32_t CALNRBGHealthStatus(void); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATUINT32_t CALNRBGGetTestEntLen(void); + +extern SATR nrbgpkxgetentropy(SATUINT32_t * puiEntropy, + SATUINT32_t uiEntLen32); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/pk.h b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/pk.h new file mode 100644 index 0000000..5983d9a --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/pk.h @@ -0,0 +1,302 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for for CAL PK. + ------------------------------------------------------------------- */ + +#ifndef PK_H +#define PK_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef PK_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALPKTrfRes(SATBOOL bBlock); + +extern SATR CALDSASign(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALDSASignCM(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALDSASignHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, const SATUINT32_t* puiK, + const SATUINT32_t* puiX, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, SATUINT32_t uiN, + SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALDSASignHashCM(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, const SATUINT32_t* puiK, + const SATUINT32_t* puiX, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, SATUINT32_t uiN, + SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALDSAVerify(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiY, const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, + const SATUINT32_t* puiQMu, SATUINT32_t uiN, SATUINT32_t uiL); + +extern SATR CALDSAVerifyHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, const SATUINT32_t* puiY, + const SATUINT32_t* puiR, const SATUINT32_t* puiS, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALECDHC(const SATUINT32_t* puiS, const SATUINT32_t* puiWx, + const SATUINT32_t* puiWy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t* puiK, const SATUINT32_t* puiR, + const SATUINT32_t* puiRMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiZ); + +extern SATR CALECDSASign(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALECDSASignTwist(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALECDSASignCM(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALECDSASignTwistCM(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALECDSASignHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiK, const SATUINT32_t* puiD, const SATUINT32_t* puiB, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSASignHashCM(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiK, const SATUINT32_t* puiD, const SATUINT32_t* puiB, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSASignTwistHash(const SATUINT32_t* puiMsg, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSAVerify(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS,const + SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress); + +extern SATR CALECDSAVerifyTwist(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALECDSAVerifyHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSAVerifyTwistHash(const SATUINT32_t* puiMsg, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALECMult(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECMultCM(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t* puiN, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress, SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECMultTwist(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiLen, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECMultTwistCM(const SATUINT32_t* puiMul, + const SATUINT32_t* puiPx, const SATUINT32_t* puiPy, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiMod,const SATUINT32_t* puiMu, + const SATUINT32_t* puiN, SATUINT32_t uiLen, SATUINT32_t* puiRx, + SATUINT32_t* puiRy); + +extern SATR CALECMultAdd(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiB, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen, SATUINT32_t uiPtPCompress, SATUINT32_t uiPtQCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECPtValidate(const SATUINT32_t* puiPx, const SATUINT32_t* puiPy, + const SATUINT32_t* puiB, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen); + +extern SATR CALECKeyPairGen(const SATUINT32_t* puiC, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + const SATUINT32_t* puiNM1, const SATUINT32_t* puiNM1Mu, const SATUINT32_t* puiB, + SATUINT32_t* puiD, SATUINT32_t* puiQx, SATUINT32_t* puiQy, SATUINT32_t uiLen); + +extern SATR CALExpo(const SATUINT32_t* puiBase, const SATUINT32_t* puiExpo, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALExpoCM(const SATUINT32_t* puiBase, const SATUINT32_t* puiExpo, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALMMult(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALMMultAdd(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiC, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALModRed(const SATUINT32_t* puiA, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiALen, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPreCompute(const SATUINT32_t* puiMod, SATUINT32_t* puiMu, + SATUINT32_t uiModLen); + +extern SATR CALRSACRT(const SATUINT32_t* puiCipher, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ,const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiLen, SATUINT32_t* puiPlain); + +extern SATR CALRSACRTCM(const SATUINT32_t* puiCipher, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t * puiE, const SATUINT32_t* puiP, + const SATUINT32_t* puiQ, const SATUINT32_t * puiN, + const SATUINT32_t * puiNMu, SATUINT32_t uiLen, SATUINT32_t uiELen, + SATUINT32_t* puiPlain); + +extern SATR CALRSACRTSign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + const SATUINT32_t* puiN, SATUINT32_t uiLen, SATUINT32_t* puiSig); + +extern SATR CALRSACRTSignCM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, const SATUINT32_t* puiQ, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSig); + +extern SATR CALRSACRTSignHash(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ,const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + const SATUINT32_t* puiN, SATUINT32_t uiMsgLen, SATUINT32_t uiModLen, + SATUINT32_t* puiSig, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALRSACRTSignHashCM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, const SATUINT32_t* puiQ, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, SATUINT32_t* puiSig, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALRSASign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiD, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, SATUINT32_t* puiSig); + +extern SATR CALRSASignHash(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiD, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, SATUINT32_t uiModLen, + SATUINT32_t* puiSig, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALRSAVerify(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, + const SATUINT32_t* puiSig); + +extern SATR CALRSAVerifyHash(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiE, SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, const SATUINT32_t* puiSig, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPurge52(SATBOOL bVerify); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/pkx.h b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/pkx.h new file mode 100644 index 0000000..c23dda4 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/pkx.h @@ -0,0 +1,409 @@ +/* ------------------------------------------------------------------- + $Rev: 1298 $ $Date: 2017-08-04 13:04:19 -0400 (Fri, 04 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for for CAL PK. + ------------------------------------------------------------------- */ + +#ifndef PKX_H +#define PKX_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* X5200 Addressing */ +#define X52BER ((volatile SATUINT32_t *) (PKX0_BASE + 0x00000000u)) +#define X52MMR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00001000u)) +#define X52TSR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00002000u)) +#define X52FPR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00003000u)) +#define X52LIR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00004000u)) +#define X52CSR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00007F80u)) +#define X52CSRMERRS ((volatile SATUINT32_t *) (PKX0_BASE + 0x00007F8Cu)) +#define X52CSRMERRT0 ((volatile SATUINT32_t *) (PKX0_BASE + 0x00007F94u)) + +#if SAT_LITTLE_ENDIAN +#define X52BER_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00008000u)) +#define X52MMR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00009000u)) +#define X52TSR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x0000A000u)) +#define X52FPR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x0000B000u)) +#define X52DMACONFIG_ENDIAN 0x8 +#else +#define X52BER_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00000000u)) +#define X52MMR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00001000u)) +#define X52TSR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00002000u)) +#define X52FPR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00003000u)) +#define X52DMACONFIG_ENDIAN 0x0 +#endif + +/* X5200 Macros */ +#define X52GO(x) (0x10 | ((x)<<8)) + +/* Counter Measures */ +#define RANDLEN 4 + +/* X5200 CSRMAIN bit field masks. */ +#define X52CSRMAINRST 1 +#define X52CSRMAINCCMPLT 2 +#define X52CSRMAINCMPLT 4 +#define X52CSRMAINBUSY 8 +#define X52CSRMAINGO 0x10 +#define X52CSRMAINPURGE 0x20 +#define X52CSRMAINECDIS 0x40 +#define X52CSRMAINALARM 0x80 +#define X52CSRMAINLIRA ((0xFFF) << 8) +#define X52CSRMERRSSEC ((0x2) << 24) +#define X52CSRMERRSA 0x1FFF + +/* Address pointers for ROM'd P-curve moduli */ +#define P192_MOD (&uiROMMods[0]) +#define P224_MOD (&uiROMMods[1]) +#define P256_MOD (&uiROMMods[2]) +#define P384_MOD (&uiROMMods[3]) +#define P521_MOD (&uiROMMods[4]) + +/* X5200 Addressing Flags */ +#define X52BYTEREVERSE_FLAG 1 +#define X52WORDREVERSE_FLAG 2 +#define X52BYTEREVERSE 0x00002000 +#define X52WORDREVERSE 0x00004000 +#define X52ADDRESSRANGE 0x2000 + +/* X5200 DMA channel configuration constants. */ +#define X52CCR_DEFAULT 0 /* BSIZE=auto, ESWP=none, PROT=user, INC=inc */ +#define X52CCR_BSIZEAUTO 0 /* BSIZE=auto */ +#define X52CCR_BSIZEBYTE 0x10 /* BSIZE=byte */ +#define X52CCR_BSIZEHWORD 0x20 /* BSIZE=half word */ +#define X52CCR_BSIZEWORD 0x30 /* BSIZE=word */ +#define X52CCR_ESWPNONE 0 /* ESWP=none */ +#define X52CCR_ESWPWORD 0x8 /* ESWP=swap bytes in word [0123]->[3210] */ +#define X52CCR_PROTUSER 0 /* PROT=user */ +#define X52CCR_PROTPRIV 0x2 /* PROT=priv */ +#define X52CCR_INCADDR 0 /* INC=inc */ +#define X52CCR_NOINCADDR 0x1 /* INC=non-inc */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef PKX_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern void CALPKXIni(void); + +extern void CALPKMem32Load(volatile SATUINT32_t * puiDst, + const SATUINT32_t * puiSrc, SATUINT32_t uiNum ); + +extern SATR CALPKXTrfRes(SATBOOL bBlock); + +extern SATR CALPKXPreCompute(const SATUINT32_t* puiMod, SATUINT32_t* puiMu, + SATUINT32_t uiModLen); + +extern SATR CALPKXExpo(const SATUINT32_t* puiBase, const SATUINT32_t* puiExpo, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALPKXExpoCM(const SATUINT32_t* puiBase, + const SATUINT32_t* puiExpo, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPKXDSASign(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXDSASignCM(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXDSASHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATUINT32_t uiDMAChConfig, const SATBOOL bCM); + +extern SATR CALPKXDSAVerify(const SATUINT32_t *puiHash, + const SATUINT32_t *puiG, const SATUINT32_t *puiY, + const SATUINT32_t *puiSigR, const SATUINT32_t *puiSigS, + const SATUINT32_t *puiP, const SATUINT32_t *puiPMu, + const SATUINT32_t *puiQ, const SATUINT32_t *puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL); + +extern SATR CALPKXDSAVHDMA(const SATUINT32_t *puiExtInput, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t *puiG, const SATUINT32_t *puiY, + const SATUINT32_t *puiSigR, const SATUINT32_t *puiSigS, + const SATUINT32_t *puiP, const SATUINT32_t *puiPMu, const SATUINT32_t *puiQ, + const SATUINT32_t *puiQMu, SATUINT32_t uiN, SATUINT32_t uiL, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXModRed(const SATUINT32_t* puiA, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiALen, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPKXMMult(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPKXMMultAdd(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiC, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALPKXECMult(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECMultTwist(const SATUINT32_t* puiMul, + const SATUINT32_t* puiPx,const SATUINT32_t* puiPy, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen, SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECMultCM(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t * puiN, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress, SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECMultTwistCM(const SATUINT32_t* puiMul, + const SATUINT32_t* puiPx, const SATUINT32_t* puiPy, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + const SATUINT32_t * puiN, SATUINT32_t uiLen, SATUINT32_t* puiRx, + SATUINT32_t* puiRy); + +extern SATR CALPKXECMultAdd(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiB, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen, SATUINT32_t uiPtPCompress, SATUINT32_t uiPtQCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECDSASign(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASignTwist(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx,const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASignCM(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASignTwistCM(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASH(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + const SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASHCM(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + const SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, SATUINT32_t uiDMAChConfig, + const SATBOOL bCM); + +extern SATR CALPKXECDSASTwistH(const SATUINT32_t* puiHash, + const SATHASHTYPE eHashType, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiK, const SATUINT32_t* puiD, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, const SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASTwistHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECDSAVerify(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVerifyTwist(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVH(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB,const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + const SATUINT32_t uiLen, const SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB,const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECDSAVTwistH(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, const SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVTwistHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECDHC(const SATUINT32_t* puiS, const SATUINT32_t* puiWx, + const SATUINT32_t* puiWy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t* puiK, const SATUINT32_t* puiR, + const SATUINT32_t* puiRMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiZ); + +extern SATR CALPKXRSACRT(const SATUINT32_t* puiCipher, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, SATUINT32_t uiLen, + SATUINT32_t* puiPlain); + +extern SATR CALPKXRSACRTCM(const SATUINT32_t* puiCipher, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiE, + const SATUINT32_t* puiP, const SATUINT32_t* puiQ, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, const SATUINT32_t uiLen, const SATUINT32_t uiELen, + SATUINT32_t* puiPlain); + +extern SATR CALPKXRSACRTSign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiCipher, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, + const SATUINT32_t* puiQMu, const SATUINT32_t* puiN, SATUINT32_t uiLen, + SATUINT32_t* puiS); + +extern SATR CALPKXRSACRTSignCM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, + const SATUINT32_t* puiP, const SATUINT32_t* puiQ, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSig); + +extern SATR CALPKXRSACRTSHDMA(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + const SATUINT32_t* puiN, SATUINT32_t uiMsgLen, SATUINT32_t uiModLen, + SATUINT32_t* puiSig, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXRSACRTSHDMACM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, + const SATUINT32_t* puiP, const SATUINT32_t* puiQ, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, SATUINT32_t uiLen, + SATUINT32_t* puiSig, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXRSASign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiD, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, SATUINT32_t* puiSig); + +extern SATR CALPKXRSASHDMA(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiD, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, SATUINT32_t* puiSig, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXRSAVerify(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, + const SATUINT32_t* puiS); + +extern SATR CALPKXRSAVHDMA(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiE,SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, const SATUINT32_t* puiS, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECPtValidate(const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiLen); + +extern SATR CALPKXECKeyPairGen(const SATUINT32_t* puiC, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + const SATUINT32_t* puiNM1, const SATUINT32_t* puiNM1Mu, const SATUINT32_t* puiB, + SATUINT32_t* puiD, SATUINT32_t* puiQx, SATUINT32_t* puiQy, SATUINT32_t uiLen); + +extern SATR CALPKXPurge52(SATBOOL bVerify); + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ +extern SATRESULT SATResults; + +/* -------- ------ --------- */ +/* External Global Constants */ +/* -------- ------ --------- */ +extern const SATUINT32_t uiROMMods[]; + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/pkxlib.h b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/pkxlib.h new file mode 100644 index 0000000..fb4c0fc --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/pkxlib.h @@ -0,0 +1,95 @@ +/* ------------------------------------------------------------------- + $Rev: 1434 $ $Date: 2017-10-20 16:46:16 -0400 (Fri, 20 Oct 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for PKX-5200 Library. + ------------------------------------------------------------------- */ + +#ifndef PKXLIB_H +#define PKXLIB_H + +#include "caltypes.h" +#include "calpolicy.h" + +#define PKX_JMP_NONE (0xFFFFu + PKX_OFFSET) + +/* jump table entry points: starting PC value */ +#define PKX_JMP_RECIP_PRECOMPUTE (0x0000 + PKX_OFFSET) +#define PKX_JMP_MOD_EXP (0x0002 + PKX_OFFSET) +#define PKX_JMP_RSA_CRT (0x0004 + PKX_OFFSET) +#define PKX_JMP_EC_PTMUL (0x0006 + PKX_OFFSET) +#define PKX_JMP_EC_DSA_SIGN (0x0008 + PKX_OFFSET) +#define PKX_JMP_EC_DSA_VERIFY (0x000A + PKX_OFFSET) +#define PKX_JMP_DSA_SIGN (0x000C + PKX_OFFSET) +#define PKX_JMP_DSA_VERIFY (0x000E + PKX_OFFSET) +#define PKX_JMP_MOD_MULT (0x0010 + PKX_OFFSET) +#define PKX_JMP_MOD_RED (0x0012 + PKX_OFFSET) +#define PKX_JMP_EC_PTDECOMP (0x0014 + PKX_OFFSET) +#define PKX_JMP_EC_DHC (0x0016 + PKX_OFFSET) +#define PKX_JMP_MOD_MULT_ADD (0x0018 + PKX_OFFSET) +#define PKX_JMP_EC_PTMUL_ADD (0x001A + PKX_OFFSET) +#define PKX_JMP_EC_PTVALIDATE (0x001C + PKX_OFFSET) +#define PKX_JMP_F5200_SHA (0x001E + PKX_OFFSET) +#define PKX_JMP_F5200_AES (0x0020 + PKX_OFFSET) +#define PKX_JMP_F5200_AESK (0x0022 + PKX_OFFSET) +#define PKX_JMP_F5200_GCM (0x0024 + PKX_OFFSET) +#define PKX_JMP_F5200_GHA (0x0026 + PKX_OFFSET) +#define PKX_JMP_F5200_AESKW (0x0028 + PKX_OFFSET) +#define PKX_JMP_F5200_AESKWP (0x002A + PKX_OFFSET) +#define PKX_JMP_RNG_INSTANTIATE (0x002C + PKX_OFFSET) +#define PKX_JMP_RNG_RESEED (0x002E + PKX_OFFSET) +#define PKX_JMP_RNG_GENERATE (0x0030 + PKX_OFFSET) +#define PKX_JMP_RNG_UNINSTANTIATE (0x0032 + PKX_OFFSET) +#define PKX_JMP_RNG_GETENTROPY (0x0034 + PKX_OFFSET) +#define PKX_JMP_F5200_SHA_HMAC (0x0036 + PKX_OFFSET) +#define PKX_JMP_F5200_AES_DMA (0x0038 + PKX_OFFSET) +#define PKX_JMP_RNG_CTRLSTATUS (0x003A + PKX_OFFSET) +#define PKX_JMP_F5200_SHA_DMA (0x003C + PKX_OFFSET) +#define PKX_JMP_SHX_KEYTREE (0x003E + PKX_OFFSET) +#define PKX_JMP_PKX_DSA_DMA (0x0040 + PKX_OFFSET) +#define PKX_JMP_PKX_RSACRT_SIGN (0x0042 + PKX_OFFSET) +#define PKX_JMP_PKX_RSA_SIGN (0x0044 + PKX_OFFSET) +#define PKX_JMP_PKX_RSA_VERIFY (0x0046 + PKX_OFFSET) +#define PKX_JMP_PKX_EC_DSA_DMA (0x0048 + PKX_OFFSET) +#define PKX_JMP_F5200_AES_KEYROLL (0x004A + PKX_OFFSET) +#define PKX_JMP_EXPM (0x004C + PKX_OFFSET) +#define PKX_JMP_RSACRTM (0x004E + PKX_OFFSET) +#define PKX_JMP_EC_PTMULM (0x0050 + PKX_OFFSET) +#define PKX_JMP_DSA_SIGN_M (0x0052 + PKX_OFFSET) +#define PKX_JMP_EC_DSA_SIGN_M (0x0054 + PKX_OFFSET) +#define PKX_JMP_EC_KEYPAIRGEN (0x0056 + PKX_OFFSET) +#define PKX_JMP_RSACRTCM_SIGN (0x0058 + PKX_OFFSET) +#define PKX_JMP_F5200_GCM_NEW (0x005A + PKX_OFFSET) +/* PKX PKRev 2180 */ +/* PKX SHARev 2160 */ +/* PKX AESRev 2135 */ +/* Hex Checksum: 0xd0d79866 */ + +extern const SATUINT32_t uiPKX_Flags; +extern const SATUINT32_t uiPKX_BERWords; +extern const SATUINT32_t uiPKX_LIRWords; +extern const SATUINT32_t uiPKX_Rev; +extern const SATUINT32_t uiPKX_LibSize; +extern const SATUINT32_t uiPKX_LibChksum; +extern const SATUINT32_t uiPKX_Lib[]; +extern SATBOOL bMPF300TS_ES; + +#endif diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/shaf5200.h b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/shaf5200.h new file mode 100644 index 0000000..da598d1 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/shaf5200.h @@ -0,0 +1,101 @@ +/* ------------------------------------------------------------------- + $Rev: 1296 $ $Date: 2017-08-01 13:54:48 -0400 (Tue, 01 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for SHA function hardware implementation for CAL. + ------------------------------------------------------------------- */ + +#ifndef SHAF5200_H +#define SHAF5200_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef SHAF5200_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATR shapkxctx(SATRESCONTEXTPTR const pContext, const void *pBuffer, + SATUINT32_t uiBufLen,void *pHash, const SATBOOL bFinal); + +extern SATR shapkxhmacctx(SATRESCONTEXTPTR const pContext, const void *pBuffer, + SATUINT32_t uiBufLen, void *pHash, const SATUINT8_t uiFlag); + +extern SATR shapkxctxload(SATRESCONTEXTPTR const pContext); + +extern void shapkxctxunload(SATRESCONTEXTPTR const pContext); + +extern SATR shapkxini(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen); + +extern SATR shapkxhmacini(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, + const void *pKey, SATUINT32_t uiKeyLen); + +extern SATR shapkxwrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR shapkxhmacwrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR shapkxread(void *pHash, SATUINT32_t uiRevFlag); + +extern SATR shapkxkeytree(SATBOOL bPathSizeSel, const SATUINT32_t* puiKey, + SATUINT8_t uiOpType, const SATUINT32_t* puiPath, SATUINT32_t* puiKeyOut); + +extern SATR shapkxdma(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, + const void *pExtSrc, const void *pExtDest, SATUINT32_t uiDMAChConfig); + +extern SATR shapkxhmacdma(SATMACTYPE eMACType, const SATUINT32_t *pKey, + SATUINT32_t uiKeyLen, const void *pMsg, SATUINT32_t uiMsgLen, + const void *pMAC, SATUINT32_t uiDMAChConfig); + +extern SATR shapkxhashtypeini(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/sym.h b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/sym.h new file mode 100644 index 0000000..2e07faa --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/sym.h @@ -0,0 +1,129 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for Symmetric Key Cryptography in CAL. + ------------------------------------------------------------------- */ + +#ifndef SYM_H +#define SYM_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef SYM_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALSymTrfRes(SATBOOL bBlock); + +extern SATR CALSymEncrypt(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen); + +extern SATR CALSymDecrypt(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen); + +extern SATR CALSymEncryptDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymDecryptDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymEncryptKR(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF); + +extern SATR CALSymDecryptKR(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF); + +extern SATR CALSymEncryptKRDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymDecryptKRDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymEncAuth(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen); + +extern SATR CALSymDecVerify(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen); + +extern SATR CALSymKw(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR CALSymKwp(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR CALSymEncAuthDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymDecVerifyDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen, SATUINT32_t uiDMAChConfig); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/utils.h b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/utils.h new file mode 100644 index 0000000..91474f0 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/utils.h @@ -0,0 +1,93 @@ +/* ------------------------------------------------------------------- + $Rev: 1300 $ $Date: 2017-08-07 11:36:02 -0400 (Mon, 07 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL utility functions. + ------------------------------------------------------------------- */ + +#ifndef UTILS_H +#define UTILS_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef UTILS_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern void CALMemCopy(void *pDst, const void *pSrc, SATUINT32_t uiNum8); + +extern void CALMemClear( void * pLoc, SATUINT32_t uiNum ); + +extern void CALMemClear32( SATUINT32_t* puiLoc, SATUINT32_t uiLen32 ); + +extern SATBOOL CALMemCmp(const void *pA, const void *pB, SATUINT32_t uiNum); + +extern void CALVol32MemLoad(volatile SATUINT32_t * puiDst, const void * pSrc, + SATUINT32_t uiNum32); + +extern void CALVol32MemRead(void * pDst, volatile SATUINT32_t * puiSrc, + SATUINT32_t uiNum32); + +extern void CALByteReverse(SATUINT32_t* puiArray, SATINT32_t iNumberBytes); + +extern void CALByteReverseWord(SATUINT32_t* puiArray, SATINT32_t iNumberWords); + +extern void CALWordReverse(SATUINT32_t *puiArray, SATINT32_t iNumberWords); + +extern void vAppendNonzero(void *puiArray, SATUINT32_t uiLen, + SATUINT32_t uiBlockSize); + +extern void vAppendZero(void *puiArray, SATUINT32_t uiLen, + SATUINT32_t uiBlockSize); + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/x52cfg_user.h b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/x52cfg_user.h new file mode 100644 index 0000000..c8d8648 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/middleware/cal/x52cfg_user.h @@ -0,0 +1,72 @@ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ +/* X5200 configuration */ +/* $Date: 2015-07-23 14:30:19 -0400 (Thu, 23 Jul 2015) $ $Rev: 2093 $ */ +/* ------------------------------------------------------------------- + Options: + * LIR ROM size : 4096 + * LIR RAM size : 2048 + * BER size : 1024 + * MMR size : 1024 + * TSR size : 1024 + * FPR size : 1024 + * Single error correct, dual error detect (SECDED) memory parity + * DMA enabled + * FPGA multipliers disabled + * AES enabled + - Fast key schedule generation + - GCM/GHASH enabled + - AES countermeasures enabled + * RNG enabled + * External PRNG disabled + * SHA enabled + - Fast SHA enabled + - SHA-1 enabled + - SHA-224 enabled + - SHA-256 enabled + - SHA-384 enabled + - SHA-512 enabled + - SHA-512/224 enabled + - SHA-512/256 enabled + - SHA countermeasures enabled + * P-curves populated in FCR: + - P-192 populated + - P-224 populated + - P-256 populated + - P-384 populated + - P-521 populated + * Data memory scrambling enabled + + ------------------------------------------------------------------- */ + +#ifndef X52CFG_H +#define X52CFG_H + +#define X52_CFG_MODEL 0xf5200 +#define X52_CFG_DATE 0x15072720 +#define X52_CFG_REV 0x0000082e +#define X52_CFG_OPT 0x0fd87ff9 +#define X52_CFG_OPT2 0xc0000000 +#define X52_LIR_LEN 0x1800 +#define X52_LIR_ROM_LEN 0x1000 +#define X52_LIR_RAM_LEN 0x0800 +#define X52_BER_LEN 0x400 +#define X52_MMR_LEN 0x400 +#define X52_TSR_LEN 0x400 +#define X52_FPR_LEN 0x400 + +#endif diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/README.md b/applications/user-crypto/miv-rv32-ccm-services/src/platform/README.md new file mode 100644 index 0000000..f7f6030 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/README.md @@ -0,0 +1,27 @@ +# Mi-V soft processor platform source code + +## Repo organization + +``` + + | + |-- drivers + | |- fpga_ip + | | | CoreGPIO + | | | CoreSysServices_PF + | | | CoreUARTapb + | | + | |- off_chip + | | | . + | | | . + | | + |-- hal + | | + |-- miv_rv32_hal + + +``` + +The drivers published here are compatible with the improved SoftConsole project folder structure being used in the latest [example projects](https://github.com/Mi-V-Soft-RISC-V/miv-rv32-bare-metal-examples). +These drivers can also be used with the legacy folder structure (projects released via Firmware Catalog) by defining the **LEGACY_DIR_STRUCTURE** macro in the SoftConsole project settings. + diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c new file mode 100644 index 0000000..1a0073f --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c @@ -0,0 +1,533 @@ +/******************************************************************************* + * (c) Copyright 2008-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file core_gpio.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreGPIO bare metal driver implementation. + * + */ +#include "coregpio_regs.h" +#include "core_gpio.h" + +/*-------------------------------------------------------------------------*//** + * + */ +#define GPIO_INT_ENABLE_MASK (uint32_t)0x00000008UL +#define OUTPUT_BUFFER_ENABLE_MASK 0x00000004UL + + +#define NB_OF_GPIO 32 + +#define CLEAR_ALL_IRQ32 (uint32_t)0xFFFFFFFF +#define CLEAR_ALL_IRQ16 (uint16_t)0xFFFF +#define CLEAR_ALL_IRQ8 (uint8_t)0xFF + +/*-------------------------------------------------------------------------*//** + * GPIO_init() + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_init +( + gpio_instance_t * this_gpio, + addr_t base_addr, + gpio_apb_width_t bus_width +) +{ + uint8_t i = 0; + addr_t cfg_reg_addr = base_addr; + + this_gpio->base_addr = base_addr; + this_gpio->apb_bus_width = bus_width; + + /* Clear configuration. */ + for( i = 0, cfg_reg_addr = base_addr; i < NB_OF_GPIO; ++i ) + { + HW_set_8bit_reg( cfg_reg_addr, 0 ); + cfg_reg_addr += 4; + } + /* Clear any pending interrupts */ + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, CLEAR_ALL_IRQ32 ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, (uint16_t)CLEAR_ALL_IRQ16 ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, (uint16_t)CLEAR_ALL_IRQ16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, (uint8_t)CLEAR_ALL_IRQ8 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_config + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_config +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint32_t config +) +{ + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + uint32_t cfg_reg_addr = this_gpio->base_addr; + cfg_reg_addr += (port_id * 4); + HW_set_32bit_reg( cfg_reg_addr, config ); + + /* + * Verify that the configuration was correctly written. Failure to read + * back the expected value may indicate that the GPIO port was configured + * as part of the hardware flow and cannot be modified through software. + * It may also indicate that the base address passed as parameter to + * GPIO_init() was incorrect. + */ + HAL_ASSERT( HW_get_32bit_reg( cfg_reg_addr ) == config ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_set_outputs + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_set_outputs +( + gpio_instance_t * this_gpio, + uint32_t value +) +{ + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, GPIO_OUT, value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, GPIO_OUT0, (uint16_t)value ); + HAL_set_16bit_reg( this_gpio->base_addr, GPIO_OUT1, (uint16_t)(value >> 16) ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT0, (uint8_t)value ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT1, (uint8_t)(value >> 8) ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT2, (uint8_t)(value >> 16) ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT3, (uint8_t)(value >> 24) ); + break; + + default: + HAL_ASSERT(0); + break; + } + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( GPIO_get_outputs( this_gpio ) == value ); +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_inputs + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_inputs +( + gpio_instance_t * this_gpio +) +{ + uint32_t gpio_in = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + gpio_in = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_IN ); + break; + + case GPIO_APB_16_BITS_BUS: + gpio_in |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_IN0 ); + gpio_in |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_IN1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + gpio_in |= HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN0 ); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN1 ) << 8); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN2 ) << 16); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return gpio_in; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_outputs + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_outputs +( + gpio_instance_t * this_gpio +) +{ + uint32_t gpio_out = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + gpio_out = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ); + break; + + case GPIO_APB_16_BITS_BUS: + gpio_out |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT0 ); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + gpio_out |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT0 ); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT1 ) << 8); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT2 ) << 16); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return gpio_out; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_set_output + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_set_output +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint8_t value +) +{ + HAL_ASSERT( port_id < NB_OF_GPIO ); + + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + { + uint32_t outputs_state; + + outputs_state = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ); + if ( 0 == value ) + { + outputs_state &= ~(1 << port_id); + } + else + { + outputs_state |= 1 << port_id; + } + HAL_set_32bit_reg( this_gpio->base_addr, GPIO_OUT, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ) == outputs_state ); + } + break; + + case GPIO_APB_16_BITS_BUS: + { + uint16_t outputs_state; + uint32_t gpio_out_reg_addr = this_gpio->base_addr + GPIO_OUT_REG_OFFSET + ((port_id >> 4) * 4); + + outputs_state = HW_get_16bit_reg( gpio_out_reg_addr ); + if ( 0 == value ) + { + outputs_state &= ~(1 << (port_id & 0x0F)); + } + else + { + outputs_state |= 1 << (port_id & 0x0F); + } + HW_set_16bit_reg( gpio_out_reg_addr, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HW_get_16bit_reg( gpio_out_reg_addr ) == outputs_state ); + } + break; + + case GPIO_APB_8_BITS_BUS: + { + uint8_t outputs_state; + uint32_t gpio_out_reg_addr = this_gpio->base_addr + GPIO_OUT_REG_OFFSET + ((port_id >> 3) * 4); + + outputs_state = HW_get_8bit_reg( gpio_out_reg_addr ); + if ( 0 == value ) + { + outputs_state &= ~(1 << (port_id & 0x07)); + } + else + { + outputs_state |= 1 << (port_id & 0x07); + } + HW_set_8bit_reg( gpio_out_reg_addr, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HW_get_8bit_reg( gpio_out_reg_addr ) == outputs_state ); + } + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_drive_inout + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_drive_inout +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + gpio_inout_state_t inout_state +) +{ + uint32_t config; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + switch( inout_state ) + { + case GPIO_DRIVE_HIGH: + /* Set output high */ + GPIO_set_output( this_gpio, port_id, 1 ); + + /* Enable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config |= OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + case GPIO_DRIVE_LOW: + /* Set output low */ + GPIO_set_output( this_gpio, port_id, 0 ); + + /* Enable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config |= OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + case GPIO_HIGH_Z: + /* Disable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config &= ~OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_enable_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_enable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t cfg_value; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + cfg_reg_addr += (port_id * 4); + cfg_value = HW_get_8bit_reg( cfg_reg_addr ); + cfg_value |= GPIO_INT_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, cfg_value ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_disable_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_disable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t cfg_value; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + cfg_reg_addr += (port_id * 4); + cfg_value = HW_get_8bit_reg( cfg_reg_addr ); + cfg_value &= ~GPIO_INT_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, cfg_value ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_clear_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_clear_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t irq_clr_value = ((uint32_t)1) << ((uint32_t)port_id); + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, irq_clr_value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, irq_clr_value >> 16 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, irq_clr_value >> 24 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_irq_sources + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_irq_sources +( + gpio_instance_t * this_gpio +) +{ + uint32_t intr_src = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + intr_src = HAL_get_32bit_reg( this_gpio->base_addr, IRQ ); + break; + + case GPIO_APB_16_BITS_BUS: + intr_src |= HAL_get_16bit_reg( this_gpio->base_addr, IRQ0 ); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + intr_src |= HAL_get_16bit_reg( this_gpio->base_addr, IRQ0 ); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ1 ) << 8); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ2 ) << 16); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return intr_src; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_clear_all_irq_sources + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_clear_all_irq_sources +( + gpio_instance_t * this_gpio, + uint32_t bitmask +) +{ + uint32_t irq_clr_value = bitmask; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, irq_clr_value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, irq_clr_value >> 16 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, irq_clr_value >> 24 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h new file mode 100644 index 0000000..88ba178 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h @@ -0,0 +1,722 @@ +/******************************************************************************* + * (c) Copyright 2008-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file core_gpio.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreGPIO bare metal driver public API. + * + */ + +/*=========================================================================*//** + @mainpage CoreGPIO Bare Metal Driver. + + @section intro_sec Introduction + The CoreGPIO hardware IP includes up to 32 general-purpose input/output GPIOs. + This driver provides a set of functions for controlling the GPIOs as part of a + bare-metal system where no operating system is available. These drivers + can be adapted for use as part of an operating system, but the implementation + of the adaptation layer between this driver and the operating system's driver + model is outside the scope of this driver. + + @section driver_configuration Driver Configuration + The individual IOs of CoreGPIO can be configured either in the hardware flow + or as part of the software application through calls to the GPIO_config() + function. GPIOs configured as part of the hardware are fixed and cannot be + modified using a call to the GPI_config() function. + + @section theory_op Theory of Operation + The CoreGPIO driver uses the Actel Hardware Abstraction Layer (HAL) to access + hardware registers. You must ensure that the Actel HAL is included as part of + your software project. The Actel HAL is available through the Actel Firmware + Catalog. + + The CoreGPIO driver functions are logically grouped into the following groups: + - Initialization + - Configuration + - Reading and writing GPIO state + - Interrupt control + + The CoreGPIO driver is initialized through a call to the GPIO_init() function. + The GPIO_init() function must be called before any other GPIO driver functions + can be called. + + Each GPIO port is individually configured through a call to the + GPIO_config() function. Configuration includes deciding if a GPIO port is + going to be used as input, output, or both. GPIO ports configured as inputs + are further configured to generate interrupts based on the state of input. + Interrupts is either level- or edge-sensitive. + Note that a CoreGPIO hardware instance is generated as part of the hardware + flow with a fixed configuration for some or all of its IOs. + Attempting to modify the configuration of such a hardware-configured IO using + the GPIO_config() function has no effect. + + The state of the GPIO ports can be read and written using the following + functions: + - GPIO_get_inputs() + - GPIO_get_outputs() + - GPIO_set_outputs() + - GPIO_drive_inout() + + Interrupts generated by GPIO ports configured as inputs are controlled using + the following functions: + - GPIO_enable_irq() + - GPIO_disable_irq() + - GPIO_clear_irq() + - GPIO_get_irq_sources() + - GPIO_clear_all_irq_sources() + + *//*=========================================================================*/ +#ifndef CORE_GPIO_H_ +#define CORE_GPIO_H_ + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + The gpio_id_t enumeration is used to identify GPIOs as part of the + parameter to functions: + - GPIO_config(), + - GPIO_drive_inout(), + - GPIO_enable_int(), + - GPIO_disable_int(), + - GPIO_clear_int() + */ +typedef enum __gpio_id_t +{ + GPIO_0 = 0, + GPIO_1 = 1, + GPIO_2 = 2, + GPIO_3 = 3, + GPIO_4 = 4, + GPIO_5 = 5, + GPIO_6 = 6, + GPIO_7 = 7, + GPIO_8 = 8, + GPIO_9 = 9, + GPIO_10 = 10, + GPIO_11 = 11, + GPIO_12 = 12, + GPIO_13 = 13, + GPIO_14 = 14, + GPIO_15 = 15, + GPIO_16 = 16, + GPIO_17 = 17, + GPIO_18 = 18, + GPIO_19 = 19, + GPIO_20 = 20, + GPIO_21 = 21, + GPIO_22 = 22, + GPIO_23 = 23, + GPIO_24 = 24, + GPIO_25 = 25, + GPIO_26 = 26, + GPIO_27 = 27, + GPIO_28 = 28, + GPIO_29 = 29, + GPIO_30 = 30, + GPIO_31 = 31 +} gpio_id_t; + +/*-------------------------------------------------------------------------*//** + Possible width of the APB bus + */ +typedef enum __gpio_apb_width_t +{ + GPIO_APB_8_BITS_BUS = 0, + GPIO_APB_16_BITS_BUS = 1, + GPIO_APB_32_BITS_BUS = 2, + GPIO_APB_UNKNOWN_BUS_WIDTH = 3 +} gpio_apb_width_t; + +/*-------------------------------------------------------------------------*//** + Structure instance holding all data regarding the CoreGPIO + */ +typedef struct __gpio_instance_t +{ + addr_t base_addr; + gpio_apb_width_t apb_bus_width; +} gpio_instance_t; + +/*-------------------------------------------------------------------------*//** + GPIO ports definitions used to identify GPIOs as part of the parameter to + function GPIO_set_outputs(). + These definitions are also be used to identity GPIO through logical operations + on the return value of function GPIO_get_inputs(). + # GPIO_0_MASK + # GPIO_1_MASK + # GPIO_2_MASK + # GPIO_3_MASK + # GPIO_4_MASK + # GPIO_5_MASK + # GPIO_6_MASK + # GPIO_7_MASK + # GPIO_8_MASK + # GPIO_9_MASK + # GPIO_10_MASK + # GPIO_11_MASK + # GPIO_12_MASK + # GPIO_13_MASK + # GPIO_14_MASK + # GPIO_15_MASK + # GPIO_16_MASK + # GPIO_17_MASK + # GPIO_18_MASK + # GPIO_19_MASK + # GPIO_20_MASK + # GPIO_21_MASK + # GPIO_22_MASK + # GPIO_23_MASK + # GPIO_24_MASK + # GPIO_25_MASK + # GPIO_26_MASK + # GPIO_27_MASK + # GPIO_28_MASK + # GPIO_29_MASK + # GPIO_30_MASK + # GPIO_31_MASK + */ +#define GPIO_0_MASK 0x00000001UL +#define GPIO_1_MASK 0x00000002UL +#define GPIO_2_MASK 0x00000004UL +#define GPIO_3_MASK 0x00000008UL +#define GPIO_4_MASK 0x00000010UL +#define GPIO_5_MASK 0x00000020UL +#define GPIO_6_MASK 0x00000040UL +#define GPIO_7_MASK 0x00000080UL +#define GPIO_8_MASK 0x00000100UL +#define GPIO_9_MASK 0x00000200UL +#define GPIO_10_MASK 0x00000400UL +#define GPIO_11_MASK 0x00000800UL +#define GPIO_12_MASK 0x00001000UL +#define GPIO_13_MASK 0x00002000UL +#define GPIO_14_MASK 0x00004000UL +#define GPIO_15_MASK 0x00008000UL +#define GPIO_16_MASK 0x00010000UL +#define GPIO_17_MASK 0x00020000UL +#define GPIO_18_MASK 0x00040000UL +#define GPIO_19_MASK 0x00080000UL +#define GPIO_20_MASK 0x00100000UL +#define GPIO_21_MASK 0x00200000UL +#define GPIO_22_MASK 0x00400000UL +#define GPIO_23_MASK 0x00800000UL +#define GPIO_24_MASK 0x01000000UL +#define GPIO_25_MASK 0x02000000UL +#define GPIO_26_MASK 0x04000000UL +#define GPIO_27_MASK 0x08000000UL +#define GPIO_28_MASK 0x10000000UL +#define GPIO_29_MASK 0x20000000UL +#define GPIO_30_MASK 0x40000000UL +#define GPIO_31_MASK 0x80000000UL + +/*-------------------------------------------------------------------------*//** + * GPIO modes + * # GPIO_INPUT_MODE + * # GPIO_OUTPUT_MODE + * # GPIO_INOUT_MODE + */ +#define GPIO_INPUT_MODE 0x0000000002UL +#define GPIO_OUTPUT_MODE 0x0000000005UL +#define GPIO_INOUT_MODE 0x0000000003UL + +/*-------------------------------------------------------------------------*//** + * Possible GPIO inputs interrupt configurations. + * # GPIO_IRQ_LEVEL_HIGH + * # GPIO_IRQ_LEVEL_LOW + * # GPIO_IRQ_EDGE_POSITIVE + * # GPIO_IRQ_EDGE_NEGATIVE + * # GPIO_IRQ_EDGE_BOTH + */ +#define GPIO_IRQ_LEVEL_HIGH 0x0000000000UL +#define GPIO_IRQ_LEVEL_LOW 0x0000000020UL +#define GPIO_IRQ_EDGE_POSITIVE 0x0000000040UL +#define GPIO_IRQ_EDGE_NEGATIVE 0x0000000060UL +#define GPIO_IRQ_EDGE_BOTH 0x0000000080UL + +/*-------------------------------------------------------------------------*//** + * Possible states for GPIO configured as INOUT + */ +typedef enum gpio_inout_state +{ + GPIO_DRIVE_LOW = 0, + GPIO_DRIVE_HIGH, + GPIO_HIGH_Z +} gpio_inout_state_t; + +/*-------------------------------------------------------------------------*//** + The GPIO_init() function initializes a CoreGPIO hardware instance and the data + structure associated with the CoreGPIO hardware instance. + Note that a CoreGPIO hardware instance is generated with a fixed configuration + for some or all of its IOs as part of the hardware flow. + Attempting to modify the configuration of such a hardware-configured IO using + the GPIO_config() function has no effect. + + @param this_gpio + Pointer to the gpio_instance_t data structure instance holding all data + regarding the CoreGPIO hardware instance being initialized. A pointer to the + same data structure is used in subsequent calls to the CoreGPIO driver + functions in order to identify the CoreGPIO instance that must perform the + operation implemented by the called driver function. + + @param base_addr + The base_addr parameter is the base address in the memory map of the + processor for the registers of the GPIO instance being initialized. + + @param bus_width + The bus_width parameter informs the driver of the APB bus width selected + during the hardware flow configuration of the CoreGPIO hardware instance. It + indicates to the driver whether the CoreGPIO hardware registers are visible + as 8, 16, or 32-bits registers. Allowed values are: + - GPIO_APB_8_BITS_BUS + - GPIO_APB_16_BITS_BUS + - GPIO_APB_32_BITS_BUS + + @return + none. + + @example + @code + #define COREGPIO_BASE_ADDR 0xC2000000 + + gpio_instance_t g_gpio; + + void system_init( void ) + { + GPIO_init( &g_gpio, COREGPIO_BASE_ADDR, GPIO_APB_32_BITS_BUS ); + } + @endcode + */ +void GPIO_init +( + gpio_instance_t * this_gpio, + addr_t base_addr, + gpio_apb_width_t bus_width +); + +/*-------------------------------------------------------------------------*//** + The GPIO_config() function is used to configure an individual GPIO port. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO port to be configured. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @param config + The config parameter specifies the configuration to be applied to the GPIO + port identified by the first parameter. It is a logical OR of GPIO mode and + interrupt mode. The interrupt mode is only relevant if the GPIO is + configured as an input. + - Possible modes are: + - GPIO_INPUT_MODE, + - GPIO_OUTPUT_MODE, + - GPIO_INOUT_MODE. + - Possible interrupt modes are: + - GPIO_IRQ_LEVEL_HIGH, + - GPIO_IRQ_LEVEL_LOW, + - GPIO_IRQ_EDGE_POSITIVE, + - GPIO_IRQ_EDGE_NEGATIVE, + - GPIO_IRQ_EDGE_BOTH + + @return + none. + + @example + For example, the following call configures GPIO 4 as an input that generates + interrupts on a low-to-high transition of the input: + @code + GPIO_config( &g_gpio, GPIO_4, GPIO_INPUT_MODE | GPIO_IRQ_EDGE_POSITIVE ); + @endcode + */ +void GPIO_config +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint32_t config +); + +/*-------------------------------------------------------------------------*//** + The GPIO_set_outputs() function is used to set the state of the GPIO ports + configured as outputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param value + The value parameter specifies the state of the GPIO ports configured as + outputs. It is a bit mask of the form (GPIO_n_MASK | GPIO_m_MASK), where n + and m are numbers identifying GPIOs. + For example, (GPIO_0_MASK | GPIO_1_MASK | GPIO_2_MASK ) specifies that the + first, second, and third GPIO must be set high and all other outputs set + low. + + @return + none. + + @example + Set GPIO 0 and 8 outputs high and all other GPIO outputs low. + @code + GPIO_set_outputs( &g_gpio, GPIO_0_MASK | GPIO_8_MASK ); + @endcode + + @example + Set GPIO 2 and 4 outputs low without affecting the other GPIO outputs. + @code + uint32_t gpio_outputs; + gpio_outputs = GPIO_get_outputs( &g_gpio ); + gpio_outputs &= ~( GPIO_2_MASK | GPIO_4_MASK ); + GPIO_set_outputs( &g_gpio, gpio_outputs ); + @endcode + + @see GPIO_get_outputs() + */ +void GPIO_set_outputs +( + gpio_instance_t * this_gpio, + uint32_t value +); + +/*-------------------------------------------------------------------------*//** + The GPIO_set_output() function is used to set the state of a single GPIO port + configured as an output. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter specifies the GPIO port that has its output set by a + call to this function. + + @param value + The value parameter specifies the desired state for the GPIO output. A value + of 0 sets the output low, and a value of 1 sets the port high. + + @return + none. + */ +void GPIO_set_output +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint8_t value +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_inputs() function is used to read the state of all GPIOs + configured as inputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @return + This function returns a 32-bit unsigned integer, where each bit represents + the state of an input. The least significant bit represents the state of + GPIO 0, and the most significant bit represents the state of GPIO 31. + */ +uint32_t GPIO_get_inputs +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_outputs() function is used to read the current state of all + GPIO outputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @return + This function returns a 32-bit unsigned integer where each bit represents + the state of an output. The least significant bit represents the state + of GPIO 0, and the most significant bit represents the state of GPIO 31. + */ +uint32_t GPIO_get_outputs +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_drive_inout() function is used to set the output state of a + GPIO configured as INOUT. An INOUT GPIO is in one of three states: + - high + - low + - high impedance + + An INOUT output is typically be used where several devices drive the state of + a signal. The high and low states are equivalent to the high and low states of + a GPIO configured as an output. The high impedance state is used to prevent + the GPIO from driving the state of the output and therefore allow reading the + state of the GPIO as an input. + Note that the GPIO port you wish to use as INOUT through this function + must be configurable through software. Therefore, the GPIO ports used as INOUT + must not have a fixed configuration selected as part of the hardware flow. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO for which this function will + change the output state. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @param inout_state + The inout_state parameter specifies the state of the I/O identified by the + first parameter. Possible states are: + - GPIO_DRIVE_HIGH, + - GPIO_DRIVE_LOW, + - GPIO_HIGH_Z (high impedance) + + @return + none. + + @example + The call to GPIO_drive_inout() below will set the GPIO 7 output to + high impedance state. + @code + GPIO_drive_inout( &g_gpio, GPIO_7, GPIO_HIGH_Z ); + @endcode + */ +void GPIO_drive_inout +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + gpio_inout_state_t inout_state +); + +/*-------------------------------------------------------------------------*//** + The GPIO_enable_irq() function is used to enable an interrupt to be + generated based on the state of the input identified as a parameter. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO input that the call to + GPIO_enable_irq() enables to generate interrupts. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + @example + The call to GPIO_enable_irq() below allows GPIO 8 to generate interrupts. + + @code + GPIO_enable_irq( &g_gpio, GPIO_8 ); + @endcode + */ +void GPIO_enable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_disable_irq() function is used to disable interrupts from being + generated based on the state of the input specified as a parameter. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO input that the call to + GPIO_disable_irq() disables from generating interrupts. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + @example + The call to GPIO_disable_irq() below prevents GPIO 8 from generating + interrupts. + @code + GPIO_disable_irq( &g_gpio, GPIO_8 ); + @endcode + */ +void GPIO_disable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_clear_irq() function is used to clear the interrupt generated by + the GPIO specified as a parameter. The GPIO_clear_irq() function must be + called as part of a GPIO interrupt service routine (ISR) in order to prevent + the same interrupt event from re-triggering a call to the GPIO ISR. + Note that interrupts may also need to be cleared in the processor's + interrupt controller. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO input for which to clear the + interrupt. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + @example + The example below demonstrates the use of the GPIO_clear_irq() function as + part of the GPIO-9 interrupt service routine. + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + GPIO_clear_irq( &g_gpio, GPIO_9 ); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +void GPIO_clear_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_irq_sources() function is used to identify the source of the + interrupt. i.e. to That is the GPIO input line, whose state change triggered + the interrupt. The GPIO_get_irq_sources() function must be called as part of + a GPIO interrupt service routine (ISR) in order to determine the interrupt + source. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @return + This function returns a 32-bit unsigned integer, where each bit represents + the pin number of a GPIO. + + @example + The example below demonstrates the use of the GPIO_get_irq_sources() + function as part of the GPIO-9 interrupt service routine. + + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + GPIO_clear_all_irq_sources(g_p_mygpio, GPIO_get_irq_sources(g_p_mygpio)); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +uint32_t GPIO_get_irq_sources +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_clear_all_irq_sources() function is used to clear all the active + interrupts generated by the GPIO specified as a parameter. The + GPIO_clear_all_irq_sources() function must be called as part of a GPIO + interrupt service routine (ISR) in order to prevent the same interrupt event + from re-triggering a call to the GPIO ISR. + Note that interrupts may also need to be cleared in the processor's + interrupt controller. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param bitmask + This bitmask parameter is a 32-bit unsigned integer where each bit + represents the GPIO pin used to clear the interrupt bit register of the + corresponding GPIO bit. The least significant bit represents the status of + GPIO 0, and the most significant bit represents the status of GPIO 31. + + @return + none. + + @example + The example below demonstrates the use of the GPIO_clear_all_irq_sources() + function as part of the GPIO-9 interrupt service routine. + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + do_interrupt_processing(); + + GPIO_clear_all_irq_sources(g_p_mygpio, GPIO_get_irq_sources(g_p_mygpio)); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +void GPIO_clear_all_irq_sources +( + gpio_instance_t * this_gpio, + uint32_t bitmask +); + +#ifdef __cplusplus +} +#endif + +#endif /* CORE_GPIO_H_ */ diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h new file mode 100644 index 0000000..41f5b7c --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h @@ -0,0 +1,45 @@ +/******************************************************************************* + * (c) Copyright 2008-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file coregpio_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreGPIO register definitions + * + */ + +#ifndef __CORE_GPIO_REGISTERS_H +#define __CORE_GPIO_REGISTERS_H 1 + +/*------------------------------------------------------------------------------ + * + */ +#define IRQ_REG_OFFSET 0x80 + +#define IRQ0_REG_OFFSET 0x80 +#define IRQ1_REG_OFFSET 0x84 +#define IRQ2_REG_OFFSET 0x88 +#define IRQ3_REG_OFFSET 0x8C + +/*------------------------------------------------------------------------------ + * + */ +#define GPIO_IN_REG_OFFSET 0x90 + +#define GPIO_IN0_REG_OFFSET 0x90 +#define GPIO_IN1_REG_OFFSET 0x94 +#define GPIO_IN2_REG_OFFSET 0x98 +#define GPIO_IN3_REG_OFFSET 0x9C + +/*------------------------------------------------------------------------------ + * + */ +#define GPIO_OUT_REG_OFFSET 0xA0 + +#define GPIO_OUT0_REG_OFFSET 0xA0 +#define GPIO_OUT1_REG_OFFSET 0xA4 +#define GPIO_OUT2_REG_OFFSET 0xA8 +#define GPIO_OUT3_REG_OFFSET 0xAC + +#endif /* __CORE_GPIO_REGISTERS_H */ diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c new file mode 100644 index 0000000..1fd3dd6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c @@ -0,0 +1,1495 @@ +/******************************************************************************* + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * CoreI2C software driver implementation. + * + */ + +#include "core_smbus_regs.h" +#include "core_i2c.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * I2C transaction direction. + */ +#define WRITE_DIR 0u +#define READ_DIR 1u + +/* -- TRANSACTIONS TYPES -- */ +#define NO_TRANSACTION 0u +#define MASTER_WRITE_TRANSACTION 1u +#define MASTER_READ_TRANSACTION 2u +#define MASTER_RANDOM_READ_TRANSACTION 3u +#define WRITE_SLAVE_TRANSACTION 4u +#define READ_SLAVE_TRANSACTION 5u + +/* -- SMBUS H/W STATES -- */ +/* -- MASTER STATES -- */ +#define ST_BUS_ERROR 0x00u /* Bus error during MST or selected slave modes */ +#define ST_I2C_IDLE 0xF8u /* No activity and no interrupt either... */ +#define ST_START 0x08u /* start condition sent */ +#define ST_RESTART 0x10u /* repeated start */ +#define ST_SLAW_ACK 0x18u /* SLA+W sent, ack received */ +#define ST_SLAW_NACK 0x20u /* SLA+W sent, nack received */ +#define ST_TX_DATA_ACK 0x28u /* Data sent, ACK'ed */ +#define ST_TX_DATA_NACK 0x30u /* Data sent, NACK'ed */ +#define ST_LOST_ARB 0x38u /* Master lost arbitration */ +#define ST_SLAR_ACK 0x40u /* SLA+R sent, ACK'ed */ +#define ST_SLAR_NACK 0x48u /* SLA+R sent, NACK'ed */ +#define ST_RX_DATA_ACK 0x50u /* Data received, ACK sent */ +#define ST_RX_DATA_NACK 0x58u /* Data received, NACK sent */ +#define ST_RESET_ACTIVATED 0xD0u /* Master reset is activated */ +#define ST_STOP_TRANSMIT 0xE0u /* Stop has been transmitted */ + +/* -- SLAVE STATES -- */ +#define ST_SLAVE_SLAW 0x60u /* SLA+W received */ +#define ST_SLAVE_SLAR_ACK 0xA8u /* SLA+R received, ACK returned */ +#define ST_SLV_LA 0x68u /* Slave lost arbitration */ +#define ST_GCA 0x70u /* GCA received */ +#define ST_GCA_LA 0x78u /* GCA lost arbitration */ +#define ST_RDATA 0x80u /* Data received */ +#define ST_SLA_NACK 0x88u /* Slave addressed, NACK returned */ +#define ST_GCA_ACK 0x90u /* Previously addresses with GCA, data ACKed */ +#define ST_GCA_NACK 0x98u /* GCA addressed, NACK returned */ +#define ST_RSTOP 0xA0u /* Stop received */ +#define ST_SLARW_LA 0xB0u /* Arbitration lost */ +#define ST_RACK 0xB8u /* Byte sent, ACK received */ +#define ST_SLAVE_RNACK 0xC0u /* Byte sent, NACK received */ +#define ST_FINAL 0xC8u /* Final byte sent, ACK received */ +#define ST_SLV_RST 0xD8u /* Slave reset state */ + + +/* I2C Channel base offset */ +#define CHANNEL_BASE_SHIFT 5u +#define CHANNEL_MASK 0x1E0u + +/* + * Maximum address offset length in slave write-read transactions. + * A maximum of two bytes will be interpreted as address offset within the slave + * tx buffer. + */ +#define MAX_OFFSET_LENGTH 2u + +/*------------------------------------------------------------------------------ + * I2C interrupts control functions implemented "i2c_interrupt.c". + * the implementation of these functions depend on the underlying hardware + * design and how the CoreI2C interrupt line is connected to the system's + * interrupt controller. + */ +void I2C_enable_irq( i2c_instance_t * this_i2c ); +void I2C_disable_irq( i2c_instance_t * this_i2c ); +static void enable_slave_if_required(i2c_instance_t * this_i2c); + +/*------------------------------------------------------------------------------ + * I2C_init() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_init +( + i2c_instance_t * this_i2c, + addr_t base_address, + uint8_t ser_address, + i2c_clock_divider_t ser_clock_speed +) +{ + psr_t saved_psr; + uint_fast16_t clock_speed = (uint_fast16_t)ser_clock_speed; + + /* + * We need to disable ints while doing this as there is no guarantee we + * have not been called already and the ISR is active. + */ + saved_psr = HAL_disable_interrupts(); + + /* + * Initialize all items of the this_i2c data structure to zero. This + * initializes all state variables to their init value. It relies on + * the fact that NO_TRANSACTION, I2C_SUCCESS and I2C_RELEASE_BUS all + * have an actual value of zero. + */ + memset(this_i2c, 0, sizeof(i2c_instance_t)); + + /* + * Set base address of I2C hardware used by this instance. + */ + this_i2c->base_address = base_address; + + /* + * Update Serial address of the device + */ + this_i2c->ser_address = ((uint_fast8_t)ser_address << 1u); + + /* + * Configure hardware. + */ + HAL_set_8bit_reg_field(this_i2c->base_address, ENS1, 0x00); /* Reset I2C hardware. */ + HAL_set_8bit_reg_field(this_i2c->base_address, ENS1, 0x01); /* set enable bit */ + HAL_set_8bit_reg_field(this_i2c->base_address, CR2, ( (clock_speed >> 2) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c->base_address, CR1, ( (clock_speed >> 1) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c->base_address, CR0, ( clock_speed & 0x01) ); + + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS, this_i2c->ser_address); + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, this_i2c->ser_address); + + /* + * Finally safe to enable interrupts. + */ + HAL_restore_interrupts( saved_psr ); +} +/*------------------------------------------------------------------------------ + * I2C_channel_init() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_channel_init +( + i2c_instance_t * this_i2c_channel, + i2c_instance_t * this_i2c, + i2c_channel_number_t channel_number, + i2c_clock_divider_t ser_clock_speed +) +{ + psr_t saved_psr; + uint_fast16_t clock_speed = (uint_fast16_t)ser_clock_speed; + + HAL_ASSERT(channel_number < I2C_MAX_CHANNELS); + HAL_ASSERT(I2C_CHANNEL_0 != channel_number); + + /* + * Cannot allow channel 0 in this function as we will trash the hardware + * base address and slave address. + */ + if ((channel_number < I2C_MAX_CHANNELS) && + (I2C_CHANNEL_0 != channel_number)) + { + /* + * We need to disable ints while doing this as the hardware should already + * be active at this stage. + */ + saved_psr = HAL_disable_interrupts(); + + /* + * Initialize channel data. + */ + memset(this_i2c_channel, 0, sizeof(i2c_instance_t)); + + this_i2c_channel->base_address = + ((this_i2c->base_address) & ~((addr_t)CHANNEL_MASK)) + | (((addr_t)channel_number) << CHANNEL_BASE_SHIFT); + + this_i2c_channel->ser_address = this_i2c->ser_address; + + HAL_set_8bit_reg_field(this_i2c_channel->base_address, ENS1, 0x00); /* Reset I2C channel hardware. */ + HAL_set_8bit_reg_field(this_i2c_channel->base_address, ENS1, 0x01); /* set enable bit */ + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR2, ( (clock_speed >> 2) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR1, ( (clock_speed >> 1) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR0, ( clock_speed & 0x01) ); + /* + * Finally safe to enable interrupts. + */ + HAL_restore_interrupts( saved_psr ); + } +} + +/*------------------------------------------------------------------------------ + * I2C_write() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_write +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * write_buffer, + uint16_t write_size, + uint8_t options +) +{ + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + saved_psr = HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_WRITE_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_WRITE_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + this_i2c->dir = WRITE_DIR; + this_i2c->master_tx_buffer = write_buffer; + this_i2c->master_tx_size = write_size; + this_i2c->master_tx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_read() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +) +{ + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + saved_psr = HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_READ_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_READ_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + + this_i2c->dir = READ_DIR; + + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_write_read() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_write_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * addr_offset, + uint16_t offset_size, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +) +{ + HAL_ASSERT(offset_size > 0u); + HAL_ASSERT(addr_offset != (uint8_t *)0); + HAL_ASSERT(read_size > 0u); + HAL_ASSERT(read_buffer != (uint8_t *)0); + + this_i2c->master_status = I2C_FAILED; + + if((read_size > 0u) && (offset_size > 0u)) + { + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + saved_psr = HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_RANDOM_READ_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_RANDOM_READ_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + + this_i2c->dir = WRITE_DIR; + + this_i2c->master_tx_buffer = addr_offset; + this_i2c->master_tx_size = offset_size; + this_i2c->master_tx_idx = 0u; + + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + + HAL_restore_interrupts( saved_psr ); + } +} + +/*------------------------------------------------------------------------------ + * I2C_get_status() + * See "core_i2c.h" for details of how to use this function. + */ +i2c_status_t I2C_get_status +( + i2c_instance_t * this_i2c +) +{ + i2c_status_t i2c_status ; + + i2c_status = this_i2c->master_status ; + + return i2c_status; +} + +/*------------------------------------------------------------------------------ + * I2C_wait_complete() + * See "core_i2c.h" for details of how to use this function. + */ +i2c_status_t I2C_wait_complete +( + i2c_instance_t * this_i2c, + uint32_t timeout_ms +) +{ + i2c_status_t i2c_status; + psr_t saved_psr; + /* + * Because we have no idea of what CPU we are supposed to be running on + * we need to guard this write to the timeout value to avoid ISR/user code + * interaction issues. Checking the status below should be fine as only a + * single byte should change in that. + */ + saved_psr = HAL_disable_interrupts(); + this_i2c->master_timeout_ms = timeout_ms; + HAL_restore_interrupts( saved_psr ); + + /* Run the loop until state returns I2C_FAILED or I2C_SUCESS*/ + do { + i2c_status = this_i2c->master_status; + } while(I2C_IN_PROGRESS == i2c_status); + return i2c_status; +} + +/*------------------------------------------------------------------------------ + * I2C_system_tick() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_system_tick +( + i2c_instance_t * this_i2c, + uint32_t ms_since_last_tick +) +{ + if(this_i2c->master_timeout_ms != I2C_NO_TIMEOUT) + { + if(this_i2c->master_timeout_ms > ms_since_last_tick) + { + this_i2c->master_timeout_ms -= ms_since_last_tick; + } + else + { + psr_t saved_psr; + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + /* + * Mark current transaction as having timed out. + */ + this_i2c->master_status = I2C_TIMED_OUT; + this_i2c->transaction = NO_TRANSACTION; + this_i2c->is_transaction_pending = 0; + + HAL_restore_interrupts( saved_psr ); + + /* + * Make sure we do not incorrectly signal a timeout for subsequent + * transactions. + */ + this_i2c->master_timeout_ms = I2C_NO_TIMEOUT; + } + } +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_tx_buffer() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_tx_buffer +( + i2c_instance_t * this_i2c, + const uint8_t * tx_buffer, + uint16_t tx_size +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + this_i2c->slave_tx_buffer = tx_buffer; + this_i2c->slave_tx_size = tx_size; + this_i2c->slave_tx_idx = 0u; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_rx_buffer() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_rx_buffer +( + i2c_instance_t * this_i2c, + uint8_t * rx_buffer, + uint16_t rx_size +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + this_i2c->slave_rx_buffer = rx_buffer; + this_i2c->slave_rx_size = rx_size; + this_i2c->slave_rx_idx = 0u; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_mem_offset_length() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_mem_offset_length +( + i2c_instance_t * this_i2c, + uint8_t offset_length +) +{ + HAL_ASSERT(offset_length <= MAX_OFFSET_LENGTH); + + /* + * Single byte update, should be interrupt safe + */ + if(offset_length > MAX_OFFSET_LENGTH) + { + this_i2c->slave_mem_offset_length = MAX_OFFSET_LENGTH; + } + else + { + this_i2c->slave_mem_offset_length = offset_length; + } +} + +/*------------------------------------------------------------------------------ + * I2C_register_write_handler() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_register_write_handler +( + i2c_instance_t * this_i2c, + i2c_slave_wr_handler_t handler +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + this_i2c->slave_write_handler = handler; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_enable_slave() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_enable_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register and slave mode flag without the I2C ISR interrupting + * us. + */ + saved_psr = HAL_disable_interrupts(); + + /* Set the Assert Acknowledge bit. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + /* Enable slave mode */ + this_i2c->is_slave_enabled = 1u; + + HAL_restore_interrupts( saved_psr ); + + /* Enable I2C IRQ*/ + I2C_enable_irq( this_i2c ); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_slave() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_disable_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + /* Reset the assert acknowledge bit. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + + /* Disable slave mode with IRQ blocked to make whole change atomic */ + this_i2c->is_slave_enabled = 0u; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * + */ +static void enable_slave_if_required +( + i2c_instance_t * this_i2c +) +{ + /* + * This function is only called from within the ISR and so does not need + * guarding on the register access. + */ + if( 0 != this_i2c->is_slave_enabled ) + { + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x01u ); + } +} +/*------------------------------------------------------------------------------ + * I2C_set_slave_second_addr() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_slave_second_addr +( + i2c_instance_t * this_i2c, + uint8_t second_slave_addr +) +{ + uint8_t second_slave_address; + + /* + This function does not support CoreI2C hardware configured with a fixed + second slave address. The current implementation of the ADDR1[0] register + bit makes it difficult for the driver to support both programmable and + fixed second slave address, so we choose to support programmable only. + With the programmable configuration, ADDR1[0] and ADDR0[0] both control + enable/disable of GCA recognition, as an effective OR of the 2 bit fields. + Therefore we set ADDR1[0] to 0 here, so that only ADDR0[0] controls GCA. + */ + second_slave_address = (uint8_t)((second_slave_addr << 1u) & (~SLAVE1_EN_MASK)); + + /* + * Single byte register write, should be interrupt safe + */ + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, second_slave_address); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_slave_second_addr() + * See "i2c.h" for details of how to use this function. + */ +void I2C_disable_slave_second_addr +( + i2c_instance_t * this_i2c +) +{ + /* + We are disabling the second slave address by setting the value of the 2nd + slave address to the primary slave address. The reason for using this method + of disabling 2nd slave address is that ADDRESS1[0] has different meaning + depending on hardware configuration. Its use would likely interfere with + the intended GCA setting. + */ + /* + * Single byte register write, should be interrupt safe + */ + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, this_i2c->ser_address); +} + +/*------------------------------------------------------------------------------ + * i2C_set_gca() + * See "i2c.h" for details of how to use this function. + */ + +void I2C_set_gca +( + i2c_instance_t * this_i2c +) +{ + /* + * This read modify write access should be interrupt safe as the address + * register is not written to in the ISR. + */ + /* accept GC addressing. */ + HAL_set_8bit_reg_field(this_i2c->base_address, GC, 0x01u); +} + +/*------------------------------------------------------------------------------ + * I2C_clear_gca() + * See "i2c.h" for details of how to use this function. + */ +void I2C_clear_gca +( + i2c_instance_t * this_i2c +) +{ + /* + * This read modify write access should be interrupt safe as the address + * register is not written to in the ISR. + */ + /* Clear GC addressing. */ + HAL_set_8bit_reg_field(this_i2c->base_address, GC, 0x00u); +} + +/*------------------------------------------------------------------------------ + * I2C_isr() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_isr +( + i2c_instance_t * this_i2c +) +{ + volatile uint8_t status; + uint8_t data; + uint8_t hold_bus; + uint8_t clear_irq = 1u; + + status = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + + switch( status ) + { + /************** MASTER TRANSMITTER / RECEIVER *******************/ + + case ST_START: /* start has been xmt'd */ + case ST_RESTART: /* repeated start has been xmt'd */ + HAL_set_8bit_reg_field( this_i2c->base_address, STA, 0x00u); + HAL_set_8bit_reg( this_i2c->base_address, DATA, this_i2c->target_addr); /* write call address */ + HAL_set_8bit_reg_field( this_i2c->base_address, DIR, this_i2c->dir); /* set direction bit */ + if(this_i2c->dir == WRITE_DIR) + { + this_i2c->master_tx_idx = 0u; + } + else + { + this_i2c->master_rx_idx = 0u; + } + + /* + * Clear the pending transaction. This condition will be true if the slave + * has acquired the bus to carry out pending master transaction which + * it had received during its slave transmission or reception mode. + */ + if(this_i2c->is_transaction_pending) + { + this_i2c->is_transaction_pending = 0u; + } + + /* + * Make sure to update proper transaction after master START + * or RESTART + */ + if(this_i2c->transaction != this_i2c->pending_transaction) + { + this_i2c->transaction = this_i2c->pending_transaction; + } + break; + + case ST_LOST_ARB: + /* Set start bit. Let's keep trying! Don't give up! */ + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + break; + + case ST_STOP_TRANSMIT: + /* Stop has been transmitted. Do nothing */ + break; + + /******************* MASTER TRANSMITTER *************************/ + case ST_SLAW_NACK: + /* SLA+W has been transmitted; not ACK has been received - let's stop. */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_FAILED; + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + case ST_SLAW_ACK: + case ST_TX_DATA_ACK: + /* data byte has been xmt'd with ACK, time to send stop bit or repeated start. */ + if (this_i2c->master_tx_idx < this_i2c->master_tx_size) + { + HAL_set_8bit_reg(this_i2c->base_address, DATA, (uint_fast8_t)this_i2c->master_tx_buffer[this_i2c->master_tx_idx++]); + } + else if ( this_i2c->transaction == MASTER_RANDOM_READ_TRANSACTION ) + { + /* We are finished sending the address offset part of a random read transaction. + * It is is time to send a restart in order to change direction. */ + this_i2c->dir = READ_DIR; + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + else /* done sending. let's stop */ + { + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + hold_bus = this_i2c->options & I2C_HOLD_BUS; + + /* Store the information of current I2C bus status in the bus_status*/ + this_i2c->bus_status = hold_bus; + if ( hold_bus == 0u ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); /*xmt stop condition */ + enable_slave_if_required(this_i2c); + } + else + { + I2C_disable_irq( this_i2c ); + clear_irq = 0u; + } + this_i2c->master_status = I2C_SUCCESS; + } + break; + + case ST_TX_DATA_NACK: + /* data byte SENT, ACK to be received + * In fact, this means we've received a NACK (This may not be + * obvious, but if we've rec'd an ACK then we would be in state + * 0x28!) hence, let's send a stop bit + */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u);/* xmt stop condition */ + this_i2c->master_status = I2C_FAILED; + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + /********************* MASTER (or slave?) RECEIVER *************************/ + + /* STATUS codes 08H, 10H, 38H are all covered in MTX mode */ + case ST_SLAR_ACK: /* SLA+R tx'ed. */ + /* Let's make sure we ACK the first data byte received (set AA bit in CTRL) unless + * the next byte is the last byte of the read transaction. + */ + if(this_i2c->master_rx_size > 1u) + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + } + else if(1u == this_i2c->master_rx_size) + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + else /* this_i2c->master_rx_size == 0u */ + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_SUCCESS; + this_i2c->transaction = NO_TRANSACTION; + } + break; + + case ST_SLAR_NACK: /* SLA+R tx'ed; let's release the bus (send a stop condition) */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_FAILED; + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + case ST_RX_DATA_ACK: /* Data byte received, ACK returned */ + /* First, get the data */ + this_i2c->master_rx_buffer[this_i2c->master_rx_idx++] = HAL_get_8bit_reg(this_i2c->base_address, DATA); + if( this_i2c->master_rx_idx >= (this_i2c->master_rx_size - 1u)) + { + /* If we're at the second last byte, let's set AA to 0 so + * we return a NACK at the last byte. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + break; + + case ST_RX_DATA_NACK: /* Data byte received, NACK returned */ + /* Get the data, then send a stop condition */ + this_i2c->master_rx_buffer[this_i2c->master_rx_idx] = HAL_get_8bit_reg(this_i2c->base_address, DATA); + + hold_bus = this_i2c->options & I2C_HOLD_BUS; + + /* Store the information of current I2C bus status in the bus_status*/ + this_i2c->bus_status = hold_bus; + if ( hold_bus == 0u ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); /*xmt stop condition */ + + /* Bus is released, now we can start listening to bus, if it is slave */ + enable_slave_if_required(this_i2c); + } + else + { + I2C_disable_irq( this_i2c ); + clear_irq = 0u; + } + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + this_i2c->master_status = I2C_SUCCESS; + break; + + /******************** SLAVE RECEIVER **************************/ + case ST_GCA_NACK: /* NACK after, GCA addressing */ + case ST_SLA_NACK: /* Re-enable AA (assert ack) bit for future transmissions */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + this_i2c->transaction = NO_TRANSACTION; + this_i2c->slave_status = I2C_SUCCESS; + + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + break; + + case ST_GCA_LA: /* Arbitr. lost (GCA rec'd) */ + case ST_SLV_LA: /* Arbitr. lost (SLA rec'd) */ + /* + * We lost arbitration and either the GCE or our address was the + * one received so pend the master operation we were starting. + */ + this_i2c->is_transaction_pending = 1u; + /* Fall through to normal ST processing as we are now in slave mode */ + + case ST_GCA: /* General call address received, ACK returned */ + case ST_SLAVE_SLAW: /* SLA+W received, ACK returned */ + this_i2c->transaction = WRITE_SLAVE_TRANSACTION; + this_i2c->slave_rx_idx = 0u; + this_i2c->random_read_addr = 0u; + /* + * If Start Bit is set clear it, but store that information since it is because of + * pending transaction + */ + if(HAL_get_8bit_reg_field(this_i2c->base_address, STA)) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + this_i2c->is_transaction_pending = 1u; + } + this_i2c->slave_status = I2C_IN_PROGRESS; +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + /* Fall through to put address as first byte in payload buffer */ +#else + /* Only break from this case if the slave address must NOT be included at the + * beginning of the received write data. */ + break; +#endif + case ST_GCA_ACK: /* DATA received; ACK sent after GCA */ + case ST_RDATA: /* DATA received; must clear DATA register */ + if((this_i2c->slave_rx_buffer != (uint8_t *)0) + && (this_i2c->slave_rx_idx < this_i2c->slave_rx_size)) + { + data = HAL_get_8bit_reg(this_i2c->base_address, DATA); + this_i2c->slave_rx_buffer[this_i2c->slave_rx_idx++] = data; + +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + if((ST_RDATA == status) || (ST_GCA_ACK == status)) + { + /* Ignore the slave address byte in the random read address + computation in the case where INCLUDE_SLA_IN_RX_PAYLOAD + is defined. */ +#endif + this_i2c->random_read_addr = (this_i2c->random_read_addr << 8) + data; +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + } +#endif + } + + if(this_i2c->slave_rx_idx >= this_i2c->slave_rx_size) + { + /* Rx buffer is full. NACK next received byte. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + break; + + case ST_RSTOP: + /* STOP or repeated START occurred. */ + /* We cannot be sure if the transaction has actually completed as + * this hardware state reports that either a STOP or repeated START + * condition has occurred. We assume that this is a repeated START + * if the transaction was a write from the master to this point.*/ + if ( this_i2c->transaction == WRITE_SLAVE_TRANSACTION ) + { + if ( this_i2c->slave_rx_idx == this_i2c->slave_mem_offset_length ) + { + this_i2c->slave_tx_idx = this_i2c->random_read_addr; + } + /* Call the slave's write transaction handler if it exists. */ + if ( this_i2c->slave_write_handler != 0u ) + { + i2c_slave_handler_ret_t h_ret; + h_ret = this_i2c->slave_write_handler( this_i2c, this_i2c->slave_rx_buffer, (uint16_t)this_i2c->slave_rx_idx ); + if ( I2C_REENABLE_SLAVE_RX == h_ret ) + { + /* There is a small risk that the write handler could + * call I2C_disable_slave() but return + * I2C_REENABLE_SLAVE_RX in error so we only enable + * ACKs if still in slave mode. */ + enable_slave_if_required(this_i2c); + } + else + { + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x0u ); + /* Clear slave mode flag as well otherwise in mixed + * master/slave applications, the AA bit will get set by + * subsequent master operations. */ + this_i2c->is_slave_enabled = 0u; + } + } + else + { + /* Re-enable address acknowledge in case we were ready to nack the next received byte. */ + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x01u ); + } + } + else /* A stop or repeated start outside a write/read operation */ + { + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * See if we need to re-enable acknowledgement as some error conditions, such + * as a master prematurely ending a transfer, can see us get here with AA set + * to 0 which will disable slave operation if we are not careful. + */ + enable_slave_if_required(this_i2c); + } + + /* Mark any previous master write transaction as complete. */ + this_i2c->slave_status = I2C_SUCCESS; + + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + + break; + + case ST_SLV_RST: /* SMBUS ONLY: timeout state. must clear interrupt */ + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction. + */ + this_i2c->transaction = NO_TRANSACTION; + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * Clear status to I2C_FAILED only if there was an operation in progress. + */ + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->slave_status = I2C_FAILED; + } + + enable_slave_if_required(this_i2c); /* Make sure AA is set correctly */ + + break; + + /****************** SLAVE TRANSMITTER **************************/ + case ST_SLAVE_SLAR_ACK: /* SLA+R received, ACK returned */ + case ST_SLARW_LA: /* Arbitration lost, and: */ + case ST_RACK: /* Data tx'ed, ACK received */ + if ( status == ST_SLAVE_SLAR_ACK ) + { + this_i2c->transaction = READ_SLAVE_TRANSACTION; + this_i2c->random_read_addr = 0u; + this_i2c->slave_status = I2C_IN_PROGRESS; + /* If Start Bit is set clear it, but store that information since it is because of + * pending transaction + */ + if(HAL_get_8bit_reg_field(this_i2c->base_address, STA)) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + this_i2c->is_transaction_pending = 1u; + } + } + if (this_i2c->slave_tx_idx >= this_i2c->slave_tx_size) + { + /* Ensure 0xFF is returned to the master when the slave specifies + * an empty transmit buffer. */ + HAL_set_8bit_reg(this_i2c->base_address, DATA, 0xFFu); + } + else + { + /* Load the data the data byte to be sent to the master. */ + HAL_set_8bit_reg(this_i2c->base_address, DATA, (uint_fast8_t)this_i2c->slave_tx_buffer[this_i2c->slave_tx_idx++]); + } + /* Determine if this is the last data byte to send to the master. */ + if (this_i2c->slave_tx_idx >= this_i2c->slave_tx_size) /* last byte? */ + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + /* Next read transaction will result in slave's transmit buffer + * being sent from the first byte. */ + this_i2c->slave_tx_idx = 0u; + } + break; + + case ST_SLAVE_RNACK: /* Data byte has been transmitted; not-ACK has been received. */ + case ST_FINAL: /* Last Data byte tx'ed, ACK received */ + /* We assume that the transaction will be stopped by the master. + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. */ + this_i2c->slave_tx_idx = 0u; + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + /* Mark previous state as complete */ + this_i2c->slave_status = I2C_SUCCESS; + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + + break; + + /* Master Reset has been activated Wait 35 ms for interrupt to be set, + * clear interrupt and proceed to 0xF8 state. */ + case ST_RESET_ACTIVATED: + case ST_BUS_ERROR: /* Bus error during MST or selected slave modes */ + default: + /* Some undefined state has encountered. Clear Start bit to make + * sure, next good transaction happen */ + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction. + */ + this_i2c->transaction = NO_TRANSACTION; + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * Clear statuses to I2C_FAILED only if there was an operation in progress. + */ + if(I2C_IN_PROGRESS == this_i2c->master_status) + { + this_i2c->master_status = I2C_FAILED; + } + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->slave_status = I2C_FAILED; + } + + break; + } + + if ( clear_irq ) + { + /* clear interrupt. */ + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + /* Read the status register to ensure the last I2C registers write took place + * in a system built around a bus making use of posted writes. */ + status = HAL_get_8bit_reg( this_i2c->base_address, STATUS); +} + +/*------------------------------------------------------------------------------ + * I2C_smbus_init() + * See "i2c.h" for details of how to use this function. + */ + +/* + * SMBSUS_NO = 1 + * SMBALERT_NO = 1 + * SMBus enable = 1 + */ +#define INIT_AND_ENABLE_SMBUS 0x54u +void I2C_smbus_init +( + i2c_instance_t * this_i2c +) +{ + /* + * Single byte register write, should be interrupt safe + */ + /* Enable SMBUS */ + HAL_set_8bit_reg(this_i2c->base_address, SMBUS, INIT_AND_ENABLE_SMBUS); +} + +/*------------------------------------------------------------------------------ + * I2C_enable_smbus_irq() + * See "i2c.h" for details of how to use this function. + */ +void I2C_enable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + if ( irq_type & I2C_SMBALERT_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_IE, 0x01u); + } + if ( irq_type & I2C_SMBSUS_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_IE, 0x01u); + } + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_smbus_irq() + * See "i2c.h" for details of how to use this function. + */ +void I2C_disable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + if ( irq_type & I2C_SMBALERT_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_IE, 0x00u); + } + if (irq_type & I2C_SMBSUS_IRQ ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_IE, 0x00u); + } + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_suspend_smbus_slave() + * See "i2c.h" for details of how to use this function. + */ +void I2C_suspend_smbus_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_NO_CONTROL, 0x00u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_resume_smbus_slave() + * See "i2c.h" for details of how to use this function. + */ +void I2C_resume_smbus_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_NO_CONTROL, 0x01u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_reset_smbus() + * See "i2c.h" for details of how to use this function. + */ +void I2C_reset_smbus +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + HAL_set_8bit_reg_field(this_i2c->base_address, SMBUS_MST_RESET, 0x01u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_smbus_alert() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_smbus_alert +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_NO_CONTROL, 0x00u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_clear_smbus_alert() + * See "i2c.h" for details of how to use this function. + */ +void I2C_clear_smbus_alert +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_NO_CONTROL, 0x01u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_get_irq_status() + * See "i2c.h" for details of how to use this function. + */ +uint8_t I2C_get_irq_status +( + i2c_instance_t * this_i2c +) +{ + uint8_t status ; + uint8_t irq_type = I2C_NO_IRQ ; + + status = HAL_get_8bit_reg(this_i2c->base_address, SMBUS); + + if( status & (uint8_t)SMBALERT_NI_STATUS_MASK ) + { + irq_type |= I2C_SMBALERT_IRQ ; + } + + if( status & (uint8_t)SMBSUS_NI_STATUS_MASK ) + { + irq_type |= I2C_SMBSUS_IRQ ; + } + + status = HAL_get_8bit_reg(this_i2c->base_address, CONTROL); + + if( status & (uint8_t)SI_MASK ) + { + irq_type |= I2C_INTR_IRQ ; + } + return(irq_type); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_addr2() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_user_data +( + i2c_instance_t * this_i2c, + void * p_user_data +) +{ + this_i2c->p_user_data = p_user_data ; +} + +/*------------------------------------------------------------------------------ + * I2C_get_user_data() + * See "i2c.h" for details of how to use this function. + */ +void * I2C_get_user_data +( + i2c_instance_t * this_i2c +) +{ + return( this_i2c->p_user_data); +} + +#ifdef __cplusplus +} +#endif + diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h new file mode 100644 index 0000000..3891ce0 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h @@ -0,0 +1,2306 @@ +/***************************************************************************//** + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * CoreI2C software driver Application Programming Interface. + * This file contains defines and function declarations allowing to interface + * with the CoreI2C software driver. + * + */ +/*=========================================================================*//** + @mainpage CoreI2C Bare Metal Driver. + The CoreI2C bare metal software driver supports I2C master and slave + operations. + + ============================================================================== + Introduction + ============================================================================== + The CoreI2C driver provides a set of functions for controlling the Microchip + CoreI2C hardware IP. The driver supports up to 16 separate I2C channels per + CoreI2C instance, with common slave address settings shared between channels + on a device. + + Optional features of the CoreI2C allow it to operate with I2C based protocols + such as System Management Bus (SMBus), Power Management Bus (PMBus), and + Intelligent Platform Management Interface (IPMI). This driver provides support + for these features when enabled in the CoreI2C IP. + + The major features provided by CoreI2C driver: + - Provides support to configuring the I2C channels of each CoreI2C peripheral device. + - I2C master operations. + - I2C slave operations. + - SMBus related operations. + + This driver is used as part of a bare metal system where no operating + system is available. The driver gets adapted as a part of an operating system, + but the implementation of the adaptation layer between the driver and the operating + system's driver model is outside the scope of this driver. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + Your application software should configure the CoreI2C driver through + calls to the I2C_init() function for each CoreI2C instance in the + hardware design. The configuration parameters include the CoreI2C hardware + instance base address and other runtime parameters, such as the I2C serial + clock frequency and the I2C device address. + + Once channel 0 of a CoreI2C peripheral has been initialized by I2C_init(), + any additional channels present should be configured by calling + I2C_channel_init() for each of the remaining channels. + + Apart from the CoreI2C hardware instance base address, no CoreI2C hardware configuration + parameters are used by the driver. Hence, no additional configuration files are required + to use the driver. + + -------------------------------- + Interrupt Control + -------------------------------- + The CoreI2C driver has to enable and disable the generation of interrupts by + CoreI2C at various times when it is operating. This enabling and disabling of + interrupts must be done through the system’s interrupt controller. For that + reason, the method of controlling the CoreI2C interrupt is system specific + and it is necessary to customize the I2C_enable_irq() and I2C_disable_irq() + functions. These functions are available in the i2c_interrupt.c file. + The default implementation calls HAL_ASSERT(0) to indicate to the application + developer that a suitable implementations for these functions must be provided. + + The implementation of the I2C_enable_irq() function should permit interrupts + generated by a CoreI2C instance to interrupt the processor. The implementation + of the I2C_disable_irq() function should prevent interrupts generated by a + CoreI2C instance from interrupting the processor. See the provided example + projects for a working implementation of these functions. + + The I2C_register_write_handler() function registers a write handler + function with the CoreI2C driver that calls on completion of an I2C write + transaction by the CoreI2C slave. It is your responsibility to create and + register the implementation of this handler function that processes or + trigger the processing of the received data. + + The SMBSUS and SMBALERT interrupts are related to the SMBus interface and are + enabled and disabled through I2C_enable_smbus_irq() and + I2C_disable_smbus_irq() respectively. It is your responsibility to create + interrupt handler functions in your application to get the desired response + for the SMBus interrupts. + + Note: You must include the path to any application header files that are + included in the i2c_interrupt.c file, as an include path in your + project's compiler settings. The details of how to do this will depend + on your development software. + + -------------------------------- + SMBus Logic Options + -------------------------------- + SMBus related APIs does not have any effect if the "Generate SMBus Logic" + is not enabled in the CoreI2C hardware configuration. Following are API's + that does not give the desired results if SMBus Logic is disabled. + + - I2C_smbus_init() + - I2C_reset_smbus() + - I2C_enable_smbus_irq() + - I2C_disable_smbus_irq() + - I2C_suspend_smbus_slave() + - I2C_resume_smbus_slave() + - I2C_set_smsbus_alert() + - I2C_clear_smsbus_alert() + - I2C_get_irq_status() + + -------------------------------- + Fixed Baud Rate Values + -------------------------------- + The serial clock frequency parameter passed to the I2C_init() and + I2C_channel_init() functions may not have any effect if fixed values were + selected for Baud rate in the hardware configuration of CoreI2C. When fixed + values are selected for these baud rates, the driver cannot overwrite + the fixed values. + + ----------------------------------- + Fixed Slave Address Options Values + ----------------------------------- + The primary slave address parameter passed to the I2C_init() function and + secondary address value passed to the I2C_set_slave_second_addr() function, + may not have the desired effect if fixed values were selected for the slave 0 + address and slave 1 address respectively. Proper operation of this version of + the driver requires the slave addresses to be programmable. + + ============================================================================== + Theory of Operation + ============================================================================== + The CoreI2C software driver is designed to allow the control of multiple + instances of CoreI2C with one or more I2C channels. Each channel in an + instance of CoreI2C in the hardware design is associated with a single + instance of the i2c_instance_t structure in the software. You must allocate + memory for one unique i2c_instance_t structure instance for each channel of + each CoreI2C hardware instance. The contents of these data structures are + initialised by calling I2C_init() and if necessary I2C_channel_init(). + A pointer to the structure is passed to the subsequent driver functions in order + to identify the CoreI2C hardware instance and channel to perform the + requested operation. + + Note: Do not attempt to directly manipulate the contents of i2c_instance_t + structures. These structures are only intended to be modified by the driver + functions. + + The CoreI2C driver functions are grouped into the following categories: + - Initialization and configuration functions + - Interrupt control + - I2C slave addressing functions + - I2C master operations functions to handle write, read, and write-read + transactions + - I2C slave operations functions to handle write, read, and write-read + transactions + - Mixed master-slave operations + - SMBus interface configuration and control + + -------------------------------- + Initialization and Configuration + -------------------------------- + The CoreI2C device is first initialized by calling the I2C_init() + function. Since each CoreI2C peripheral supports up to 16 channels, an + additional function, I2C_channel_init(), is required to initialize the + remaining channels with their own data structures. + + I2C_init() function initializes channel 0 of a CoreI2C and the i2c_instance_t + for channel 0 acts as the basis for further channel initialization as the + hardware base address and I2C serial address are same across all the channels. + Ensure to call I2C_init() function before calling any other I2C driver function + calls. The I2C_init() call for each CoreI2C takes the I2C serial address assigned + to the I2C and the serial clock divider to generate its I2C clock as configuration + parameters. + + I2C_channel_init() function takes as input parameters a pointer to the CoreI2C + i2c_instance_t which has been initialized by calling the I2C_init() and a pointer + to a separate i2c_instance_t which represents this new channel. Another input + parameter which is required by this function is serial clock divider which generates + its I2C clock. + + -------------------------------- + Interrupt Control + -------------------------------- + The CoreI2C driver is interrupt driven and it uses each channels INT + interrupt to drive the state machine which is at the heart of the driver. + The application is responsible for providing the link between the interrupt + generating hardware and the CoreI2C interrupt handler and must ensure that + the I2C_isr() function is called with the correct i2c_instance_t structure + pointer for the CoreI2C channel initiating the interrupt. + + The driver enables and disables the generation of INT interrupts by CoreI2C + at various times when it is operating through the user supplied + I2C_enable_irq() and I2C_disable_irq() functions. + + The I2C_register_write_handler() function is used to register a write + handler function with the CoreI2C driver which is called on completion + of an I2C write transaction by the CoreI2C slave. It is the user + applications responsibility to create and register the implementation of + this handler function that processes or triggers the processing of the + received data. + + The other two interrupt sources in the CoreI2C are related to SMBus + operation and are enabled and disabled through I2C_enable_smbus_irq() and + I2C_disable_smbus_irq() respectively. Due to the application specific + nature of the response to SMBus interrupts, you must design interrupt + handler functions in the application to get the desired behaviour for + SMBus related interrupts. + + If enabled, the SMBA_INT signal from the CoreI2C is asserted if an + SMBALERT condition is signalled on the SMBALERT_NI input for the channel. + + If enabled, the SMBS_INT signal from the CoreI2C is asserted if an + SMBSUSPEND condition is signalled on the SMBSUS_NI input for the channel. + + ## I2C Slave Addressing Functions + A CoreI2C peripheral responds to the following three slave addresses: + - Slave address 0 - This is the primary slave address that accesses + a CoreI2C channel when it acts as a slave in + I2C transactions. You must configure the primary slave + address using I2C_init(). + + - Slave address 1 - This is the secondary slave address which might be + required in certain application specific scenarios. + The secondary slave address is configured by + I2C_set_slave_second_addr() and is disabled by + I2C_disable_slave_second_addr(). + + - General call address - A CoreI2C slave can be configured to respond to + a broadcast command by a master transmitting the + general call address of 0x00. Use the I2C_set_gca() + function to enable the slave to respond to the general + call address. If the CoreI2C slave is not required to + respond to the general call address, disable this + address by calling I2C_clear_gca(). + + Note: All channels on a CoreI2C instance share the same slave address logic. + This means that they cannot have separate slave addresses and rely on + the separate physical I2C bus connections to distinguish them. + + -------------------------------- + Transaction Types + -------------------------------- + The I2C driver is designed to handle three types of I2C transaction: + - Write transactions + - Read transactions + - Write-read transactions + + ## Write Transaction + The master I2C device initiates a write transaction by sending a START bit + as soon as the bus becomes free. The START bit is followed by the 7-bit + serial address of the target slave device followed by the read/write bit + indicating the direction of the transaction. The slave acknowledges the + receipt of it's address with an acknowledge bit. The master sends data one + byte at a time to the slave, which must acknowledge the receipt of each byte + for the next byte to be sent. The master sends a STOP bit to complete the + transaction. The slave can abort the transaction by replying with a + non-acknowledge bit instead of an acknowledge bit. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ## Read Transaction + The master I2C device initiates a read transaction by sending a START bit + as soon as the bus becomes free. The START bit is followed by the 7-bit + serial address of the target slave device followed by the read/write bit + indicating the direction of the transaction. The slave acknowledges the + receipt of it's slave address with an acknowledge bit. The slave sends + data one byte at a time to the master, which must acknowledge the receipt of + each byte for the next byte to be sent. The master sends a non-acknowledge + bit following the last byte it wishes to read followed by a STOP bit. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ## Write-Read Transaction + The write-read transaction is a combination of a write transaction + immediately followed by a read transaction. There is no STOP bit in between + the write and read phases of a write-read transaction. A repeated START + bit is sent between the write and read phases. + + Whilst the write handler is being executed, the slave holds the clock line + low to stretch the clock until the response is ready. + + The write-read transaction is typically used to send a command or offset + in the write transaction specifying the logical data to be transferred + during the read phase. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ## Master Operations + The application can use the I2C_write(), I2C_read(), and I2C_write_read() + functions to initiate an I2C bus transaction. The application can then wait + for the transaction to complete using the I2C_wait_complete() function + or poll the status of the I2C transaction using the I2C_get_status() + function until it returns a value different from I2C_IN_PROGRESS. The + I2C_system_tick() function is used to set a time base for the + I2C_wait_complete() function's time out delay. + + ## Slave Operations + To configure the I2C driver to operate as an I2C slave requires the use + of the following functions: + - I2C_set_slave_tx_buffer() + - I2C_set_slave_rx_buffer() + - I2C_set_slave_mem_offset_length() + - I2C_register_write_handler() + - I2C_enable_slave() + + Use of all functions is not required if the slave I2C does not need to support + all types of I2C read transactions. The subsequent sections list the functions + that must be used to support each transaction type. + + ## Responding to Read Transactions + The following functions are used to configure the CoreI2C driver to + respond to I2C read transactions: + • I2C_set_slave_tx_buffer() + • I2C_enable_slave() + + The I2C_set_slave_tx_buffer() function specifies the data buffer that + is transmitted when the I2C slave is the target of an I2C read + transaction. It is then up to the application to manage the content of + that buffer to control the data that will be transmitted to the I2C + master as a result of the read transaction. + + The I2C_enable_slave() function enables the I2C hardware instance + to respond to the I2C transactions. It must be called after the I2C driver + has been configured to respond to the required transaction types. + + ## Responding to Write Transactions + The following functions are used to configure the I2C driver to respond + to I2C write transactions: + • I2C_set_slave_rx_buffer() + • I2C_register_write_handler() + • I2C_enable_slave() + + The I2C_set_slave_rx_buffer() function specifies the data buffer that + stored the data received by the I2C slave when it targets an I2C write + transaction. + + The I2C_register_write_handler() function specifies the handler function + that must be called on completion of the I2C write transaction. It is this + handler function that processes or triggers the processing of the received + data. + + The I2C_enable_slave() function enables the I2C hardware instance + to respond to I2C transactions. It must be called after the I2C driver + has been configured to respond to the required transaction types. + + ## Responding to Write-Read Transactions + The following functions are used to configure the CoreI2C driver to + respond to write-read transactions: + - I2C_set_slave_mem_offset_length() + - I2C_set_slave_tx_buffer() + - I2C_set_slave_rx_buffer() + - I2C_register_write_handler() + - I2C_enable_slave() + + The I2C_set_slave_mem_offset_length() function specifies the number of + bytes expected by the I2C slave during the write phase of the write-read + transaction. + + The I2C_set_slave_tx_buffer() function specifies the data that is + transmitted to the I2C master during the read phase of the write-read + transaction. The value received by the I2C slave during the write phase of + the transaction will be used as an index into the transmit buffer + specified by this function. It decides which part of the transmit buffer + will be transmitted to the I2C master as part of the read phase of the + write-read transaction. + + The I2C_set_slave_rx_buffer() function specifies the data buffer that + stores the data received by the I2C slave during the write phase of + the write-read transaction. This buffer must be large enough to accommodate + the number of bytes specified through the I2C_set_slave_mem_offset_length() + function. + + The I2C_register_write_handler() function can optionally be used to + specify a handler function that is called on completion of the write phase + of the I2C write-read transaction. If a handler function is registered, it + is responsible for processing the received data in the slave receive + buffer and populating the slave transmit buffer with the data that will be + transmitted to the I2C master as part of the read phase of the write-read + transaction. + + The I2C_enable_slave() function enables the CoreI2C hardware instance to + respond to the I2C transactions. It must be called after configuring the + CoreI2C driver to respond to the required transaction types. + + ## Mixed Master-Slave Operations + The CoreI2C device supports mixed master and slave operations. If the + CoreI2C slave has a transaction in progress and your application attempts to + begin a master mode transaction, the CoreI2C driver queues the master mode + transaction until the bus is released and the CoreI2C can switch to master + mode and acquire the bus. The CoreI2C master then starts the previously + queued master transaction. + + ## SMBus Control + The CoreI2C driver enables the CoreI2C peripheral’s SMBus functionality + using the I2C_smbus_init() function. + + The I2C_suspend_smbus_slave() function is used with a master mode CoreI2C + to force slave devices on the SMBus to enter their Power-Down/Suspend mode. + The I2C_resume_smbus_slave() function is used to end the suspend operation + on the SMBus. + + The I2C_reset_smbus() function is used with a master mode CoreI2C to force + all devices on the SMBus to reset their SMBUs interface. + + The I2C_set_smsbus_alert() function is used by a slave mode CoreI2C to + force communication with the SMBus master. Once communications with the + master is initiated, the I2C_clear_smsbus_alert() function clears the alert + condition. + + The I2C_enable_smbus_irq() and I2C_disable_smbus_irq() functions are used to + enable and disable the SMBSUS and SMBALERT SMBus interrupts. + + *//*=========================================================================*/ + +#ifndef CORE_I2C_H_ +#define CORE_I2C_H_ + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#include "hal_assert.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + I2C_RELEASE_BUS + ======================================= + The I2C_RELEASE_BUS constant is used to specify the options parameter to + functions I2C_read(), I2C_write() and I2C_write_read() to indicate + that a STOP bit must be generated at the end of the I2C transaction to release + the bus. + */ +#define I2C_RELEASE_BUS 0x00u + +/*-------------------------------------------------------------------------*//** + I2C_HOLD_BUS + ======================================= + The I2C_HOLD_BUS constant specify the options parameter to functions I2C_read(), + I2C_write(), and I2C_write_read() to indicate that a STOP bit must not be + generated at the end of the I2C transaction in order to retain the bus ownership. + This causes the next transaction to begin with a repeated START bit and no STOP + bit between the transactions. + */ +#define I2C_HOLD_BUS 0x01u + +/*-------------------------------------------------------------------------*//** + Interrupt Identifier Number + ======================================= + The following constants specify the interrupt identifier number which is + solely used by the driver API. This has nothing to do with hardware interrupt + line. I2C_INTR_IRQ is the primary interrupt signal which drives the state machine + of the CoreI2C driver. The I2C_SMBALERT_IRQ and I2C_SMBSUS_IRQ are used by + SMBus interrupt enable and disable functions. These IRQ numbers are also used + by I2C_get_irq_status(). + + | Constant | Description | + |--------------------|--------------------------------------------------------| + | I2C_NO_IRQ | No interrupt | + | I2C_SMBALERT_IRQ | Used by SMBus interrupt enable functions | + | I2C_SMBSUS_IRQ | Used by SMBus interrupt disable functions | + | I2C_INTR_IRQ | Primary interrupt signal which drives the state machine| + + */ +#define I2C_NO_IRQ 0x00u +#define I2C_SMBALERT_IRQ 0x01u +#define I2C_SMBSUS_IRQ 0x02u +#define I2C_INTR_IRQ 0x04u + +/*-------------------------------------------------------------------------*//** + I2C_NO_TIMEOUT + ======================================= + The I2C_wait_complete() function uses I2C_NO_TIMEOUT constant as a parameter + to indicate that the wait for completion of the transaction should not time out. + */ +#define I2C_NO_TIMEOUT 0u + +/***************************************************************************//** + The i2c_channel_number_t type is used to specify the channel number of a + CoreI2C instance. + */ +typedef enum i2c_channel_number { + I2C_CHANNEL_0 = 0u, + I2C_CHANNEL_1, + I2C_CHANNEL_2, + I2C_CHANNEL_3, + I2C_CHANNEL_4, + I2C_CHANNEL_5, + I2C_CHANNEL_6, + I2C_CHANNEL_7, + I2C_CHANNEL_8, + I2C_CHANNEL_9, + I2C_CHANNEL_10, + I2C_CHANNEL_11, + I2C_CHANNEL_12, + I2C_CHANNEL_13, + I2C_CHANNEL_14, + I2C_CHANNEL_15, + I2C_MAX_CHANNELS = 16u +} i2c_channel_number_t; + +/***************************************************************************//** + The i2c_clock_divider_t type specifies the divider to be applied + to the I2C PCLK or BCLK signal in order to generate the I2C clock. + The I2C_BCLK_DIV_8 value selects a clock frequency based on division of BCLK, + all other values select a clock frequency based on division of PCLK. + */ +typedef enum i2c_clock_divider { + I2C_PCLK_DIV_256 = 0u, + I2C_PCLK_DIV_224, + I2C_PCLK_DIV_192, + I2C_PCLK_DIV_160, + I2C_PCLK_DIV_960, + I2C_PCLK_DIV_120, + I2C_PCLK_DIV_60, + I2C_BCLK_DIV_8 +} i2c_clock_divider_t; + +/***************************************************************************//** + The i2c_status_t type is used to report the status of I2C transactions. + */ +typedef enum i2c_status +{ + I2C_SUCCESS = 0u, + I2C_IN_PROGRESS, + I2C_FAILED, + I2C_TIMED_OUT +} i2c_status_t; + +/***************************************************************************//** + The i2c_slave_handler_ret_t type is used by slave write handler functions + to indicate whether or not the received data buffer should be released. + */ +typedef enum i2c_slave_handler_ret { + I2C_REENABLE_SLAVE_RX = 0u, + I2C_PAUSE_SLAVE_RX = 1u +} i2c_slave_handler_ret_t; + +/***************************************************************************//** + This structure identifies various CoreI2C hardware instances in the system + and the I2C channels within them. The application software should declare + one instance of this structure for each channel of each instance of CoreI2C + in your system. I2C_init() and I2C_channel_init() functions initialize this + structure depending on whether it is channel 0 or one of the additional + channels, respectively. A pointer to an initialized instance of the + structure should be passed as the first parameter to the CoreI2C driver + functions, to identify which CoreI2C hardware instance and channel should + perform the requested operation. + + The contents of this data structure should not be modified or used outside of + the CoreI2C driver. Software using the CoreI2C driver should only need to + create one single instance of this data structure for each channel of each + CoreI2C hardware instance in the system then pass a pointer to these data + structures with each call to the CoreI2C driver in order to identify which + CoreI2C hardware instance to use. + */ +typedef struct i2c_instance i2c_instance_t ; +/***************************************************************************//* + Slave write handler functions prototype +/***************************************************************************//** + This defines the function prototype that must be followed by I2C slave write + handler functions. These functions are registered with the CoreI2C driver + through the I2C_register_write_handler() function. + + Declaring and Implementing Slave Write Handler Functions: + + Slave write handler functions should follow the following prototype: + @code + i2c_slave_handler_ret_t write_handler + ( + i2c_instance_t *instance, uint8_t * data, uint16_t size + ); + @endcode + + The instance parameter is a pointer to the i2c_instance_t for which this + slave write handler has been declared. + + The data parameter is a pointer to a buffer (received data buffer) holding + the data written to the I2C slave. + + Define the INCLUDE_SLA_IN_RX_PAYLOAD macro for the driver to insert the + actual address used to access the slave as the first byte in the buffer. + This allows the applications to tailor their response based on the actual + address used to access the slave (primary address, secondary address, or GCA). + + The size parameter is the number of bytes held in the received data buffer. + Handler functions must return one of the following values: + - I2C_REENABLE_SLAVE_RX + - I2C_PAUSE_SLAVE_RX + + If the handler function returns I2C_REENABLE_SLAVE_RX, the driver releases + the received data buffer and allows further I2C write transactions to the + I2C slave. + + If the handler function returns I2C_PAUSE_SLAVE_RX, the I2C slave responds + to subsequent write requests with a non-acknowledge bit (NACK), until the + received data buffer content gets processed by some other part of the + software application. + + Call the I2C_enable_slave() after returning the I2C_PAUSE_SLAVE_RX to release + the received data buffer in order to store the data received by the subsequent + I2C write transactions. + */ +typedef i2c_slave_handler_ret_t (*i2c_slave_wr_handler_t)(i2c_instance_t *instance, uint8_t *, uint16_t ); + +/***************************************************************************//** + This structure is used to identify the various CoreI2C hardware instances in + your system and the I2C channels within them. Your application software should + declare one instance of this structure for each channel of each instance of + CoreI2C in your system. The functions I2C_init() and I2C_channel_init() + initialize this structure depending on whether it is channel 0 or one of the + additional channels respectively. A pointer to an initialized instance of the + structure should be passed as the first parameter to the CoreI2C driver + functions, to identify which CoreI2C hardware instance and channel should + perform the requested operation. + + The contents of this data structure should not be modified or used outside of + the CoreI2C driver. Software using the CoreI2C driver should only need to + create one single instance of this data structure for each channel of each + CoreI2C hardware instance in the system then pass a pointer to these data + structures with each call to the CoreI2C driver in order to identify the + CoreI2C hardware instance it wishes to use. + */ +struct i2c_instance +{ + addr_t base_address; + uint_fast8_t ser_address; + + /* Transmit related info:*/ + uint_fast8_t target_addr; + + /* Current transaction type (WRITE, READ, RANDOM_READ)*/ + uint8_t transaction; + + uint_fast16_t random_read_addr; + + uint8_t options; + + /* Master TX INFO: */ + const uint8_t * master_tx_buffer; + uint_fast16_t master_tx_size; + uint_fast16_t master_tx_idx; + uint_fast8_t dir; + + /* Master RX INFO: */ + uint8_t * master_rx_buffer; + uint_fast16_t master_rx_size; + uint_fast16_t master_rx_idx; + + /* Master Status */ + volatile i2c_status_t master_status; + uint32_t master_timeout_ms; + + /* Slave TX INFO */ + const uint8_t * slave_tx_buffer; + uint_fast16_t slave_tx_size; + uint_fast16_t slave_tx_idx; + + /* Slave RX INFO */ + uint8_t * slave_rx_buffer; + uint_fast16_t slave_rx_size; + uint_fast16_t slave_rx_idx; + /* Slave Status */ + volatile i2c_status_t slave_status; + + /* Slave data: */ + uint_fast8_t slave_mem_offset_length; + i2c_slave_wr_handler_t slave_write_handler; + uint8_t is_slave_enabled; + + /* user specific data */ + void *p_user_data ; + + /* I2C bus status */ + uint8_t bus_status; + + /* Is transaction pending flag */ + uint8_t is_transaction_pending; + + /* I2C Pending transaction */ + uint8_t pending_transaction; +}; + +/*------------------------Public Function-------------------------------------*/ + +/***************************************************************************//** + The I2C_init() function configures channel 0 of a CoreI2C instance. It sets + the base hardware address which is used to locate the CoreI2C instance + in memory and also used internally by I2C_channel_init() to calculate the + register addresses for any additional channels. The slave serial address set + is shared by all channels on a CoreI2C instance. + + If only one channel is configured in a CoreI2C, the address of the + i2c_instance_t used in I2C_Init() will also be used in subsequent calls to the + CoreI2C driver functions. If more than one channel is configured in the + CoreI2C, I2C_channel_init() will be called after I2C_init(), which initializes + the i2c_instance_t data structure for a specific channel. + + @param this_i2c + Pointer to the i2c_instance_t data structure that holds all the data + related to channel 0 of the CoreI2C instance is initialized. A pointer + to this structure is used in all subsequent calls to the CoreI2C driver + functions which operates on channel 0 of this CoreI2C instance. + + @param base_address + Base address in the processor's memory map of the registers of the CoreI2C + instance being initialized. + + @param ser_address + This parameter sets the primary I2C serial address (SLAVE0 address) for the + CoreI2C to initialize. It is the principal I2C bus address to which the + CoreI2C instance will respond. CoreI2C can operate in master mode or slave + mode and the serial address is significant only in the case of I2C slave + mode. In master mode, CoreI2C does not require a serial address and the + value of this parameter is not important. If you do not intend to use the + CoreI2C device in slave mode, then provide any dummy slave address value + to this parameter. However, in systems where the CoreI2C is expected to + switch from master mode to slave mode, it is advisable to initialize the + CoreI2C device with a valid serial slave address. Call the I2C_init() + function whenever it is required to change the primary slave address as + there is no separate function to set the primary slave address of the + I2C device. The serial address initialized through this function is + basically the primary slave address or slave address0. + I2C_set_slave_second_addr() is used to set the secondary slave address + or slave address 1. + Note : ser_address parameter does not have any affect if fixed slave + address is enabled in CoreI2C hardware design. CoreI2C will + be always addressed with the hardware configured fixed slave + address. + Note : ser_address parameter will not have any affect if the CoreI2C + instance is only used in master mode. + + @param ser_clock_speed + This parameter sets the I2C serial clock frequency. It selects the divider + that generates the serial clock from the APB PCLK or from the BCLK. + It can be one of the following: + - I2C_PCLK_DIV_256 + - I2C_PCLK_DIV_224 + - I2C_PCLK_DIV_192 + - I2C_PCLK_DIV_160 + - I2C_PCLK_DIV_960 + - I2C_PCLK_DIV_120 + - I2C_PCLK_DIV_60 + - I2C_BCLK_DIV_8 + Note: serial_clock_speed value does not have any affect if the fixed baud + rate is enabled in CoreI2C hardware instance configuration dialogue + window. The fixed baud rate divider value overrides the value passed + as parameter in this function. + Note: serial_clock_speed value is not critical for devices that only operate + as slaves and can be set to any of the above values. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void system_init( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + } + @endcode + */ +void I2C_init +( + i2c_instance_t * this_i2c, + addr_t base_address, + uint8_t ser_address, + i2c_clock_divider_t ser_clock_speed +); + +/***************************************************************************//** + The I2C_channel_init() function initializes and configures hardware and data + structures of one of the additional channels of a CoreI2C instance. + I2C_init() must be called before calling this function to set the CoreI2C + instance hardware base address and I2C serial address. I2C_channel_init() also + initializes I2C serial clock divider to set the serial clock baud rate. + The pointer to data structure i2c_instance_t used for a particular channel + is used as an input parameter to subsequent CoreI2C driver functions + which operate on this channel. + + @param this_i2c_channel + Pointer to the i2c_instance_t data structure that holds all data related to + the CoreI2C channel gets initialized. A pointer to the same data structure + is used in subsequent calls to the CoreI2C driver functions in order to + identify the CoreI2C channel instance that should perform the operation + implemented by the called driver function. + + @param this_i2c + This is a pointer to an i2c_instance_t structure, previously initialized by + I2C_init(). It holds information regarding the hardware base address and + I2C serial address for the CoreI2C containing the channel to be + initialized. This information is required by I2C_channel_init() to + initialize the i2c_instance_t structure pointed by this_i2c_channel as + all channels in a CoreI2C instance share the same base address and serial + address. It is very important that the i2c_instance_t structure pointed + by this_i2c must be previously initialized by calling I2C_init(). + + @param channel_number + This parameter of type i2c_channel_number_t identifies the channel to be + initialized. + + @param ser_clock_speed + This parameter sets the I2C serial clock frequency. It selects the divider + that is used to generate the serial clock from the APB PCLK or from + the BCLK. It can be one of the following: + - I2C_PCLK_DIV_256 + - I2C_PCLK_DIV_224 + - I2C_PCLK_DIV_192 + - I2C_PCLK_DIV_160 + - I2C_PCLK_DIV_960 + - I2C_PCLK_DIV_120 + - I2C_PCLK_DIV_60 + - I2C_BCLK_DIV_8 + Note: serial_clock_speed value does not have any affect if the fixed baud + rate is enabled in CoreI2C hardware instance configuration dialogue + window. The fixed baud rate divider value will supersede the value + passed as parameter in this function. + Note: ser_clock_speed value is not critical for devices that only operate + as slaves and can be set to any of the above values. + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_SER_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + i2c_instance_t g_i2c_channel_1_inst; + + uint8_t tx_buffer[DATA_LENGTH]; + uint8_t write_length = DATA_LENGTH; + + void system_init( void ) + { + uint8_t target_slave_addr = 0x12; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize CoreI2C channel 1 with different clock speed + I2C_channel_init( &g_i2c_channel_1_inst, &g_i2c_inst, I2C_CHANNEL_1, + I2C_PCLK_DIV_224 ); + + // Write data to Channel 1 of CoreI2C instance. + I2C_write( &g_i2c_channel_1_inst, target_slave_addr, tx_buffer, + write_length, I2C_RELEASE_BUS ); + } + @endcode + +*/ +void I2C_channel_init +( + i2c_instance_t * this_i2c_channel, + i2c_instance_t * this_i2c, + i2c_channel_number_t channel_number, + i2c_clock_divider_t ser_clock_speed +); + +/***************************************************************************//** + The I2C_isr function is the CoreI2C interrupt service routine. User must + call this function from their application level CoreI2C interrupt handler + function. This function runs the I2C state machine based on previous and + current status. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREINTERRUPT_BASE_ADDR 0xCC000000u + #define COREI2C_SER_ADDR 0x10u + #define I2C_IRQ_NB 2u + + i2c_instance_t g_i2c_inst; + + void core_i2c_isr( void ) + { + I2C_isr( &g_i2c_inst ); + } + + void main( void ) + { + CIC_init( COREINTERRUPT_BASE_ADDR ); + NVIC_init(); + CIC_set_irq_handler( I2C_IRQ_NB, core_i2c_isr ); + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + NVIC_enable_interrupt( NVIC_IRQ_0 ); + } + @endcode + */ +void I2C_isr +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//* + #Master Specific Functions + + The following functions are only used within an I2C master's implementation. +/***************************************************************************//** + This function initiates an I2C master write transaction. This function returns + immediately after initiating the transaction. The content of the write buffer + passed as parameter should not be modified until the write transaction + completes. It also means that the memory allocated for the write buffer should + not be freed or should not go out of scope before the write completes. You can + check for the write transaction completion using the I2C_status() function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr + This parameter specifies the serial address of the target I2C device. + + @param write_buffer + This parameter is a pointer to a buffer holding the data to be written to + the target I2C device. Do not to release the memory used by this buffer + before the write transaction completes. For example, it is not appropriate + to return from a function allocating this buffer as an auto array variable + before the write transaction completes as this would result in the buffer's + memory being de-allocated from the stack when the function returns. This + memory could then be subsequently reused and modified causing unexpected + data to be written to the target I2C device. + + @param write_size + Number of bytes held in the write_buffer to be written to the target I2C + device. + + @param options + The options parameter is used to indicate if the I2C bus should be released + on completion of the write transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the write transaction causing the bus to be released for other I2C + devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the write + transaction, preventing other I2C devices from initiating a bus transaction. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t tx_buffer[DATA_LENGTH]; + uint8_t write_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Write data to Channel 0 of CoreI2C instance. + I2C_write( &g_i2c_inst, target_slave_addr, tx_buffer, write_length, + I2C_RELEASE_BUS ); + + // Wait for completion and record the outcome + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_write +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * write_buffer, + uint16_t write_size, + uint8_t options +); + +/***************************************************************************//** + This function initiates an I2C master read transaction. This function returns + immediately after initiating the transaction. + The contents of the read buffer passed as parameter should not be modified + until the read transaction completes. It also means that the memory allocated + for the read buffer should not be freed or should not go out of scope before + the read completes. You can check for the read transaction completion using + the I2C_status() function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr + This parameter specifies the serial address of the target I2C device. + + @param read_buffer + This is a pointer to a buffer where the data received from the target device + gets stored. Do not to release the memory used by this buffer before the read + transaction completes. For example, it is not appropriate to return from a + function allocating this buffer as an auto array variable before the read + transaction completes as this would result in the buffer's memory being + de-allocated from the stack when the function returns. This memory could + then be subsequently reallocated resulting in the read transaction + corrupting the newly allocated memory. + + @param read_size + This parameter specifies the number of bytes to read from the target device. + This size must not exceed the size of the read_buffer buffer. + + @param options + The options parameter is used to indicate if the I2C bus should be released + on completion of the read transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the read transaction causing the bus to be released for other I2C + devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the read transaction, + preventing other I2C devices from initiating a bus transaction. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t rx_buffer[DATA_LENGTH]; + uint8_t read_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Read data from target slave Channel 0 of CoreI2C instance. + I2C_read( &g_i2c_inst, target_slave_addr, rx_buffer, read_length, + I2C_RELEASE_BUS ); + + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +); + +/***************************************************************************//** + This function initiates an I2C write-read transaction where data is first + written to the target device before issuing a restart condition and changing + the direction of the I2C transaction in order to read from the target device. + + The same warnings about buffer allocation in I2C_write() and I2C_read() + applies to this function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr + This parameter specifies the serial address of the target I2C device. + + @param addr_offset + This parameter is a pointer to the buffer containing the data that is sent + to the slave during the write phase of the write-read transaction. This + data is typically used to specify an address offset specifying to the I2C + slave device what data it must return during the read phase of the + write-read transaction. + + @param offset_size + This parameter specifies the number of offset bytes to be written during the + write phase of the write-read transaction. This is typically the size of the + buffer pointed by the addr_offset parameter. + + @param read_buffer + This parameter is a pointer to the buffer where the data read from the I2C + slave will be stored. + + @param read_size + This parameter specifies the number of bytes to read from the target I2C + slave device. This size must not exceed the size of the buffer pointed by + the read_buffer parameter. + + @param options + The options parameter is used to indicate if the I2C bus should be released + on completion of the write-read transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the write-read transaction causing the bus to be released for other + I2C devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the write-read + transaction, preventing other I2C devices from initiating a bus transaction. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define TX_LENGTH 16u + #define RX_LENGTH 8u + + i2c_instance_t g_i2c_inst; + uint8_t rx_buffer[RX_LENGTH]; + uint8_t read_length = RX_LENGTH; + uint8_t tx_buffer[TX_LENGTH]; + uint8_t write_length = TX_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + I2C_write_read( &g_i2c_inst, target_slave_addr, tx_buffer, write_length, + rx_buffer, read_length, I2C_RELEASE_BUS ); + + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_write_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * addr_offset, + uint16_t offset_size, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +); + +/***************************************************************************//** + This function indicates the current state of a CoreI2C channel. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + The return value indicates the current state of a CoreI2C channel or the + outcome of the previous transaction if no transaction is in progress. + Following are the return values are: + - I2C_SUCCESS + The last I2C transaction has completed successfully. + - I2C_IN_PROGRESS + There is an I2C transaction in progress. + - I2C_FAILED + The last I2C transaction failed. + - I2C_TIMED_OUT + The request has failed to complete in the allotted time. + + @example + @code + i2c_instance_t g_i2c_inst; + + while( I2C_IN_PROGRESS == I2C_get_status( &g_i2c_inst ) ) + { + // Do something useful while waiting for I2C operation to complete + our_i2c_busy_task(); + } + + if( I2C_SUCCESS != I2C_get_status( &g_i2c_inst ) ) + { + // Something went wrong... + our_i2c_error_recovery( &g_i2c_inst ); + } + @endcode + */ +i2c_status_t I2C_get_status +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + This function waits for the current I2C transaction to complete. The return + value indicates whether the last I2C transaction was successful or not. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + @param timeout_ms + The timeout_ms parameter specifies the delay within which the current I2C + transaction should complete. The time out delay is given in + milliseconds. I2C_wait_complete() will return I2C_TIMED_OUT if the current + transaction has not completed after the time out delay has expired. This + parameter can be set to I2C_NO_TIMEOUT to indicate that I2C_wait_complete() + must not time out. + + @return + The return value indicates the outcome of the last I2C transaction. It can + be one of the following: + - I2C_SUCCESS + The last I2C transaction has completed successfully. + - I2C_FAILED + The last I2C transaction failed. + - I2C_TIMED_OUT + The last transaction failed to complete within the time out delay given + as second parameter. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t rx_buffer[DATA_LENGTH]; + uint8_t read_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Read data from Channel 0 of CoreI2C instance. + I2C_read( &g_i2c_inst, target_slave_addr, rx_buffer, read_length, + I2C_RELEASE_BUS ); + + // Wait for completion and record the outcome + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +i2c_status_t I2C_wait_complete +( + i2c_instance_t * this_i2c, + uint32_t timeout_ms +); + +/***************************************************************************//** + This function is used to control the expiration of the time out delay + specified as a parameter to the I2C_wait_complete() function. It must be + called from the interrupt service routine of a periodic interrupt source such + as the SysTick timer interrupt. It takes the period of the interrupt + source as its ms_since_last_tick parameter and uses it as the time base for + the I2C_wait_complete() function's time out delay. + + Note: This function does not need to be called if the I2C_wait_complete() + function is called with a timeout_ms value of I2C_NO_TIMEOUT. + + Note: If this function is not called then the I2C_wait_complete() function + will behave as if its timeout_ms was specified as I2C_NO_TIMEOUT and it + will not time out. + + Note: If this function is being called from an interrupt handler (for example, + SysTick) it is important that the calling interrupt have a lower priority + than the CoreI2C interrupt(s) to ensure any updates to the shared data are + protected. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + @param ms_since_last_tick + The ms_since_last_tick parameter specifies the number of milliseconds that + elapsed since the last call to I2C_system_tick(). This parameter would + typically be a constant specifying the interrupt rate of a timer used to + generate system ticks. + + @return None. + + @example + The following example shows how the I2C_system_tick() function. I2C_system_tick() + is called for each I2C channel from the SysTick timer interrupt service routine. + The following example shows how the SysTick is configured to generate an interrupt + in every 10 milliseconds. + @code + #define SYSTICK_INTERVAL_MS 10 + + void SysTick_Handler(void) + { + I2C_system_tick(&g_core_i2c0, SYSTICK_INTERVAL_MS); + I2C_system_tick(&g_core_i2c2, SYSTICK_INTERVAL_MS); + } + @endcode + */ +void I2C_system_tick +( + i2c_instance_t * this_i2c, + uint32_t ms_since_last_tick +); + +/***************************************************************************//* + #Slave Specific Functions + + The following functions are only used within the implementation of an I2C slave device. + +/***************************************************************************//** + This function specifies the memory buffer holding the data that will be sent + to the I2C master when this CoreI2C channel is the target of an I2C read or + write-read transaction. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param tx_buffer + This parameter is a pointer to the memory buffer holding the data to be + returned to the I2C master when this CoreI2C channel is the target of an + I2C read or write-read transaction. + + @param tx_size + Size of the transmit buffer pointed by the tx_buffer parameter. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Specify the transmit buffer containing the data that will be + // returned to the master during read and write-read transactions. + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + } + @endcode + */ +void I2C_set_slave_tx_buffer +( + i2c_instance_t * this_i2c, + const uint8_t * tx_buffer, + uint16_t tx_size +); + +/***************************************************************************//** + This function specifies the memory buffer that is used by the CoreI2C channel + to receive data when it is a slave. This buffer is the memory where data gets + stored when the CoreI2C channel is the target of an I2C master write + transaction (that is, when it is the slave). + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param rx_buffer + This parameter is a pointer to the memory buffer allocated by the caller + software to be used as a slave receive buffer. + + @param rx_size + Size of the slave receive buffer. This is the amount of memory allocated + to the buffer pointed by rx_buffer. + Note: Indirectly, this buffer size specifies the maximum I2C write + transaction length this CoreI2C channel targets. This is because + this CoreI2C channel responds to further received bytes with + a non-acknowledge bit (NACK) as soon as its receive buffer is + full. This causes the write transaction to fail. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_RX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_rx_buffer[SLAVE_RX_BUFFER_SIZE]; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Specify the buffer used to store the data written by the I2C master. + I2C_set_slave_rx_buffer( &g_i2c_inst, g_slave_rx_buffer, + sizeof(g_slave_rx_buffer) ); + } + @endcode + */ +void I2C_set_slave_rx_buffer +( + i2c_instance_t * this_i2c, + uint8_t * rx_buffer, + uint16_t rx_size +); + +/***************************************************************************//** + This function is used as part of the configuration of a CoreI2C channel to + operate as a slave supporting write-read transactions. It specifies the + number of bytes expected as part of the write phase of a write-read + transaction. The bytes received during the write phase of a write-read + transaction will be interpreted as an offset into the slave's transmit buffer. + This allows random access into the I2C slave transmit buffer from a remote + I2C master. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param offset_length + The offset_length parameter configures the number of bytes to be interpreted + by the CoreI2C slave as a memory offset value during the write phase of + write-read transactions. The maximum value for the offset_length parameter + is two. The value of offset_length has the following effect on the + interpretation of the received data. + • If offset_length is 0, the offset into the transmit buffer is fixed at 0. + • If offset_length is 1, a single byte of received data is interpreted as an + unsigned 8-bit offset value in the range 0 to 255. + • If offset_length is 2, 2 bytes of received data are interpreted as an + unsigned 16-bit offset value in the range 0 to 65535. The first byte + received in this case provides the high order bits of the offset and + the second byte provides the low order bits. + If the number of bytes received does not match the non 0 value of + offset_length, the transmit buffer offset is set to 0. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + I2C_set_slave_mem_offset_length( &g_i2c_inst, 1 ); + } + @endcode + */ +void I2C_set_slave_mem_offset_length +( + i2c_instance_t * this_i2c, + uint8_t offset_length +); + +/***************************************************************************//** + Register the function that is called to process the data written to this + CoreI2C channel when it is the slave in an I2C write transaction. + + Note: If a write handler is registered, it is called on completion of the + write phase of a write-read transaction and responsible for processing + the received data in the slave receive buffer and populating the slave + transmit buffer with the data that is transmitted to the I2C master + as part of the read phase of the write-read transaction. If a write + handler is not registered, the write data of a write-read transaction is + interpreted as an offset into the slave’s transmit buffer and handled by + the driver. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param handler + Pointer to the function that processes the I2C write request. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + // local function prototype + void slave_write_handler + ( + i2c_instance_t * this_i2c, + uint8_t * p_rx_data, + uint16_t rx_size + ); + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + I2C_set_slave_mem_offset_length( &g_i2c_inst, 1 ); + I2C_register_write_handler( &g_i2c_inst, slave_write_handler ); + } + @endcode +*/ +void I2C_register_write_handler +( + i2c_instance_t * this_i2c, + i2c_slave_wr_handler_t handler +); + +/***************************************************************************//** + This function enables slave mode operation for a CoreI2C channel. It enables + the CoreI2C slave to receive data when it is the target of an I2C read, write, + or write-read transaction. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + // Enable I2C slave + I2C_enable_slave( &g_i2c_inst ); + @endcode + */ +void I2C_enable_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + This function disables the slave mode operation for a CoreI2C channel. It stops + the CoreI2C slave that acknowledges the I2C read, write, or write-read + transactions targeted at it. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + // Disable I2C slave + I2C_disable_slave( &g_i2c_inst ); + @endcode + */ +void I2C_disable_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_slave_second_addr() function sets the secondary slave address for + a CoreI2C slave device. This is an additional slave address required in certain + applications, for example, to enable fail-safe operation in a system. As the + CoreI2C device supports 7-bit addressing, the highest value assigned to second + slave address is 127 (0x7F). + + Note: This function does not support CoreI2C hardware configured with a fixed + second slave address. The current implementation of the ADDR1[0] register + bit makes it difficult for the driver to support both programmable and + fixed second slave address, so we choose to support programmable only. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param second_slave_addr + The second_slave_addr parameter is the secondary slave address of the I2C + device. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SECOND_SLAVE_ADDR 0x20u + + i2c_instance_t g_i2c_inst; + void main( void ) + { + // Initialize the CoreI2C driver with its base address, primary I2C + // serial address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_second_addr( &g_i2c_inst, SECOND_SLAVE_ADDR ); + } + @endcode + */ +void I2C_set_slave_second_addr +( + i2c_instance_t * this_i2c, + uint8_t second_slave_addr +); + +/***************************************************************************//** + The I2C_disable_slave_second_addr() function disables the secondary slave + address of the CoreI2C slave device. + + Note: This version of the driver only supports CoreI2C hardware configured + with a programmable second slave address. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + i2c_instance_t g_i2c_inst; + I2C_disable_slave_second_addr( &g_i2c_inst); + @endcode + */ +void I2C_disable_slave_second_addr +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_gca() function is used to set the general call acknowledgement bit + of a CoreI2C slave device. This allows all channels of the CoreI2C slave + device to respond to a general call or broadcast message from an I2C master. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + i2c_instance_t g_i2c_inst; + + // Enable recognition of the General Call Address + I2C_set_gca( &g_i2c_inst ); + @endcode + */ +void I2C_set_gca +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_clear_gca() function is used to clear the general call acknowledgement + bit of a CoreI2C slave device. This will stop all channels of the I2C slave + device responding to any general call or broadcast message from the master. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + i2c_instance_t g_i2c_inst; + + // Disable recognition of the General Call Address + I2C_clear_gca( &g_i2c_inst ); + @endcode + */ + +void I2C_clear_gca +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//* + #I2C SMBUS Specific APIs + +/***************************************************************************//** + The I2C_smbus_init() function enables SMBus timeouts and status logic for a + CoreI2C channel. + + Note: This and any of the other SMBus related functionality will only have an + effect if the CoreI2C was instantiated with the Generate SMBus Logic + option checked. + + Note: If the CoreI2C was instantiated with the Generate IPMI Logic option + checked this function then enables the IPMI 3mS SCL low timeout but + none of the other SMBus functions will have any effect. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void system_init( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst); + } + @endcode + */ +void I2C_smbus_init +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_enable_smbus_irq() function is used to enable the CoreI2C channel’s + SMBSUS and SMBALERT SMBus interrupts. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param irq_type + The irq_type specify the SMBUS interrupt(s) which will be enabled. + The two possible interrupts are: + - I2C_SMBALERT_IRQ + - I2C_SMBSUS_IRQ + To enable both interrupts in one call, use I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ. + + @return + None + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both I2C_SMBALERT_IRQ & I2C_SMBSUS_IRQ interrupts + I2C_enable_smbus_irq( &g_i2c_inst, + (uint8_t)(I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ) ); + } + @endcode + */ +void I2C_enable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +); + +/***************************************************************************//** + The I2C_disable_smbus_irq() function disable the CoreI2C channel’s SMBSUS and + SMBALERT SMBus interrupts. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param irq_type + The irq_type specifies the SMBUS interrupt(s) which are disabled. + The two possible interrupts are: + • I2C_SMBALERT_IRQ + • I2C_SMBSUS_IRQ + To disable both ints in one call, use I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both SMBALERT & SMBSUS interrupts + I2C_enable_smbus_irq( &g_i2c_inst, + (uint8_t)(I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ)); + + ... + + // Disable the SMBALERT interrupt + I2C_disable_smbus_irq( &g_i2c_inst, I2C_SMBALERT_IRQ ); + } + @endcode + */ +void I2C_disable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +); + +/***************************************************************************//** + The I2C_suspend_smbus_slave() function forces any SMBUS slave devices + connected to a CoreI2C channel into Power-Down or Suspend mode by asserting + the channel's SMBSUS signal. The CoreI2C channel is the SMBus master in this + case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // suspend SMBus slaves + I2C_suspend_smbus_slave( &g_i2c_inst ); + + ... + + // Re-enable SMBus slaves + I2C_resume_smbus_slave( &g_i2c_inst ); + } + @endcode + */ +void I2C_suspend_smbus_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_resume_smbus_slave() function de-asserts the CoreI2C channel's SMBSUS + signal to take any connected slave devices out of the Suspend mode. The CoreI2C + channel is the SMBus master in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // suspend SMBus slaves + I2C_suspend_smbus_slave( &g_i2c_inst ); + + ... + + // Re-enable SMBus slaves + I2C_resume_smbus_slave( &g_i2c_inst ); + } + @endcode + */ +void I2C_resume_smbus_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_reset_smbus() function resets the CoreI2C channel's SMBus connection + by forcing SCLK low for 35 mS. The reset that automatically cleares after 35 ms + gets elapsed. The CoreI2C channel is the SMBus master in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Make sure the SMBus channel is in a known state by resetting it + I2C_reset_smbus( &g_i2c_inst ); + } + @endcode + */ +void I2C_reset_smbus +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_smbus_alert() function is used to force master communication with + an I2C slave device by asserting the CoreI2C channel's SMBALERT signal. The + CoreI2C channel is the SMBus slave in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Get the SMBus masters attention + I2C_set_smbus_alert( &g_i2c_inst ); + + ... + + // Once we are happy, drop the alert + I2C_clear_smbus_alert( &g_i2c_inst ); + } + @endcode + */ +void I2C_set_smbus_alert +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_clear_smbus_alert() function is used to de-assert the CoreI2C channel's + SMBALERT signal once a slave device gets a response from the master. The + CoreI2C channel is the SMBus slave in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Get the SMBus masters attention + I2C_set_smbus_alert( &g_i2c_inst ); + + ... + + // Once we are happy, drop the alert + I2C_clear_smbus_alert( &g_i2c_inst ); + } + @endcode + */ +void I2C_clear_smbus_alert +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_get_irq_status function returns information about which interrupts are + currently pending in a CoreI2C channel. + The interrupts supported by CoreI2C are: + • SMBUSALERT + • SMBSUS + • INTR + + The macros I2C_NO_IRQ, I2C_SMBALERT_IRQ, I2C_SMBSUS_IRQ, and I2C_INTR_IRQ are + provided to use with this function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + This function returns the status of the CoreI2C channel's interrupts as a + single byte bitmap where a bit is set to indicate a pending interrupt. + The following are the bit positions associated with each interrupt type: + Bit 0 - SMBUS_ALERT_IRQ + Bit 1 - SMBSUS_IRQ + Bit 2 - INTR_IRQ + It returns 0, if there are no pending interrupts. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + uint8_t irq_to_enable = I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ; + uint8_t pending_irq = 0u; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both I2C_SMBALERT_IRQ & I2C_SMBSUS_IRQ irq + I2C_enable_smbus_irq( &g_i2c_inst, irq_to_enable ); + + // Get I2C IRQ type + pending_irq = I2C_get_irq_status( &g_i2c_inst ); + + // Let's assume, in system, INTR and SMBALERT IRQ is pending. + // So pending_irq will return status of both the IRQs + + if( pending_irq & I2C_SMBALERT_IRQ ) + { + // if true, it means SMBALERT_IRQ is there in pending IRQ list + } + if( pending_irq & I2C_INTR_IRQ ) + { + // if true, it means I2C_INTR_IRQ is there in pending IRQ list + } + } + @endcode + */ +uint8_t I2C_get_irq_status +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_user_data() function allows the association of a block of application + specific data with a CoreI2C channel. The composition of the data block is an + application matter and the driver simply provides the means for the application + to set and retrieve the pointer. For example, this is used to provide additional + channel specific information to the slave write handler. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param p_user_data + The p_user_data parameter is a pointer to the user specific data block for + this channel. It is defined as void * as the driver does not know the actual + type of data being pointed to and simply stores the pointer for later + retrieval by the application. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + app_data_t channel_xdata; + + void main( void ) + { + app_data_t *p_xdata; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Store location of user data in instance structure + I2C_set_user_data( &g_i2c_inst, (void *)&channel_xdata ); + + ... + + // Retrieve location of user data and do some work on it + p_xdata = (app_data_t *)I2C_get_user_data( &g_i2c_inst ); + if( NULL != p_xdata ) + { + p_xdata->foo = 123; + } + } + @endcode + */ +void I2C_set_user_data +( + i2c_instance_t * this_i2c, + void * p_user_data +); + +/***************************************************************************//** + The I2C_get_user_data() function is used to allows the retrieval of the address + of a block of application specific data associated with a CoreI2C channel. + The composition of the data block is an application matter and the driver + simply provides the means for the application to set and retrieve the pointer. + For example, this is used to provide additional channel specific information + to the slave write handler. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + This function returns a pointer to the user specific data block for this + channel. It is defined as void * as the driver does not know the actual type + of data being pointed. If no user data has been registered for this channel + a NULL pointer is returned. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + app_data_t channel_xdata; + + void main( void ) + { + app_data_t *p_xdata; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Store location of user data in instance structure + I2C_set_user_data( &g_i2c_inst, (void *)&channel_xdata ); + + ... + + // Retrieve location of user data and do some work on it + p_xdata = (app_data_t *)I2C_get_user_data( &g_i2c_inst ); + if( NULL != p_xdata ) + { + p_xdata->foo = 123; + } + } + @endcode + */ +void * I2C_get_user_data +( + i2c_instance_t * this_i2c +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h new file mode 100644 index 0000000..b1d872d --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h @@ -0,0 +1,190 @@ +/******************************************************************************* + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + */ + +#ifndef __CORE_SMBUS_REGISTERS +#define __CORE_SMBUS_REGISTERS 1 + +/*------------------------------------------------------------------------------ + * CONTROL register details + */ +#define CONTROL_REG_OFFSET 0x00u + +/* + * CR0 bits. + */ +#define CR0_OFFSET 0x00u +#define CR0_MASK 0x01u +#define CR0_SHIFT 0u + +/* + * CR1 bits. + */ +#define CR1_OFFSET 0x00u +#define CR1_MASK 0x02u +#define CR1_SHIFT 1u + +/* + * AA bits. + */ +#define AA_OFFSET 0x00u +#define AA_MASK 0x04u +#define AA_SHIFT 2u + +/* + * SI bits. + */ +#define SI_OFFSET 0x00u +#define SI_MASK 0x08u +#define SI_SHIFT 3u + +/* + * STO bits. + */ +#define STO_OFFSET 0x00u +#define STO_MASK 0x10u +#define STO_SHIFT 4u + +/* + * STA bits. + */ +#define STA_OFFSET 0x00u +#define STA_MASK 0x20u +#define STA_SHIFT 5u + +/* + * ENS1 bits. + */ +#define ENS1_OFFSET 0x00u +#define ENS1_MASK 0x40u +#define ENS1_SHIFT 6u + +/* + * CR2 bits. + */ +#define CR2_OFFSET 0x00u +#define CR2_MASK 0x80u +#define CR2_SHIFT 7u + +/*------------------------------------------------------------------------------ + * STATUS register details + */ +#define STATUS_REG_OFFSET 0x04u + +/*------------------------------------------------------------------------------ + * DATA register details + */ +#define DATA_REG_OFFSET 0x08u + +/* + * TARGET_ADDR bits. + */ +#define TARGET_ADDR_OFFSET 0x08u +#define TARGET_ADDR_MASK 0xFEu +#define TARGET_ADDR_SHIFT 1u + +/* + * DIR bit. + */ +#define DIR_OFFSET 0x08u +#define DIR_MASK 0x01u +#define DIR_SHIFT 0u + + +/*------------------------------------------------------------------------------ + * ADDRESS register details + */ +#define ADDRESS_REG_OFFSET 0x0Cu + +/* + * GC bits. + */ +#define GC_OFFSET 0x0Cu +#define GC_MASK 0x01u +#define GC_SHIFT 0u + +/* + * ADR bits. + */ +#define OWN_SLAVE_ADDR_OFFSET 0x0Cu +#define OWN_SLAVE_ADDR_MASK 0xFEu +#define OWN_SLAVE_ADDR_SHIFT 1u + +/*------------------------------------------------------------------------------ + * SMBUS register details + */ +#define SMBUS_REG_OFFSET 0x10u + +/* + * SMBALERT_IE bits. + */ +#define SMBALERT_IE_OFFSET 0x10u +#define SMBALERT_IE_MASK 0x01u +#define SMBALERT_IE_SHIFT 0u + +/* + * SMBSUS_IE bits. + */ +#define SMBSUS_IE_OFFSET 0x10u +#define SMBSUS_IE_MASK 0x02u +#define SMBSUS_IE_SHIFT 1u + +/* + * SMB_IPMI_EN bits. + */ +#define SMB_IPMI_EN_OFFSET 0x10u +#define SMB_IPMI_EN_MASK 0x04u +#define SMB_IPMI_EN_SHIFT 2u + +/* + * SMBALERT_NI_STATUS bits. + */ +#define SMBALERT_NI_STATUS_OFFSET 0x10u +#define SMBALERT_NI_STATUS_MASK 0x08u +#define SMBALERT_NI_STATUS_SHIFT 3u + +/* + * SMBALERT_NO_CONTROL bits. + */ +#define SMBALERT_NO_CONTROL_OFFSET 0x10u +#define SMBALERT_NO_CONTROL_MASK 0x10u +#define SMBALERT_NO_CONTROL_SHIFT 4u + +/* + * SMBSUS_NI_STATUS bits. + */ +#define SMBSUS_NI_STATUS_OFFSET 0x10u +#define SMBSUS_NI_STATUS_MASK 0x20u +#define SMBSUS_NI_STATUS_SHIFT 5u + +/* + * SMBSUS_NO_CONTROL bits. + */ +#define SMBSUS_NO_CONTROL_OFFSET 0x10u +#define SMBSUS_NO_CONTROL_MASK 0x40u +#define SMBSUS_NO_CONTROL_SHIFT 6u + +/* + * SMBUS_MST_RESET bits. + */ +#define SMBUS_MST_RESET_OFFSET 0x10u +#define SMBUS_MST_RESET_MASK 0x80u +#define SMBUS_MST_RESET_SHIFT 7u + +/*------------------------------------------------------------------------------ + * SLAVE ADDRESS 1 register details + */ + +#define ADDRESS1_REG_OFFSET 0x1Cu + +/* + * SLAVE1_EN bit of Slave Address 1 . + */ +#define SLAVE1_EN_OFFSET 0x1Cu +#define SLAVE1_EN_MASK 0x01u +#define SLAVE1_EN_SHIFT 0u + +#endif /* __CORE_SMBUS_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c new file mode 100644 index 0000000..12e352d --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * CoreI2C driver interrupt control. + * + */ +#include "core_i2c.h" + +/*------------------------------------------------------------------------------ + * This function must be modified to enable interrupts generated from the + * CoreI2C instance identified as parameter. + */ +void I2C_enable_irq( i2c_instance_t * this_i2c ) +{ + HAL_ASSERT(0) +} + +/*------------------------------------------------------------------------------ + * This function must be modified to disable interrupts generated from the + * CoreI2C instance identified as parameter. + */ +void I2C_disable_irq( i2c_instance_t * this_i2c ) +{ + HAL_ASSERT(0) +} diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.c b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.c new file mode 100644 index 0000000..2e11750 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.c @@ -0,0 +1,1345 @@ +/***************************************************************************//** + * Copyright 2013-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * CoreSPI bare metal driver implementation for CoreSPI. + * + * This Core SPI driver provides functions for implementing SPI master or + * SPI slave operations with the CoreSPI version 4.2.xxx It is not compatible + * with CoreSPI version 3.0.xxx. + * + * @file core_spi.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreSPI software configuration + * + */ + +#include "core_spi.h" +#include "corespi_regs.h" +#include + +/******************************************************************************* + * Null parameters with appropriate type definitions + */ +#define NULL_ADDR ( ( addr_t ) 0u ) +#define NULL_INSTANCE ( ( spi_instance_t * ) 0u ) +#define NULL_BUFF ( ( uint8_t * ) 0u ) +#define NULL_FRAME_HANDLER ( ( spi_frame_rx_handler_t ) 0u ) +#define NULL_BLOCK_HANDLER ( ( spi_block_rx_handler_t ) 0u ) +#define NULL_SLAVE_TX_UPDATE_HANDLER ( ( spi_slave_frame_tx_handler_t ) 0u ) +#define NULL_SLAVE_CMD_HANDLER NULL_BLOCK_HANDLER + +#define SPI_ALL_INTS (0xFFu) /* For clearing all active interrupts */ + +/******************************************************************************* + * Possible states for different register bit fields + */ + +#define DISABLE 0u +#define ENABLE 1u + + +/******************************************************************************* + * Function return values + */ +enum { + FAILURE = 0u, + SUCCESS = 1u +}; + +/******************************************************************************* + * Local function declarations + */ +static void fill_slave_tx_fifo( spi_instance_t * this_spi ); +static void read_slave_rx_fifo( spi_instance_t * this_spi ); +static void recover_from_rx_overflow( const spi_instance_t * this_spi ); + +/******************************************************************************* + * SPI_init() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_init +( + spi_instance_t * this_spi, + addr_t base_addr, + uint16_t fifo_depth +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( NULL_ADDR != base_addr ); + HAL_ASSERT( SPI_MAX_FIFO_DEPTH >= fifo_depth ); + HAL_ASSERT( SPI_MIN_FIFO_DEPTH <= fifo_depth ); + + if( ( NULL_INSTANCE != this_spi ) && ( base_addr != NULL_ADDR ) ) + { + /* + * Initialize all transmit / receive buffers and handlers + * + * Relies on the fact that byte filling with 0x00 will equate + * to 0 for any non byte sized items too. + */ + + /* First fill struct with 0s */ + memset( this_spi, 0, sizeof(spi_instance_t) ); + + /* Configure CoreSPI instance attributes */ + this_spi->base_addr = (addr_t)base_addr; + + /* Store FIFO depth or fall back to minimum if out of range */ + if( ( SPI_MAX_FIFO_DEPTH >= fifo_depth ) && ( SPI_MIN_FIFO_DEPTH <= fifo_depth ) ) + { + this_spi->fifo_depth = fifo_depth; + } + else + { + this_spi->fifo_depth = SPI_MIN_FIFO_DEPTH; + } + /* Make sure the CoreSPI is disabled while we configure it */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Ensure all slaves are deselected */ + HAL_set_8bit_reg( this_spi->base_addr, SSEL, 0u ); + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Ensure RXAVAIL, TXRFM, SSEND and CMDINT are disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, 0u ); + /* + * Enable the CoreSPI in the reset default of master mode + * with TXUNDERRUN, RXOVFLOW and TXDONE interrupts disabled. + * The driver does not currently use interrupts in master mode. + */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL1, ENABLE | CTRL1_MASTER_MASK ); + } +} + +/***************************************************************************//** + * SPI_configure_slave_mode() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_configure_slave_mode +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Don't yet know what slave transfer mode will be used */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_NONE; + + /* Make sure the CoreSPI is disabled while we configure it */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Ensure RXAVAIL, TXRFM, SSEND and CMDINT are disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, 0u ); + /* + * Enable the CoreSPI in slave mode with TXUNDERRUN, RXOVFLOW and TXDONE + * interrupts disabled. The appropriate interrupts will be enabled later + * on when the transfer mode is configured. + */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL1, ENABLE ); + } +} + +/***************************************************************************//** + * SPI_configure_master_mode() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_configure_master_mode +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Disable the CoreSPI for a little while, while we configure the CoreSPI */ + HAL_set_8bit_reg_field(this_spi->base_addr, CTRL1_ENABLE, DISABLE); + + /* Reset slave transfer mode to unknown in case it has been set previously */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_NONE; + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Ensure RXAVAIL, TXRFM, SSEND and CMDINT are disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, 0u ); + + /* Enable the CoreSPI in master mode with TXUNDERRUN, RXOVFLOW and TXDONE interrupts disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL1, ENABLE | CTRL1_MASTER_MASK ); + } +} + +/***************************************************************************//** + * SPI_set_slave_select() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +) +{ + spi_slave_t temp = (spi_slave_t)(0x00u) ; + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( SPI_MAX_NB_OF_SLAVES > slave ); + + if( ( NULL_INSTANCE != this_spi ) && ( SPI_MAX_NB_OF_SLAVES > slave ) ) + { + /* This function is only intended to be used with an SPI master */ + if( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW ) ) + { + recover_from_rx_overflow( this_spi ); + } + /* Set the correct slave select bit */ + temp = (spi_slave_t)( HAL_get_8bit_reg( this_spi->base_addr, SSEL ) | ((uint32_t)1u << (uint32_t)slave) ); + HAL_set_8bit_reg( this_spi->base_addr, SSEL, (uint_fast8_t)temp ); + } + } +} + +/***************************************************************************//** + * SPI_clear_slave_select() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_clear_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +) +{ + spi_slave_t temp = (spi_slave_t) (0x00u) ; + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( SPI_MAX_NB_OF_SLAVES > slave ); + + if( ( NULL_INSTANCE != this_spi ) && ( SPI_MAX_NB_OF_SLAVES > slave ) ) + { + /* This function is only intended to be used with an SPI master. */ + if( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW) ) + { + recover_from_rx_overflow( this_spi ); + } + /* Clear the correct slave select bit */ + temp = (spi_slave_t)( HAL_get_8bit_reg( this_spi->base_addr, SSEL ) & ~((uint32_t)1u << (uint32_t)slave) ); + HAL_set_8bit_reg( this_spi->base_addr, SSEL, (uint_fast8_t)temp ) ; + } + } +} + +/***************************************************************************//** + * SPI_transfer_frame() + * See "core_spi.h" for details of how to use this function. + */ +uint32_t SPI_transfer_frame +( + spi_instance_t * this_spi, + uint32_t tx_bits +) +{ + volatile uint32_t rx_data = 0u; /* Ensure consistent return value if in slave mode */ + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI master. */ + if( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Flush the receive and transmit FIFOs by resetting both */ + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK); + + /* Send frame. */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, tx_bits ); + + /* Wait for frame Tx to complete. */ + while ( ENABLE != HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_DONE ) ) + { + ; + } + + /* Read received frame. */ + rx_data = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + } + } + + /* Finally, return the frame we received from the slave or 0 */ + return( rx_data ); +} + + +/***************************************************************************//** + * SPI_transfer_block() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_transfer_block +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_buffer, + uint16_t rx_byte_size +) +{ + uint32_t transfer_size = 0U; /* Total number of bytes to transfer. */ + uint16_t transfer_idx = 0U; /* Number of bytes transferred so far */ + uint16_t tx_idx = 0u; /* Number of valid data bytes sent */ + uint16_t rx_idx = 0u; /* Number of valid response bytes received */ + uint16_t transit = 0U; /* Number of bytes "in flight" to avoid FIFO errors */ + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI master. */ + if( ( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) && + /* Check for empty transfer as well */ + ( 0u != ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) ) ) + { + /* + * tansfer_size is one less than the real amount as we have to write + * the last frame separately to trigger the slave deselect in case + * the SPS option is in place. + */ + transfer_size = ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) - 1u; + /* Flush the receive and transmit FIFOs */ + HAL_set_8bit_reg(this_spi->base_addr, CMD, (uint32_t)(CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK )); + + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW) ) + { + recover_from_rx_overflow( this_spi ); + } + + /* Disable the Core SPI for a little bit, while we load the TX FIFO */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + while( ( tx_idx < transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out 0s to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + } + ++transit; + ++tx_idx; + } + + /* If room left to put last frame in before the off, then do it */ + if( ( tx_idx == transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data, not expecting any reply this time */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out last 0 to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + } + + ++transit; + ++tx_idx; + } + + /* FIFO is all loaded up so enable Core SPI to start transfer */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + + /* Perform the remainder of the transfer by sending a byte every time a byte + * has been received. This should ensure that no Rx overflow can happen in + * case of an interrupt occurring during this function. + * + * We break the transfer down into stages to minimise the processing in + * each loop as the SPI interface is very demanding at higher clock rates. + * This works well with FIFOs but might be less efficient if there is only + * a single frame buffer. + * + * First stage transfers remaining command bytes (if any). + * At this stage anything in the RX FIFO can be discarded as it is + * not part of a valid response. + */ + while( tx_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + /* Send another byte. */ + if( tx_idx == transfer_size ) /* Last frame is special... */ + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Read and discard. */ + HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now, we are writing dummy bytes to push through the response from + * the slave but we still have to keep discarding any read data that + * corresponds with one of our command bytes. + */ + while( transfer_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + if( tx_idx < transfer_size ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Read and discard. */ + HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now we are now only sending dummy data to push through the + * valid response data which we store in the response buffer. + */ + while( tx_idx < transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received byte. */ + rx_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* If we still need to send the last frame */ + while( tx_idx == transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received byte. */ + rx_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* + * Finally, we are now finished sending data and are only reading + * valid response data which we store in the response buffer. + */ + while( transfer_idx <= transfer_size ) + { + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received byte. */ + rx_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + } + } + } + } +} + +/***************************************************************************//** + * SPI_transfer_block_store_all_resp() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_transfer_block_store_all_resp +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_data_buffer, + uint16_t rx_byte_size, + uint8_t * cmd_response_buffer +) +{ + uint32_t transfer_size = 0U; /* Total number of bytes to transfer. */ + uint16_t transfer_idx = 0U; /* Number of bytes transferred so far */ + uint16_t tx_idx = 0u; /* Number of valid data bytes sent */ + uint16_t rx_idx = 0u; /* Number of valid response bytes received */ + uint16_t transit = 0U; /* Number of bytes "in flight" to avoid FIFO errors */ + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI master. */ + if( ( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) && + /* Check for empty transfer as well */ + ( 0u != ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) ) ) + { + /* + * tansfer_size is one less than the real amount as we have to write + * the last frame separately to trigger the slave deselect in case + * the SPS option is in place. + */ + transfer_size = ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) - 1u; + /* Flush the receive and transmit FIFOs */ + HAL_set_8bit_reg(this_spi->base_addr, CMD, (uint32_t)(CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK )); + + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW) ) + { + recover_from_rx_overflow( this_spi ); + } + + /* Disable the Core SPI for a little bit, while we load the TX FIFO */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + while( ( tx_idx < transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out 0s to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + } + ++transit; + ++tx_idx; + } + + /* If room left to put last frame in before the off, then do it */ + if( ( tx_idx == transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data, not expecting any reply this time */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out last 0 to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + } + + ++transit; + ++tx_idx; + } + + /* FIFO is all loaded up so enable Core SPI to start transfer */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + + /* Perform the remainder of the transfer by sending a byte every time a byte + * has been received. This should ensure that no Rx overflow can happen in + * case of an interrupt occurring during this function. + * + * We break the transfer down into stages to minimise the processing in + * each loop as the SPI interface is very demanding at higher clock rates. + * This works well with FIFOs but might be less efficient if there is only + * a single frame buffer. + * + * First stage transfers remaining command bytes (if any). + * At this stage anything in the RX FIFO can be discarded as it is + * not part of a valid response. + */ + while( tx_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + /* Send another byte. */ + if( tx_idx == transfer_size ) /* Last frame is special... */ + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received command byte. */ + cmd_response_buffer[transfer_idx] = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now, we are writing dummy bytes to push through the response from + * the slave, which we store in the command response buffer. + */ + while( transfer_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + if( tx_idx < transfer_size ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received command byte. */ + cmd_response_buffer[transfer_idx] = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now we are now only sending dummy data to push through the + * valid response data which we store in the data response buffer. + */ + while( tx_idx < transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received data byte. */ + rx_data_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* If we still need to send the last frame */ + while( tx_idx == transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received data byte. */ + rx_data_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* + * Finally, we are now finished sending data and are only reading + * valid response data which we store in the data response buffer. + */ + while( transfer_idx <= transfer_size ) + { + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received data byte. */ + rx_data_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + } + } + } + } +} +/***************************************************************************//** + * SPI_set_frame_rx_handler() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_frame_rx_handler +( + spi_instance_t * this_spi, + spi_frame_rx_handler_t rx_handler +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if(NULL_INSTANCE != this_spi) + { + /* This function is only intended to be used with an SPI slave. */ + if(DISABLE == HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER)) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Disable SSEND and CMD interrupts as we are not doing block transfers */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTSSEND, DISABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + + /* Disable block Rx handler as they are mutually exclusive. */ + this_spi->block_rx_handler = 0U; + + /* Keep a copy of the pointer to the Rx handler function. */ + this_spi->frame_rx_handler = rx_handler; + + if( SPI_SLAVE_XFER_FRAME != this_spi->slave_xfer_mode ) + { + /* + * Either just coming from init or were previously in block mode + * so no tx frame handler is set at this point in time... + * + * Don't allow TXDONE interrupts. + */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXDONE, DISABLE ); + } + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK); + + /* Enable Rx and FIFO error interrupts */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTRXOVFLOW, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXURUN, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTRXDATA, ENABLE ); + + /* Make sure correct mode is selected */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_FRAME; + + /* Finally re-enable the CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } + } +} + +/***************************************************************************//** + * SPI_set_slave_tx_frame() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_slave_tx_frame +( + spi_instance_t * this_spi, + uint32_t frame_value, + spi_slave_frame_tx_handler_t slave_tx_frame_handler +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI slave. */ + if( DISABLE == HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Disable SSEND and CMD interrupts as we are not doing block transfers */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTSSEND, DISABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + + if( SPI_SLAVE_XFER_FRAME != this_spi->slave_xfer_mode ) + { + /* + * Either just coming from init or were previously in block mode + * so no rx frame handler is set at this point in time... + * + * Don't allow RXDATA interrupts. + */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTRXDATA, DISABLE ); + } + + /* Disable slave block tx buffer as it is mutually exclusive with frame + * level handling. */ + this_spi->slave_tx_buffer = NULL_BUFF; + this_spi->slave_tx_size = 0U; + this_spi->slave_tx_idx = 0U; + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK); + + /* Assign the slave frame update handler - NULL_SLAVE_TX_UPDATE_HANDLER for none */ + this_spi->slave_tx_frame_handler = slave_tx_frame_handler; + + /* Keep a copy of the slave Tx frame value. */ + this_spi->slave_tx_frame = frame_value; + + /* Load one frame into Tx data register. */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, this_spi->slave_tx_frame ); + + /* Enable Tx Done interrupt in order to reload the slave Tx frame after each + * time it has been sent. */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXDONE, ENABLE ); + + /* Make sure correct mode is selected */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_FRAME; + + /* Ready to go so enable CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } + } +} + +/***************************************************************************//** + * SPI_set_slave_block_buffers() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_slave_block_buffers +( + spi_instance_t * this_spi, + const uint8_t * tx_buffer, + uint32_t tx_buff_size, + uint8_t * rx_buffer, + uint32_t rx_buff_size, + spi_block_rx_handler_t block_rx_handler +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI slave. */ + if( DISABLE == HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Make sure correct mode is selected */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_BLOCK; + /* + * No command handler should be setup at this stage so fake this + * to ensure 0 padding works. + */ + this_spi->cmd_done = 1u; + + /* Disable frame handlers as they are mutually exclusive with block Rx handler. */ + this_spi->frame_rx_handler = NULL_FRAME_HANDLER; + this_spi->slave_tx_frame_handler = NULL_SLAVE_TX_UPDATE_HANDLER; + + /* Keep a copy of the pointer to the block Rx handler function. */ + this_spi->block_rx_handler = block_rx_handler; + + /* Assign slave receive buffer */ + this_spi->slave_rx_buffer = rx_buffer; + this_spi->slave_rx_size = rx_buff_size; + this_spi->slave_rx_idx = 0U; + + /* Assign slave transmit buffer*/ + this_spi->slave_tx_buffer = tx_buffer; + this_spi->slave_tx_size = tx_buff_size; + this_spi->slave_tx_idx = 0U; + + /* Flush the receive and transmit FIFOs */ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Preload the transmit FIFO. */ + while( !(HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_TXFULL)) && + ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->slave_tx_buffer[this_spi->slave_tx_idx] ); + ++this_spi->slave_tx_idx; + } + /* + * Disable TXDATA interrupt as we will look after transmission in rx handling + * because we know that once we have read a frame it is safe to send another one. + */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTTXDATA, DISABLE ); + + /* Enable Rx, FIFO error and SSEND interrupts */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTRXOVFLOW, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXURUN, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTRXDATA, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTSSEND, ENABLE ); + + /* Disable command handler until it is set explicitly */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + + /* Now enable the CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } + } +} + +/***************************************************************************//** + * SPI_set_cmd_handler() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_cmd_handler +( + spi_instance_t * this_spi, + spi_block_rx_handler_t cmd_handler, + uint32_t cmd_size +) +{ + uint32_t ctrl2 = 0u; + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( NULL_SLAVE_CMD_HANDLER != cmd_handler ); + HAL_ASSERT( 0u < cmd_size ); + + if( ( NULL_INSTANCE != this_spi ) && ( 0u < cmd_size ) && + ( NULL_SLAVE_CMD_HANDLER != cmd_handler ) ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + /* + * Note we don't flush the FIFOs as this has been done already when + * block mode was configured. + * + * Clear this flag so zero padding is disabled until command response + * has been taken care of. + */ + this_spi->cmd_done = 0u; + + /* Assign user handler for Command received interrupt */ + this_spi->cmd_handler = cmd_handler; + + /* Configure the command size and Enable Command received interrupt */ + ctrl2 = HAL_get_8bit_reg( this_spi->base_addr, CTRL2 ); + + /* First clear the count field then insert count and int enables */ + ctrl2 &= ~(uint32_t)CTRL2_CMDSIZE_MASK; + ctrl2 |= (uint32_t)((cmd_size & CTRL2_CMDSIZE_MASK) | CTRL2_INTCMD_MASK | CTRL2_INTRXDATA_MASK); + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, ctrl2 ); + + /* Now enable the CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } +} + +/***************************************************************************//** + * SPI_set_cmd_response() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_cmd_response +( + spi_instance_t * this_spi, + const uint8_t * resp_tx_buffer, + uint32_t resp_buff_size +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( NULL_BUFF != resp_tx_buffer ); + HAL_ASSERT( 0u < resp_buff_size ); + + if( ( NULL_INSTANCE != this_spi ) && ( 0u < resp_buff_size ) && + ( NULL_BUFF != resp_tx_buffer ) ) + { + this_spi->resp_tx_buffer = resp_tx_buffer; + this_spi->resp_buff_size = resp_buff_size; + this_spi->resp_buff_tx_idx = 0u; + + fill_slave_tx_fifo(this_spi); + } +} + + +/***************************************************************************//** + * SPI_enable() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_enable +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } +} + + +/***************************************************************************//** + * SPI_disable() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_disable +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + } +} + + +/***************************************************************************//** + * SPI interrupt service routine. + */ +void SPI_isr +( + spi_instance_t * this_spi +) +{ + uint32_t rx_frame; + int32_t guard; + +/* + * The assert and the NULL check here can be commented out to reduce the interrupt + * latency once you are sure the interrupt vector code is correct. + */ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + if( NULL_INSTANCE != this_spi ) + { + /* Handle receive. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_RXDATA ) ) + { + /* + * Service receive data according to transfer mode in operation. + * + * We check block mode first as this is most likely to have back to back + * transfers with multiple bytes. + * + * Note the order of the checks here will effect interrupt latency and + * for critical timing the mode you are using most often should probably be + * be the first checked. + */ + if( SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode ) /* Block handling mode. */ + { + while( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Read irrespective to clear the RX IRQ */ + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + if( this_spi->slave_rx_idx < this_spi->slave_rx_size ) + { + this_spi->slave_rx_buffer[this_spi->slave_rx_idx] = (uint8_t)rx_frame; + } + ++this_spi->slave_rx_idx; + } + /* + * Now handle updating of tx FIFO to keep the data flowing. + * First see if there is anything in slave_tx_buffer to send. + */ + while( ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) + && ( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->slave_tx_buffer[this_spi->slave_tx_idx] ); + ++this_spi->slave_tx_idx; + } + /* + * Next see if there is anything in resp_tx_buffer to send. + */ + if( this_spi->slave_tx_idx >= this_spi->slave_tx_size ) + { + while( ( this_spi->resp_buff_tx_idx < this_spi->resp_buff_size ) + && ( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->resp_tx_buffer[this_spi->resp_buff_tx_idx] ); + ++this_spi->resp_buff_tx_idx; + } + } + /* + * Lastly, see if we are ready to pad with 0s . + */ + if( this_spi->cmd_done && ( this_spi->slave_tx_idx >= this_spi->slave_tx_size ) && + ( this_spi->resp_buff_tx_idx >= this_spi->resp_buff_size ) ) + { + guard = 1 + ((int32_t)this_spi->fifo_depth / 4); + while( ( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) + && ( 0 != guard ) ) + { + /* + * Pad TX FIFO with 0s for consistent behaviour if the master + * tries to transfer more than we expected. + */ + HAL_set_32bit_reg(this_spi->base_addr, TXDATA, 0x00u); + /* + * We use the guard count to cover the event that we are never + * seeing the TX FIFO full because the data is being pulled + * out as fast as we can stuff it in. In this case we never spend + * more than our allocated time spinning here. + */ + guard--; + } + } + } + else if( SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode ) /* Single frame handling mode. */ + { + while( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + if( NULL_FRAME_HANDLER != this_spi->frame_rx_handler ) + { + this_spi->frame_rx_handler( rx_frame ); + } + } + } + else /* Slave transfer mode not set up so discard anything in RX FIFO */ + { + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_RXFIFORST_MASK ); + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_RXDATA, ENABLE ); + } + + /* Handle transmit. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_TXDONE ) ) + { + /* + * Note, the driver only currently uses the txdone interrupt when + * in frame transmit mode. In block mode all TX handling is done by the + * receive interrupt handling code as we know that for every frame received + * a frame must be placed in the TX FIFO. + */ + if( SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode ) + { + /* Execute the user callback to update the slave_tx_frame */ + if( NULL_SLAVE_TX_UPDATE_HANDLER != this_spi->slave_tx_frame_handler ) + { + this_spi->slave_tx_frame_handler ( this_spi ); + } + + /* Reload slave tx frame into Tx data register. */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, this_spi->slave_tx_frame ); + } + else if( SPI_SLAVE_XFER_BLOCK != this_spi->slave_xfer_mode ) + { + /* Slave transfer mode not set up so discard anything in TX FIFO */ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK ); + } + else + { + /* Nothing to do, no slave mode configured */ + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_TXDONE, ENABLE ); + } + + + /* Handle receive overflow. */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, INTMASK_RXOVERFLOW)) + { + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_RXFIFORST_MASK); + HAL_set_8bit_reg_field(this_spi->base_addr, INTCLR_RXOVERFLOW, ENABLE); + } + + /* Handle transmit under run. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_TXUNDERRUN ) ) + { + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK ); + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_TXUNDERRUN, ENABLE ); + } + + /* Handle command interrupt. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_CMDINT ) ) + { + read_slave_rx_fifo( this_spi ); + + /* + * Call the command handler if one exists. + */ + if( NULL_SLAVE_CMD_HANDLER != this_spi->cmd_handler ) + { + this_spi->cmd_handler( this_spi->slave_rx_buffer, this_spi->slave_rx_idx ); + } + this_spi->cmd_done = 1u; + /* Disable command interrupt until slave select becomes de-asserted to avoid retriggering. */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_CMDINT, ENABLE ); + } + + /* Handle slave select becoming de-asserted. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_SSEND) ) + { + /* Only supposed to do all this if transferring blocks... */ + if(SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode) + { + uint32_t rx_size; + + /* Empty any remaining bytes in RX FIFO */ + read_slave_rx_fifo( this_spi ); + rx_size = this_spi->slave_rx_idx; + /* + * Re-enable command interrupt if required. + * Must be done before re loading FIFO to ensure stale response + * data is not pushed into the FIFO. + */ + if(NULL_SLAVE_CMD_HANDLER != this_spi->cmd_handler) + { + this_spi->cmd_done = 0u; + this_spi->resp_tx_buffer = 0u; + this_spi->resp_buff_size = 0u; + this_spi->resp_buff_tx_idx = 0u; + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_CMDINT, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, ENABLE ); + } + /* + * Reset the transmit index to 0 to restart transmit at the start of the + * transmit buffer in the next transaction. This also requires flushing + * the Tx FIFO and refilling it with the start of Tx data buffer. + */ + this_spi->slave_tx_idx = 0u; + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + fill_slave_tx_fifo( this_spi ); + + /* Prepare to receive next packet. */ + this_spi->slave_rx_idx = 0u; + /* + * Call the receive handler if one exists. + */ + if( NULL_BLOCK_HANDLER != this_spi->block_rx_handler ) + { + this_spi->block_rx_handler( this_spi->slave_rx_buffer, rx_size ); + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_RXDATA, ENABLE ); + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_SSEND, ENABLE ); + } + } +} + +/******************************************************************************* + * Local function definitions + */ + +/***************************************************************************//** + * Fill the transmit FIFO (used for slave block transfers). + */ +static void fill_slave_tx_fifo +( + spi_instance_t * this_spi +) +{ + /* First see if slave_tx_buffer needs transmitting */ + while( ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) && + !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->slave_tx_buffer[this_spi->slave_tx_idx] ); + ++this_spi->slave_tx_idx; + } + + /* Then see if it is safe to look at putting resp_tx_buffer in FIFO? */ + if( this_spi->slave_tx_idx >= this_spi->slave_tx_size ) + { + while( ( this_spi->resp_buff_tx_idx < this_spi->resp_buff_size ) && + !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->resp_tx_buffer[this_spi->resp_buff_tx_idx] ); + ++this_spi->resp_buff_tx_idx; + } + } +} + +/***************************************************************************//** + * + */ +static void read_slave_rx_fifo +( + spi_instance_t * this_spi +) +{ + uint32_t rx_frame; + + if( SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode ) /* Block handling mode. */ + { + while( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); /* Read irresepective to clear the RX IRQ */ + if( this_spi->slave_rx_idx < this_spi->slave_rx_size ) + { + this_spi->slave_rx_buffer[this_spi->slave_rx_idx] = (uint8_t)rx_frame; + } + ++this_spi->slave_rx_idx; + } + } + else if( SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode ) /* Frame handling mode */ + { + while( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Single frame handling mode. */ + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + if( NULL_FRAME_HANDLER != this_spi->frame_rx_handler ) + { + this_spi->frame_rx_handler( rx_frame ); + } + } + } + else /* Slave transfer mode not set up so discard anything in RX FIFO */ + { + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_RXFIFORST_MASK ); + } +} + +/***************************************************************************//** + * This function is to recover the CoreSPI from receiver overflow. + * It temporarily disables the CoreSPI from interacting with external world, flushes + * the transmit and receiver FIFOs, clears all interrupts and then re-enables + * the CoreSPI instance referred by this_spi parameter. + */ +static void recover_from_rx_overflow +( + const spi_instance_t * this_spi +) +{ + /* Disable CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Reset TX and RX FIFOs */ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Enable CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); +} + + diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.h b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.h new file mode 100644 index 0000000..c6873f7 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.h @@ -0,0 +1,1324 @@ +/***************************************************************************//** + * Copyright 2013-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Core SPI bare metal software driver public API. + * + * This Core SPI driver provides functions for implementing SPI master or + * SPI slave operations with the CoreSPI version 4.2.xxx It is not compatible + * with CoreSPI version 3.0.xxx. + * + * The Core SPI driver supports two classes of data transfer operation: + * SPI frame operation or SPI block transfer operations. + * + * Frame operations allow transferring individual SPI frames from 4 to 32-bits + * in length. Block operations allow transferring blocks of data organized as + * 8-bit frames. + * + * @file core_spi.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreSPI prototypes + * + */ + +/*=========================================================================*//** + @mainpage Core SPI Bare Metal Driver. + + ============================================================================== + Introduction + ============================================================================== + CoreSPI is an IP component that implements a full-duplex, synchronous, and + configurable serial peripheral interface (SPI) with frame sizes from 4 to 32 + bits and bus interface sizes of 8-, 16-, or 32-bit. Each CoreSPI instance + communicates with up to eight slave devices. + + This driver provides a set of functions for controlling CoreSPI as part of + the bare metal system where no operating system is available. These drivers + can be adapted to be used as a part of an operating system, but the + implementation of the adaptation layer between driver and the operating + system's driver model is outside the scope of this User's Guide. + + ============================================================================== + Driver Configuration + ============================================================================== + Your application software should configure the CoreSPI driver through calls + to the SPI_init() function for each CoreSPI instance in the hardware design. + This function configures a default set of parameters that include a CoreSPI + hardware instance base address and the depth of the FIFOs for this instance. + + The CoreSPI instance is configured at the time of instantiation in hardware + design for APB width, frame size, FIFO depth, serial clock speed, serial + clock polarity, serial clock phase, and slave select state parameters. + + CoreSPI can communicate with up to eight different slave devices that match + the CoreSPI configuration at the time of hardware instantiation. + + The functions SPI_configure_slave_mode() and SPI_configure_master_mode() are + used to configure the CoreSPI instance as a master or slave as required by + the application. + + When CoreSPI wishes to communicate with a specific slave device, call + the SPI_set_slave_select() function with the slave number as an argument. + This function selects the slave device. A previously selected slave gets + unselected by calling the SPI_clear_slave_select() function. + + ============================================================================== + Theory of Operation + ============================================================================== + The CoreSPI driver functions are grouped into the following categories: + • Initialization + • Configuration for either master or slave operations + • SPI master frame transfer control + • SPI master block transfer control + • SPI slave frame transfer control + • SPI slave block transfer control + + Frame transfers allow CoreSPI to write or read up to 32-bits of data in a + single SPI transaction. For example, a frame transfer of 12-bits might be used + to read the result of an ADC conversion from a SPI analog to digital converter. + + Block transfers allow CoreSPI to write and/or read a number of bytes in a single + SPI transaction. With the driver as is, block transfer transactions allow data + transfers in multiples of 8-bits (8, 16, 24, 32, 40,...) and the CoreSPI instance + has to be configured for 8-bit frames. For other frame sizes, the + SPI_transfer_block() code can act as a template for developing a frame block + transfer function. + Block transfers are typically used with byte oriented devices like SPI + FLASH devices. + + Note: The CoreSPI instance in the hardware design must be configured for + the frame size required by the application; configuration by driver is + not possible. + + -------------------------------- + Initialization + -------------------------------- + The CoreSPI driver is initialized through a call to the SPI_init() function. + The SPI_init() function takes a pointer to the global CoreSPI instance data + structure of type spi_instance_t and the base address of the CoreSPI instance + as defined by the hardware design. The CoreSPI instance global data structure + is used by the driver to store state information for each CoreSPI instance. + A pointer to these data structures is also used as the first parameter to + any of the driver functions to identify which CoreSPI will be used by the + called function. It is the responsibility of the application programmer to + create and maintain these global CoreSPI instance data structures. Any call + to a CoreSPI driver function should be of the form SPI_function_name + ( &g_core_spi0, ... ). + The SPI_init() function resets the transmit and receives FIFOs of CoreSPI + instance being initialized. + The SPI_init() function must be called before any other CoreSPI driver + functions can be called. + + ---------------------------------------------------- + Configuration + ---------------------------------------------------- + A CoreSPI instance can operate either as a master or as a slave SPI device. + There are two distinct functions for configuring a CoreSPI instance for + master or slave operations. + + ## Master Configuration + The SPI_configure_master_mode() function configures the specified CoreSPI + block for operations as an SPI master. This function must be called once + before the CoreSPI block communicates with an SPI slave device. + + ## Slave Configuration + The SPI_configure_slave_mode() function configures the specified CoreSPI + block for operations as a SPI slave. This function must be called after + calling the SPI_init() to configure the CoreSPI instance referred by this_spi + parameter to operate in the slave mode. + + ------------------------------------- + SPI Master Frame Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI master frame transfers: + • SPI_set_slave_select() + • SPI_transfer_frame() + • SPI_clear_slave_select() + + The master must first select the target slave or slaves to be addressed by + calling the SPI_set_slave_select() function. This causes the relevant select + line(s) to become asserted while data is clocked out onto the SPI data line. + + A function call is then made to SPI_transfer_frame() specifying the value + of the data frame to be sent and returning the value read. + + After the transfer is complete, use the SPI_clear_slave_select() function + to prevent this slave select line from being asserted during subsequent SPI + transactions. A call to this function is required only if the master is + communicating with multiple slave devices. + + ------------------------------------- + SPI Master Block Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI master block transfers: + • SPI_set_slave_select() + • SPI_transfer_block() + • SPI_clear_slave_select() + + The master must first select the target slave or slaves by calling + SPI_set_slave_select(). This causes the relevant slave select line(s) to + become asserted while data is clocked out onto the SPI data line. + Alternatively, a general purpose input/output (GPIO) can be used to control + the state of the target slave device's chip select signal. + + A call is then made to the SPI_transfer_block() function. The parameters of + this function specify the following: + • The number of bytes to be transmitted + • A pointer to the buffer containing the data to be transmitted + • The number of bytes to be received + • A pointer to the buffer where the received data gets stored + + The number of bytes to be transmitted can be set to zero to indicate that the + transfer is purely a block read transfer. The number of bytes to be received + can be set to zero to specify that the transfer is purely a block write + transfer. + + Block mode transfers as implemented by the driver are effectively half duplex + as we do not store the values received from the slave device whilst we are + transmitting. If full duplex operation is required, the driver + SPI_transfer_block() function can serve as a starting point for implementing + full duplex block transfers. + + The SPI_clear_slave_select() function can be used after the transfer is + complete to prevent this slave select line from being asserted during + subsequent SPI transactions. A call to this function is only required if + the master is communicating with multiple slave devices. + + ------------------------------------- + SPI Slave Frame Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI slave frame transfers: + • SPI_set_frame_rx_handler() + • SPI_set_slave_tx_frame() + + The SPI_set_frame_rx_handler() function specifies the receive handler + function that is called when a frame of data has been received by the + SPI when it is configured as a slave. The receive handler function specified + through this call processes the frame data written over the SPI bus to the + SPI slave by the remote SPI master. The receive handler function must be + implemented as part of the application. It is only required if the SPI slave + is the target of SPI frame write transactions. + + The SPI_set_slave_tx_frame() function specifies the frame data that is + returned to the SPI master. The frame data specified through this function + is the value that will be read over the SPI bus by the remote SPI master, + when it initiates a transaction. Call the SPI_set_slave_tx_frame() function + only if the SPI slave is the target of SPI read transactions. That is, if + data is meant to be read over CoreSPI. + + If both frame handlers are required, call the SPI_set_frame_rx_handler() + first, otherwise the initial TX frame gets discarded when SPI_set_frame_rx_handler() + clears the FIFOs as part of its initialization. + + ------------------------------------- + SPI Slave Block Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI slave block transfers: + • SPI_set_slave_block_buffers() + • SPI_set_cmd_handler() + • SPI_set_cmd_response() + + The SPI_set_slave_block_buffers() function is used to configure an SPI slave + for block transfer operations. It specifies the following: + • The buffer containing the data that will be returned to the remote SPI + master + • The buffer where data received from the remote SPI master will be + stored + • The optional handler function that will be called after the receive + buffer is filled + + The SPI_set_cmd_handler() function specifies a command handler function that + is called by the driver once a specific number of frames have been + received after the SPI chip select signal becomes active. The number of + bytes making up the command part of the transaction is specified as part of + the parameters to the SPI_set_cmd_handler() function. The command handler + function is implemented as a part of the application making use of the SPI + driver and typically calls the SPI_set_cmd_response() function. + + The SPI_set_cmd_response() function specifies the data that gets returned + to the master. Typically, the SPI_set_slave_block_buffers() function is + called as a part of the system initialisation to specify the data sent to + the master while the command bytes are being received. The transmit buffer + specified through calling the SPI_set_slave_block_buffers() function would + also typically include one or more bytes allowing the turn around time + for the command handler function to execute and call the + SPI_set_cmd_response() function. + + *//*=========================================================================*/ +#ifndef CORE_SPI_H_ +#define CORE_SPI_H_ + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#include "hal_assert.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + SPI FIFO Depth + ======================================= + SPI_MAX_FIFO_DEPTH & SPI_MIN_FIFO_DEPTH constants define the maximum and minimum + FIFO depths allowed for the CoreSPI instance. User need to inform the driver of + the FIFO depth for each CoreSPI instance to ensure that the FIFOs are managed correctly. + + | Constant | Description | + |--------------------|----------------------------------------------------| + | SPI_MAX_FIFO_DEPTH | Maximum FIFO depth allowed for the CoreSPI instance| + | SPI_MIN_FIFO_DEPTH | Minimum FIFO depth allowed for the CoreSPI instance| + + */ +#define SPI_MAX_FIFO_DEPTH 32u +#define SPI_MIN_FIFO_DEPTH 1u + +/***************************************************************************//** + Instances of this structure are used to identify the specific CoreSPI hardware + instances. A pointer to an instance of the spi_instance_t structure is passed + as the first parameter to the CoreSPI driver functions to identify which SPI + performs the requested operation. + */ +typedef struct spi_instance spi_instance_t; + +/***************************************************************************//** + This function pointer type is to assign a callback function for TX interrupt + when slave wants to send the next updated frame. + + Declaring and Implementing Slave Frame Transmit Handler Functions: + Slave transmit frame update handler functions should follow the following + prototype: + void slave_tx_frame_update_handler ( spi_instance_t * this_spi ); + The actual name of the transmit handler is unimportant. You can use any name + of your choice for the frame update handler. + + A common handler function may be used when multiple CoreSPI instances are + configured as slave, as the particular slave device currently requiring + service is indicated by the function parameter. + */ +typedef void (*spi_slave_frame_tx_handler_t)( spi_instance_t * this_spi ); + +/***************************************************************************//** + This defines the function prototype that must be followed by the SPI slave + frame receive handler functions. These functions are registered with the SPI + driver through the SPI_set_frame_rx_handler() function. + + Declaring and Implementing the Slave Frame Receive Handler Functions: + The Slave frame receive handler functions should follow the following + prototype: + void slave_frame_receive_handler(uint32_t rx_frame); + The actual name of the receive handler is unimportant. You can use any name + of your choice for the receive frame handler. The rx_frame parameter contains + the value of the received frame. + + Separate handler functions are required for each slave instance as there is + no indication of the slave requiring service passed to the handler. + + */ +typedef void (*spi_frame_rx_handler_t)( uint32_t rx_frame ); + +/***************************************************************************//** + This defines the function prototype that must be followed by SPI slave + block receive handler functions. These functions are registered with the + SPI driver through the SPI_set_slave_block_buffers() function. + + Declaring and Implementing Slave Block Receive Handler Functions: + Slave block receive handler functions should follow the following prototype: + void spi_block_rx_handler ( uint8_t * rx_buff, uint16_t rx_size ); + The actual name of the receive handler is unimportant. You can use any name + of your choice for the receive frame handler. The rx_buff parameter contains + a pointer to the start of the received block. The rx_size parameter contains + the number of bytes of the received block. + + Separate handler functions are required for each slave instance as there is + no indication of the slave requiring service passed to the handler. + + */ +typedef void (*spi_block_rx_handler_t)( uint8_t * rx_buff, uint32_t rx_size ); + +/***************************************************************************//** + This enumeration is used to select a specific SPI slave device (0 to 7). It is + used as a parameter to the SPI_configure_master_mode(), SPI_set_slave_select(), + and SPI_clear_slave_select() functions. + */ +typedef enum __spi_slave_t +{ + SPI_SLAVE_0 = 0, + SPI_SLAVE_1 = 1, + SPI_SLAVE_2 = 2, + SPI_SLAVE_3 = 3, + SPI_SLAVE_4 = 4, + SPI_SLAVE_5 = 5, + SPI_SLAVE_6 = 6, + SPI_SLAVE_7 = 7, + SPI_MAX_NB_OF_SLAVES = 8 +} spi_slave_t; + +/***************************************************************************//** + This enumeration is used to indicate the current slave mode transfer type so + that we are not relying on buffer comparisons to dictate the logic of the driver. + */ +typedef enum __spi_sxfer_mode_t +{ + SPI_SLAVE_XFER_NONE = 0, /* Not configured yet */ + SPI_SLAVE_XFER_BLOCK = 1, /* Block transfers, with SSEND delimiting end of block */ + SPI_SLAVE_XFER_FRAME = 2 /* Single frame transfers */ +} spi_sxfer_mode_t; + +/***************************************************************************//** + There is one instance of this structure for each of the core SPIs. Instances + of this structure are used to identify a specific SPI. A pointer to an + instance of the spi_instance_t structure is passed as the first parameter to + SPI driver functions to identify which SPI should perform the requested operation. + */ +struct spi_instance{ + + /* Base address in the processor's memory map for the + registers of the CoreSPI instance being initialized */ + addr_t base_addr; /* Base address of SPI hardware instance */ + + uint32_t rx_frame; /* received data */ + + /* Internal transmit state: */ + const uint8_t * slave_tx_buffer; /* Pointer to slave transmit buffer */ + uint32_t slave_tx_size; /* Size of slave transmit buffer */ + uint32_t slave_tx_idx; /* Current index into slave transmit buffer */ + + /* Slave command response buffer: */ + const uint8_t * resp_tx_buffer; + uint32_t resp_buff_size; + uint32_t resp_buff_tx_idx; + spi_block_rx_handler_t cmd_handler; + uint32_t cmd_done; /* Flag which indicates response has been set up and + it is safe to pad with 0s once the response is sent */ + + /* Internal receive state: */ + uint8_t * slave_rx_buffer; /* Pointer to buffer where data received by a slave will be stored */ + uint32_t slave_rx_size; /* Slave receive buffer size */ + uint32_t slave_rx_idx; /* Current index into slave receive buffer */ + + /* Slave received frame handler: */ + spi_frame_rx_handler_t frame_rx_handler; /* Pointer to function that will be called when a frame + is received when the SPI block is configured as slave */ + /* Slave transmitted frame handler: */ + uint32_t slave_tx_frame; /* Value of the data frame that will be transmitted + when the SPI block is configured as slave */ + spi_slave_frame_tx_handler_t slave_tx_frame_handler; /* Callback function pointer to update slave_tx_frame */ + + /* Slave block rx handler: */ + spi_block_rx_handler_t block_rx_handler; /* Pointer to the function that will be called when a data block has been received */ + + /* Per instance specific hardware information that the driver needs to know */ + uint16_t fifo_depth; /* Depth of RX and TX FIFOs in frames */ + + /* How we are expecting to deal with slave transfers */ + spi_sxfer_mode_t slave_xfer_mode; /* Current slave mode transfer configuration */ +}; + +/*------------------------Public Function-------------------------------------*/ + +/***************************************************************************//** + The SPI_init() function initializes the hardware and data structures of a + CoreSPI instance referenced by this_spi parameter. This function must be + called for each CoreSPI instance with a unique this_spi and base_addr + parameter combination. The SPI_init() function must be called before any + other CoreSPI driver functions are called. + + After calling the SPI_init() the CoreSPI is configured as a master, + all interrupt sources will be masked and all the slaves are deselected. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to be initialized. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @param base_addr + The base_addr parameter is the base address in the processor's memory map for + the registers of the CoreSPI instance being initialized. It is assumed that + any non NULL value passed in here points to a valid instance of a CoreSPI as + the driver has no way of verifying this. Failure to pass in a valid address + can result in system instability. + + @param fifo_depth + The fifo_depth parameter specifies the number of frames in the receive + and transmit FIFOs of the CoreSPI instance being initialized. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + @endcode + */ +void SPI_init +( + spi_instance_t * this_spi, + addr_t base_addr, + uint16_t fifo_depth +); + +/***************************************************************************//** + The SPI_configure_slave_mode() function is used when a CoreSPI instance is + to be configured as a SPI slave. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to be configured. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + + int main(void) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_slave_mode ( &g _spi0 ); + } + @endcode + */ +void SPI_configure_slave_mode +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_configure_master_mode() function is used when a CoreSPI instance is + to be configured as a SPI master. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to be configured. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + + int main(void) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_master_mode ( &g _spi0 ); + } + @endcode + */ +void SPI_configure_master_mode +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_set_slave_select() function is used by a CoreSPI master to select a + specific slave. This function causes the relevant slave select signal to be + asserted while data is clocked out onto the SPI data line. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param slave + The slave parameter is one of the spi_slave_t enumerated constants + identifying a slave. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + const uint32_t master_tx_frame = 0x0100A0E1; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0 ); + SPI_transfer_frame( &g_spi0, master_tx_frame ); + SPI_clear_slave_select( &g_spi0, SPI_SLAVE_0 ); + + @endcode + */ +void SPI_set_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +); + +/***************************************************************************//** + The SPI_clear_slave_select() function is used by a CoreSPI master to + deselect a specific slave. This function causes the relevant slave select + signal to be de-asserted. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param slave + The slave parameter is one of the spi_slave_t enumerated constants + identifying a slave. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + const uint32_t master_tx_frame = 0x0100A0E1; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0 ); + SPI_transfer_frame( &g_spi0, master_tx_frame ); + SPI_clear_slave_select( &g_spi0, SPI_SLAVE_0 ); + @endcode + */ +void SPI_clear_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +); + +/***************************************************************************//** + The SPI_transfer_frame() function is used by a SPI master to transmit and + receive a single frame of the size that has been configured at the time of + CoreSPI hardware instantiation. This function is typically used for + transactions with a SPI slave where the number of transmit and receive bits + are not divisible by 8 or where full duplex exchange of frames is required. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param tx_bits + The tx_bits parameter is a 32-bit word containing the value that will be + transmitted. If the frame size configured for the CoreSPI is less than 32-bits, + the upper bits will be ignored. + Note: The bit length of the value to be transmitted to the slave is + set when the CoreSPI is instantiated in the hardware design. + + @return + This function returns a 32-bit word containing the value that is received + from the slave. If the frame size configured for the CoreSPI in question is + less that 32-bits, the upper bits will be 0. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + const uint32_t master_tx_frame = 0x0100A0E1; + uint32_t master_rx; + + SPI_init(&g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ); + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0 ); + master_rx = SPI_transfer_frame( &g_spi0, master_tx_frame ); + SPI_clear_slave_select( &g_spi0, SPI_SLAVE_0 ); + @endcode + */ +uint32_t SPI_transfer_frame +( + spi_instance_t * this_spi, + uint32_t tx_bits +); + +/***************************************************************************//** + The SPI_transfer_block() function is used by the SPI master to transmit and + receive blocks of data organized as a specified number of 8-bit frames. It + can be used for the following: + • Writing a data block to a slave + • Reading a data block from a slave + • Sending a command to a slave followed by reading the outcome of + the command in a single SPI transaction. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param cmd_buffer + The cmd_buffer parameter is a pointer to the buffer that contains the data + sent by the master from the beginning of the transfer. This pointer can be + null (0) if the master does not need to send a command before reading data. + + @param cmd_byte_size + The cmd_byte_size parameter specifies the number of bytes in cmd_buffer that + will be sent. A value ‘0’ indicates that no data needs to be sent to the slave. + + @param rx_buffer + The rx_buffer parameter is a pointer to the buffer that stores the data received + from the slave after sending the command. This pointer can be null (0) if the + master does not receive any data from the slave. + + @param rx_byte_size + The rx_byte_size parameter specifies the number of bytes received from + the slave and stored in the rx_buffer. A value ‘0’ indicates that no data is + to be read from the slave. + + @return + This function does not return any value. + + @example + @code + Polled write transfer example + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + + uint8_t master_tx_buffer[MASTER_TX_BUFFER] = + { + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A + }; + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0) ; + SPI_transfer_block + ( + &g_spi0, + master_tx_buffer, + sizeof(master_tx_buffer), + 0, + 0 + ); + SPI_clear_slave_select(&g_spi0, SPI_SLAVE_0 ); + @endcode + */ +void SPI_transfer_block +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_buffer, + uint16_t rx_byte_size +); + +/***************************************************************************//** + The SPI_transfer_block_store_all_resp() function is used by the SPI master + to transmit and receive blocks of data organized as a specified number + of 8-bit frames. It can be used for the following: + • Writing a data block to a slave + • Reading a data block from a slave + • Sending a command to a slave followed by reading the outcome of + the command in a single SPI transaction + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param cmd_buffer + The cmd_buffer parameter is a pointer to the buffer that contains the data sent by + the master from the beginning of the transfer. This pointer can be null (0) + if the master does not need to send a command before reading data. + + @param cmd_byte_size + The cmd_byte_size parameter specifies the number of bytes contained in + cmd_buffer that will be sent. A value ‘0’ indicates that no data needs + to be sent to the slave. + + @param rx_data_buffer + The rx_data_buffer parameter is a pointer to the buffer that stores the data received + from the slave after sending the command. This pointer can be null (0) if the + master does not receive any data from the slave. + + @param rx_byte_size + The rx_byte_size parameter specifies the number of bytes received from + the slave and stores in the rx_buffer. A value ‘0’ indicates that no data is + to be read from the slave. + + @param cmd_response_buffer + The cmd_response_buffer parameter is a pointer to the buffer which stores the + command response from the slave, while the master is transmitting the number + of bytes indicated by cmd_byte_size parameter. + + @return + This function does not return any value. + + @example + @code + Polled write transfer example + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + + uint8_t master_tx_buffer[MASTER_TX_BUFFER] = + { + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A + }; + + uint8_t cmd_rx_buffer[CMD_RX_BUFFER]={0}; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0) ; + SPI_transfer_block_store_all_resp + ( + &g_spi0, + master_tx_buffer, + sizeof(master_tx_buffer), + 0, + 0, + cmd_response_buffer + ); + SPI_clear_slave_select(&g_spi0, SPI_SLAVE_0 ); + @endcode + */ +void SPI_transfer_block_store_all_resp +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_data_buffer, + uint16_t rx_byte_size, + uint8_t * cmd_response_buffer +); + +/***************************************************************************//** + The SPI_set_frame_rx_handler() function is used by the SPI slaves to specify + the receive handler function that is called by the SPI driver interrupt + handler when a frame of data is received by the SPI slave. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param rx_handler + The rx_handler parameter is a pointer to the frame receive handler that must + be called when a frame is received by the CoreSPI slave. Passing in a NULL + pointer disables the receive handler but does enable the receive interrupt to + ensure the RX FIFO is empty each time a frame is received. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + uint32_t g_slave_rx_frame = 0; + spi_instance_t g_spi0; + + void slave_frame_handler(uint32_t rx_frame) + { + g_slave_rx_frame = rx_frame; + } + int setup_slave( void ) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_slave_mode( &g_spi0 ); + SPI_set_frame_rx_handler( &g_spi0, slave_frame_handler ); + } + @endcode + */ +void SPI_set_frame_rx_handler +( + spi_instance_t * this_spi, + spi_frame_rx_handler_t rx_handler +); + +/***************************************************************************//** + The SPI_set_slave_tx_frame() function is used by the SPI slaves to specify + the frame that gets transmitted when a transaction is initiated by the SPI + master. This function allows you to assign a slave_tx_frame_handler function, + which will be executed upon transmit interrupt when the SPI is in slave mode. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param frame_value + The frame_value parameter contains the value of the frame to be sent to the + master. + Note: The bit length of the value to be transmitted to the master is + set when the CoreSPI is instantiated in the hardware design. + + @param slave_tx_frame_handler + The slave_tx_frame_handler function pointer is executed upon occurrence of + transmit interrupt when CoreSPI is operating in slave mode. This parameter + is optional and if set to NULL it is assumed that the frame value is static or + updated asynchronously. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + const uint32_t slave_tx_frame[2] = { 0x0110F761, 0x0110F671 }; + uint32_t master_rx; + uint32_t slave_frame_idx = 0 ; + + slave_frame_update( spi_instance_t * this_spi ) + { + this_spi->slave_tx_frame = slave_tx_frame[slave_frame_idx++]; + if( slave_frame_idx > 2 ) + slave_frame_idx = 0; + } + main() + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ) ; + SPI_set_slave_tx_frame( &g_spi0, slave_tx_frame[slave_frame_idx++], + &slave_frame_update ); + } + @endcode + */ +void SPI_set_slave_tx_frame +( + spi_instance_t * this_spi, + uint32_t frame_value, + spi_slave_frame_tx_handler_t slave_tx_frame_handler +); + +/***************************************************************************//** + The SPI_set_slave_block_buffers() function is used to configure an SPI slave + for block transfer operations. It specifies one or more of the following: + • The data that is transmitted when accessed by a master. + • The buffer where the data received from a master is stored. + • The handler function that must be called after the receive buffer has + been filled. + • The number of bytes that must be received from the master before calling + the recieve handler function. + These parameters allow the following use cases: + • Slave performing an action after receiving a block of data from a + master containing a command. This action is performed by the + receive handler based on the content of the receive data buffer. + • Slave returning a block of data to the master. The type of information + is always the same but the actual values change over time. For example, + returning the voltage of a predefined set of analog inputs. + • Slave returning data based on a command contained in the first part of + the SPI transaction. For example, reading the voltage of the analog + input specified by the first data byte by the master. This is achieved + by using the SPI_set_slave_block_buffers() function in conjunction with + functions SPI_set_cmd_handler() and SPI_set_cmd_response(). + + See the SPI_set_cmd_handler() function description for details of + this use case. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param tx_buffer + The tx_buffer parameter is a pointer to a buffer containing the data that + will be sent to the master. This parameter can be set to ‘0’ if the SPI + slave is not intended to be the target of SPI read transactions. + + @param tx_buff_size + The tx_buff_size parameter specifies the number of bytes that are + transmitted by the SPI slave. It is the number of bytes contained in the + tx_buffer. This parameter can be set to ‘0’ if the SPI slave is not + intended to be the target of SPI read transactions. The driver returns 0s + to the master if there is no buffer specified or the master reads beyond the + end of the buffer. + Note: If SPI_transfer_block() is used to read from this slave and there is + no command handler involved, the buffer size here must be at least the + combined length of the command and response specified by the master. + On receiving this data, the master discards the data bytes equal to + command length bytes from the start of the received buffer. + + @param rx_buffer + The rx_buffer parameter is a pointer to the buffer where data received + from the master is stored. This parameter can be set to ‘0’ if the + SPI slave is not intended to be the target of SPI write or write-read + transactions. + + @param rx_buff_size + The rx_buff_size parameter specifies the size of the receive buffer. It is + also the number of bytes that must be received before the receive handler + is called, if a receive handler is specified using the block_rx_handler + parameter. Any bytes received in excess of the size specified by the + rx_buff_size parameter are discarded. This parameter can be set to ‘0’ + if the SPI slave is not intended to be the target of SPI write or + write-read transactions. + + @param block_rx_handler + The block_rx_handler parameter is a pointer to a function that is called + when receive buffer has been filled or the slave select has been de-asserted. + This parameter can be set to ‘0’ if the SPI slave is not intended to be the + target of SPI write or write-read transactions. + + @return + This function does not return any value. + + @example + @code + Slave Performing Operation Based on Master Command: + In this example the SPI slave is configured to receive 10 bytes of data + or command from the SPI slave, and process the data received from the master. + + #define SPI0_BASE_ADDR 0xC2000000 + + uint32_t nb_of_rx_handler_calls = 0; + spi_instance_t g_spi0; + + void spi1_block_rx_handler_b + ( + uint8_t * rx_buff, + uint16_t rx_size + ) + { + ++nb_of_rx_handler_calls; + } + + void setup_slave( void ) + { + uint8_t slave_rx_buffer[10] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_slave_mode( &g_spi0 ); + + SPI_set_slave_block_buffers + ( + &g_spi0, + 0, + 0, + slave_rx_buffer, + sizeof( master_tx_buffer ), + spi1_block_rx_handler_b + ); + } + @endcode + */ +void SPI_set_slave_block_buffers +( + spi_instance_t * this_spi, + const uint8_t * tx_buffer, + uint32_t tx_buff_size, + uint8_t * rx_buffer, + uint32_t rx_buff_size, + spi_block_rx_handler_t block_rx_handler +); + +/***************************************************************************//** + The SPI_isr() function is the top level interrupt handler function for the + CoreSPI driver. You must call SPI_isr() from the system level + (CoreInterrupt and NVIC level) interrupt handler assigned to the interrupt + triggered by the CoreSPI SPIINT signal. Your system level interrupt handler + must also clear the system level interrupt triggered by the CoreSPI SPIINT + signal before returning, to prevent a re-assertion of the same interrupt. + + This function supports all types of interrupt triggered by CoreSPI. It is not + a complete interrupt handler by itself; rather, it is a top level wrapper that + abstracts CoreSPI command interrupt and slave mode transmit interrupt handling + by calling lower level handler functions specific to each type of CoreSPI + interrupt. You must create the lower level handler functions to suit your + application and register them with the driver through calling the + SPI_set_cmd_handler(), SPI_set_cmd_response(), and SPI_set_slave_tx_frame() + functions. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + + @example + @code + + Example of configuring a CoreInterrupt connected to the Fabric Interrupt on a + SmartFusion device to handle CoreSPI interrupt. + + #define #define SPI1_INT_IRQ_NB 0 + spi_instance_t g_spi0; + + Void CIC_irq1_handler(void) + { + SPI_isr( &g_spi0 ); + } + + void Fabric_IRQHandler( void ) + { + // Call the CoreInterrupt driver ISR to determine the source of the + // interrupt and call the relevant ISR registered to it. + CIC_irq_handler(); + + // Clear NVIC interrupt status to allow further interrupts + NVIC_ClearPendingIRQ( Fabric_IRQn ); + } + + main() + { + ... + + CIC_init( CIC_BASE_ADDR ); + + // Install handler for SPI IRQ + CIC_set_irq_handler( SPI0_INT_IRQ_NB, CIC_irq1_handler ); + + NVIC_ClearPendingIRQ( Fabric_IRQn ); + NVIC_EnableIRQ( Fabric_IRQn ); + + CIC_enable_irq( SPI1_INT_IRQ_NB ); + + ... + } + @endcode + */ +void SPI_isr +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_set_cmd_handler() function specifies a command handler function that + will be called when the number of bytes received reaches the command size + specified as cmd_size parameter. + + This function is used by the SPI slaves performing block transfers. Its + purpose is to allow an SPI slave to decide the data that will be returned to + the master while an SPI transaction is taking place. Typically, one or more + command bytes are sent by the master to request some specific data. The slave + interprets the command byte(s) while one or more turn-around bytes are + transmitted. The slave adjusts its transmit data buffer based on the command + during the turn around time. + + The following table provides an example of the use of this function where the + SPI slave returns data bytes D0 to D6 based on the value of a command. The + 3 bytes long command is made up of a command opcode byte followed by an + address byte followed by a size byte. The cmd_handler() function specified + through an earlier call to SPI_set_cmd_handler() is called by the CoreSPI + driver once the third byte is received. The cmd_handler() function + interprets the command bytes and calls SPI_set_cmd_response() to set the SPI + slave's response transmit buffer with the data to be transmitted after the + turnaround bytes (T0 to T3). The number of turnaround bytes must be + sufficient to give enough time for the cmd_handler() to execute. The number + of turnaround bytes is specified by the protocol used on top of the SPI + transport layer so that master and slave agree on the number of turn around + bytes. + +|Timestamp| SPI Transaction | Bytes | Comments | +|---------|-------------|----------------------|---------------| +| t0|COMMAND|C A S |C - command opcode byte, A - address byte, S - size byte| +|t1| TURN-AROUND|T0 T1 |cmd_handler() called here (T0 to T3 are TURN-AROUND bytes)| +|t2|TURN-AROUND|T2 T3|SPI_set_cmd_response() called here by implementation of cmd_handler() +|| | |to set the data that will be transmitted by the SPI slave.| +|t3| DATA | D0 D1 D2 D3 D4 D5 D6 |Data transmition (SPI slave return data bytes)| + + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure identifying + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @param cmd_handler + The cmd_handler parameter is a pointer to a function with the prototype: + void cmd_handler(uint8_t * rx_buff, uint32_t rx_size); + It specifies the function that will be called when the number of bytes + specified by the cmd_size parameter has been received. + + @param cmd_size + The cmd_size parameter specifies the number of bytes that must be received + before calling the command handler function specified by the cmd_handler. + The CoreSPI supports cmd_size values in the range 1 to 7. + + @return + This function does not return any value. + + @example + @code + The following example demonstrates how to configure CoreSPI to implement + the protocol given as an example above. The configure_slave() function + configures CoreSPI. It sets receive and transmit buffers. The transmit + buffer specified through the call to SPI_set_slave_block_buffers() function + specifies the data that will be returned to the master in bytes between + t0 and t3. These bytes will be sent to the master while the master transmits + the command and dummy bytes. The spi_slave_cmd_handler() function will be + called by the driver at time t1 after the 3 command bytes have been received. + The spi_block_rx_handler() function will be called by the driver at time t4, + when the transaction completes and the slave select signal becomes + de-asserted. + + #define SPI0_BASE_ADDR 0xC2000000 + #define COMMAND_SIZE 3 + #define NB_OF_DUMMY_BYTES 4 + #define MAX_TRANSACTION_SIZE 16 + + spi_instance_t g_spi0; + uint8_t slave_tx_buffer[COMMAND_SIZE + NB_OF_DUMMY_BYTES]; + uint8_t slave_rx_buffer[MAX_TRANSACTION_SIZE]; + + void configure_slave( void ) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_slave_mode( &g_spi0 ); + SPI_set_slave_block_buffers + ( + &g_spi0, + slave_tx_buffer, + COMMAND_SIZE + NB_OF_DUMMY_BYTES, + slave_rx_buffer, + sizeof(slave_rx_buffer), + spi_block_rx_handler + ); + + SPI_set_cmd_handler + ( + &g_spi0, + spi_slave_cmd_handler, + COMMAND_SIZE + ); + } + + void spi_slave_cmd_handler + ( + uint8_t * rx_buff, + uint32_t rx_size + ) + { + uint8_t command; + uint8_t address; + uint8_t size; + uint8_t * p_response; + uint32_t response_size; + + command = rx_buff[0]; + address = rx_buff[1]; + size = rx_buff[2]; + + p_response = get_response_data( command, address, size, &response_size ); + SPI_set_cmd_response( &g_spi0, p_response, response_size ); + } + + void spi_block_rx_handler + ( + uint8_t * rx_buff, + uint32_t rx_size + ) + { + process_rx_data( rx_buff, rx_size ); + } + @endcode + */ +void SPI_set_cmd_handler +( + spi_instance_t * this_spi, + spi_block_rx_handler_t cmd_handler, + uint32_t cmd_size +); + +/***************************************************************************//** + The SPI_set_cmd_response() function specifies the data that will be returned + to the master. See the description of SPI_set_cmd_handler() for details. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param resp_tx_buffer + The resp_tx_buffer parameter is a pointer to the buffer containing the data + that must be returned to the host in the data phase of an SPI transaction. + + @param resp_buff_size + The resp_buff_size parameter specifies the size of the buffer pointed by the + resp_tx_buffer parameter. + + @return + This function does not return any value. + */ +void SPI_set_cmd_response +( + spi_instance_t * this_spi, + const uint8_t * resp_tx_buffer, + uint32_t resp_buff_size +); + +/***************************************************************************//** + The SPI_enable() function enables the CoreSPI and allows it to respond to the external + signals. It is usually called to re-enable a CoreSPI instance which has been + disabled previously via by calling the SPI_disable() as the normal state of a CoreSPI + after enabling the initialization. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + */ +void SPI_enable +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_disable() function disables the CoreSPI and stops responding to the + external signals. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + */ +void SPI_disable +( + spi_instance_t * this_spi +); + +#ifdef __cplusplus +} +#endif + +#endif /* CORE_SPI_H_*/ diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreSPI/corespi_regs.h b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreSPI/corespi_regs.h new file mode 100644 index 0000000..a3e5b2a --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreSPI/corespi_regs.h @@ -0,0 +1,270 @@ +/***************************************************************************//** + * Copyright 2011-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file corespi_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreSPI memory map + * + */ + +#ifndef CORESPI_REGS_H_ +#define CORESPI_REGS_H_ + +/******************************************************************************* + * Control register 1: + *------------------------------------------------------------------------------ + */ +#define CTRL1_REG_OFFSET 0x00u + +#define CTRL1_ENABLE_OFFSET 0x00u +#define CTRL1_ENABLE_MASK 0x01u +#define CTRL1_ENABLE_SHIFT 0x00 + +#define CTRL1_MASTER_OFFSET 0x00u +#define CTRL1_MASTER_MASK 0x02u +#define CTRL1_MASTER_SHIFT 0x01 + +#define CTRL1_INTRXDATA_OFFSET 0x00u +#define CTRL1_INTRXDATA_MASK 0x04u +#define CTRL1_INTRXDATA_SHIFT 0x02 + +#define CTRL1_INTTXDONE_OFFSET 0x00u +#define CTRL1_INTTXDONE_MASK 0x08u +#define CTRL1_INTTXDONE_SHIFT 0x03 + +#define CTRL1_INTRXOVFLOW_OFFSET 0x00u +#define CTRL1_INTRXOVFLOW_MASK 0x10u +#define CTRL1_INTRXOVFLOW_SHIFT 0x04 + +#define CTRL1_INTTXURUN_OFFSET 0x00u +#define CTRL1_INTTXURUN_MASK 0x20u +#define CTRL1_INTTXURUN_SHIFT 0x05 + +#define CTRL1_FRAMEURUN_OFFSET 0x00u +#define CTRL1_FRAMEURUN_MASK 0x40u +#define CTRL1_FRAMEURUN_SHIFT 0x06 + +#define CTRL1_OENOFF_OFFSET 0x00u +#define CTRL1_OENOFF_MASK 0x80u +#define CTRL1_OENOFF_SHIFT 0x07 + +/******************************************************************************* + * Interrupt clear register: + *------------------------------------------------------------------------------ + */ +#define INTCLR_REG_OFFSET 0x04u + +#define INTCLR_TXDONE_OFFSET 0x04u +#define INTCLR_TXDONE_MASK 0x01u +#define INTCLR_TXDONE_SHIFT 0x00 + +#define INTCLR_RXDONE_OFFSET 0x04u +#define INTCLR_RXDONE_MASK 0x02u +#define INTCLR_RXDONE_SHIFT 0x01 + +#define INTCLR_RXOVERFLOW_OFFSET 0x04u +#define INTCLR_RXOVERFLOW_MASK 0x04u +#define INTCLR_RXOVERFLOW_SHIFT 0x02 + +#define INTCLR_TXUNDERRUN_OFFSET 0x04u +#define INTCLR_TXUNDERRUN_MASK 0x08u +#define INTCLR_TXUNDERRUN_SHIFT 0x03 + +#define INTCLR_CMDINT_OFFSET 0x04u +#define INTCLR_CMDINT_MASK 0x10u +#define INTCLR_CMDINT_SHIFT 0x04 + +#define INTCLR_SSEND_OFFSET 0x04u +#define INTCLR_SSEND_MASK 0x20u +#define INTCLR_SSEND_SHIFT 0x05 + +#define INTCLR_RXDATA_OFFSET 0x04u +#define INTCLR_RXDATA_MASK 0x40u +#define INTCLR_RXDATA_SHIFT 0x06 + +#define INTCLR_TXDATA_OFFSET 0x04u +#define INTCLR_TXDATA_MASK 0x80u +#define INTCLR_TXDATA_SHIFT 0x07 + +/******************************************************************************* + * Receive data register: + *------------------------------------------------------------------------------ + */ +#define RXDATA_REG_OFFSET 0x08u + +/******************************************************************************* + * Transmit data register: + *------------------------------------------------------------------------------ + */ +#define TXDATA_REG_OFFSET 0x0Cu + +/******************************************************************************* + * Masked interrupt status register: + *------------------------------------------------------------------------------ + */ +#define INTMASK_REG_OFFSET 0x10u + +#define INTMASK_TXDONE_OFFSET 0x10u +#define INTMASK_TXDONE_MASK 0x01u +#define INTMASK_TXDONE_SHIFT 0x00 + +#define INTMASK_RXDONE_OFFSET 0x10u +#define INTMASK_RXDONE_MASK 0x02u +#define INTMASK_RXDONE_SHIFT 0x01 + +#define INTMASK_RXOVERFLOW_OFFSET 0x10u +#define INTMASK_RXOVERFLOW_MASK 0x04u +#define INTMASK_RXOVERFLOW_SHIFT 0x02 + +#define INTMASK_TXUNDERRUN_OFFSET 0x10u +#define INTMASK_TXUNDERRUN_MASK 0x08u +#define INTMASK_TXUNDERRUN_SHIFT 0x03 + +#define INTMASK_CMDINT_OFFSET 0x10u +#define INTMASK_CMDINT_MASK 0x10u +#define INTMASK_CMDINT_SHIFT 0x04 + +#define INTMASK_SSEND_OFFSET 0x10u +#define INTMASK_SSEND_MASK 0x20u +#define INTMASK_SSEND_SHIFT 0x05 + +#define INTMASK_RXDATA_OFFSET 0x10u +#define INTMASK_RXDATA_MASK 0x40u +#define INTMASK_RXDATA_SHIFT 0x06 + +#define INTMASK_TXDATA_OFFSET 0x10u +#define INTMASK_TXDATA_MASK 0x80u +#define INTMASK_TXDATA_SHIFT 0x07 + +/******************************************************************************* + * Raw interrupt status register: + *------------------------------------------------------------------------------ + */ +#define INTRAW_REG_OFFSET 0x14u + +#define INTRAW_TXDONE_OFFSET 0x14u +#define INTRAW_TXDONE_MASK 0x01u +#define INTRAW_TXDONE_SHIFT 0x00 + +#define INTRAW_RXDONE_OFFSET 0x14u +#define INTRAW_RXDONE_MASK 0x02u +#define INTRAW_RXDONE_SHIFT 0x01 + +#define INTRAW_RXOVERFLOW_OFFSET 0x14u +#define INTRAW_RXOVERFLOW_MASK 0x04u +#define INTRAW_RXOVERFLOW_SHIFT 0x02 + +#define INTRAW_TXUNDERRUN_OFFSET 0x14u +#define INTRAW_TXUNDERRUN_MASK 0x08u +#define INTRAW_TXUNDERRUN_SHIFT 0x03 + +#define INTRAW_CMDINT_OFFSET 0x14u +#define INTRAW_CMDINT_MASK 0x10u +#define INTRAW_CMDINT_SHIFT 0x04 + +#define INTRAW_SSEND_OFFSET 0x14u +#define INTRAW_SSEND_MASK 0x20u +#define INTRAW_SSEND_SHIFT 0x05 + +#define INTRAW_RXDATA_OFFSET 0x14u +#define INTRAW_RXDATA_MASK 0x40u +#define INTRAW_RXDATA_SHIFT 0x06 + +#define INTRAW_TXDATA_OFFSET 0x14u +#define INTRAW_TXDATA_MASK 0x80u +#define INTRAW_TXDATA_SHIFT 0x07 + +/******************************************************************************* + * Control register 2: + *------------------------------------------------------------------------------ + */ +#define CTRL2_REG_OFFSET 0x18u + +#define CTRL2_CMDSIZE_OFFSET 0x18u +#define CTRL2_CMDSIZE_MASK 0x07u +#define CTRL2_CMDSIZE_SHIFT 0x00 + +#define CTRL2_INTCMD_OFFSET 0x18u +#define CTRL2_INTCMD_MASK 0x10u +#define CTRL2_INTCMD_SHIFT 0x04 + +#define CTRL2_INTSSEND_OFFSET 0x18u +#define CTRL2_INTSSEND_MASK 0x20u +#define CTRL2_INTSSEND_SHIFT 0x05 + +#define CTRL2_INTRXDATA_OFFSET 0x18u +#define CTRL2_INTRXDATA_MASK 0x40u +#define CTRL2_INTRXDATA_SHIFT 0x06 + +#define CTRL2_INTTXDATA_OFFSET 0x18u +#define CTRL2_INTTXDATA_MASK 0x80u +#define CTRL2_INTTXDATA_SHIFT 0x07 + +/******************************************************************************* + * Command register: + *------------------------------------------------------------------------------ + */ +#define CMD_REG_OFFSET 0x1Cu + +#define CMD_RXFIFORST_OFFSET 0x1Cu +#define CMD_RXFIFORST_MASK 0x01u +#define CMD_RXFIFORST_SHIFT 0x00 + +#define CMD_TXFIFORST_OFFSET 0x1Cu +#define CMD_TXFIFORST_MASK 0x02u +#define CMD_TXFIFORST_SHIFT 0x01 + +/******************************************************************************* + * Status register: + *------------------------------------------------------------------------------ + */ +#define STATUS_REG_OFFSET 0x20u + +#define STATUS_FIRSTFRAME_OFFSET 0x20u +#define STATUS_FIRSTFRAME_MASK 0x01u +#define STATUS_FIRSTFRAME_SHIFT 0x00 + +#define STATUS_DONE_OFFSET 0x20u +#define STATUS_DONE_MASK 0x02u +#define STATUS_DONE_SHIFT 0x01 + +#define STATUS_RXEMPTY_OFFSET 0x20u +#define STATUS_RXEMPTY_MASK 0x04u +#define STATUS_RXEMPTY_SHIFT 0x02 + +#define STATUS_TXFULL_OFFSET 0x20u +#define STATUS_TXFULL_MASK 0x08u +#define STATUS_TXFULL_SHIFT 0x03 + +#define STATUS_RXOVFLOW_OFFSET 0x20u +#define STATUS_RXOVFLOW_MASK 0x10u +#define STATUS_RXOVFLOW_SHIFT 0x04 + +#define STATUS_TXUNDERRUN_OFFSET 0x20u +#define STATUS_TXUNDERRUN_MASK 0x20u +#define STATUS_TXUNDERRUN_SHIFT 0x05 + +#define STATUS_SSEL_OFFSET 0x20u +#define STATUS_SSEL_MASK 0x40u +#define STATUS_SSEL_SHIFT 0x06 + +#define STATUS_ACTIVE_OFFSET 0x20u +#define STATUS_ACTIVE_MASK 0x80u +#define STATUS_ACTIVE_SHIFT 0x07 + +/******************************************************************************* + * Slave select register: + *------------------------------------------------------------------------------ + */ +#define SSEL_REG_OFFSET 0x24u + +/******************************************************************************* + * Transmit data last register: + *------------------------------------------------------------------------------ + */ +#define TXLAST_REG_OFFSET 0x28u + + +#endif /*CORESPI_REGS_H_*/ diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.c b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.c new file mode 100644 index 0000000..b8adaed --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.c @@ -0,0 +1,889 @@ +/******************************************************************************* + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * PF_System_Services driver implementation. See file "core_syservices_pf.h" for + * description of the functions implemented in this file. + * + */ + +#include "core_sysservices_pf.h" +#include "coresysservicespf_regs.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define NULL_BUFFER (( uint8_t* ) 0) + +static uint8_t execute_ss_command +( + uint8_t cmd_opcode, + const uint8_t* cmd_data, + uint16_t cmd_data_size, + const uint8_t* p_response, + uint16_t response_size, + uint16_t mb_offset, + uint16_t response_offset +); + +uint32_t g_css_pf_base_addr = 0u; + +/***************************************************************************//** + * SYS_init() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +void +SYS_init +( + uint32_t base_addr +) +{ + g_css_pf_base_addr = base_addr; +} + +/***************************************************************************//** + * SYS_get_serial_number() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_serial_number +( + const uint8_t * p_serial_number, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if (p_serial_number == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(SERIAL_NUMBER_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_serial_number, + SERIAL_NUMBER_RESP_LEN, + mb_offset, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_get_user_code() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_user_code +( + const uint8_t * p_user_code, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_user_code == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(USERCODE_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_user_code, + USERCODE_RESP_LEN, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_get_design_info() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_design_info +( + const uint8_t * p_design_info, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_design_info == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(DESIGN_INFO_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_design_info, + DESIGN_INFO_RESP_LEN, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_get_device_certificate() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_device_certificate +( + const uint8_t * p_device_certificate, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_device_certificate == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(DEVICE_CERTIFICATE_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_device_certificate, + DEVICE_CERTIFICATE_RESP_LEN, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_read_digest() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_read_digest +( + const uint8_t * p_digest, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_digest == NULL_BUFFER) + { + return status; + } + +#ifndef CORESYSSERVICES_MPFS + status = execute_ss_command(READ_DIGEST_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_digest, + READ_DIGEST_RESP_LEN, + mb_offset, + 0u); +#else + status = execute_ss_command(READ_DIGEST_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_digest, + READ_DIGEST_MPFS_RESP_LEN, + mb_offset, + 0u); +#endif + return status; + +} + +/***************************************************************************//** + * SYS_query_security() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_query_security +( + uint8_t * p_security_locks, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint8_t idx = 0u; + + if(p_security_locks == NULL_BUFFER) + { + return status; + } + +#ifndef CORESYSSERVICES_MPFS + uint8_t buf[12] = {0}; + /* Actual QUERY_SECURITY_RESP_LEN is 9 or 33 but PF_System_Services core + * needs number of words instead of number of bytes to be written to or read + * from MailBox */ + status = execute_ss_command(QUERY_SECURITY_REQUEST_CMD, + NULL_BUFFER, + 0u, + buf, + (QUERY_SECURITY_RESP_LEN + 3u), + mb_offset, + 0u); + + for (idx = 0u; idx < 9u; idx++) + { + *(p_security_locks+idx) = buf[idx]; + } + +#else + uint8_t buf[36] = {0}; + + status = execute_ss_command(QUERY_SECURITY_REQUEST_CMD, + NULL_BUFFER, + 0u, + buf, + (QUERY_SECURITY_MPFS_RESP_LEN + 3u), + mb_offset, + 0u); + + for (idx = 0u; idx < 33u; idx++) + { + *(p_security_locks+idx) = buf[idx]; + } + +#endif + + return status; +} + +/***************************************************************************//** + * SYS_read_debug_info() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_read_debug_info +( + const uint8_t * p_debug_info, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_debug_info == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(READ_DEBUG_INFO_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_debug_info, + READ_DEBUG_INFO_RESP_LEN, + mb_offset, + 0u); + return status; +} + +#ifdef CORESYSSERVICES_MPFS +/***************************************************************************//** + * SYS_read_envm_parameter() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_read_envm_parameter +( + uint8_t * p_envm_param, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_envm_param == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(READ_ENVM_PARAM_REQUEST_CMD, + NULL_BUFFER, + 0, + p_envm_param, + READ_ENVM_PARAM_RESP_LEN, + mb_offset, + 0); + return status; +} + +#endif + +/***************************************************************************//** + * SYS_puf_emulation_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_puf_emulation_service +( + const uint8_t * p_challenge, + uint8_t op_type, + uint8_t* p_response, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint8_t mb_format[20] = {0x00}; + uint8_t index = 0u; + + if((p_response == NULL_BUFFER) || (p_challenge == NULL_BUFFER)) + { + return status; + } + + /* Frame the data required for mailbox */ + mb_format[index] = op_type; + + for (index = 4u; index < 20u; index++) + { + mb_format[index] = p_challenge[index - 4u]; + } + + status = execute_ss_command(PUF_EMULATION_SERVICE_REQUEST_CMD, + mb_format, + PUF_EMULATION_SERVICE_CMD_LEN, + p_response, + PUF_EMULATION_SERVICE_RESP_LEN, + mb_offset, + 5u); /* mentioning offset to number of words instead of bytes */ + + return status; +} + +/***************************************************************************//** + * SYS_digital_signature_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_digital_signature_service +( + const uint8_t* p_hash, + uint8_t format, + uint8_t* p_response, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if((p_hash == NULL_BUFFER) || (p_response == NULL_BUFFER)) + { + return status; + } + + if (format == DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD) + { + status = execute_ss_command(DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD, + p_hash, + DIGITAL_SIGNATURE_HASH_LEN, + p_response, + DIGITAL_SIGNATURE_RAW_FORMAT_RESP_SIZE, + mb_offset, + 12u); /* mentioning offset to number of words instead of bytes */ + } + else + { + status = execute_ss_command(DIGITAL_SIGNATURE_DER_FORMAT_REQUEST_CMD, + p_hash, + DIGITAL_SIGNATURE_HASH_LEN, + p_response, + DIGITAL_SIGNATURE_DER_FORMAT_RESP_SIZE, + mb_offset, + 12u); /* mentioning offset to number of words instead of bytes */ + } + + return status; +} + +/***************************************************************************//** + * SYS_secure_nvm_write() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_secure_nvm_write +( + uint8_t format, + uint8_t snvm_module, + const uint8_t* p_data, + const uint8_t* p_user_key, + uint16_t mb_offset +) +{ + uint8_t frame[256] = {0x00}; + uint8_t* p_frame = &frame[0]; + uint16_t index = 0u; + uint8_t status = SYS_PARAM_ERR; + + HAL_ASSERT(!(NULL_BUFFER == p_data)); + HAL_ASSERT(!(snvm_module >= 221u)); + if (format != SNVM_NON_AUTHEN_TEXT_REQUEST_CMD) + { + HAL_ASSERT(!(NULL_BUFFER == p_user_key)); + } + + if ((p_data == NULL_BUFFER) || (snvm_module >= 221)) + { + return status; + } + + if ((format != SNVM_NON_AUTHEN_TEXT_REQUEST_CMD) + && (p_user_key == NULL_BUFFER)) + { + return status; + } + + if ((format != SNVM_NON_AUTHEN_TEXT_REQUEST_CMD) + && (format != SNVM_AUTHEN_TEXT_REQUEST_CMD) + && (format != SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD)) + { + return status; + } + + *p_frame = snvm_module; /* SNVMADDR - SNVM module */ + + p_frame += 4u; /* Next 3 bytes RESERVED - For alignment */ + + /* Copy user key and send the command/data to mailbox. */ + if ((format == SNVM_AUTHEN_TEXT_REQUEST_CMD) || + (format == SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD)) + { + /* Copy user data */ + for (index = 0u; index < (AUTHENTICATED_TEXT_DATA_LEN - USER_SECRET_KEY_LEN - 4u); index++) + { + *p_frame = p_data[index]; + p_frame++; + } + + /* Copy user key */ + for (index = 0u; index < USER_SECRET_KEY_LEN; index++) + { + *p_frame = p_user_key[index]; + p_frame++; + } + + status = execute_ss_command(format, + &frame[0], + AUTHENTICATED_TEXT_DATA_LEN, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + } + else + { + /* Copy user data */ + for (index = 0u; index < (NON_AUTHENTICATED_TEXT_DATA_LEN - 4u); index++) + { + *(p_frame+index) = p_data[index]; + } + + status = execute_ss_command(format, + &frame[0], + NON_AUTHENTICATED_TEXT_DATA_LEN, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + } + + return status; +} + +/***************************************************************************//** + * SYS_secure_nvm_read() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_secure_nvm_read +( + uint8_t snvm_module, + const uint8_t* p_user_key, + uint8_t* p_admin, + uint8_t* p_data, + uint16_t data_len, + uint16_t mb_offset +) +{ + /* Frame the message. */ + uint8_t frame[16] = {0x00u}; + uint8_t* p_frame = &frame[0u]; + uint8_t status = SYS_PARAM_ERR; + uint8_t response[256] = {0x00u}; + uint16_t index = 0u; + + HAL_ASSERT(!(NULL_BUFFER == p_data)); + HAL_ASSERT(!(NULL_BUFFER == p_admin)); + HAL_ASSERT(!(snvm_module > 221u)); + + HAL_ASSERT(data_len == 236u || data_len == 252u); + + if((p_data == NULL_BUFFER) || + (snvm_module >= 221) || + (p_admin == NULL_BUFFER)) + { + return status; + } + + *p_frame = snvm_module; /* SNVMADDR - SNVM module */ + + p_frame += 4u; /* RESERVED - For alignment */ + + /* Copy user key */ + if (236u == data_len) + { + HAL_ASSERT(p_user_key != NULL_BUFFER); + + if(p_user_key == NULL_BUFFER) + { + return status; + } + + for (index = 0u; index < 12u; index++) + { + *p_frame = p_user_key[index]; + p_frame++; + } + } + else + { + p_frame += 12u; + } + + status = execute_ss_command(SNVM_READ_REQUEST_CMD, + &frame[0], + 16u, + response, + (data_len + 4u), + mb_offset, + 4u); /* mentioning offset to number of words instead of bytes */ + + if (SYS_SUCCESS == status) + { + for (index = 0u; index < 4u; index++) + { + *(p_admin+index) = (uint32_t)response[index]; + } + + + /* Copy data into user buffer. */ + for (index = 4u; index < (data_len + 4u); index++) + { + *(p_data + (index - 4u)) = response[index]; + } + } + else + { + ; + } + + return status; +} + +/***************************************************************************//** + * SYS_nonce_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_nonce_service +( + const uint8_t * p_nonce, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if((p_nonce == NULL_BUFFER)) + { + return status; + } + + status = execute_ss_command(NONCE_SERVICE_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_nonce, + NONCE_SERVICE_RESP_LEN, + mb_offset, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_bitstream_authenticate_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_bitstream_authenticate_service +( + uint32_t spi_flash_address, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint32_t l_spi_flash_address = spi_flash_address; + status = execute_ss_command(BITSTREAM_AUTHENTICATE_CMD, + (uint8_t* )&l_spi_flash_address, + 4u, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_IAP_image_authenticate_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_IAP_image_authenticate_service +( + uint8_t spi_idx +) +{ + uint8_t status = SYS_PARAM_ERR; + + HAL_ASSERT(!(spi_idx == 1u)); + + if (spi_idx == 1u) + { + return status; + } + + status = execute_ss_command(IAP_BITSTREAM_AUTHENTICATE_CMD, + NULL_BUFFER, + 0u, + NULL_BUFFER, + 0u, + spi_idx, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_digest_check_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_digest_check_service +( + uint32_t options, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint32_t l_options = options; + + status = execute_ss_command(DIGEST_CHECK_CMD, + (uint8_t* )&l_options, + 4u, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_iap_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_iap_service +( + uint8_t iap_cmd, + uint32_t spiaddr, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint16_t l_mb_offset = 0u; + uint16_t cmd_data_size = 0u; + uint8_t* cmd_data = NULL_BUFFER; + bool invalid_param = false; + + if (((IAP_PROGRAM_BY_SPIIDX_CMD == iap_cmd) + || (IAP_VERIFY_BY_SPIIDX_CMD == iap_cmd)) + && (1u == spiaddr)) + { + invalid_param = true; + HAL_ASSERT(!invalid_param); + } + + if (!invalid_param) + { + switch(iap_cmd) + { + case IAP_PROGRAM_BY_SPIIDX_CMD: + case IAP_VERIFY_BY_SPIIDX_CMD: + /*In SPI_IDX based program and verify commands, + * Mailbox is not Required. Instead of mailbox offset + * SPI_IDX is passed as parameter.*/ + l_mb_offset = (uint16_t)(0xFFu & spiaddr); + break; + + case IAP_PROGRAM_BY_SPIADDR_CMD: + case IAP_VERIFY_BY_SPIADDR_CMD: + /*In SPI_ADDR based program and verify commands, + * Mailbox is Required*/ + l_mb_offset = mb_offset; + /*command data size is four bytes holding the + * SPI Address in it.*/ + cmd_data_size = 4u; + cmd_data = (uint8_t*)&spiaddr; + break; + + case IAP_AUTOUPDATE_CMD: + /*In auto update command Mailbox is not Required*/ + l_mb_offset = 0u; + break; + + default: + l_mb_offset = 0u; + + } + + status = execute_ss_command( + (uint8_t)iap_cmd, + cmd_data, + cmd_data_size, + NULL_BUFFER, + 0, + (uint16_t)l_mb_offset, + 0); + } + + return status; +} + +/***************************************************************************//** + Internal functions. +*/ +/* +This function executes the SS command. If Mailbox input data is required by the +it will first load it from cmd_data into the Mailbox. If the service requires +the response data to be read from mailbox, it will do so and store it in p_response. +*/ +static uint8_t execute_ss_command +( + uint8_t cmd_opcode, + const uint8_t* cmd_data, + uint16_t cmd_data_size, + const uint8_t* p_response, + uint16_t response_size, + uint16_t mb_offset, + uint16_t response_offset +) +{ + /* Pointer used during Writing to Mailbox memory. */ + uint32_t status = 0u; + uint16_t idx = 0u; + uint16_t ss_command = 0u; + uint32_t* word_buf; + uint16_t timeout_count = SS_TIMEOUT_COUNT; + + /* making sure that the system controller is not executing any service i.e. + SS_USER_BUSY is gone 0 */ + + while (1u == HAL_get_32bit_reg_field(g_css_pf_base_addr, SS_USER_BUSY)) + { + --timeout_count; + + if (timeout_count == 0) + { + return SS_USER_BUSY_TIMEOUT; + } + } + + /* Form the SS command: bit 0to6 is the opcode, bit 7to15 is the Mailbox offset + For some services this field has another meaning + (e.g. for IAP bitstream auth. it means spi_idx) */ + ss_command = ((mb_offset << 7u) | (cmd_opcode & 0x7Fu)); + + /* Load the command register with the SS request command code*/ + HAL_set_32bit_reg(g_css_pf_base_addr, SS_CMD, ss_command); + + if (cmd_data_size > 0u) + { + HAL_ASSERT(!(NULL_BUFFER == cmd_data)); + HAL_ASSERT(!(cmd_data_size % 4u)); + + /* Load the MBX_WCNT register with number of words */ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_WCNT, (cmd_data_size/4u)); + + /* Load the MBX_WADDR register with offset of input data (write to Mailbox) + For all the services this offset remains either 0 or Not applicable + for the services in which no Mailbox write is required.*/ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_WADDR, (0x00u + mb_offset)); + + } + + if (response_size > 0u) + { + HAL_ASSERT(!(NULL_BUFFER == p_response)); + HAL_ASSERT(!(response_size % 4u)); + + /* + Load the MBX_RWCNT register with number of words to be read from Mailbox + */ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_RCNT, (response_size/4u)); + + /* + Load the MBX_RADRDESC register with offset address within the mailbox + format for that particular service. + It will be 0 for the services where there is no output data from G5CONTROL + is expected. + This function assumes that this value is pre-calculated by service specific + functions as this value is fixed for each service. + */ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_RADDR, (response_offset + mb_offset)); + } + + /*Set the request bit in SYS_SERV_REQ register to start the service*/ + HAL_set_32bit_reg_field(g_css_pf_base_addr, SS_REQ_REQ, 0x01u); + + if (cmd_data_size > 0u) + { + word_buf = (uint32_t*)cmd_data; + + /* Write the user data into mail box. */ + for (idx = 0u; idx < (cmd_data_size/4u); idx++) + { + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_WDATA, word_buf[idx]); + } + } + + timeout_count = SS_TIMEOUT_COUNT; + if (response_size > 0u) + { + word_buf = (uint32_t*)p_response; + + for (idx = 0u; idx < (response_size/4u); idx++) + { + while (0u == HAL_get_32bit_reg_field(g_css_pf_base_addr, + SS_USER_RDVLD)) + { + --timeout_count; + + if (timeout_count == 0) + { + return SS_USER_RDVLD_TIMEOUT; + } + } + word_buf[idx] = HAL_get_32bit_reg(g_css_pf_base_addr, MBX_RDATA); + } + } + + timeout_count = SS_TIMEOUT_COUNT; + /* make sure that service is complete i.e. SS_USER_BUSY is gone 0 */ + while (1u == HAL_get_32bit_reg_field(g_css_pf_base_addr, SS_USER_BUSY)) + { + --timeout_count; + + if (timeout_count == 0) + { + return SS_USER_RDVLD_TIMEOUT; + } + } + + /* Read the status returned by System Controller */ + status = HAL_get_32bit_reg(g_css_pf_base_addr, SS_STAT); + + return (uint8_t)status; +} + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h new file mode 100644 index 0000000..8e0ebb6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h @@ -0,0 +1,1249 @@ +/******************************************************************************* + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the + * CoreSysServices_PF bare metal driver. + */ +/*=========================================================================*//** + @mainpage CoreSysServices_PF Bare Metal Driver. + + @section intro_sec Introduction + The PolarFire System Services (PF_SYSTEM_SERVICES) SgCore enables executing + the system services on the PolarFire and PolarFire SoC device. The system services + are the system controller actions initiated by the System Controller's System + Service Interface (SSI). The PolarFire System Services "SgCore" provides a + method to initiate these system services. The PF_SYSTEM_SERVICES interacts + with the system controller on SSI and Mailbox interface to initiate system + services, exchange data required for that services, and to know the successful + completion or error status. + + The PF_SYSTEM_SERVICES provides an APB interface for controlling the registers + functions for controlling the PF_SYSTEM_SERVICES as part of a bare metal system + register implemented within it. This software driver provides a set of where no + part of an operating system but the implementation of the adaptation layer + operating system is available. This driver is adapted for use in + between this driver and the operating system's driver model is outside the + scope of this driver. + + ## Features + The CoreSysServices_PF driver provides the following features: + - Executing device and design information services + - Executing design services + - Executing data security services + - Executing Fabric services + + The CoreSysServices_PF driver is provided as C source code. + + @section Driver Configuration + The application software should configure the CoreSysServices_PF driver through + calling the SYS_init() function. Only one instance of PF_SYSTEM_SERVICES SgCore is + supported. No additional configuration files are required to use the driver. + If using this driver on RT PolarFire device FPGA, define RT_DEVICE_FAMILY + macro in application. + + @section theory_op Theory of Operation + The CoreSysServices_PF driver provides access to the PolarFire system services. + These system services are grouped into the following categories: + + Device and Design Information Service + - Serial Number Service + - USERCODE Service + - Design Info Service + - Device Certificate Services + - Read Digests + - Query Security + - Read Debug Info + - Read eNVM param + + Design Services + - Bitstream authentication service + - IAP bitstream authentication service + + Data Security Services + - Digital Signature Service + - Secure NVM (SNVM) Functions + - PUF Emulation Service + - Nonce Service + + Fabric Services + - Digest Check Service + - In Application programming(IAP)/Auto-Update service + + Initialization and Configuration + + The CoreSysServices_PF driver is initialized by calling the SYS_init() + function. The SYS_init() function must be called before calling any other + CoreSysServices_PF driver functions. + + Device and Design Information Services + + The CoreSysServices_PF driver is used to read information about the device + and the design using the following functions: + - SYS_get_serial_number() + - SYS_get_user_code() + - SYS_get_design_info() + - SYS_get_device_certificate() + - SYS_read_digest() + - SYS_query_security() + - SYS_read_debug_info() + + Design Authentication Services + + The CoreSysServices_PF driver is used to execute design services using the + following functions: + - SYS_bitstream_authenticate_service() + - SYS_IAP_image_authenticate_service() + + Data Security Services + + The CoreSysServices_PF driver is used to execute data security services + using the following functions: + - SYS_digital_signature_service() + - SYS_secure_nvm_write() + - SYS_secure_nvm_read() + - SYS_puf_emulation_service () + - SYS_nonce_service () + + Executing Fabric Services + + The CoreSysServices_PF driver is used to execute fabric services using the + following functions: + - SYS_digest_check_service() + - SYS_iap_service() + + All the service execution functions return the 8-bit status, which is returned + by the system controller on executing the given service. A '0' value indicates + successful execution of that service. A non-zero value indicates error. + The error codes for each service are different. See individual function + description to know the exact meanings of the error codes for each service. + + The function descriptions in this file mainly focus on the details required + by the user to use the APIs provided by this driver to execute the services. + To know the complete details of the system services, see the + PolarFire FPGA and PolarFire SoC FPGA System Services [document](https://onlinedocs.microchip.com/pr/GUID-1409CF11-8EF9-4C24-A94E-70979A688632-en-US-3/index.html) + + *//*=========================================================================*/ +#ifndef __CORE_SYSSERV_PF_H +#define __CORE_SYSSERV_PF_H 1 + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#include "hal_assert.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** +* # Service Execution Success and Error Status Codes +* +* The following status codes are the return values from the system service functions. +* For any service, a return value '0' indicates that the service was executed +* successfully. A non-zero return value indicates that the service was not +* executed successfully. For all the services, the return value represents the +* status code returned by the system controller for the respective service, +* except the values SYS_PARAM_ERR, SS_USER_BUSY_TIMEOUT, and SS_USER_RDVLD_TIMEOUT. +* These three values indicate the error conditions detected by this driver and +* they do not overlap with the status code returned by the system controller for +* any of the system service. +* +* SYS_SUCCESS +* System service executed successfully +* +* SYS_PARAM_ERR +* System service cannot be executed as one or more parameters are not as +* expected by this driver. No read/write access is performed with the +* IP. +* +* SS_USER_BUSY_TIMEOUT +* The System service request is initiated and the driver timed-out while +* waiting for the system service to complete. The System Service +* completion is indicated by de-assertion of the SS_USER_BUSY bit by the +* IP. +* +* SS_USER_RDVLD_TIMEOUT +* The System service request is initiated and the driver timed-out while +* waiting for SS_USER_RDVLD bit, which indicates availability of data to +* be read from the mailbox, to become active. +*/ +#define SYS_SUCCESS 0u +#define SYS_PARAM_ERR 0xFFu +#define SS_USER_BUSY_TIMEOUT 0xFAu +#define SS_USER_RDVLD_TIMEOUT 0xFBu + +/** +* # System Service Timeout Count +* +* The SS_TIMEOUT_COUNT value is used by the driver as a timeout count +* while waiting for either the SS_USER_BUSY or SS_USER_RDVLD. This empirical +* value is sufficiently large so that the operations are falsely +* timeout in the normal circumstance. It is provided as a way to provide +* more debug information to the application in case there are some +* unforeseen issues. You may change this value for your need based on your +* system design. +*/ +#define SS_TIMEOUT_COUNT 40000u +/* + * SYS_DCF_DEVICE_MISMATCH + * Public key or FSN do not match device + * + * + * SYS_DCF_INVALID_SIGNATURE + * Certificate signature is invalid + * + * SYS_DCF_SYSTEM_ERROR + * PUF or storage failure + */ +#define SYS_DCF_DEVICE_MISMATCH 1u +#define SYS_DCF_INVALID_SIGNATURE 2u +#define SYS_DCF_SYSTEM_ERROR 3u + +/* + * SYS_NONCE_PUK_FETCH_ERROR + * Error fetching PUK + * + * SYS_NONCE_SEED_GEN_ERROR + * Error generating seed + */ +#define SYS_NONCE_PUK_FETCH_ERROR 1u +#define SYS_NONCE_SEED_GEN_ERROR 2u + +/** + * # Secure Nvm Write Error Codes + * + * SNVM_WRITE_INVALID_SNVMADDR + * Illegal page address + * + * SNVM_WRITE_FAILURE + * PNVM program/verify failed + * + * SNVM_WRITE_SYSTEM_ERROR + * PUF or storage failure + * + * SNVM_WRITE_NOT_PERMITTED + * Write is not permitted + */ +#define SNVM_WRITE_INVALID_SNVMADDR 1u +#define SNVM_WRITE_FAILURE 2u +#define SNVM_WRITE_SYSTEM_ERROR 3u +#define SNVM_WRITE_NOT_PERMITTED 4u + +/** + * # Secure Nvm Read Error Codes + * + * SNVM_READ_INVALID_SNVMADDR + * Illegal page address + * + * SNVM_READ_AUTHENTICATION_FAILURE + * Storage corrupt or incorrect USK + * + * SNVM_READ_SYSTEM_ERROR + * PUF or storage failure + * + */ +#define SNVM_READ_INVALID_SNVMADDR 1u +#define SNVM_READ_AUTHENTICATION_FAILURE 2u +#define SNVM_READ_SYSTEM_ERROR 3u + +/** + * # Digital Signature Service Error Codes + * + * DIGITAL_SIGNATURE_FEK_FAILURE_ERROR + * Error retrieving FEK + * + * DIGITAL_SIGNATURE_DRBG_ERROR + * Failed to generate nonce + * + * DIGITAL_SIGNATURE_ECDSA_ERROR + * ECDSA failed + */ +#define DIGITAL_SIGNATURE_FEK_FAILURE_ERROR 1u +#define DIGITAL_SIGNATURE_DRBG_ERROR 2u +#define DIGITAL_SIGNATURE_ECDSA_ERROR 3u + +/** + * # Digest Check Error Codes + * + * NOTE: When these error occur, the DIGEST tamper flag is triggered. + * + * DIGEST_CHECK_FABRICERR + * Fabric digest check error + * + * DIGEST_CHECK_CCERR + * UFS Fabric Configuration (CC) segment digest check error + * + * DIGEST_CHECK_SNVMERR + * ROM digest in SNVM segment digest check error + * + * DIGEST_CHECK_ULERR + * UFS UL segment digest check error + * + * DIGEST_CHECK_UK0ERR + * UKDIGEST0 in User Key segment digest check error + * + * DIGEST_CHECK_UK1ERR + * UKDIGEST1 in User Key segment digest check error + * + * DIGEST_CHECK_UK2ERR + * UKDIGEST2 in User Key segment (UPK1) digest check error + * + * DIGEST_CHECK_UK3ERR + * UKDIGEST3 in User Key segment (UK1) digest check error + * + * DIGEST_CHECK_UK4ERR + * UKDIGEST4 in User Key segment (DPK) digest check error + * + * DIGEST_CHECK_UK5ERR + * UKDIGEST5 in User Key segment (UPK2) digest check error + * + * DIGEST_CHECK_UK6ERR + * UKDIGEST6 in User Key segment (UK2) digest check error + * + * DIGEST_CHECK_UPERR + * UFS Permanent Lock (UPERM) segment digest check error + * + * DIGEST_CHECK_SYSERR + * M3 ROM, Factory and Factory Key Segments digest check error + * + */ +#define DIGEST_CHECK_FABRICERR 0x00u +#define DIGEST_CHECK_CCERR 0x01u +#define DIGEST_CHECK_SNVMERR 0x02u +#define DIGEST_CHECK_ULERR 0x03u +#define DIGEST_CHECK_UK0ERR 0x04u +#define DIGEST_CHECK_UK1ERR 0x05u +#define DIGEST_CHECK_UK2ERR 0x06u +#define DIGEST_CHECK_UK3ERR 0x07u +#define DIGEST_CHECK_UK4ERR 0x08u +#define DIGEST_CHECK_UK5ERR 0x09u +#define DIGEST_CHECK_UK6ERR 0x10u +#define DIGEST_CHECK_UPERR 0x11u +#define DIGEST_CHECK_SYSERR 0x12u + +/** + * # Bitstream Authentication and Iap Bitstream Authentication Return Status + * + * BSTREAM_AUTH_CHAINING_MISMATCH_ERR + * Validator or hash chaining mismatch. Incorrectly constructed bitstream or + * wrong key used. + * + * BSTREAM_AUTH_UNEXPECTED_DATA_ERR + * Unexpected data received. + * Additional data received after end of EOB component. + * + * BSTREAM_AUTH_INVALID_ENCRY_KEY_ERR + * Invalid/corrupt encryption key. + * The requested key mode is disabled or the key could not be read/reconstructed. + * + * BSTREAM_AUTH_INVALID_HEADER_ERR + * Invalid component header + * + * BSTREAM_AUTH_BACK_LEVEL_NOT_SATISFIED_ERR + * Back level not satisfied + * + * BSTREAM_AUTH_ILLEGAL_BITSTREAM_MODE_ERR + * Illegal bitstream mode. + * Requested bitstream mode is disabled by user security. + * + * BSTREAM_AUTH_DNS_BINDING_MISMATCH_ERR + * DSN binding mismatch + * + * BSTREAM_AUTH_ILLEGAL_COMPONENT_SEQUENCE_ERR + * Illegal component sequence + * + * BSTREAM_AUTH_INSUFF_DEVICE_CAPAB_ERR + * Insufficient device capabilities + * + * BSTREAM_AUTH_INCORRECT_DEVICEID_ERR + * Incorrect DEVICEID + * + * BSTREAM_AUTH_PROTOCOL_VERSION_ERR + * Unsupported bitstream protocol version (regeneration required) + * + * BSTREAM_AUTH_VERIFY_ERR + * Verify not permitted on this bitstream + * + * BSTREAM_AUTH_INVALID_DEV_CERT_ERR + * Invalid Device Certificate. + * Device SCAC is invalid or not present. + * + * BSTREAM_AUTH_INVALID_DIB_ERR + * Invalid DIB + * + * BSTREAM_AUTH_SPI_NOT_MASTER_ERR + * Device not in SPI Master Mode. + * Error may occur only when bitstream is executed through IAP mode. + * + * BSTREAM_AUTH_AUTOIAP_NO_VALID_IMAGE_ERR + * No valid images found. + * Error may occur when bitstream is executed through Auto Update mode. + * Occurs when no valid image pointers are found. + * + * BSTREAM_AUTH_INDEXIAP_NO_VALID_IMAGE_ERR + * No valid images found. + * Error may occur when bitstream is executed through IAP mode via Index Mode. + * Occurs when No valid image pointers are found. + * + * BSTREAM_AUTH_NEWER_DESIGN_VERSION_ERR + * Programmed design version is newer than AutoUpdate image found. + * Error may occur when bitstream is executed through Auto Update mode. + * + * BSTREAM_AUTH_INVALID_IMAGE_ERR + * Selected image was invalid and no recovery was performed due to valid design + * in device. + * Error may occur only when bitstream is executed through Auto Update or IAP mode + * (This error is here for completeness but only can be observed by running the + * READ_DEBUG_INFO instruction and looking at IAP Error code field). + * + * BSTREAM_AUTH_IMAGE_PROGRAM_FAILED_ERR + * Selected and Recovery image failed to program. + * Error may occur only when bitstream is executed through Auto Update or + * IAP mode + * (This error is here for completeness but only can be observed by running the + * READ_DEBUG_INFO instruction and looking at IAP Error code field). + * + * BSTREAM_AUTH_ABORT_ERR + * Abort. + * Non-bitstream instruction executed during bitstream loading. + * + * BSTREAM_AUTH_NVMVERIFY_ERR + * Fabric/UFS verification failed (min or weak limit) + * + * BSTREAM_AUTH_PROTECTED_ERR + * Device security prevented modification of non-volatile memory + * + * BSTREAM_AUTH_NOTENA + * Programming mode not enabled + * + * BSTREAM_AUTH_PNVMVERIFY + * pNVM verify operation failed + * + * BSTREAM_AUTH_SYSTEM + * System hardware error (PUF or DRBG) + * + * BSTREAM_AUTH_BADCOMPONENT + * An internal error was detected in a component payload + * + * BSTREAM_AUTH_HVPROGERR + * HV programming subsystem failure (pump failure) + * + * BSTREAM_AUTH_HVSTATE + * HV programming subsystem in unexpected state (internal error) + * + */ +#define BSTREAM_AUTH_CHAINING_MISMATCH_ERR 1 +#define BSTREAM_AUTH_UNEXPECTED_DATA_ERR 2 +#define BSTREAM_AUTH_INVALID_ENCRY_KEY_ERR 3 +#define BSTREAM_AUTH_INVALID_HEADER_ERR 4 +#define BSTREAM_AUTH_BACK_LEVEL_NOT_SATISFIED_ERR 5 +#define BSTREAM_AUTH_ILLEGAL_BITSTREAM_MODE_ERR 6 +#define BSTREAM_AUTH_DNS_BINDING_MISMATCH_ERR 7 +#define BSTREAM_AUTH_ILLEGAL_COMPONENT_SEQUENCE_ERR 8 +#define BSTREAM_AUTH_INSUFF_DEVICE_CAPAB_ERR 9 +#define BSTREAM_AUTH_INCORRECT_DEVICEID_ERR 10 +#define BSTREAM_AUTH_PROTOCOL_VERSION_ERR 11 +#define BSTREAM_AUTH_VERIFY_ERR 12 +#define BSTREAM_AUTH_INVALID_DEV_CERT_ERR 13 +#define BSTREAM_AUTH_INVALID_DIB_ERR 14 +#define BSTREAM_AUTH_SPI_NOT_MASTER_ERR 21 +#define BSTREAM_AUTH_AUTOIAP_NO_VALID_IMAGE_ERR 22 +#define BSTREAM_AUTH_INDEXIAP_NO_VALID_IMAGE_ERR 23 +#define BSTREAM_AUTH_NEWER_DESIGN_VERSION_ERR 24 +/* 25 Reserved */ +#define BSTREAM_AUTH_INVALID_IMAGE_ERR 26 +#define BSTREAM_AUTH_IMAGE_PROGRAM_FAILED_ERR 27 +#define BSTREAM_AUTH_ABORT_ERR 127 +#define BSTREAM_AUTH_NVMVERIFY_ERR 128 +#define BSTREAM_AUTH_PROTECTED_ERR 129 +#define BSTREAM_AUTH_NOTENA 130 +#define BSTREAM_AUTH_PNVMVERIFY 131 +#define BSTREAM_AUTH_SYSTEM 132 +#define BSTREAM_AUTH_BADCOMPONENT 133 +#define BSTREAM_AUTH_HVPROGERR 134 +#define BSTREAM_AUTH_HVSTATE 135 + +/***************************************************************************//** + * # Mailbox ECC Status + * Provides ECC status when the mailbox is read. The values are as follows: + * 00: No ECC errors detected, data is correct. + * 01: Exactly one bit error occurred and has been corrected. + * 10: Exactly two bits error occurred and no correction performed. + * 11: Reserved. + */ +#define SYS_MBOX_ECC_NO_ERROR_MASK 0x00u +#define SYS_MBOX_ONEBIT_ERROR_CORRECTED_MASK 0x40u +#define SYS_MBOX_TWOBIT_ERROR_MASK 0xC0u + +/***************************************************************************//** + * Service request command opcodes: +*/ +#define SERIAL_NUMBER_REQUEST_CMD 0x00u +#define USERCODE_REQUEST_CMD 0x01u +#define DESIGN_INFO_REQUEST_CMD 0x02u +#define DEVICE_CERTIFICATE_REQUEST_CMD 0x03u +#define READ_DIGEST_REQUEST_CMD 0x04u +#define QUERY_SECURITY_REQUEST_CMD 0x05u +#define READ_DEBUG_INFO_REQUEST_CMD 0x06u +#define READ_ENVM_PARAM_REQUEST_CMD 0x07u +#define SNVM_NON_AUTHEN_TEXT_REQUEST_CMD 0x10u +#define SNVM_AUTHEN_TEXT_REQUEST_CMD 0x11u +#define SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD 0x12u +#define SNVM_READ_REQUEST_CMD 0x18u +#define DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD 0x19u +#define PUF_EMULATION_SERVICE_REQUEST_CMD 0x20u +#define NONCE_SERVICE_REQUEST_CMD 0x21u +#define DIGITAL_SIGNATURE_DER_FORMAT_REQUEST_CMD 0x1Au + +#define BITSTREAM_AUTHENTICATE_CMD 0x23u +#define IAP_BITSTREAM_AUTHENTICATE_CMD 0x22u + +#define DIGEST_CHECK_CMD 0x47u + +#define IAP_PROGRAM_BY_SPIIDX_CMD 0x42u +#define IAP_VERIFY_BY_SPIIDX_CMD 0x44u +#define IAP_PROGRAM_BY_SPIADDR_CMD 0x43u +#define IAP_VERIFY_BY_SPIADDR_CMD 0x45u +#define IAP_AUTOUPDATE_CMD 0x46u + +/***************************************************************************//** + * Service request Mailbox return data length + */ +#define SERIAL_NUMBER_RESP_LEN 16u +#define USERCODE_RESP_LEN 4u +#define DESIGN_INFO_RESP_LEN 36u +#define DEVICE_CERTIFICATE_RESP_LEN 1024u +#define READ_DIGEST_RESP_LEN 416u +#define QUERY_SECURITY_RESP_LEN 9u +#define READ_DEBUG_INFO_RESP_LEN 76u +#define READ_ENVM_PARAM_RESP_LEN 256u +#define NONCE_SERVICE_RESP_LEN 32u + +#define PUF_EMULATION_SERVICE_CMD_LEN 20u +#define PUF_EMULATION_SERVICE_RESP_LEN 32u + +#define DIGITAL_SIGNATURE_HASH_LEN 48u +#define DIGITAL_SIGNATURE_RAW_FORMAT_RESP_SIZE 96u +#define DIGITAL_SIGNATURE_DER_FORMAT_RESP_SIZE 104u + +#define USER_SECRET_KEY_LEN 12u + +/* Same driver can be used on PolarFire SoC platform and the response length + * is different for PolarFire SoC. Constants defined below are used only when the + * PF System services driver is used with PolarFire SoC Platform. + */ +#define READ_DIGEST_MPFS_RESP_LEN 576u +#define QUERY_SECURITY_MPFS_RESP_LEN 33u + +/* SNVM Input data length from sNVM write. */ +#ifndef RT_DEVICE_FAMILY +/* SNVMADDR + RESERVED + PT + USK */ +#define NON_AUTHENTICATED_TEXT_DATA_LEN 256u + +/* SNVMADDR + RESERVED + PT */ +#define AUTHENTICATED_TEXT_DATA_LEN 252u +#else +/* SNVMADDR + RESERVED + PT + USK */ +#define NON_AUTHENTICATED_TEXT_DATA_LEN 224u + +/* SNVMADDR + RESERVED + PT */ +#define AUTHENTICATED_TEXT_DATA_LEN 220u +#endif + +/** + * # Digest Check Input Options + * + * DIGEST_CHECK_FABRIC + * Carry out digest check on Fabric + * + * DIGEST_CHECK_CC + * Carry out digest check on UFS Fabric Configuration (CC) segment + * + * DIGEST_CHECK_SNVM + * Carry out digest check on ROM digest in SNVM segment + * + * DIGEST_CHECK_UL + * Carry out digest check on UFS UL segment + * + * DIGEST_CHECK_UKDIGEST0 + * Carry out digest check on UKDIGEST0 in User Key segment + * + * DIGEST_CHECK_UKDIGEST1 + * Carry out digest check on UKDIGEST1 in User Key segment + * + * DIGEST_CHECK_UKDIGEST2 + * Carry out digest check on UKDIGEST2 in User Key segment (UPK1) + * + * DIGEST_CHECK_UKDIGEST3 + * Carry out digest check on UKDIGEST3 in User Key segment (UK1) + * + * DIGEST_CHECK_UKDIGEST4 + * Carry out digest check on UKDIGEST4 in User Key segment (DPK) + * + * DIGEST_CHECK_UKDIGEST5 + * Carry out digest check on UKDIGEST5 in User Key segment (UPK2) + * + * DIGEST_CHECK_UKDIGEST6 + * Carry out digest check on UKDIGEST6 in User Key segment (UK2) + * + * DIGEST_CHECK_UPERM + * Carry out digest check on UFS Permanent lock (UPERM) segment + * + * DIGEST_CHECK_SYS + * Carry out digest check on Factory and Factory Key Segments + * + */ +#define DIGEST_CHECK_FABRIC (0x01<<0x00u) /*Fabric digest*/ +#define DIGEST_CHECK_CC (0x01<<0x01u) /*UFS Fabric Configuration (CC) segment*/ +#define DIGEST_CHECK_SNVM (0x01<<0x02u) /*ROM digest in SNVM segment*/ +#define DIGEST_CHECK_UL (0x01<<0x03u) /*UFS UL segment*/ +#define DIGEST_CHECK_UKDIGEST0 (0x01<<0x04u) /*UKDIGEST0 in User Key segment*/ +#define DIGEST_CHECK_UKDIGEST1 (0x01<<0x05u) /*UKDIGEST1 in User Key segment*/ +#define DIGEST_CHECK_UKDIGEST2 (0x01<<0x06u) /*UKDIGEST2 in User Key segment (UPK1)*/ +#define DIGEST_CHECK_UKDIGEST3 (0x01<<0x07u) /*UKDIGEST3 in User Key segment (UK1)*/ +#define DIGEST_CHECK_UKDIGEST4 (0x01<<0x08u) /*UKDIGEST4 in User Key segment (DPK)*/ +#define DIGEST_CHECK_UKDIGEST5 (0x01<<0x09u) /*UKDIGEST5 in User Key segment (UPK2)*/ +#define DIGEST_CHECK_UKDIGEST6 (0x01<<0x0au) /*UKDIGEST6 in User Key segment (UK2)*/ +#define DIGEST_CHECK_UPERM (0x01<<0x0bu) /*UFS Permanent lock (UPERM) segment*/ +#define DIGEST_CHECK_SYS (0x01<<0x0cu) /*Factory and Factory Key Segments.*/ + +/***************************************************************************//** + * The function SYS_init() is used to initialize the internal data structures of + * this driver. Currently this function is empty. + * + * @param base_addr The base_addr parameter specifies the base address of the + * PF_System_services core. + * + * @return This function does not return a value. + */ +void +SYS_init +( + uint32_t base_addr +); + +/***************************************************************************//** + * The function SYS_get_serial_number() is used to execute "serial number" system + * service. + * + * @param p_serial_number The p_serial_number parameter is a pointer to a buffer + * in which the data returned by system controller + * is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t +SYS_get_serial_number +( + const uint8_t * p_serial_number, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_get_user_code() is used to execute "USERCODE" system + * service. + * @param p_user_code The p_user_code parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t +SYS_get_user_code +( + const uint8_t * p_user_code, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_get_design_info() is used to execute "Get Design Info" system + * service. + * + * @param p_design_info The p_design_info parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. Total size of debug information is 36 bytes. + * The data from the system controller includes the 256-bit + * user-defined design ID, 16-bit design version, and 16-bit + * design back level. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t +SYS_get_design_info +( + const uint8_t * p_design_info, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_get_device_certificate() is used to execute "Get Device + * Certificate" system service. + * + * @param p_device_certificate The p_device_certificate parameter is a pointer + * to a buffer in which the data returned by the + * system controller is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code means that + * the service was executed successfully. + * + */ +uint8_t +SYS_get_device_certificate +( + const uint8_t * p_device_certificate, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_read_digest() is used to execute "Read Digest" system service. + * + * @param p_digest The p_digest parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t SYS_read_digest +( + const uint8_t * p_digest, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_query_security() is used to execute "Query Security" system + * service. + * + * @param p_security_locks The p_security_locks parameter is a pointer to a buffer + * in which the data returned by system controller is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code means that + * the service was executed successfully. + */ +uint8_t SYS_query_security +( + uint8_t * p_security_locks, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_read_debug_info() is used to execute "Read Debug info" system + * service. + * + * @param p_debug_info The p_debug_info parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t SYS_read_debug_info +( + const uint8_t * p_debug_info, + uint16_t mb_offset +); + +#ifdef CORESYSSERVICES_PFSOC +/***************************************************************************//** + * The function SYS_read_envm_parameter() is used to retrieve all parameters needed + * for the eNVM operation and programming. + * + * NOTE: This service is available only on PolarFire SoC Platform. + * This service is not yet supported by PF_SYSTEM_SERVICES 3.0.100. + * + * @param p_envm_param The p_envm_param parameter is a pointer to a buffer + * in which the data returned by system controller is copied. + * This buffer stores all the eNVM parameters. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_read_envm_parameter service will return zero if the + * service executed successfully, otherwise, it will return + * one indicating error. + */ +uint8_t SYS_read_envm_parameter +( + uint8_t * p_envm_param, + uint16_t mb_offset +); +#endif +/***************************************************************************//** + * The function SYS_puf_emulation_service() is used to authenticate a device. + * + * The SYS_puf_emulation_service() function accept a challenge comprising a + * 8-bit optype and 128-bit challenge and return a 256-bit response unique to + * the given challenge and the device. + * + * @param p_challenge The p_challenge parameter specifies the 128-bit challenge + * to generate the 256-bits unique response. + * + * @param op_type The op_type parameter specifies the operational parameter + * to generate the 256-bits unique response. + * + * @param p_response The p_response parameter is a pointer to a buffer where + * the data returned which is the response by system controller + * is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_puf_emulation_service function will return zero + * if the service executed successfully, otherwise, it will + * return one indicating error. + */ +uint8_t SYS_puf_emulation_service +( + const uint8_t * p_challenge, + uint8_t op_type, + uint8_t* p_response, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_digital_signature_service() function is used to generate P-384 ECDSA + * signature based on SHA384 hash value. + * + * @param p_hash The p_hash parameter is a pointer to the buffer which + * contain the 48 bytes SHA384 Hash value (input value). + * + * @param format The format parameter specifies the output format of + * generated SIGNATURE field. The different types of output + * signature formats are as follow: + * - DIGITAL_SIGNATURE_RAW_FORMAT + * - DIGITAL_SIGNATURE_DER_FORMAT + * + * @param p_response The p_response parameter is a pointer to a buffer that + * contains the generated ECDSA signature. The field may be + * 96 bytes or 104 bytes depending upon the output format. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digital_signature_service function returns + * zero if the service executed successfully, otherwise, it + * returns non-zero values indicating error. + */ +uint8_t SYS_digital_signature_service +( + const uint8_t* p_hash, + uint8_t format, + uint8_t* p_response, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_secure_nvm_write() function writes data in the sNVM region. + * Data gets stored in the following format: + * - Non-authenticated plaintext + * - Authenticated plaintext + * - Authenticated ciphertext + * + * Note: If you are executing this function with Authenticated plaintext + * or Authenticated ciphertext on a device whose sNVM was never previously + * written to, then the service may fail. For it to work, you must first write + * Authenticated data to the sNVM using Libero along with USK client and + * custom security. This flow generates the SMK. See UG0753 PolarFire FPGA + * Security User Guide for further details. + + * @param format The format parameter specifies the format used to write + * data in sNVM region. The different type of text formats + * are as follow: + * - NON_AUTHENTICATED_PLAINTEXT_FORMAT + * - AUTHENTICATED_PLAINTEXT_FORMAT + * - AUTHENTICATED_CIPHERTEXT_FORMAT + * + * @param snvm_module The snvm_module parameter specifies the the sNVM module + * in which the data need to be written. + * + * @param p_data The p_data parameter is a pointer to a buffer which + * contains the data to be stored in sNVM region. The data + * length to be written is fixed depending on the format + * parameter. If NON_AUTHENTICATED_PLAINTEXT_FORMAT is + * selected, then you can write 252 bytes in the sNVM module. + * For other two formats the data length is 236 bytes. + * + * @param p_user_key The p_user_key parameter is a pointer to a buffer which + * contain the 96-bit key USK (user secret key). This user + * secret key will enhance the security when authentication + * is used. That is, when Authenticated plaintext and + * Authenticated ciphertext format is selected. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digital_signature_service function returns + * zero if the service executed successfully, otherwise, it + * returns non-zero values indicating error. + */ +uint8_t SYS_secure_nvm_write +( + uint8_t format, + uint8_t snvm_module, + const uint8_t* p_data, + const uint8_t* p_user_key, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_secure_nvm_read() function is used to read data present in sNVM region. + * User should provide USK key, if the data was programmed using authentication. + * If the data was written in the sNVM using the authenticated plaintext or the + * authenticated ciphertext service option then this service will return the + * valid data only when authentication is successful. For more details, see + * SYS_secure_nvm_write() function. If the data was written in + * the sNVM using the authenticated plaintext or the authenticated ciphertext + * service option then this service will return the valid data only when + * authentication is successful. For more details, see SYS_secure_nvm_write() + * function and its parameter description. + * + * @param snvm_module The snvm_module parameter specifies the sNVM module + * from which the data need to be read. + * + * @param p_user_key The p_user_key parameter is a pointer to a buffer which + * contain the 96-bit key USK (user secret key). User should + * provide same secret key which is previously used for + * authentication while writing data in sNVM region. + * + * @param p_admin The p_admin parameter is a pointer to the buffer where + * the output page admin data is stored. The page admin + * data is 4 bytes long. + * + * @param p_data The p_data parameter is a pointer to a buffer which + * contains the data read from sNVM region. User should + * provide the buffer large enough to store the read data. + * + * @param data_len The data_len parameter specifies the number of bytes to be + * read from sNVM. + * The application should know whether the data written in the + * chose sNVM module was previously stored using Authentication + * or not. + * The data_len should be 236 bytes, for authenticated data. + * For not authenticated data the data_len should be 252 bytes. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digital_signature_service function returns + * zero if the service executed successfully, otherwise, it + * returns non-zero values indicating error. + */ +uint8_t SYS_secure_nvm_read +( + uint8_t snvm_module, + const uint8_t* p_user_key, + uint8_t* p_admin, + uint8_t* p_data, + uint16_t data_len, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_nonce_service() is used to issue "Nonce Service" system + * service to the system controller. + * + * @param p_nonce The p_nonce parameter is a pointer to a buffer + * in which the data returned by system controller is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code means + * that the service was executed successfully and a non-zero + * value indicates error. See the document link + * provided in the theory of operation section to know more + * about the service and service response. + */ +uint8_t SYS_nonce_service +( + const uint8_t * p_nonce, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_bitstream_authenticate_service() function is used to authenticate + * the Bitstream which is located in SPI through a system service routine. Prior + * to using the IAP service, it may be required to first validate the new + * bitstream before committing the device to reprogramming, thus avoiding the + * need to invoke recovery procedures if the bitstream is invalid. + * + * This service is applicable to bitstreams stored in SPI Flash memory only. + * + * @param spi_flash_address + * The spi_flash_address parameter specifies the address within + * SPI Flash memory where the bit-stream is stored. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_bitstream_authenticate_service function will return + * zero if the service executed successfully and the non-zero + * response from system controller indicates error. See + * the document link provided in the theory of + * operation section to know more about the service and service + * response. + */ +uint8_t SYS_bitstream_authenticate_service +( + uint32_t spi_flash_address, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_IAP_image_authenticate_service() function is used to authenticate + * the IAP image which is located in SPI through a system service routine. The + * service checks the image descriptor and the referenced bitstream and optional + * initialization data. If the image is authenticated successfully, then the + * image is guaranteed to be valid when used by an IAP function. + * + * This service is applicable to bitstreams stored in SPI Flash memory only. + * + * @param spi_idx + * The spi_idx parameter specifies the index in the SPI directory to + * be used where the IAP bit-stream is stored. + * Note: To support recovery SPI_IDX=1 should be an empty slot and the recovery + * image should be located in SPI_IDX=0. Since SPI_IDX=1 should be an + * empty slot, it shouldn’t be passed into the system service. + * + * @return The SYS_IAP_image_authenticate_service function will return + * zero if the service executed successfully the non-zero + * response from system controller indicates error. Please + * refer to the document link provided in the theory of + * operation section to know more about the service and service + * response. + */ +uint8_t SYS_IAP_image_authenticate_service +( + uint8_t spi_idx +); + +/***************************************************************************//** + * The SYS_digest_check_service() function is used to Recalculates and compares + * digests of selected non-volatile memories. If the fabric digest is to be + * checked, then the user design must follow all prerequisite steps for the + * FlashFreeze service before invoking this service. + * This service is applicable to bitstreams stored in SPI Flash memory only. + * @param options + * The options parameter specifies the digest check options which + * indicate the area on which the digest check should be performed. + * Below is the list of options. You can OR these options to indicate + * to perform digest check on multiple segments. + * Note: The options parameter is of 2 bytes when used with PF + * device and 4 bytes when used with PolarFire SoC device. + * Options[i] | Description + * ---------------|---------------------------------- + * 0x01 | Fabric digest + * 0x02 | Fabric Configuration (CC) segment + * 0x04 | ROM digest in SNVM segment + * 0x08 | UL segment + * 0x10 | UKDIGEST0 in User Key segment + * 0x20 | UKDIGEST1 in User Key segment + * 0x40 | UKDIGEST2 in User Key segment (UPK1) + * 0x80 | UKDIGEST3 in User Key segment (UK1) + * 0x100 | UKDIGEST4 in User Key segment (DPK) + * 0x200 | UKDIGEST5 in User Key segment (UPK2) + * 0x400 | UKDIGEST6 in User Key segment (UK2) + * 0x800 | UFS Permanent lock (UPERM) segment + * 0x1000 | Factory and Factory Key Segments. + * 0x2000 | UKDIGEST7 in User Key segment (HWM) (PFSoC) + * 0x4000 | ENVMDIGEST (PFSoC only) + * 0x8000 | UKDIGEST8 for MSS Boot Info (PFSoC only) + * 0x10000 | SNVM_RW_ACCESS_MAP Digest (PFSoC only) + * 0x20000 | SBIC revocation digest (PFSoC only) + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digest_check_service function will return + * zero if the service executed successfully the non-zero + * response from system controller indicates error. Pleaes + * refer to the document link provided in the theory of + * operation section to know more about the service and service + * response. + */ +uint8_t SYS_digest_check_service +( + uint32_t options, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_iap_service() function is used to IAP service. The IAP service allows + * the user to reprogram the device without the need for an external master. The + * user design writes the bitstream to be programmed into a SPI Flash connected + * to the SPI port. When the service is invoked, the System Controller + * automatically reads the bitstream from the SPI flash and programs the device. + * The service allows the image to be executed in either VERIFY or PROGRAM modes. + * Another option for IAP is to perform the auto-update sequence. In this case + * the newest image of the first two images in the SPI directory is chosen to be + * programmed. + * + * @param iap_cmd + * The iap_cmd parameter specifies the specific IAP command which + * depends upon VERIFY or PROGRAM modes and the SPI address method. + * iap_cmd | Description + * -----------------------|------------ + * IAP_PROGRAM_BY_SPIIDX_CMD | IAP program. + * IAP_VERIFY_BY_SPIIDX_CMD | Fabric Configuration (CC) segment + * IAP_PROGRAM_BY_SPIADDR_CMD | ROM digest in SNVM segment + * IAP_VERIFY_BY_SPIADDR_CMD | UL segment + * IAP_AUTOUPDATE_CMD | UKDIGEST0 in User Key segment + * + * @param spiaddr + * The spiaddr parameter specifies either the index + * in the SPI directory or the SPI address in the SPI Flash memory. + * Below is the list of the possible meaning of spiaddr parameter + * in accordance with the iap_cmd parameter. + * iap_cmd | spiaddr + * ----------------------|----------------- + * IAP_PROGRAM_BY_SPIIDX_CMD | Index in the SPI directory. + * IAP_VERIFY_BY_SPIIDX_CMD | Index in the SPI directory. + * IAP_PROGRAM_BY_SPIADDR_CMD | SPI address in the SPI Flash memory + * IAP_VERIFY_BY_SPIADDR_CMD | SPI address in the SPI Flash memory + * IAP_AUTOUPDATE_CMD | spiaddr is ignored as No index/address required for this command. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * Note: For the IAP services with command IAP_PROGRAM_BY_SPIIDX_CMD and + * IAP_VERIFY_BY_SPIIDX_CMD To support recovery SPI_IDX=1 should be an + * empty slot and the recovery image should be located in SPI_IDX=0. + * Since SPI_IDX=1 should be an empty slot it shouldn’t be passed into + * the system service. + * + * @return The SYS_iap_service function will return zero if the service + * executed successfully and the non-zero response from system + * controller indicates error. Please refer to the document + * link provided in the theory of operation section to know + * more about the service and service response. + */ +uint8_t SYS_iap_service +( + uint8_t iap_cmd, + uint32_t spiaddr, + uint16_t mb_offset +); + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_SYSSERV_PF_H */ diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h new file mode 100644 index 0000000..8b14b7e --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h @@ -0,0 +1,149 @@ +/******************************************************************************* + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Register bit offsets and masks definitions for CoreSysServices_PF driver. + */ + +#ifndef __CORE_SYSSERV_PF_REGISTERS +#define __CORE_SYSSERV_PF_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * SYS_SERV_CMD (offset 0x04) register details + */ +#define SS_CMD_REG_OFFSET 0x04u + +#define SS_CMD_OFFSET 0x04 +#define SS_CMD_MASK 0x0000FFFFu +#define SS_CMD_SHIFT 0u + +/*------------------------------------------------------------------------------ + * SYS_SERV_STAT (offset 0x08) register details + */ +#define SS_STAT_REG_OFFSET 0x08u + +#define SS_STAT_OFFSET 0x08 +#define SS_STAT_MASK 0x0000FFFFu +#define SS_STAT_SHIFT 0u + +/*------------------------------------------------------------------------------ + * SYS_SERV_REQ (offset 0x0C) register details + */ +#define SS_REQ_REG_OFFSET 0x0Cu + + +#define SS_REQ_REQ_OFFSET 0x0Cu +#define SS_REQ_REQ_MASK 0x00000001UL +#define SS_REQ_REQ_SHIFT 0u + +#define SS_REQ_ABUSY_OFFSET 0x0Cu +#define SS_REQ_ABUSY_MASK 0x00000002UL +#define SS_REQ_ABUSY_SHIFT 1u + +#define SS_REQ_NABUSY_OFFSET 0x0Cu +#define SS_REQ_NABUSY_MASK 0x00000004UL +#define SS_REQ_NABUSY_SHIFT 2u + +#define SS_REQ_SSBUSY_OFFSET 0x0Cu +#define SS_REQ_SSBUSY_MASK 0x00000008UL +#define SS_REQ_SSBUSY_SHIFT 3u + +#define SS_REQ_AREQ_OFFSET 0x0Cu +#define SS_REQ_AREQ_MASK 0x00000010UL +#define SS_REQ_AREQ_SHIFT 4u + +#define SS_REQ_NAREQ_OFFSET 0x0Cu +#define SS_REQ_NAREQ_MASK 0x00000020UL +#define SS_REQ_NAREQ_SHIFT 5u +/*------------------------------------------------------------------------------ + * MBX_ECCSTATUS (offset 0x10) register details + */ +#define MBX_ECCSTATUS_REG_OFFSET 0x10u + +#define MBX_ECCSTATUS_OFFSET 0x10 +#define MBX_ECCSTATUS_MASK 0x03u +#define MBX_ECCSTATUS_SHIFT 0u + + +/*------------------------------------------------------------------------------ + * MBX_WCNT (offset 0x14) register details + */ +#define MBX_WCNT_REG_OFFSET 0x14u + +#define MBX_WCNT_OFFSET 0x14 +#define MBX_WCNT_MASK 0x000001FFu +#define MBX_WCNT_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_RWCNT (offset 0x18) register details + */ +#define MBX_RCNT_REG_OFFSET 0x18u + +#define MBX_RCNT_OFFSET 0x18 +#define MBX_RCNT_MASK 0x000001FFu +#define MBX_RCNT_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_WADRDESC (offset 0x1C) register details + */ +#define MBX_WADDR_REG_OFFSET 0x1Cu + +#define MBX_WADDR_OFFSET 0x1C +#define MBX_WADDR_MASK 0x000001FFu +#define MBX_WADDR_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_RADRDESC (offset 0x20) register details + */ +#define MBX_RADDR_REG_OFFSET 0x20u + +#define MBX_RADDR_OFFSET 0x20 +#define MBX_RADDR_MASK 0x000001FFu +#define MBX_RADDR_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_WDATA (offset 0x28) register details + */ +#define MBX_WDATA_REG_OFFSET 0x28u + +#define MBX_WDATA_OFFSET 0x28 +#define MBX_WDATA_MASK 0xFFFFFFFFu +#define MBX_WDATA_SHIFT 0u + + +/*------------------------------------------------------------------------------ + * MBX_RDATA (offset 0x2C) register details + */ +#define MBX_RDATA_REG_OFFSET 0x2Cu + +#define MBX_RDATA_OFFSET 0x2C +#define MBX_RDATA_MASK 0xFFFFFFFFu +#define MBX_RDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * SS_USER (offset 0x30) register details + */ +#define SS_USER_REG_OFFSET 0x30u + +#define SS_USER_BUSY_OFFSET 0x30 +#define SS_USER_BUSY_MASK 0x00000001u +#define SS_USER_BUSY_SHIFT 0u + +#define SS_USER_RDVLD_OFFSET 0x30 +#define SS_USER_RDVLD_MASK 0x00000002u +#define SS_USER_RDVLD_SHIFT 1u + +#define SS_USER_CMDERR_OFFSET 0x30 +#define SS_USER_CMDERR_MASK 0x00000004u +#define SS_USER_CMDERR_SHIFT 2u + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_SYSSERV_PF_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c new file mode 100644 index 0000000..0c0a866 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c @@ -0,0 +1,297 @@ +/******************************************************************************* + * (c) Copyright 2007-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file core_uart_apb.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreUARTapb driver implementation. See file "core_uart_apb.h" for + * description of the functions implemented in this file. + * + */ + +#include "coreuartapb_regs.h" +#include "core_uart_apb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define NULL_INSTANCE ( ( UART_instance_t* ) 0 ) +#define NULL_BUFFER ( ( uint8_t* ) 0 ) + +#define MAX_LINE_CONFIG ( ( uint8_t )( DATA_8_BITS | ODD_PARITY ) ) +#define MAX_BAUD_VALUE ( ( uint16_t )( 0x1FFF ) ) +#define STATUS_ERROR_MASK ( ( uint8_t )( STATUS_PARITYERR_MASK | \ + STATUS_OVERFLOW_MASK | \ + STATUS_FRAMERR_MASK ) ) +#define BAUDVALUE_LSB ( (uint16_t) (0x00FF) ) +#define BAUDVALUE_MSB ( (uint16_t) (0xFF00) ) +#define BAUDVALUE_SHIFT ( (uint8_t) (5) ) + +#define STATUS_ERROR_OFFSET STATUS_PARITYERR_SHIFT + +/***************************************************************************//** + * UART_init() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_init +( + UART_instance_t * this_uart, + addr_t base_addr, + uint16_t baud_value, + uint8_t line_config +) +{ + uint8_t rx_full; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( line_config <= MAX_LINE_CONFIG ) + HAL_ASSERT( baud_value <= MAX_BAUD_VALUE ) + + if( ( this_uart != NULL_INSTANCE ) && + ( line_config <= MAX_LINE_CONFIG ) && + ( baud_value <= MAX_BAUD_VALUE ) ) + { + /* + * Store lower 8-bits of baud value in CTRL1. + */ + HAL_set_8bit_reg( base_addr, CTRL1, (uint_fast8_t)(baud_value & + BAUDVALUE_LSB ) ); + + /* + * Extract higher 5-bits of baud value and store in higher 5-bits + * of CTRL2, along with line configuration in lower 3 three bits. + */ + HAL_set_8bit_reg( base_addr, CTRL2, (uint_fast8_t)line_config | + (uint_fast8_t)((baud_value & + BAUDVALUE_MSB) >> BAUDVALUE_SHIFT ) ); + + this_uart->base_address = base_addr; +#ifndef NDEBUG + { + uint8_t config; + uint8_t temp; + uint16_t baud_val; + baud_val = HAL_get_8bit_reg( this_uart->base_address, CTRL1 ); + config = HAL_get_8bit_reg( this_uart->base_address, CTRL2 ); + /* + * To resolve operator precedence between & and << + */ + temp = ( config & (uint8_t)(CTRL2_BAUDVALUE_MASK ) ); + baud_val |= (uint16_t)( (uint16_t)(temp) << BAUDVALUE_SHIFT ); + config &= (uint8_t)(~CTRL2_BAUDVALUE_MASK); + HAL_ASSERT( baud_val == baud_value ); + HAL_ASSERT( config == line_config ); + } +#endif + + /* + * Flush the receive FIFO of data that may have been received before the + * driver was initialized. + */ + rx_full = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_RXFULL_MASK; + while ( rx_full ) + { + HAL_get_8bit_reg( this_uart->base_address, RXDATA ); + rx_full = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_RXFULL_MASK; + } + + /* + * Clear status of the UART instance. + */ + this_uart->status = (uint8_t)0; + } +} + +/***************************************************************************//** + * UART_send() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_send +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +) +{ + size_t char_idx; + uint8_t tx_ready; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( tx_buffer != NULL_BUFFER ) + HAL_ASSERT( tx_size > 0 ) + + if( (this_uart != NULL_INSTANCE) && + (tx_buffer != NULL_BUFFER) && + (tx_size > (size_t)0) ) + { + for ( char_idx = (size_t)0; char_idx < tx_size; char_idx++ ) + { + /* Wait for UART to become ready to transmit. */ + do { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( !tx_ready ); + /* Send next character in the buffer. */ + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)tx_buffer[char_idx] ); + } + } +} + +/***************************************************************************//** + * UART_fill_tx_fifo() + * See "core_uart_apb.h" for details of how to use this function. + */ +size_t +UART_fill_tx_fifo +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +) +{ + uint8_t tx_ready; + size_t size_sent = 0u; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( tx_buffer != NULL_BUFFER ) + HAL_ASSERT( tx_size > 0 ) + + /* Fill the UART's Tx FIFO until the FIFO is full or the complete input + * buffer has been written. */ + if( (this_uart != NULL_INSTANCE) && + (tx_buffer != NULL_BUFFER) && + (tx_size > 0u) ) + { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + if ( tx_ready ) + { + do { + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)tx_buffer[size_sent] ); + size_sent++; + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( (tx_ready) && ( size_sent < tx_size ) ); + } + } + return size_sent; +} + +/***************************************************************************//** + * UART_get_rx() + * See "core_uart_apb.h" for details of how to use this function. + */ +size_t +UART_get_rx +( + UART_instance_t * this_uart, + uint8_t * rx_buffer, + size_t buff_size +) +{ + uint8_t new_status; + uint8_t rx_full; + size_t rx_idx = 0u; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( rx_buffer != NULL_BUFFER ) + HAL_ASSERT( buff_size > 0 ) + + if( (this_uart != NULL_INSTANCE) && + (rx_buffer != NULL_BUFFER) && + (buff_size > 0u) ) + { + rx_idx = 0u; + new_status = HAL_get_8bit_reg( this_uart->base_address, STATUS ); + this_uart->status |= new_status; + rx_full = new_status & STATUS_RXFULL_MASK; + while ( ( rx_full ) && ( rx_idx < buff_size ) ) + { + rx_buffer[rx_idx] = HAL_get_8bit_reg( this_uart->base_address, + RXDATA ); + rx_idx++; + new_status = HAL_get_8bit_reg( this_uart->base_address, STATUS ); + this_uart->status |= new_status; + rx_full = new_status & STATUS_RXFULL_MASK; + } + } + return rx_idx; +} + +/***************************************************************************//** + * UART_polled_tx_string() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_polled_tx_string +( + UART_instance_t * this_uart, + const uint8_t * p_sz_string +) +{ + uint32_t char_idx; + uint8_t tx_ready; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( p_sz_string != NULL_BUFFER ) + + if( ( this_uart != NULL_INSTANCE ) && ( p_sz_string != NULL_BUFFER ) ) + { + char_idx = 0U; + while( 0U != p_sz_string[char_idx] ) + { + /* Wait for UART to become ready to transmit. */ + do { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( !tx_ready ); + /* Send next character in the buffer. */ + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)p_sz_string[char_idx] ); + char_idx++; + } + } +} + +/***************************************************************************//** + * UART_get_rx_status() + * See "core_uart_apb.h" for details of how to use this function. + */ +uint8_t +UART_get_rx_status +( + UART_instance_t * this_uart +) +{ + uint8_t status = UART_APB_INVALID_PARAM; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + /* + * Extract UART error status and place in lower bits of "status". + * Bit 0 - Parity error status + * Bit 1 - Overflow error status + * Bit 2 - Frame error status + */ + if( this_uart != NULL_INSTANCE ) + { + status = ( ( this_uart->status & STATUS_ERROR_MASK ) >> + STATUS_ERROR_OFFSET ); + /* + * Clear the sticky status for this instance. + */ + this_uart->status = (uint8_t)0; + } + return status; +} + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h new file mode 100644 index 0000000..c016403 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h @@ -0,0 +1,451 @@ +/******************************************************************************* + * (c) Copyright 2007-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file core_uart_apb.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief This file contains the application programming interface for the + * CoreUARTapb bare metal driver. + * + */ +/*=========================================================================*//** + @mainpage CoreUARTapb Bare Metal Driver. + + @section intro_sec Introduction + CoreUARTapb is an implementation of the Universal Asynchronous + Receiver/Transmitter aimed at minimal FPGA tile usage within a Microchip FPGA. + The CoreUARTapb bare metal software driver is designed to be used in systems + with no operating system. + + The CoreUARTapb driver provides functions for basic polled transmitting and + receiving operations. It also provide functions that allow the use of the + CoreUARTapb in interrupt-driven mode but leaves the management of interrupts + to the calling application, as interrupt enabling and disabling are not + controlled through the CoreUARTapb registers. The CoreUARTapb driver is + provided as C source code. + + @section driver_configuration Driver Configuration + Your application software should configure the CoreUARTapb driver by calling + the UART_init() function for each CoreUARTapb instance in the hardware design. + The configuration parameters include the CoreUARTapb hardware instance base + address and other runtime parameters, such as baud rate, bit width, and + parity. No CoreUARTapb hardware configuration parameters are needed by the + driver, apart from the CoreUARTapb hardware instance base address. Hence, no + additional configuration files are required to use the driver. + + A CoreUARTapb hardware instance is generated with fixed baud rate, character + size, and parity configuration settings as part of the hardware flow. The + baud_value and line_config parameter values passed to the UART_init() function + have no effect if fixed values were selected for the baud rate, character + size, and parity in the hardware configuration of CoreUARTapb. When fixed + values are selected for these hardware configuration parameters, the driver is + unable to overwrite the fixed values in the CoreUARTapb control registers, + CTRL1 and CTRL2. + + @section theory_op Theory of Operation + The CoreUARTapb software driver is designed to allow the control of multiple + instances of CoreUARTapb. Each instance of CoreUARTapb in the hardware design + is associated with a single instance of the UART_instance_t structure in the + software. You need to allocate memory for one unique UART_instance_t structure + instance for each CoreUARTapb hardware instance. The contents of these data + structures are initialized while calling the UART_init() function. A pointer + to the structure is passed to the subsequent driver functions in order to + identify the CoreUARTapb hardware instance you wish to perform the requested + operation on. + + Note: Do not attempt to directly manipulate the content of UART_instance_t + structures. This structure is only intended to be modified by the driver + function. + + Once initialized, the driver transmits and receives data. Transmit is + performed using the UART_send() function. If this function blocks, then it + returns only when the data passed to it has been sent to the CoreUARTapb + hardware. Data received by the CoreUARTapb hardware is read by the user + application using the UART_get_rx() function. + + The UART_fill_tx_fifo() function is also provided as a part of the + interrupt-driven transmit. This function fills the CoreUARTapb hardware + transmit FIFO with the content of a data buffer passed as a parameter before + returning. The control of the interrupts must be implemented outside the + driver, as the CoreUARTapb hardware does not provide the ability to enable + or disable its interrupt sources. + + The UART_polled_tx_string() function is provided to transmit a NULL-terminated + string in polled mode. If this function blocks, then it returns only when the + data passed to it has been sent to the CoreUARTapb hardware. + + The UART_get_rx_status() function returns the error status of the CoreUARTapb + receiver. This is used by applications to take appropriate action in case of + receiver errors. +*//*=========================================================================*/ +#ifndef __CORE_UART_APB_H +#define __CORE_UART_APB_H 1 + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + Data Bits Length Defines + ======================== + These constants define the data length in a UART packet. + | Constant | Description | + |-------------|---------------------------------------| + | DATA_7_BITS | Data length is 7-bits | + | DATA_8_BITS | Data length is 8-bits | + */ +#define DATA_7_BITS 0x00u +#define DATA_8_BITS 0x01u + +/***************************************************************************//** + Parity Defines + ============== + These constants define parity check options. + | Constant | Description | + |-------------|---------------------------------------| + | NO_PARITY | No Parity bit | + | EVEN_PARITY | Even Parity bit | + | ODD_PARITY | ODD Parity bit | + */ +#define NO_PARITY 0x00u +#define EVEN_PARITY 0x02u +#define ODD_PARITY 0x06u + +/***************************************************************************//** + Error Status Definitions + ======================== + These constants define the different types of possible errors in UART + transmission of data. + | Constant | Description | + |-------------------------|---------------------------------------| + | UART_APB_PARITY_ERROR | Data parity error | + | UART_APB_OVERFLOW_ERROR | Data overflow error | + | UART_APB_FRAMING_ERROR | Data framing error | + | UART_APB_NO_ERROR | No error | + | UART_APB_INVALID_PARAM | Invalid parameter | + */ +#define UART_APB_PARITY_ERROR 0x01u +#define UART_APB_OVERFLOW_ERROR 0x02u +#define UART_APB_FRAMING_ERROR 0x04u +#define UART_APB_NO_ERROR 0x00u +#define UART_APB_INVALID_PARAM 0xFFu + +/***************************************************************************//** + * There should be one instance of this structure for each instance of + * CoreUARTapb in your system. This structure instance identifies various UARTs + * in a system and should be passed as first parameter to UART functions to + * identify which UART performs the requested operation. The 'status' element in + * the structure is used to provide sticky status information. + */ +typedef struct +{ + addr_t base_address; + uint8_t status; +} UART_instance_t; + +/***************************************************************************//** + * The UART_init() function initializes the UART with the configuration passed + * as parameters. The configuration parameters are the baud_value that generates + * the baud rate and the line configuration (bit length and parity). + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data regarding + * this instance of the CoreUARTapb. This pointer is used to + * identify the target CoreUARTapb hardware instance in + * subsequent calls to the CoreUARTapb functions. + * @param base_addr The base_address parameter is the base address in the + * processor's memory map for the registers of the + * CoreUARTapb instance being initialized. + * @param baud_value The baud_value parameter selects the baud rate for the + * UART. The baud value is calculated from the frequency of + * the system clock in hertz and the desired baud rate using + * the following equation: + * baud_value = (clock / (baud_rate * 16)) - 1. + * The baud_value parameter must be a value in the range 0 + * to 8191 (or 0x0000 to 0x1FFF). + * @param line_config This parameter is the line configuration, specifies the + * bit length and parity settings. This is the logical OR of: + * - DATA_7_BITS + * - DATA_8_BITS + * - NO_PARITY + * - EVEN_PARITY + * - ODD_PARITY + * For example, 8 bits even parity would be specified as + * (DATA_8_BITS | EVEN_PARITY). + * @return This function does not return a value. + * @example + * @code + * #define BAUD_VALUE_57600 25 + * + * #define COREUARTAPB0_BASE_ADDR 0xC3000000UL + * + * UART_instance_t g_uart; + * int main() + * { + * UART_init(&g_uart, COREUARTAPB0_BASE_ADDR, + BAUD_VALUE_57600, (DATA_8_BITS | EVEN_PARITY)); + * } + * @endcode + */ +void +UART_init +( + UART_instance_t * this_uart, + addr_t base_addr, + uint16_t baud_value, + uint8_t line_config +); + +/***************************************************************************//** + * The UART_send() function is used to transmit data. It transfers the content + * of the transmitter data buffer, passed as a function parameter, into the + * UART's hardware transmitter FIFO. It returns when the full content of the + * transmitter data buffer has been transferred to the UART's transmitter FIFO. + * + * Note: You should not assume that the data you are sending using this function + * has been received at the other end by the time this function returns. The + * actual transmission over the serial connection is still be taking place at + * the time of the function return. It is safe to release or reuse the memory + * used as the transmit buffer once this function returns. + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data + * regarding this instance of the CoreUARTapbUART. + * @param tx_buffer The tx_buffer parameter is a pointer to a buffer that + * contains the data to be transmitted. + * @param tx_size The tx_size parameter is the size in bytes of the + * transmitted data. + * + * @return This function does not return a value. + * + * @example + * @code + * uint8_t testmsg1[] = {"\n\r\n\r\n\rUART_send() test message 1"}; + * UART_send(&g_uart,(const uint8_t *)&testmsg1,sizeof(testmsg1)); + * @endcode + */ +void +UART_send +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +); + +/***************************************************************************//** + * The UART_fill_tx_fifo() function fills the UART's transmitter hardware FIFO + * with the data found in the transmitter buffer that is passed in as a + * function parameter. The function returns either when the FIFO is full or + * when the complete contents of the transmitter buffer have been copied into + * the FIFO. It returns the number of bytes copied into the UART's transmitter + * hardware FIFO. This function is intended to be used as part of + * interrupt-driven transmission. + * + * Note: You should not assume that the data you transmit using this function + * has been received at the other end by the time this function returns. The + * actual transmission over the serial connection is still be taking place at + * the time of the function return. + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data + * regarding this instance of the UART. + * @param tx_buffer The tx_buffer parameter is a pointer to a buffer that + * contains the data to be transmitted. + * @param tx_size The tx_size parameter is the size in bytes of the + * transmitted data. + * @return This function returns the number of bytes copied into + * the UART's transmitter hardware FIFO. + * + * @example + * @code + * void send_using_interrupt + * ( + * uint8_t * pbuff, + * size_t tx_size + * ) + * { + * size_t size_in_fifo; + * size_in_fifo = UART_fill_tx_fifo( &g_uart, pbuff, tx_size ); + * } + * @endcode + */ +size_t +UART_fill_tx_fifo +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +); + +/***************************************************************************//** + * The UART_get_rx() function reads the content of the UART's receiver hardware + * FIFO and stores it in the receiver buffer that is passed in as a function + * parameter. It copies either the full contents of the FIFO into the receiver + * buffer, or just enough data from the FIFO to fill the receiver buffer, + * depending on the size of the receiver buffer. The size of the receiver + * buffer is passed in as a function parameter. UART_get_rx() returns the number + * of bytes copied into the receiver buffer. If no data was received at the time + * the function is called, the function returns 0. + * + * Note: This function reads and accumulates the receiver status of the + * CoreUARTapb instance before reading each byte from the receiver's + * data register/FIFO. This allows the driver to maintain a sticky + * record of any receiver errors that occur as the UART receives each + * data byte; receiver errors would otherwise be lost after each read + * from the receiver's data register. A call to the UART_get_rx_status() + * function returns any receiver errors accumulated during the execution + * of the UART_get_rx() function. + * + * Note: When FIFO mode is disabled in the CoreUARTapb hardware configuration, + * the driver accumulates a sticky record of any parity errors, framing + * errors, or overflow errors. When FIFO mode is enabled, the driver + * accumulates a sticky record of overflow errors only; in this case, + * interrupts must be used to handle parity errors or framing errors. + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data + * regarding this instance of the UART. + * @param rx_buffer The rx_buffer parameter is a pointer to a buffer where + * the received data is copied. + * @param buff_size The buff_size parameter is the size of the receive + * buffer in bytes. + * @return This function returns the number of bytes copied into + * the receive buffer. + * + * @example + * @code + * #define MAX_RX_DATA_SIZE 256 + * + * uint8_t rx_data[MAX_RX_DATA_SIZE]; + * uint8_t rx_size = 0; + * + * rx_size = UART_get_rx( &g_uart, rx_data, sizeof(rx_data) ); + * @endcode + */ +size_t +UART_get_rx +( + UART_instance_t * this_uart, + uint8_t * rx_buffer, + size_t buff_size +); + +/***************************************************************************//** + * The UART_polled_tx_string() function is used to transmit a NULL ('\0') + * terminated string. Internally, it polls for the transmit ready status and + * transfers the text starting at the address pointed by p_sz_string into + * the UART's hardware transmitter FIFO. It is a blocking function and returns + * only when the complete string has been transferred to the UART's transmit + * FIFO. + * + * Note: You should not assume that the data you transmit using this function + * has been received at the other end by the time this function returns. The + * actual transmission over the serial connection is still be taking place at + * the time of the function return. + * + * @param this_uart The this_uart parameter is the pointer to a + * UART_instance_t structure, which holds all data + * regarding this instance of the UART. + * @param p_sz_string The p_sz_string parameter is a pointer to a buffer + * containing the NULL ('\0') terminated string to be + * transmitted. + * @return This function does not return a value. + * + * @example + * @code + * uint8_t testmsg1[] = {"\r\n\r\nUART_polled_tx_string() test message 1\0"}; + * UART_polled_tx_string(&g_uart,(const uint8_t *)&testmsg1); + * @endcode + */ +void +UART_polled_tx_string +( + UART_instance_t * this_uart, + const uint8_t * p_sz_string +); + +/***************************************************************************//** + * The UART_get_rx_status() function returns the receiver error status of the + * CoreUARTapb instance. It reads both the current error status of the receiver + * and the accumulated error status from preceding calls to the UART_get_rx() + * function and combines them using a bitwise OR. It returns the cumulative + * parity, framing, and overflow error status of the receiver, since the + * previous call to UART_get_rx_status() as an 8-bit encoded value. + * + * Note: The UART_get_rx() function reads and accumulates the receiver status + * of the CoreUARTapb instance before reading each byte from the receiver's data + * register/FIFO. The driver maintains a sticky record of the cumulative error + * status, which persists after the UART_get_rx() function returns. The + * UART_get_rx_status() function clears this accumulated record of receiver + * errors before returning. + * + * @param this_uart The this_uart parameter is a pointer to a + * UART_instance_t structure which holds all data regarding + * this instance of the UART. + * @return This function returns the UART receiver error status as + * an 8-bit encoded value. The return value is 0, if there + * are no receiver errors occurred. The driver provides a + * set of bit mask constants, which should be compared with + * and/or used to mask the returned value to determine the + * receiver error status. + * When the return value is compared to the following bit + * masks, a non-zero result indicates that the + * corresponding error occurred: + * UART_APB_PARITY_ERROR (bit mask = 0x01) + * UART_APB_OVERFLOW_ERROR (bit mask = 0x02) + * UART_APB_FRAMING_ERROR (bit mask = 0x04) + * When the return value is compared to the following bit + * mask, a non-zero result indicates that no error + * occurred: + * UART_APB_NO_ERROR (0x00) + * + * @example + * @code + * UART_instance_t g_uart; + * uint8_t rx_data[MAX_RX_DATA_SIZE]; + * uint8_t err_status; + * err_status = UART_get_err_status(&g_uart); + * + * if(UART_APB_NO_ERROR == err_status ) + * { + * rx_size = UART_get_rx( &g_uart, rx_data, MAX_RX_DATA_SIZE ); + * } + * @endcode + */ +uint8_t +UART_get_rx_status +( + UART_instance_t * this_uart +); + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_UART_APB_H */ diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h new file mode 100644 index 0000000..c123cc3 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h @@ -0,0 +1,133 @@ +/******************************************************************************* + * (c) Copyright 2007-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file coreuartapb_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreUARTapb register definitions + */ + +#ifndef __CORE_UART_APB_REGISTERS +#define __CORE_UART_APB_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * TxData register details + */ +#define TXDATA_REG_OFFSET 0x0u + +/* + * TxData bits. + */ +#define TXDATA_OFFSET 0x0u +#define TXDATA_MASK 0xFFu +#define TXDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * RxData register details + */ +#define RXDATA_REG_OFFSET 0x4u + +/* + * RxData bits. + */ +#define RXDATA_OFFSET 0x4u +#define RXDATA_MASK 0xFFu +#define RXDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * ControReg1 register details + */ +#define CTRL1_REG_OFFSET 0x8u + +/* + * Baud value (Lower 8-bits) + */ +#define CTRL1_BAUDVALUE_OFFSET 0x8u +#define CTRL1_BAUDVALUE_MASK 0xFFu +#define CTRL1_BAUDVALUE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * ControReg2 register details + */ +#define CTRL2_REG_OFFSET 0xCu + +/* + * Bit length + */ +#define CTRL2_BIT_LENGTH_OFFSET 0xCu +#define CTRL2_BIT_LENGTH_MASK 0x01u +#define CTRL2_BIT_LENGTH_SHIFT 0u + +/* + * Parity enable. + */ +#define CTRL2_PARITY_EN_OFFSET 0xCu +#define CTRL2_PARITY_EN_MASK 0x02u +#define CTRL2_PARITY_EN_SHIFT 1u + +/* + * Odd/even parity selection. + */ +#define CTRL2_ODD_EVEN_OFFSET 0xCu +#define CTRL2_ODD_EVEN_MASK 0x04u +#define CTRL2_ODD_EVEN_SHIFT 2u + +/* + * Baud value (Higher 5-bits) + */ +#define CTRL2_BAUDVALUE_OFFSET 0xCu +#define CTRL2_BAUDVALUE_MASK 0xF8u +#define CTRL2_BAUDVALUE_SHIFT 3u + +/*------------------------------------------------------------------------------ + * StatusReg register details + */ +#define StatusReg_REG_OFFSET 0x10u + +#define STATUS_REG_OFFSET 0x10u + +/* + * Transmit ready. + */ +#define STATUS_TXRDY_OFFSET 0x10u +#define STATUS_TXRDY_MASK 0x01u +#define STATUS_TXRDY_SHIFT 0u + +/* + * Receive full. + */ +#define STATUS_RXFULL_OFFSET 0x10u +#define STATUS_RXFULL_MASK 0x02u +#define STATUS_RXFULL_SHIFT 1u + +/* + * Parity error. + */ +#define STATUS_PARITYERR_OFFSET 0x10u +#define STATUS_PARITYERR_MASK 0x04u +#define STATUS_PARITYERR_SHIFT 2u + +/* + * Overflow. + */ +#define STATUS_OVERFLOW_OFFSET 0x10u +#define STATUS_OVERFLOW_MASK 0x08u +#define STATUS_OVERFLOW_SHIFT 3u + +/* + * Frame Error. + */ +#define STATUS_FRAMERR_OFFSET 0x10u +#define STATUS_FRAMERR_MASK 0x10u +#define STATUS_FRAMERR_SHIFT 4u + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_UART_APB_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.c b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.c new file mode 100644 index 0000000..a2f4911 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.c @@ -0,0 +1,765 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Mi-V I2C Soft IP bare-metal driver. This module is delivered as part of + * Extended Sub System(ESS) MIV_ESS. + * Please refer to miv_i2c.h file for more information. + */ + +#include "miv_i2c.h" + +#define MIV_I2C_ERROR 0xFFu + +/*------------------------------------------------------------------------------ + * MIV I2C transaction direction. + */ +#define MIV_I2C_WRITE_DIR 0u +#define MIV_I2C_READ_DIR 1u + +/* -- TRANSACTIONS TYPES -- */ +#define MIV_I2C_NO_TRANSACTION 0u +#define MIV_I2C_MASTER_WRITE_TRANSACTION 1u +#define MIV_I2C_MASTER_READ_TRANSACTION 2u +#define MIV_I2C_MASTER_SEQUENTIAL_READ_TRANSACTION 3u + +/*------------------------------------------------------------------------------ + * MIV I2C HW states + */ +#define MIV_I2C_IDLE 0x00u +#define MIV_I2C_TX_STA_CB 0x01u +#define MIV_I2C_TX_DATA 0x02u +#define MIV_I2C_RX_DATA 0x03u + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_disable_irq() disables the Mi-V I2C interrupt. + */ +void +MIV_I2C_disable_irq +( + void +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_enable_irq() enables the Mi-V I2C interrupt. + */ +void +MIV_I2C_enable_irq +( + void +); + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_init +( + miv_i2c_instance_t *this_i2c, + addr_t base_addr +) +{ + /* Assign the base address + * Clock Prescale value set + * MIV_I2C interrupt enabled + * I2C core enable + */ + psr_t processor_state; + + /* Disabling the interrupts */ + processor_state = HAL_disable_interrupts(); + + /* + * Initialize all items of the this_miv_i2c data structure to zero. This + * initializes all state variables to their init value. It relies on + * the fact that NO_TRANSACTION, MIV_I2C_SUCCESS and I2C_RELEASE_BUS all + * have an actual value of zero. + */ + memset(this_i2c, 0, sizeof(miv_i2c_instance_t)); + + this_i2c->base_addr = base_addr; + + HAL_restore_interrupts(processor_state); +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_config +( + miv_i2c_instance_t *this_i2c, + uint16_t clk_prescale +) +{ + /* Assign the base address + * Clock Prescale value set + * MIV_I2C interrupt enabled + * I2C core enable + */ + psr_t processor_state; + + /* Disabling the interrupts */ + processor_state = HAL_disable_interrupts(); + + /* Before writing to prescale reg, the core enable must be zero */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CTRL_CORE_EN, 0x00u); + + /* Set the prescale value */ + HAL_set_16bit_reg(this_i2c->base_addr, PRESCALE, clk_prescale); + + /* Enable the MIV I2C interrupts */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CTRL_IRQ_EN, 0x01u); + + /* Enable the MIV I2C core */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CTRL_CORE_EN, 0x01u); + + this_i2c->master_state = MIV_I2C_IDLE; + + HAL_restore_interrupts(processor_state); +} + +/* + * Please refer to miv_i2c.h for more info + */ +uint8_t +MIV_I2C_start +( + miv_i2c_instance_t *this_i2c +) +{ + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + /* Generate I2C start condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + HAL_restore_interrupts(processor_state); + + return 0u; +} + +/* + * Please refer to miv_i2c.h for more info + */ +uint8_t +MIV_I2C_stop +( + miv_i2c_instance_t *this_i2c +) +{ + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + /* Generate I2C stop condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + HAL_restore_interrupts(processor_state); + + return 0u; +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_write +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t bus_options, + uint8_t ack_polling_options +) +{ + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + /* I2C write flow + * + * Check I2C status for ongoing transaction + * Populate the structure with input data + * Generate start condition + * Set the write_direction and target address. + */ + + /* Update the transaction only when there is no ongoing I2C transaction */ + if (this_i2c->transaction == MIV_I2C_NO_TRANSACTION) + { + this_i2c->transaction = MIV_I2C_MASTER_WRITE_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MIV_I2C_MASTER_WRITE_TRANSACTION ; + + /* Populate the i2c instance structure */ + + /* Set the target addr */ + this_i2c->target_addr = i2c_target_addr; + this_i2c->dir = MIV_I2C_WRITE_DIR; + + /* Set up the tx buffer */ + this_i2c->master_tx_buffer = write_buffer; + this_i2c->master_tx_size = write_size; + this_i2c->master_tx_idx = 0u; + + /* Set the I2C status in progress and setup the options */ + this_i2c->bus_options = bus_options; + this_i2c->ack_polling_options = ack_polling_options; + this_i2c->master_status = MIV_I2C_IN_PROGRESS; + + + /* Generate I2C start condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* write target address and write bit */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, MIV_I2C_WRITE_DIR); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, i2c_target_addr); + + /* Set WR bit to transmit start condition and control byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + /* Set current master hw state -> transmitted start condition and + * control byte + */ + this_i2c->master_state = MIV_I2C_TX_STA_CB; + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( MIV_I2C_HOLD_BUS == this_i2c->bus_status ) + { + /* Must toggle IACK bit to clear the MIV_I2C IRQ*/ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00); + } + + MIV_I2C_enable_irq(); + + HAL_restore_interrupts(processor_state); + +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_read +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +) +{ + psr_t processor_state; + uint8_t status = MIV_I2C_SUCCESS; + + processor_state = HAL_disable_interrupts(); + + /* MIV I2C Read operation flow + * + * Check for ongoing transaction + * Populate the i2c instance structure + * Generate the start condition + * Set the READ_direction bit and target addr + */ + + uint8_t read_stat = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_TIP); + + /* Update the transaction only when there is no ongoing I2C transaction */ + if (this_i2c->transaction == MIV_I2C_NO_TRANSACTION) + { + this_i2c->transaction = MIV_I2C_MASTER_READ_TRANSACTION; + } + + this_i2c->pending_transaction = MIV_I2C_MASTER_READ_TRANSACTION; + + /* Populate the MIV I2C instance structure */ + + this_i2c->target_addr = i2c_target_addr; + this_i2c->dir = MIV_I2C_READ_DIR; + + /* Populate read buffer */ + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set the BUS and ACK polling options */ + this_i2c->bus_options = bus_options; + this_i2c->ack_polling_options = ack_polling_options; + + /* Generate the start condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* Set the DIR bit and target addr */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, MIV_I2C_READ_DIR); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, i2c_target_addr); + + /* Set the WR bit to transmit the start condition and command byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + /* Set the i2c master state and status transmitting STA and Command Byte */ + this_i2c->master_state = MIV_I2C_TX_STA_CB; + this_i2c->master_status = MIV_I2C_IN_PROGRESS; + + /* Toggle the IACK bit if required */ + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( MIV_I2C_HOLD_BUS == this_i2c->bus_status ) + { + /* Must toggle IACK bit to clear the MIV_I2C IRQ*/ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00); + } + /* Enable the I2C interrupt */ + MIV_I2C_enable_irq(); + + HAL_restore_interrupts(processor_state); +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_write_read +( + miv_i2c_instance_t *this_i2c, + uint8_t target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +) +{ + uint8_t status = MIV_I2C_SUCCESS; + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + uint8_t read_stat = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_TIP); + + /* I2C write read operation flow + * + * Used to read the data from set address offset + * + * Configure the i2c instance structure + * generate the start and configure the dir and target addr + * set wr bit to transmit the start and command byte + * + */ + + /* Update the transaction only when there is no ongoing I2C transaction */ + if (this_i2c->transaction == MIV_I2C_NO_TRANSACTION) + { + this_i2c->transaction = MIV_I2C_MASTER_READ_TRANSACTION; + } + + this_i2c->pending_transaction = MIV_I2C_MASTER_READ_TRANSACTION; + + /* Populate the I2C instance */ + + this_i2c->target_addr = target_addr; + + /* setup the i2c direction */ + this_i2c->dir = MIV_I2C_WRITE_DIR; + + /* set up transmit buffer */ + this_i2c->master_tx_buffer = write_buffer; + this_i2c->master_tx_size = write_size; + this_i2c->master_tx_idx = 0u; + + /* set up receive buffer */ + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set the bus and ack polling options */ + this_i2c->bus_options = bus_options; + this_i2c->ack_polling_options = ack_polling_options; + + /* Generate the start command */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* Set the DIR and target addr */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + /* Set the WR bit to transmit the start command and command byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + /* Set the i2c master state and status transmitting STA and Command Byte */ + this_i2c->master_state = MIV_I2C_TX_STA_CB; + this_i2c->master_status = MIV_I2C_IN_PROGRESS; + + /* + * Clear interrupt if required + */ + if ( MIV_I2C_HOLD_BUS == this_i2c->bus_status ) + { + /* Must toggle IACK bit to clear the MIV_I2C IRQ*/ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00u); + } + + /* Enable the I2C interrupt */ + MIV_I2C_enable_irq(); + + HAL_restore_interrupts(processor_state); +} + +/* MIV_I2C_isr() + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_isr +( + miv_i2c_instance_t *this_i2c +) +{ + uint8_t i2c_state; + uint8_t i2c_ack_status; + uint8_t i2c_al_status; + uint8_t hold_bus; + + /* Read the I2C master state */ + i2c_state = this_i2c->master_state; + + /* Read the ack and al status */ + i2c_ack_status = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_RXACK); + i2c_al_status = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_AL); + + switch (i2c_state) + { + /* I2C ISR State Machine + * + * Cases: + * - Transmit start condition and control byte + * - Received ACK and bus arbitration was not lost (Read or Write) + * - Received NACK + * - Bus arbitration lost + * + * - Transmit data + * - Received ACK and bus arbitration was not lost (Read or Write) + * - Received NACK + * - Bus arbitration lost + * + * - Receive data + * - Received ACK and bus arbitration was not lost (Read or Write) + * - Bus arbitration lost + */ + + case MIV_I2C_TX_STA_CB: + + /* Received ACK from target and I2C bus arbitration is not lost */ + if (i2c_ack_status == 0u && i2c_al_status == 0u) + { + /* If I2C master write operation */ + if (this_i2c->dir == MIV_I2C_WRITE_DIR) + { + /* write first byte of data and set the WR bit to transfer the data */ + HAL_set_8bit_reg(this_i2c->base_addr, TRANSMIT, + this_i2c->master_tx_buffer[this_i2c->master_tx_idx]); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + /* Increment the index */ + this_i2c->master_tx_idx++; + + /* Set the master state to TX data */ + this_i2c->master_state = MIV_I2C_TX_DATA; + } + /* Master read operation */ + else + { + if (this_i2c->master_rx_size == 1u) + { + /* Send the ACK if the rx size is 1, transmit NACK to slave + * after receiving 1 byte to indicate slave to stop sending + * the data + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_ACK, 0x01u); + } + + /* Send the RD command to slave */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_RD, 0x01u); + + /* Increment the index */ + this_i2c->master_rx_idx++; + + /* Change state to receive data */ + this_i2c->master_state = MIV_I2C_RX_DATA; + } + } + else if (i2c_ack_status == 1u) + { + if (this_i2c->ack_polling_options == MIV_I2C_ACK_POLLING_ENABLE) + { + /* Target responded with NACK and ACK polling option is enabled + * + * Re-send the start condition and control byte + * + * TO-DO: This might become infinite loop check for timeout + * options. + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + this_i2c->master_tx_idx = 0u; + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + else + { + /* Target responded with NACK and ACK polling is disabled + * Abort the transaction and move to IDLE state + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + + this_i2c->master_status = MIV_I2C_FAILED; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + + this_i2c->master_state = MIV_I2C_IDLE; + } + } + + else if (i2c_al_status == 1u) + { + /* Arbitration was lost on the BUS during the transmission of + * previous start condition and control byte. + * Re-send the STA and CB + */ + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + break; + + /* Transmit master data */ + case MIV_I2C_TX_DATA: + + /* ACK received and arbitration was not lost */ + if (i2c_ack_status == 0u && i2c_al_status == 0u) + { + uint8_t tx_buff[this_i2c->master_tx_size]; + if (this_i2c->master_tx_idx < this_i2c->master_tx_size) + { + HAL_set_8bit_reg(this_i2c->base_addr, TRANSMIT, + this_i2c->master_tx_buffer[this_i2c->master_tx_idx]); + + tx_buff[this_i2c->master_tx_idx] = this_i2c->master_tx_buffer[this_i2c->master_tx_idx]; + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + /* Increment the index */ + this_i2c->master_tx_idx++; + + /* Set the master state to TX data */ + this_i2c->master_state = MIV_I2C_TX_DATA; + } + + /* All the bytes are transmitted */ + else if (this_i2c->master_tx_idx == this_i2c->master_tx_size) + { + /* If this is a MASTER_READ_TRANSACTION, hold bus and start a + new transfer in read mode now that the read address has been + written to the slave */ + if(this_i2c->transaction == MIV_I2C_MASTER_READ_TRANSACTION) + + { + //Switch direction to READ + this_i2c->dir = MIV_I2C_READ_DIR; + + // Set the STA bit + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* Set the DIR bit and target addr */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, MIV_I2C_READ_DIR); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, this_i2c->target_addr); + + /* Set the WR bit to transmit the start condition and command byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + // Reset the buffer index + this_i2c->master_tx_idx = 0u; + this_i2c->master_rx_idx = 0u; + + /* Set the master state to RX data */ + this_i2c->master_state = MIV_I2C_RX_DATA; + } + + else + { + /* If releasing the bus, transmit the stop condition at the end + * of the transfer. + */ + hold_bus = this_i2c->bus_status & MIV_I2C_HOLD_BUS; + + if (hold_bus == 0) + { + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + } + else + { + MIV_I2C_disable_irq(); + } + this_i2c->master_status = MIV_I2C_SUCCESS; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + this_i2c->master_state = MIV_I2C_IDLE; + } + } + } + + else if (i2c_ack_status == 1u) + { + /* Received NACK from target device + * + * Release the bus and end the transfer + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + + this_i2c->master_status = MIV_I2C_FAILED; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + + this_i2c->master_state = MIV_I2C_IDLE; + } + + else if (i2c_al_status == 1u) + { + /* Arbitration was lost on the BUS during the transmission of + * previous start condition and control byte. + * Re-send the STA and CB + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, + this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + break; + + /* Receive target device data */ + case MIV_I2C_RX_DATA: + + if (i2c_al_status == 0u) + { + if (this_i2c->master_rx_idx < this_i2c->master_rx_size) + { + this_i2c->master_rx_buffer[this_i2c->master_rx_idx - 1u] = + HAL_get_8bit_reg(this_i2c->base_addr, RECEIVE); + + /* If next byte is last one + * Send NACK to target device to stop sending data + */ + if (this_i2c->master_rx_idx == (this_i2c->master_rx_size - 1u)) + { + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_ACK, 0x01u); + } + + else + { + /* Send ACK to receive next bytes */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_ACK, 0x00u); + } + + /* Set RD bit to receive next byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_RD, 0x01u); + + this_i2c->master_rx_idx++; + } + + /* Received all bytes */ + else //if (this_i2c->master_rx_idx == this_i2c->master_rx_size) + { + this_i2c->master_rx_buffer[this_i2c->master_rx_idx - 1] = + HAL_get_8bit_reg(this_i2c->base_addr, RECEIVE); + + hold_bus = this_i2c->bus_status & MIV_I2C_HOLD_BUS; + + if (hold_bus == 0) + { + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + } + else + { + MIV_I2C_disable_irq(); + } + this_i2c->master_status = MIV_I2C_SUCCESS; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + + this_i2c->master_state = MIV_I2C_IDLE; + } + } + + else if (i2c_al_status == 1u) + { + /* Arbitration was lost on the BUS during the transmission of + * previous start condition and control byte. + * Re-send the STA and CB + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, + this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + break; + } + + /* Toggle the IACK bit to clear interrupt */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00u); +} + +/* + * Please refer to miv_i2c.h for more info + */ +uint8_t +MIV_I2C_get_status +( + miv_i2c_instance_t *this_i2c +) +{ + uint8_t i2c_status; + + i2c_status = HAL_get_8bit_reg(this_i2c->base_addr, STATUS); + + return i2c_status; +} diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.h b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.h new file mode 100644 index 0000000..c5e704d --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.h @@ -0,0 +1,854 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * I2C module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(MIV_ESS). + */ + +/*=========================================================================*//** + @mainpage Mi-V I2C Bare Metal Driver + + ============================================================================== + Introduction + ============================================================================== + The Mi-V I2C driver provides a set of functions for controlling the Mi-V I2C + Soft-IP module. This module is delivered as a part of the Mi-V Extended + Sub System(MIV_ESS). The driver provides a minimal APB-driven I2C interface, + supporting initiator read and write access to peripheral I2C devices. + + The major features provided by the Mi-V I2C driver are: + - Support for configuring the I2C instance. + - I2C master operations. + - I2C ISR. + + This driver can be used as part of a bare metal system where no operating + system is available. The driver can be adapted for use as part of an + operating system, but the implementation of the adaptation layer between the + driver and the operating system's driver model is outside the scope of this + driver. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + The application software should initialize and configure the Mi-V I2C through + the call to the MIV_I2C_init() and MIV_I2C_config() function for Mi-V I2C + instance in the design. The configuration parameter include base address and + Prescaler value. + + ------------------------------ + Interrupt Control + ------------------------------ + The Mi-V I2C driver has to enable and disable the generation of interrupts by + Mi-V I2C at various times while operating. This enabling and disabling of the + interrupts must be done through the Mi-V RV32 HAL provided interrupt handlers. + For that reason, the method controlling the Mi-V I2C interrupts is system + specific and it is necessary to customize the MIV_I2C_enable_irq() and + MIV_I2C_disable_irq() functions as per requirement. + + The implementation of MIV_I2C_enable_irq() should permit the interrupts + generated by the Mi-V I2C to the processor through a call to respective miv-hal + interrupt handler. The implementation of MIV_I2C_disable_irq() should prevent + the interrupts generated by a Mi-V I2C from interrupting the processor. + Please refer to the miv_i2c_interrupt.c for more information about the + implementation. + + No MIV_I2C hardware configuration parameters are used by the driver, apart + from the MIV_I2C base address. Hence, no additional configuration files + are required to use the driver. + + ============================================================================== + Theory of Operation + ============================================================================== + The Mi-V I2C software driver is designed to allow the control of multiple + instances of Mi-V I2C. Each instance of Mi-V I2C in the hardware design is + associated with a single instance of the miv_i2c_instance_t structure in the + software. User must allocate memory for one unique miv_i2c_instance_t + structure for each instance of Mi-V I2C in the hardware. + A pointer to the structure is passed to the subsequent driver functions in + order to identify the MIV_I2C hardware instance and to perform requested + operation. + + Note: Do not attempt to directly manipulate the contents of the + miv_i2c_instance_t structure. These structures are only intended to be modified + by the driver functions. + + The Mi-V I2C driver functions are grouped into following categories: + - Initialization and configuration + - I2C master operation functions to handle write, read and write_read + operations. + - Interrupt control + + -------------------------------- + Initialization and configuration + -------------------------------- + The Mi-V I2C device is first initialized by the call to MIV_I2C_init(). This + function initializes the instance of Mi-V I2C with the base address. + MIV_I2C_init() function must be called before any other Mi-V I2C driver API. + + The configuration of the Mi-V I2C instance is done via call to the + MIV_I2C_config() function. This function will set the prescale value which is + used to set the frequency of the I2C clock(SCLK) generated by I2C module. + + --------------------------------- + Transaction types + --------------------------------- + The driver is designed to handle three types of transactions: + - Write transactions + - Read transactions + - Write-Read transaction + + ### Write Transaction + The write transaction begins with master sending a start condition, followed + by device address byte with the R/W bit set to logic '0', and then by the + word address bytes. The slave acknowledges the receipt of its address with + acknowledge bit. The master sends one byte at a time to the slave, which must + acknowledge the receipt of each byte for the next byte to be sent. The master + sends STOP condition to complete the transaction. The slave can abort the + transaction by replying with negative acknowledge. + + The application programmer can choose not to send the STOP bit at the end of + the transaction causing repetitive start conditions. + + ### Read Transaction + The master I2C device initiates a read transaction by sending a START bit + as soon as the bus becomes free. The start condition is followed by the + control byte which contains 7-bit slave address followed by R/W bit set to + logic '1'. The slave sends data one byte at a time to the master, which must + acknowledge receipt of each byte for the next byte to be sent. The master + sends a non-acknowledge bit following the last byte it wishes to read + followed by a STOP bit. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ### Write-Read Transaction + The write read transaction is a combination of a write transaction + immediately followed by a read transaction. There is no STOP condition sent + between the write and read phase of write-read transaction. A repeated START + condition is sent between the write and read phases. + + Whilst the write handler is being executed, the slave holds the clock line + low to stretch the clock until the response is ready. + + The write-read transaction is typically used to send an memory/register + address in the write transaction specifying the start address of the data to + be transferred during the read phase. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ------------------------------------- + Interrupt Control + ------------------------------------- + The Mi-V I2C driver is interrupt driven and it uses the MIV_I2C_irq() function + to drive the ISR state machine which is at the heart of the driver. The + application is responsible for providing the link between the interrupt + generating hardware and the Mi-V I2C interrupt handler and must ensure that + the MIV_I2C_isr() function is called with the correct miv_i2c_instance_t + structure pointer for the Mi-V I2C instance initiating the interrupt. + +*//*=========================================================================*/ +#ifndef MIV_I2C_H_ +#define MIV_I2C_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "miv_i2c_regs.h" +#include + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#else +#include "hal.h" +#endif + +/*-------------------------------------------------------------------------*//** + The miv_i2c_status_t type is used to report the status of I2C transactions. + */ +typedef enum miv_i2c_status +{ + MIV_I2C_SUCCESS = 0u, + MIV_I2C_IN_PROGRESS, + MIV_I2C_FAILED, + MIV_I2C_TIMED_OUT +}miv_i2c_status_t; + +/*-------------------------------------------------------------------------*//** + This structure is used to identify the MIV_I2C hardware instances in a system. + Your application software should declare one instance of this structure for + each instance of the MIV_I2C in your system. The function MIV_I2C_init() + Initializes this structure. A pointer to an initialised instance of the structure + should be passed as the first parameter to the MIV_I2C driver functions, to + identify which MIV_I2C hardware instance should perform the requested operation. + + The contents of this data structure should not be modified or used outside of + the MIV_I2C driver. Software using the MIV_I2C driver should only need to + create one single instance of this data structure for each MIV_I2C hardware + instance in the system, then pass a pointer to these data structures with each + call to the MIV_I2C driver in order to identify the MIV_I2C hardware instance + it wishes to use. +*/ + +typedef struct miv_i2c_instance +{ + addr_t base_addr; + + /* Transmit related info:*/ + uint_fast8_t target_addr; + + /* Current transaction type */ + uint8_t transaction; + + uint8_t bus_options; + + uint8_t ack_polling_options; + + /* Current State of the I2C master */ + uint8_t master_state; + + /* Master TX INFO: */ + const uint8_t * master_tx_buffer; + uint_fast16_t master_tx_size; + uint_fast16_t master_tx_idx; + uint_fast8_t dir; + + /* Master RX INFO: */ + uint8_t * master_rx_buffer; + uint_fast16_t master_rx_size; + uint_fast16_t master_rx_idx; + + /* Master Status */ + volatile miv_i2c_status_t master_status; + uint32_t master_timeout_ms; + + /* user specific data */ + void *p_user_data ; + + /* I2C bus status */ + uint8_t bus_status; + + /* Is transaction pending flag */ + uint8_t is_transaction_pending; + + /* I2C Pending transaction */ + uint8_t pending_transaction; + +}miv_i2c_instance_t; + + +/*-------------------------------------------------------------------------*//** + MIV_I2C_RELEASE_BUS + ===================== + The MIV_I2C_RELEASE_BUS constant is used to specify the bus_options parameter + for MIV_I2C_read(), MIV_I2C_write() and MIV_I2C_write_read() to indicate + that a STOP bit must be generated at the end of the I2C transaction to release + the bus. + */ +#define MIV_I2C_RELEASE_BUS 0x00u + + +/*-------------------------------------------------------------------------*//** + MIV_I2C_HOLD_BUS + ===================== + The MIV_I2C_HOLD_BUS constant is used to specify the bus_optionsparameter + for MIV_I2C_read(), MIV_I2C_write() and MIV_I2C_write_read() to indicate + that a STOP bit must not be generated at the end of the I2C transaction in + order to retain the bus ownership. This causes the next transaction to + begin with a repeated START bit and no STOP bit between the transactions. + */ +#define MIV_I2C_HOLD_BUS 0x01u + +/*-------------------------------------------------------------------------*//** + MIV_I2C_ACK_POLLING_DISABLE + ===================== + The MIV_I2C_ACK_POLLING_DISABLE constant is used to specify the + ack_polling_options parameter to functions MIV_I2C_write(), + MIV_I2C_write_read() and MIV_I2C_read(). Acknowledgment polling is used when + working with I2C memory devices such as EEPROM, which feature an internal + write cycle. + + With acknowledgment polling disabled, if the target slave device responds to the + control byte with a NACK, the MIV_I2C will abort the transfer. + */ +#define MIV_I2C_ACK_POLLING_DISABLE 0x00u + +/*-------------------------------------------------------------------------*//** + MIV_I2C_ACK_POLLING_ENABLE + ===================== + The MIV_I2C_ACK_POLLING_ENABLE constant is used to specify the + ack_polling_options parameter to functions MIV_I2C_write(), + MIV_I2C_write_read() and MIV_I2C_read(). acknowledgment polling is used when + working with I2C memory devices such as EEPROM, which feature an internal + write cycle. + + With acknowledgment polling enabled, if the slave device responds to the + control byte with a NACK, the MIV_I2C will repeatedly transmit another control + byte until the slave device accepts the connection with an ACK, or the timeout + specified in the MIV_I2C_wait_complete() function is reached. Acknowledgment + polling allows for the next read/write operation to be started as soon as the + EEPROM has completed its internal write cycle. + */ +#define MIV_I2C_ACK_POLLING_ENABLE 0x01u + +/*--------------------------------Public APIs---------------------------------*/ + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_init() function is used to initialize the Mi-V I2C module instance + with the base address. + + Note: This function should be called before calling any other Mi-V I2C + functions. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + @param base_addr + Base address of the Mi-V I2C module instance in the MIV_ESS + soft IP. + + @return + This function does not return any value. + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + } + @endcode + */ +void +MIV_I2C_init +( + miv_i2c_instance_t *this_i2c, + addr_t base_addr +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_config() function is used to configure the Mi-V I2C module. This + function will set the prescale value which is used to set the frequency of + the I2C clock(SCLK) generated by I2C module and also enables the I2C core and + interrupts. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param clk_prescale + The value used to set the frequency of Mi-V I2C serial clock + (SCLK) generated by the Mi-V I2C module instance. The + prescaler value required to set particular frequency of + Mi-V I2C can be calculated using following formula: + + prescaler = (System Clock Frequency) / (5 * (Desired I2C Clock Frequency)) - 1 + + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + } + @endcode + */ +void +MIV_I2C_config +( + miv_i2c_instance_t *this_i2c, + uint16_t clk_prescale +); + + +uint8_t +MIV_I2C_start +( + miv_i2c_instance_t *this_i2c +); + + +uint8_t +MIV_I2C_stop +( + miv_i2c_instance_t *this_i2c +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_write() is used to set up and start the Mi-V I2C master write + transaction. This function is used for all Mi-V master write operation. + + For more information about the operation, please refer to the 'theory of + operations' section at the start of this document. + + This function returns immediately after initiating the transaction. The content + of the write buffer passed as parameter should not be modified until the write + transaction completes. It also means that the memory allocated for the write + buffer should not be freed or should not go out of scope before the write + completes. + You can check for the write transaction completion by polling the master_status + from miv_i2c_instance_t structure as shown in the sample code. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param i2c_target_addr + This parameter specifies the serial address for the slave + device. + + @param write_buffer + This parameter is a pointer to the buffer holding data to be + written to target I2C device. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param write_size + Number of bytes held in the write_buffer to be written to the + I2C device. + @param bus_options: + The bus_options parameter is used to indicate if the I2C bus + should be released on completion of the write transaction. + Using the MIV_I2C_RELEASE_BUS constant for the bus_options + parameter causes a STOP bit to be generated at the end of the + write transaction causing the bus to be released for other I2C + devices to use. Using the MIV_I2C_HOLD_BUS constant as + bus_options parameter prevents a STOP bit from being generated + at the end of the write transaction, preventing other I2C + devices from initiating a bus transaction. + + @param ack_polling_options: + The ack_polling_options parameter is used to indicate how the + MIV_I2C will respond if the slave device transmits a NACK to + the I2C control byte. Using the MIV_I2C_ACK_POLLING_DISABLE + constant for the ack_polling_options parameter causes the + MIV_I2C to abort the transfer if the slave device responds to + the I2C control byte with a NACK. Using the + MIV_I2C_ACK_POLLING_ENABLE constant for the ack_polling_options + parameter causes the MIV_I2C to repeatedly transmit a control + byte to the slave device until the slave device responds with + an ACK. + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + + MIV_I2C_write (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_tx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + } + @endcode + */ +void +MIV_I2C_write +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t bus_options, + uint8_t ack_polling_options +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_read() is used to set up and start the Mi-V I2C master read + transaction. This function is used for all MIV_I2C master read operation. + + For more information about the operation, please refer to the 'theory of + operations' section at the start of this document. + + This function returns immediately after initiating the transaction. The content + of the read buffer passed as parameter should not be modified until the write + transaction completes. It also means that the memory allocated for the read + buffer should not be freed or should not go out of scope before the read + completes. + You can check for the write transaction completion by polling the master_status + from miv_i2c_instance_t structure as shown in the sample code. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param i2c_target_addr + This parameter specifies the serial address for the slave + device. + + @param read_buffer + This parameter is a pointer to the buffer where the data + received from the I2C slave device is stored. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param read_size + Number of bytes held in the write_buffer to be read from the + I2C device. + + @param bus_options: + The bus_options parameter is used to indicate if the I2C bus + should be released on completion of the write transaction. + Using the MIV_I2C_RELEASE_BUS constant for the bus_options + parameter causes a STOP bit to be generated at the end of the + write transaction causing the bus to be released for other I2C + devices to use. Using the MIV_I2C_HOLD_BUS constant as + bus_options parameter prevents a STOP bit from being generated + at the end of the write transaction, preventing other I2C + devices from initiating a bus transaction. + + @param ack_polling_options: + The ack_polling_options parameter is used to indicate how the + MIV_I2C will respond if the slave device transmits a NACK to + the I2C control byte. Using the MIV_I2C_ACK_POLLING_DISABLE + constant for the ack_polling_options parameter causes the + MIV_I2C to abort the transfer if the slave device responds to + the I2C control byte with a NACK. Using the + MIV_I2C_ACK_POLLING_ENABLE constant for the ack_polling_options + parameter causes the MIV_I2C to repeatedly transmit a control + byte to the slave device until the slave device responds with + an ACK. + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + + MIV_I2C_write (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_tx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + + // reset miv_i2c_status variable + miv_i2c_status = 0u; + + MIV_I2C_read (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_rx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + } + @endcode + */ +void +MIV_I2C_read +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_write_read() is used to set up and start the Mi-V I2C master + write_read transaction. This function is used for all MIV_I2C master write_read + operation. + + This function is used in cases where data is being requested from a specific + address offset inside the target I2C slave device. + In this type of I2C operation, the I2C master starts by initiating a write + operation. During this write operation, the specific address offset is written + to the I2C slave. Once the address offset has been written to the I2C slave, + the I2C master transmits a repeated start, and initiates a read operation to + read data from the set address. + + For more information about the operation, please refer to the 'theory of + operations' section at the start of this document. + + This function returns immediately after initiating the transaction. The content + of the write and read buffer passed as parameter should not be modified until + the write transaction completes. It also means that the memory allocated for + the write and read buffer should not be freed or should not go out of scope + before the operation completes. + You can check for the write_read transaction completion by polling the + master_status from miv_i2c_instance_t structure. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param i2c_target_addr + This parameter specifies the serial address for the slave + device. + + @param write_buffer + This parameter is a pointer to the buffer holding data to be + written to target I2C device. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param write_size + Number of bytes held in the write_buffer to be written to the + I2C device. + + @param read_buffer + This parameter is a pointer to the buffer where the data + received from the I2C slave device is stored. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param read_size + Number of bytes held in the write_buffer to be read from the + I2C device. + + @param bus_options: + The bus_options parameter is used to indicate if the I2C bus + should be released on completion of the write transaction. + Using the MIV_I2C_RELEASE_BUS constant for the bus_options + parameter causes a STOP bit to be generated at the end of the + write transaction causing the bus to be released for other I2C + devices to use. Using the MIV_I2C_HOLD_BUS constant as + bus_options parameter prevents a STOP bit from being generated + at the end of the write transaction, preventing other I2C + devices from initiating a bus transaction. + + @param ack_polling_options: + The ack_polling_options parameter is used to indicate how the + MIV_I2C will respond if the slave device transmits a NACK to + the I2C control byte. Using the MIV_I2C_ACK_POLLING_DISABLE + constant for the ack_polling_options parameter causes the + MIV_I2C to abort the transfer if the slave device responds to + the I2C control byte with a NACK. Using the + MIV_I2C_ACK_POLLING_ENABLE constant for the ack_polling_options + parameter causes the MIV_I2C to repeatedly transmit a control + byte to the slave device until the slave device responds with + an ACK or the timeout specified in the MIV_I2C_wait_complete() + function is reached. + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + + MIV_I2C_write (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_tx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + + // reset miv_i2c_status variable + miv_i2c_status = 0u; + + uint8_t addr_offset[2] = {0x00, 0x00}; + MIV_I2C_write_read(&miv_i2c, + DUALEE_SLAVEADDRESS_1, + addr_offset, + sizeof(addr_offset), + i2c_rx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + } + @endcode + */ +void +MIV_I2C_write_read +( + miv_i2c_instance_t *this_i2c, + uint8_t target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_isr() function contains the MIV_I2C's interrupt service routine. + This ISR is at the heart of the MIV_I2C driver, and is used to control the + interrupt-driven, byte-by-byte I2C read and write operations. + + The ISR operates as a Finite State Machine (FSM), which uses the previously + completed I2C operation and its result to determine which I2C operation will + be performed next. + + The ISR operation is divided into following categories: + - MIV_I2C_IDLE + - MIV_I2C_TX_STA_CB + - MIV_I2C_TX_DATA + - MIV_I2C_RX_DATA + + ##### MIV_I2C_IDLE + The MIV_I2C_IDLE is entered on reset, or when an I2C master operation has been + completed or aborted. + Upon entering, the FSM will remain in this state until a write, read, or + write-read operation is requested + + ##### MIV_I2C_STA_CB + The MIV_I2C_TX_STA_CB operation is performed when the start condition and + control byte(i2c target address(7-bit) and direction of transaction(1-bit)) is + transmitted by the Mi-V I2C master device to the slave. + If the target I2C slave device responded to the previous START Condition + + Control Byte with an ACK, the MIV_I2C will start the requested I2C + read/write operation. + If the target slave I2C slave device responds with NACK, the MIV_I2C will + remain in this state or return to the idle state based on ack_polling + configuration. + + ##### MIV_I2C_TX_DATA + The MIV_I2C_TX_DATA state is entered after the target slave device accepts a + write request with an ACK. + This state is used to handle the byte-by-byte MIV_I2C write operations. + The FSM will remain in this state until either all data bytes have been + written to the target slave device, or an error occurs during the write + operation. + + ##### MIV_I2C_RX_DATA + The MIV_I2C_RX_DATA state is entered after the target slave device accepts a + read request with an ACK. + This state is used to handle the byte-by-byte MIV_I2C read operations. + The FSM will remain in this state until either all data bytes have been + received from the target slave device, or an error occurs. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + */ +void +MIV_I2C_isr +( + miv_i2c_instance_t *this_i2c +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_get_status() returns the 8-bit Mi-V I2C status register value. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + @return + This function returns 8-bit Mi-V I2C status register value. + */ +uint8_t +MIV_I2C_get_status +( + miv_i2c_instance_t *this_i2c +); + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_I2C_H_ */ diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_interrupt.c b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_interrupt.c new file mode 100644 index 0000000..871eafe --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_interrupt.c @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains functions used for MIV_I2C driver interrupt control. + * User should enable and disable the interrupts according to their design. + * Please refer to miv_i2c.h file for more information. + */ + +#include "miv_rv32_hal/miv_rv32_hal.h" + +void MIV_I2C_disable_irq(void) +{ +/* Disable I2C interrupt */ + MRV_disable_local_irq(MRV32_MSYS_EIE2_IRQn); +} + +void MIV_I2C_enable_irq(void) +{ +/* Enable I2C interrupt */ + MRV_enable_local_irq(MRV32_MSYS_EIE2_IRQn); +} + + diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_regs.h b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_regs.h new file mode 100644 index 0000000..9a4bfbf --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_regs.h @@ -0,0 +1,158 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP I2C module driver. This module is delivered as a part of Mi-V extended + * Sub-System(MIV_ESS). + */ + +#ifndef MIV_I2C_APB_REGISTERS +#define MIV_I2C_APB_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * Prescale register details + */ +#define PRESCALE_REG_OFFSET 0x00u + +/* Prescale register bits */ +#define PRESCALE_OFFSET 0x00u +#define PRESCALE_MASK 0xFFFFu +#define PRESCALE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Control register details + */ +#define CONTROL_REG_OFFSET 0x04u + +/* Control register bits */ +#define CONTROL_OFFSET 0x04u +#define CONTROL_MASK 0xC0u +#define CONTROL_SHIFT 0u + +/* Control register Core Enable Bit */ +#define CTRL_CORE_EN_OFFSET 0x04u +#define CTRL_CORE_EN_MASK 0x80u +#define CTRL_CORE_EN_SHIFT 7u + +/* Control register IRQ Enable bit */ +#define CTRL_IRQ_EN_OFFSET 0x04u +#define CTRL_IRQ_EN_MASK 0x40u +#define CTRL_IRQ_EN_SHIFT 6u + +/*------------------------------------------------------------------------------ + * Transmit register details + */ +#define TRANSMIT_REG_OFFSET 0x08u + +/* Transmit register bits */ +#define TRANSMIT_OFFSET 0x08u +#define TRANSMIT_MASK 0xFFu +#define TRANSMIT_SHIFT 0u + +/* Transmit register DIR bit */ +#define TX_DIR_OFFSET 0x08u +#define TX_DIR_MASK 0x01u +#define TX_DIR_SHIFT 0u + +/* Transmit register TARGET_ADDR bit */ +#define TX_TARGET_ADDR_OFFSET 0x08u +#define TX_TARGET_ADDR_MASK 0xFEu +#define TX_TARGET_ADDR_SHIFT 1u + +/*------------------------------------------------------------------------------ + * Receive register details + */ +#define RECEIVE_REG_OFFSET 0x0Cu + +/* Receive register bits */ +#define RECEIVE_OFFSET 0x0Cu +#define RECEIVE_MASK 0xFFu +#define RECEIVE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Command register details + */ +#define COMMAND_REG_OFFSET 0x10u + +/* Command register bits */ +#define COMMAND_OFFSET 0x10u +#define COMMAND_MASK 0xF9u +#define COMMAND_SHIFT 0u + +/* Command register IACK bit */ +#define CMD_IACK_OFFSET 0x10u +#define CMD_IACK_MASK 0x01u +#define CMD_IACK_SHIFT 0u + +/* Command register ACK bit */ +#define CMD_ACK_OFFSET 0x10u +#define CMD_ACK_MASK 0x08u +#define CMD_ACK_SHIFT 3u + +/* Command register WR bit */ +#define CMD_WR_OFFSET 0x10u +#define CMD_WR_MASK 0x10u +#define CMD_WR_SHIFT 4u + +/* Command register RD bit */ +#define CMD_RD_OFFSET 0x10u +#define CMD_RD_MASK 0x20u +#define CMD_RD_SHIFT 5u + +/* Command register STO bit */ +#define CMD_STO_OFFSET 0x10u +#define CMD_STO_MASK 0x40u +#define CMD_STO_SHIFT 6u + +/* Command register STA bit */ +#define CMD_STA_OFFSET 0x10u +#define CMD_STA_MASK 0x80u +#define CMD_STA_SHIFT 7u + +/*------------------------------------------------------------------------------ + * Status register details + */ +#define STATUS_REG_OFFSET 0x14u + +/* Command register bits */ +#define STATUS_OFFSET 0x14u +#define STATUS_MASK 0xFFu +#define STATUS_SHIFT 0u + +/* Status register Interrupt Flag(IF) bit */ +#define STAT_IF_OFFSET 0x14u +#define STAT_IF_MASK 0x01u +#define STAT_IF_SHIFT 0u + +/* Status register Transfer in Progress(TIP) bit */ +#define STAT_TIP_OFFSET 0x14u +#define STAT_TIP_MASK 0x02u +#define STAT_TIP_SHIFT 1u + +/* Status register Arbitration Lost(AL) bit */ +#define STAT_AL_OFFSET 0x14u +#define STAT_AL_MASK 0x20u +#define STAT_AL_SHIFT 5u + +/* Status register Busy(BUSY) bit */ +#define STAT_BUSY_OFFSET 0x14u +#define STAT_BUSY_MASK 0x40u +#define STAT_BUSY_SHIFT 6u + +/* Status register Ack received(RXACK) bit */ +#define STAT_RXACK_OFFSET 0x14u +#define STAT_RXACK_MASK 0x80u +#define STAT_RXACK_SHIFT 7u + + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_I2C_APB_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.c b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.c new file mode 100644 index 0000000..903f029 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.c @@ -0,0 +1,283 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * MI-V Soft IP fabric bare-metal driver for Mi-V PLIC module. This module is + * delivered as a part of Mi-V Extended Sub System(MIV_ESS). + * Please refer to miv_plic.h file for more information. + */ + +#include "miv_plic.h" + +/***************************************************************************//** + * Mi-V PLIC interrupt handler function declaration. + * These functions are called by the external interrupt handler of the MIV_RV32 + * core base on the PLIC source causing the interrupt. + */ +uint8_t Invalid_IRQHandler(void); +uint8_t MIV_PLIC_EXT0_IRQHandler(void); +uint8_t MIV_PLIC_EXT1_IRQHandler(void); +uint8_t MIV_PLIC_EXT2_IRQHandler(void); +uint8_t MIV_PLIC_EXT3_IRQHandler(void); +uint8_t MIV_PLIC_EXT4_IRQHandler(void); +uint8_t MIV_PLIC_EXT5_IRQHandler(void); +uint8_t MIV_PLIC_EXT6_IRQHandler(void); +uint8_t MIV_PLIC_EXT7_IRQHandler(void); +uint8_t MIV_PLIC_EXT8_IRQHandler(void); +uint8_t MIV_PLIC_EXT9_IRQHandler(void); +uint8_t MIV_PLIC_EXT10_IRQHandler(void); +uint8_t MIV_PLIC_EXT11_IRQHandler(void); +uint8_t MIV_PLIC_EXT12_IRQHandler(void); +uint8_t MIV_PLIC_EXT13_IRQHandler(void); +uint8_t MIV_PLIC_EXT14_IRQHandler(void); +uint8_t MIV_PLIC_EXT15_IRQHandler(void); +uint8_t MIV_PLIC_EXT16_IRQHandler(void); +uint8_t MIV_PLIC_EXT17_IRQHandler(void); +uint8_t MIV_PLIC_EXT18_IRQHandler(void); +uint8_t MIV_PLIC_EXT19_IRQHandler(void); +uint8_t MIV_PLIC_EXT20_IRQHandler(void); +uint8_t MIV_PLIC_EXT21_IRQHandler(void); +uint8_t MIV_PLIC_EXT22_IRQHandler(void); +uint8_t MIV_PLIC_EXT23_IRQHandler(void); +uint8_t MIV_PLIC_EXT24_IRQHandler(void); +uint8_t MIV_PLIC_EXT25_IRQHandler(void); +uint8_t MIV_PLIC_EXT26_IRQHandler(void); +uint8_t MIV_PLIC_EXT27_IRQHandler(void); +uint8_t MIV_PLIC_EXT28_IRQHandler(void); +uint8_t MIV_PLIC_EXT29_IRQHandler(void); +uint8_t MIV_PLIC_EXT30_IRQHandler(void); + +/***************************************************************************//** + * MIV_PLIC interrupt handler for external interrupts. + * The array of the function pointers pointing to the weak handler of the Mi-V + * PLIC interrupt handlers. + * These functions are called by the external interrupt handler of the MIV_RV32 + * core base on the PLIC source causing the interrupt. + */ +uint8_t (* const ext_irq_handler_table[32]) (void) = +{ + Invalid_IRQHandler, + MIV_PLIC_EXT0_IRQHandler, + MIV_PLIC_EXT1_IRQHandler, + MIV_PLIC_EXT2_IRQHandler, + MIV_PLIC_EXT3_IRQHandler, + MIV_PLIC_EXT4_IRQHandler, + MIV_PLIC_EXT5_IRQHandler, + MIV_PLIC_EXT6_IRQHandler, + MIV_PLIC_EXT7_IRQHandler, + MIV_PLIC_EXT8_IRQHandler, + MIV_PLIC_EXT9_IRQHandler, + MIV_PLIC_EXT10_IRQHandler, + MIV_PLIC_EXT11_IRQHandler, + MIV_PLIC_EXT12_IRQHandler, + MIV_PLIC_EXT13_IRQHandler, + MIV_PLIC_EXT14_IRQHandler, + MIV_PLIC_EXT15_IRQHandler, + MIV_PLIC_EXT16_IRQHandler, + MIV_PLIC_EXT17_IRQHandler, + MIV_PLIC_EXT18_IRQHandler, + MIV_PLIC_EXT19_IRQHandler, + MIV_PLIC_EXT20_IRQHandler, + MIV_PLIC_EXT21_IRQHandler, + MIV_PLIC_EXT22_IRQHandler, + MIV_PLIC_EXT23_IRQHandler, + MIV_PLIC_EXT24_IRQHandler, + MIV_PLIC_EXT25_IRQHandler, + MIV_PLIC_EXT26_IRQHandler, + MIV_PLIC_EXT27_IRQHandler, + MIV_PLIC_EXT28_IRQHandler, + MIV_PLIC_EXT29_IRQHandler, + MIV_PLIC_EXT30_IRQHandler +}; + +/* Mi-V PLIC interrupt weak handlers */ +__attribute__((weak)) uint8_t Invalid_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT0_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT1_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT2_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT3_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT4_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT5_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT6_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT7_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT8_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT9_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT10_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT11_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT12_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT13_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT14_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT15_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT16_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT17_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT18_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT19_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT20_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT21_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT22_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT23_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT24_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT25_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT26_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT27_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT28_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT29_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT30_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +/*-------------------------------------------------------------------------*//** + * Please refer to miv_plic.h for more information about this function. +*/ +void +MIV_PLIC_isr +( + miv_plic_instance_t *this_plic +) +{ + unsigned long hart_id = read_csr(mhartid); + + /* claim the interrupt from PLIC controller */ + + uint32_t int_num = HAL_get_32bit_reg(this_plic->base_addr + + (0x1000 * hart_id), INT_CLAIM_COMPLETE); + + uint8_t disable = EXT_IRQ_KEEP_ENABLED; + disable = ext_irq_handler_table[int_num](); + + /* Indicate the PLIC controller that the interrupt is processed and claim is + * complete. */ + HAL_set_32bit_reg(this_plic->base_addr + + (0x1000 * hart_id), INT_CLAIM_COMPLETE, int_num); + + if (EXT_IRQ_DISABLE == disable) + { + MIV_PLIC_disable_irq(this_plic, (miv_plic_irq_num_t)int_num); + } +} diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.h b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.h new file mode 100644 index 0000000..f5d64cd --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.h @@ -0,0 +1,425 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * PLIC module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(ESS). + */ + /*=========================================================================*//** + @mainpage Mi-V PLIC Bare Metal Driver + + ============================================================================== + Introduction + ============================================================================== + The Mi-V driver provides a set of functions for controlling the Mi-V PLIC + (platform level interrupt controller) soft-IP module. This module is delivered + as a part of the MIV_ESS. The PLIC multiplexes external interrupt signals into + a single interrupt signal that is connected to an external interrupt of the + processor. + + The major features provided by the driver are: + - Support for configuring the PLIC instances. + - Enabling and Disabling interrupts + - Interrupt Handling + + This driver can be used as part of a bare metal system where no operating + system is available. The driver can be adapted for use as part of an + operating system, but the implementation of the adaptation layer between the + driver and the operating system's driver model is outside the scope of this + driver. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + The application software should initialize the Mi-V PLIC through the call to + the MIV_PLIC_init() function for Mi-V PLIC instance in the design. + + No Mi-V PLIC hardware configuration parameters are used by the driver, apart + from the Mi-V PLIC base address. Hence, no additional configuration files + are required to use the driver. + + ============================================================================== + Theory of Operation + ============================================================================== + The operation of Mi-V PLIC driver is divided into following steps: + - Initialization + - Enabling and Disabling interrupts + - Interrupt control + + -------------------------------------------- + Initialization + -------------------------------------------- + The Mi-V PLIC module is first initialized by the call to MIV_PLIC_init(). This + function takes a pointer to the Mi-V PLIC instance data structure and the base + address of the Mi-V PLIC instance is defined by the hardware design. The + instance data structure is used to store the base address of the Mi-V PLIC + module and a pointer to the Mi-V PLIC register data structure. The Mi-V PLIC + register data structure maps the address of the Mi-V PLIC registers. + + --------------------------------------------- + Enabling and Disabling interrupts + --------------------------------------------- + The MIV_PLIC_enable_irq() function enables the specific interrupt provided by + user. A call to this function will allow the enabling of each of the global + interrupts corresponding to the bit in the interrupt enable register of Mi-V + PLIC. + The MIV_PLIC_disable_irq() function disables the specific interrupt provided + by the user. This function can be used to disable the interrupts from outside + of the external interrupt handler. + + ---------------------------------------- + Interrupt Control + ---------------------------------------- + When an interrupt occurs on an enabled interrupt, the PLIC gateway captures + the interrupt and asserts the corresponding interrupt pending bit. Once + the enable bit and pending bit are asserted, then the PLIC_IRQ signal asserts + until the interrupt is claimed by the driver interrupt handler MIV_PLIC_irq() + function. + When multiple interrupts assert then the lowest interrupt number will be + serviced first, for example, if interrupt 1 and 6 assert at the same time, + interrupt 1 will be serviced first, followed by interrupt 6. + +*/ + +#ifndef MIV_PLIC_H_ +#define MIV_PLIC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "miv_plic_regs.h" + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#include "miv_rv32_hal/miv_rv32_hal.h" +#else +#include "hal.h" +#include "miv_rv32_hal.h" +#endif + +/*-------------------------------------------------------------------------*//** + This enumeration is used to select a specific Mi-V PLIC interrupt. It is + used as a parameter to enable or disable the interrupt. +*/ +typedef enum miv_plic_irq_num +{ + NoInterrupt_IRQn = 0, + MIV_PLIC_EXT0_IRQn = 1, + MIV_PLIC_EXT1_IRQn = 2, + MIV_PLIC_EXT2_IRQn = 3, + MIV_PLIC_EXT3_IRQn = 4, + MIV_PLIC_EXT4_IRQn = 5, + MIV_PLIC_EXT5_IRQn = 6, + MIV_PLIC_EXT6_IRQn = 7, + MIV_PLIC_EXT7_IRQn = 8, + MIV_PLIC_EXT8_IRQn = 9, + MIV_PLIC_EXT9_IRQn = 10, + MIV_PLIC_EXT10_IRQn = 11, + MIV_PLIC_EXT11_IRQn = 12, + MIV_PLIC_EXT12_IRQn = 13, + MIV_PLIC_EXT13_IRQn = 14, + MIV_PLIC_EXT14_IRQn = 15, + MIV_PLIC_EXT15_IRQn = 16, + MIV_PLIC_EXT16_IRQn = 17, + MIV_PLIC_EXT17_IRQn = 18, + MIV_PLIC_EXT18_IRQn = 19, + MIV_PLIC_EXT19_IRQn = 20, + MIV_PLIC_EXT20_IRQn = 21, + MIV_PLIC_EXT21_IRQn = 22, + MIV_PLIC_EXT22_IRQn = 23, + MIV_PLIC_EXT23_IRQn = 24, + MIV_PLIC_EXT24_IRQn = 25, + MIV_PLIC_EXT25_IRQn = 26, + MIV_PLIC_EXT26_IRQn = 27, + MIV_PLIC_EXT27_IRQn = 28, + MIV_PLIC_EXT28_IRQn = 29, + MIV_PLIC_EXT29_IRQn = 30, + MIV_PLIC_EXT30_IRQn = 31 +} miv_plic_irq_num_t; + +/*--------------------------------------------------------------------------*//* + * This structure maps the priority threshold and claim complete register in + * the memory. + */ +typedef struct +{ + volatile uint32_t PRIORITY_THRESHOLD; + volatile uint32_t CLAIM_COMPLETE; + volatile uint32_t reserved[1022]; +} IRQ_Target_Type; + +/*--------------------------------------------------------------------------*//* + * This structure maps the Interrupt enable sources from 0 - 1023 for one + * context. + */ +typedef struct +{ + volatile uint32_t ENABLES[32]; +} Target_Enables_Type; + +/*-------------------------------------------------------------------------*//** + This structure holds the base address of the Mi-V PLIC module. This structure + is used by all the functions to access the Mi-V PLIC registers. +*/ +typedef struct miv_plic_instance +{ + addr_t base_addr; +} miv_plic_instance_t; + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_isr is the top level interrupt handler function for the Mi-V PLIC + * driver. You must call the MIV_PLIC_isr() from the system level interrupt + * handler(External_IRQHandler). + * This function must be called from the external interrupt handler function + * provided by the processor hardware abstraction layer. In case of MIV_RV32 + * soft processor, it must be called from External_IRQHandler() function + * provided by MIV_RV32 HAL. + * + * The MIV_PLIC_isr() function claims the interrupt number + * that triggered the interrupt and then invokes the appropriate PLIC interrupt + * handler. + * After handling the PLIC interrupt, this function will complete the interrupt + * by clearing the claim complete bit for the particular interrupt source. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * + * @return + * This function does not return any value. + * + * Example: + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * uint8_t MIV_PLIC_EXT0_IRQHandler(void) + * { + * *** ISR operation *** + * + * return(EXT_IRQ_KEEP_ENABLED); + * } + * + * void External_IRQHandler(void) + * { + * uint32_t reg_val = read_csr(mip); + * MIV_PLIC_isr(&g_plic); + * } + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * } + * @endcode + */ +void MIV_PLIC_isr(miv_plic_instance_t *this_plic); + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_init() function initializes the Mi-V PLIC instance with base + * address. This function resets the PLIC controller by disabling all the PLIC + * interrupts. + * + * Note: This function must be called before calling any other Mi-V PLIC driver + * function. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * + * @param base_addr + * Base address of the Mi-V PLIC instance in the MIV_ESS soft-IP. + * + * @param ext_intr_sources + * Number of interrupts initialized in the design. + * + * @return + * This function does not return any value. + * + * Example + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * } + * @endcode + */ +static inline void +MIV_PLIC_init +( + miv_plic_instance_t *this_plic, + addr_t base_addr, + uint8_t ext_intr_sources +) +{ + uint32_t inc; + unsigned long hart_id = read_csr(mhartid); + + this_plic->base_addr = base_addr; + + /* Disable all interrupts for the current hart. + * The PLIC_EXT_INTR_SOURCES should be defined in the hw_platform.h. This + * macro holds the number of PLIC interrupts enabled in the design. + */ + for(inc = 0; inc < ((ext_intr_sources + 32u) / 32u); ++inc) + { + HAL_set_32bit_reg( + (this_plic->base_addr + inc + (hart_id * 128)), INT_ENABLE , 0x0u); + } +} + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_enable_irq() function enables the PLIC interrupt provided with + * IRQn parameter. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * @param IRQn + * Number of PLIC interrupt to enable. + * + * @return + * This function does not return any value. + * + * Example + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * } + * @endcode + */ +static inline void +MIV_PLIC_enable_irq +( + miv_plic_instance_t *this_plic, + miv_plic_irq_num_t IRQn +) +{ + unsigned long hart_id = read_csr(mhartid); + + uint32_t current = HAL_get_32bit_reg( + (this_plic->base_addr + (IRQn/32) + (hart_id * 128)) , INT_ENABLE); + + current |= (uint32_t)1 << (IRQn % 32); + + HAL_set_32bit_reg( + (this_plic->base_addr + (IRQn/32) + (hart_id * 128)), INT_ENABLE, current); + +} + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_disable_irq() function disables the PLIC interrupt provided with + * IRQn parameter. + * + * NOTE: + * This function can be used to disable the PLIC interrupt from outside the + * external interrupt handler functions. + * If you wish to disable the PLIC interrupt from the external interrupt handler, + * you should use the return value of EXT_IRQ_DISABLE. This will disable the + * selected PLIC interrupt from the Mi-V PLIC driver interrupt handler. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * @param IRQn + * Number of PLIC interrupt to disable. + * + * @return + * This function does not return any value. + * + * Example + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * } + * @endcode + */ +static inline void +MIV_PLIC_disable_irq +( + miv_plic_instance_t *this_plic, + miv_plic_irq_num_t IRQn +) +{ + unsigned long hart_id = read_csr(mhartid); + + uint32_t current = HAL_get_32bit_reg((this_plic->base_addr + (IRQn/32) + (hart_id * 128)) , INT_ENABLE); + + current &= ~((uint32_t)1 << (IRQn % 32)); + + HAL_set_32bit_reg((this_plic->base_addr + (IRQn/32) + (hart_id * 128)), INT_ENABLE, current); + +} + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_PLIC_H_ */ diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic_regs.h b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic_regs.h new file mode 100644 index 0000000..76cbc0b --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic_regs.h @@ -0,0 +1,31 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP PLIC module driver. This module is delivered as a part of Mi-V extended + * Sub-System(MIV_ESS). + */ + +#ifndef MIV_PLIC_REGISTERS +#define MIV_PLIC_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Interrupt pending register offset */ +#define INT_PENDING_REG_OFFSET 0x1000u + +/* Interrupt enable register */ +#define INT_ENABLE_REG_OFFSET 0x2000u + +/* Interrupt claim complete register */ +#define INT_CLAIM_COMPLETE_REG_OFFSET 0x200004u + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_PLIC_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_timer/miv_timer.h b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_timer/miv_timer.h new file mode 100644 index 0000000..5f00889 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_timer/miv_timer.h @@ -0,0 +1,329 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Mi-V Timer Soft IP bare-metal driver. This module is delivered as part of + * the Mi-V Extended Sub System(ESS) MIV_ESS. + */ + +/*=========================================================================*//** + @mainpage Mi-V Timer Bare Metal Driver. + The Mi-V Timer bare metal software driver supports the timer module which + serves as a system timer for the Mi-V Extended Sub System(ESS). + + @section intro_sec Introduction + The MI-V Timer driver supports set of functions for controlling the Mi-V + Timer module. + The Mi-V Timer can generate a timer interrupt signal for the system based on + special system clock intervals specified by the parameters that can be passed + in by the user. + + The major features provided by Mi-V Timer driver are: + - Support for Mi-V Timer instance for each Mi-V Timer peripheral. + - Read current time + - Write to the machine time compare register + + @section hw_dependencies Hardware Flow dependency + The application should configure the Mi-V Timer driver through calls to + MIV_TIMER_init() functions for each MIV_TIMER instance in the hardware + design. The configuration parameter include the MIV_TIMER hardware instance, + base address and number of ticks to generate timer interrupt. + + MIV_RV32 core offers flexibility in terms of generating the MTIME and MTIMECMP + registers internal to the core or using external time reference. + When MIV_ESS is interfaced with MIV_RV32 core, the timer module in the MIV_ESS + can be configured as follows: + - Internal MTIME External MTIME IRQ + Generate the MTIME internally(MIV_RV32) and have a timer interrupt input + to the core as external pin(from MIV_ESS). + + - External MTIME Internal MTIME IRQ + Generate the time value externally(from MIV_ESS), in this case a 64-bit + port will open in the MIV_RV32 core as input and MIV_ESS will output the + 64-bit TIME_COUNT value. The generation of mtimecmp and interrupt is + done internally(MIV_RV32). + + - External MTIME External MTIME IRQ + Generate both the time and timer interrupt externally. + In this case 64-bit port will be available on the Mi-V RV32 core as input + and a 1 pin port will be available for timer interrupt. + + The design must be configured accordingly to use these combinations in the + firmware. + + No MIV_TIMER hardware configuration parameters are used by the driver, apart + from MIV_TIMER base address. Hence, no additional configuration files are + required to use the driver. + + @section theory_op Theory of Operation + + The MIV_TIMER module is a simple systick timer which can generate a timer + interrupt signal for the system at specific intervals specified by the + parameters that can be passed by the user. + These interrupt signal are then fed to the MIV_RV32 core via timer interrupt. + + The operation of MIV_TIMER is divided into following steps: + - Initialization + - Configuration + - Read/Write TIME + + ## Initialization + The MIV_TIMER is first initialized by a call to MIV_TIMER_init(). This + function initializes the instance of Mi-V TIMER with the base address. + The MIV_TIMER_init() function must be called before any other Mi-V Timer driver + function. + + ## Configuration + The Mi-V TIMER configuration includes writing the mtimecmp register with the + initial time value at which timer interrupt should be generated. + When the mtime register value becomes greater than or equal to mtimecmp value, + a timer interrupt signal(TIMER_IRQ) is generated. + + ## Read/Write TIME + The time value can be read by reading the mtime register via call to the + MIV_TIMER_read_mtime(). This function reads the MTIME register which contains + the 64-bit value of the timer count. The count increments by 1 every time the + prescale ticks. This function returns 64-bit MTIME_COUNT value which is the + current value of timer count. + + The time value read in the MIV_TIMER_read_mtime() function can be written to + the mtimecmp register by calling MIV_TIMER_write_mtimecmp() to generate + periodic interrupts. + The writing of the mtimecmp register should be done in the systick_handler() + function. + */ + +#ifndef MIV_TIMER_H_ +#define MIV_TIMER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#endif +/*-------------------------------------------------------------------------*//** +MIV_TIMER_SUCCESS +===================== + +The MIV_TIMER_SUCCESS constant indicates successful configuration of +Mi-V Timer module. +*/ +#define MIV_TIMER_SUCCESS 0u + +/*-------------------------------------------------------------------------*//** +MIV_TIMER_ERROR +===================== + +The MIV_TIMER_ERROR constant indicates that there is an error with +configuring the Mi-V Timer module. +*/ +#define MIV_TIMER_ERROR 1u + +/*-------------------------------------------------------------------------*//* +MIV_TIMER_MASK_32BIT +===================== + +32-bit mask constant used in calculation of 64-bit register value. +*/ +#define MIV_TIMER_MASK_32BIT 0xFFFFFFFFu + +/*-------------------------------------------------------------------------*//* +Mi-V Timer register offsets +===================== +The MTIMECMP is the 64-bit timer compare register, it pre-sets the threshold +which needs to be reached by the timer count register. +This 64-bit register is accessed with 2 32-bit address offset, lower 32-bits +and higher 32-bits. + - MIV_TIMER_MTIMECMP_L_REG_OFFSET + - MIV_TIMER_MTIMECMP_H_REG_OFFSET + +The MTIME is the 64-bit register that contains the 64-bit timer count. The +count increments by 1 every time the prescaler ticks. +This 64-bit register is accessed with 2 32-bit address offset, lower 32-bits +and higher 32-bits. + - MIV_TIMER_MTIME_L_REG_OFFSET + - MIV_TIMER_MTIME_H_REG_OFFSET + +The PRESCALE register is used to determine the amount of clock cycles the +selected clock needs to go through, for MTIME register to increment count. + - MIV_TIMER_PRESCALAR_REG_OFFSET +*/ + +/// @cond private +#define MIV_TIMER_MTIMECMP_L_REG_OFFSET 0x4000u +#define MIV_TIMER_MTIMECMP_H_REG_OFFSET 0x4004u + +#define MIV_TIMER_MTIME_L_REG_OFFSET 0xBFF8u +#define MIV_TIMER_MTIME_H_REG_OFFSET 0xBFFCu + +#define MIV_TIMER_PRESCALAR_REG_OFFSET 0x5000u +/// @endcond + +/*-------------------------------------------------------------------------*//** + This structure holds the base address of the Mi-V Timer module and instance + of the Mi-V Timer register structure. +*/ +typedef struct miv_timer_instance +{ + addr_t base_addr; +} miv_timer_instance_t; + +/** The MIV_TIMER_init() is used to initialize the Mi-V Timer module. This + function will assign the base addresses of the Mi-V Timer module. + User should call this function before calling any of the Mi-V Timer driver + APIs. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @param base_address + Base address of the Mi-V Timer module. + + @return + This function does not return any value. + */ +static inline void +MIV_TIMER_init +( + miv_timer_instance_t* this_timer, + addr_t base_addr +) +{ + this_timer->base_addr = base_addr; +} + +/** MIV_TIMER_read_current_time() is used to read the mtimecmp register values. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @return + This function returns 64-bit mtimecmp register value. + */ +static inline uint64_t +MIV_TIMER_read_current_time +( + miv_timer_instance_t* this_timer +) +{ + volatile uint64_t read_data = 0u; + volatile uint32_t mtime_hi = 0u; + volatile uint32_t mtime_lo = 0u; + + /* when mtime lower word is 0xFFFFFFFF, there will be rollover and + * returned value could be wrong. */ + do { + mtime_hi = HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIME_H); + mtime_lo = HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIME_L); + + } while(mtime_hi != HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIME_H)); + + read_data = mtime_hi; + + return(((read_data) << 32u) | mtime_lo); +} + +/** MIV_TIMER_write_compare_time() is used to write to the MTIMECMP register in + the event of interrupt. User must use this function in the interrupt handler + to de-assert the MIV_TIMER interrupt. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @param write_value + Value to write into the mtimecmp register. + + @return + This function does not return any value. + */ +static inline void +MIV_TIMER_write_compare_time +( + miv_timer_instance_t* this_timer, + uint64_t compare_reg_value +) +{ + HAL_set_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIMECMP_H, MIV_TIMER_MASK_32BIT); + + HAL_set_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIMECMP_L, + (compare_reg_value & MIV_TIMER_MASK_32BIT)); + + HAL_set_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIMECMP_H, + ((compare_reg_value >> 32u) & MIV_TIMER_MASK_32BIT)); +} + +/** The MIV_TIMER_config() is used to configure the MIV_ESS Timer module. The + prescale value serves to divide the count of clock cycles for the timer and + provides control over what point in time, the timer interrupt gets + asserted. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @param ticks + Number of ticks after which interrupt will be generated. + + @return + This function returns Mi-V Timer configuration status. + */ +static inline uint32_t +MIV_TIMER_config +( + miv_timer_instance_t* this_timer, + uint64_t ticks +) +{ + uint32_t ret_val = MIV_TIMER_ERROR; + uint64_t mtime_val = 0u; + uint32_t prescalar = 0u; + uint64_t miv_timer_increment = 0U; + + prescalar = HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_PRESCALAR); + + miv_timer_increment = (uint64_t)(ticks) / prescalar; + + if (miv_timer_increment > 0U) + { + mtime_val = MIV_TIMER_read_current_time(this_timer); + + MIV_TIMER_write_compare_time(this_timer ,(mtime_val + miv_timer_increment)); + + ret_val = MIV_TIMER_SUCCESS; + } + + return ret_val; +} + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_TIMER_H */ diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c new file mode 100644 index 0000000..cbd9652 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c @@ -0,0 +1,109 @@ +/******************************************************************************* + * (c) Copyright 2022-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Mi-V uDMA Soft IP bare-metal driver. This module is delivered as part of + * Mi-V Extended Sub System(MIV_ESS) + */ + +#include "miv_udma_regs.h" +#include "miv_udma.h" + +/***************************************************************************//** + * MIV_uDMA_init() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_init +( + miv_udma_instance_t* this_udma, + addr_t base_addr +) +{ + /* Assign the Mi-V uDMA base address to the uDMA instance structure */ + this_udma->base_address = base_addr; +} + +/***************************************************************************//** + * MIV_uDMA_config() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_config +( + miv_udma_instance_t* this_udma, + addr_t src_addr, + addr_t dest_addr, + uint32_t transfer_size, + uint32_t irq_config +) +{ + /* Source memory start address */ + HAL_set_32bit_reg(this_udma->base_address, SRC_START_ADDR, src_addr); + + /* Destination memory start address */ + HAL_set_32bit_reg(this_udma->base_address, DEST_START_ADDR, dest_addr); + + /* Data transfer size */ + HAL_set_32bit_reg(this_udma->base_address, BLK_SIZE, transfer_size); + + /* Configure the uDMA IRQ */ + HAL_set_32bit_reg(this_udma->base_address, IRQ_CFG, irq_config); +} + +/***************************************************************************//** + * MIV_uDMA_start() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_start +( + miv_udma_instance_t* this_udma +) +{ + /* Start the uDMA transfer */ + HAL_set_32bit_reg(this_udma->base_address, CONTROL_SR, CTRL_START_TX_MASK); +} + +/***************************************************************************//** + * MIV_uDMA_reset() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_reset +( + miv_udma_instance_t* this_udma +) +{ + /* Toggle the uDMA_reset bit to reset the uDMA. + * Resetting the uDMA will clear all the configuration made by + * MIV_uDMA_config(). + * + * This function should be called from the interrupt handler to clear the + * IRQ. + */ + HAL_set_32bit_reg_field(this_udma->base_address, CTRL_RESET_TX, 0x1u); + HAL_set_32bit_reg_field(this_udma->base_address, CTRL_RESET_TX, 0x0u); +} + +/***************************************************************************//** + * MIV_uDMA_read_status() + * See "miv_udma.h" for details of how to use this function. + */ +uint32_t +MIV_uDMA_read_status +( + miv_udma_instance_t* this_udma +) +{ + uint32_t status = 0u; + + /* Read the status of the uDMA transfer. + * The transfer status register can be Error or Busy depending on the + * current uDMA transfer. + */ + status = HAL_get_32bit_reg(this_udma->base_address, TX_STATUS); + + return status; +} diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h new file mode 100644 index 0000000..efa8731 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h @@ -0,0 +1,290 @@ +/******************************************************************************* + * Copyright 2022-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * uDMA module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(MIV_ESS). + */ + +/*=========================================================================*//** + @mainpage Mi-V uDMA Bare Metal Driver. + The Mi-V uDMA bare metal software driver. + + @section intro_sec Introduction + The Mi-V uDMA driver provides a set of functions to control the Mi-V uDMA + module in the Mi-V Extended Subsystem (MIV_ESS) soft-IP. The Mi-V uDMA module + allows peripherals with AHB interfaces to transfer data independently of the + MIV_RV32 RISC-V processor. + + Following are the major features provided by the Mi-V uDMA driver: + - Initialization and configuration + - Start and reset the transaction + + This driver can be used as part of a bare metal system where no operating + system is available. The driver can be adapted for use as part of an + operating system, but the implementation of the adaptation layer between the + driver and the operating system's driver model is outside the scope of this + driver. + + @section hw_dependencies Hardware Flow Dependency + The application software should initialize and configure the Mi-V uDMA through + calling the MIV_uDMA_init() and MIV_uDMA_config() functions for each Mi-V + uDMA instance in the design. + + The uDMA can operate in two possible transfer configurations: + + - AHBL Read -> AHBL Write: + In this configuration, the uDMA reads data from the source memory over an + AHBL (mirrored main/initiator) read interface and writes data to the + destination memory over an AHBL (mirrored main/initiator) write interface. + + - AHBL Read -> TAS Write: + In this configuration, the uDMA reads data from the source memory over an + AHBL (mirrored main/initiator) read interface and writes data to the + destination memory over the TAS (mirrored main/initiator) write interface. + + Note: The AHBL Read -> TAS Write configuration is out of scope for this + driver. + + @section theory_op Theory of Operation + The uDMA module in the Mi-V Extended Sub System (MIV_ESS) is a single-channel + uDMA module that allows peripherals to perform read-write operations between + source and destination memory. The Mi-V uDMA driver is used in + interrupt-driven mode and uses the Mi-V uDMA IRQ signal to drive the + interrupt service routine (ISR), which signifies a transfer has completed. + The status is checked in the ISR to ensure the transfer is completed + successfully. + The reset operation in the ISR resets the Mi-V uDMA controller. Once the Mi-V + uDMA transfer is complete, Mi-V uDMA retires. To initiate another + transaction, Mi-V uDMA needs to be configured again. + + The operation of the Mi-V uDMA driver is divided into the following + categories: + - Initialization + - Configuration + - Start and reset the transfer + + Initialization and configuration: + Mi-V uDMA is first initialized by calling MIV_uDMA_init() function. This + function initializes the instance of Mi-V uDMA with the base address. The + MIV_uDMA_init() function must be called before calling any other Mi-V uDMA + driver functions. + + The Mi-V uDMA is configured by calling MIV_uDMA_config() function. This + function configures the source_addr and dest_addr registers of the Mi-V + uDMA with source and destination addresses for Mi-V uDMA transfers. + This function also configures the transfer size and interrupt preference for + successful transfers using Mi-V uDMA. + + Start and reset the transfer: + Once the Mi-V uDMA is configured, initiate the transfers by calling the + MIV_uDMA_start() function. Once the Mi-V uDMA transfer is started, it cannot + be aborted, and the status of the transfer should be read from the ISR by + calling the MIV_uDMA_read_status() function. + + Reset the Mi-V uDMA to the default state by calling the MIV_uDMA_reset() + function. After performing the reset operation, reconfigure the Mi-V uDMA to + perform transfers as MIV_uDMA_reset() resets the Mi-V uDMA controller. + */ + +#ifndef MIV_uDMA_H_ +#define MIV_uDMA_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#include "hal/cpu_types.h" + +#else +#include "hal.h" +#include "cpu_types.h" +#endif + +/*-------------------------------------------------------------------------*//** + MIV_uDMA_CTRL_IRQ_CONFIG + ===================== + + The MIV_uDMA_CTRL_IRQ_CONFIG macro is used to assert the uDMA IRQ when an error + occurs during a uDMA transfer or on the completion of a uDMA transfer. + */ +#define MIV_uDMA_CTRL_IRQ_CONFIG 1u + +/*-------------------------------------------------------------------------*//** + MIV_uDMA_STATUS_BUSY + ===================== + + The MIV_uDMA_STATUS_BUSY macro is used to indicate that the uDMA transfer is + in progress. + */ +#define MIV_uDMA_STATUS_BUSY 1u + +/*-------------------------------------------------------------------------*//** + MIV_uDMA_STATUS_ERROR + ===================== + + The MIV_uDMA_STATUS_ERROR macro is used to indicate that the last uDMA + transfer has caused an error. + */ +#define MIV_uDMA_STATUS_ERROR 2u + +/***************************************************************************//** + * This structure holds the base of the Mi-V uDMA module, which is used in the + * other functions of the driver to access the uDMA registers. + */ +typedef struct miv_udma_instance +{ + addr_t base_address; +} miv_udma_instance_t; + +/***************************************************************************//** + * The MIV_uDMA_init() function assigns the base address of the Mi-V uDMA module + * to the uDMA instance structure. + * This address is used in a later part of the driver to access the uDMA + * registers. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure. + * + * @param base_addr + * Base address of the Mi-V uDMA module. + * + * @return + * This function does not return a value. + */ +void +MIV_uDMA_init +( + miv_udma_instance_t* this_udma, + addr_t base_addr +); + +/***************************************************************************//** + * The MIV_uDMA_config() function is used to configure the Mi-V uDMA controller. + * This function will set the source address, destination address, block size, + * and IRQ configuration register. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @param base_addr + * Base address of the Mi-V uDMA. + * + * @param src_addr + * Source address of memory from where the uDMA reads the data. + * + * @param dest_addr + * Destination address where the data is written from src_addr. + * + * @param transfer_size + * Number of 32-bit words to transfer. + * + * @param irq_config + * uDMA IRQ configuration + * - When set, the IRQ is asserted when an error occurs during a uDMA + * transfer or on the completion of the uDMA transfer. + * - When clear, the IRQ is only asserted when an error occurs during a + * uDMA transfer. + * + * @return + * This function does not return any value. + */ +void +MIV_uDMA_config +( + miv_udma_instance_t* this_udma, + addr_t src_addr, + addr_t dest_addr, + uint32_t transfer_size, + uint32_t irq_config +); + +/***************************************************************************//** + * The MIV_uDMA_start() function is used to start the uDMA transfer. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @return + * This function does not return any value. + */ +void +MIV_uDMA_start +( + miv_udma_instance_t* this_udma +); + +/***************************************************************************//** + * The MIV_uDMA_reset() function is used to clear the uDMA interrupt and reset + * the uDMA transfer. + * + * This function should be called from the interrupt handler to reset the values + * set during MIV_uDMA_config(). + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @return + * This function does not return any value. + */ +void +MIV_uDMA_reset +( + miv_udma_instance_t* this_udma +); + +/***************************************************************************//** + * The MIV_uDMA_read_status() function is used to read the status of the uDMA + * transfer. When interrupt is enabled, this function can be called from the + * interrupt handler to know the reason for a uDMA interrupt. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @return + * The return value indicates an error due to the busy status of the uDMA + * channel. + * + * |Bit Number| Name | Description | + * |----------|---------|------------------------------------------------------| + * | 0 | Busy | When set indicates that uDMA transfer is in progress| + * | 1 | Error | When set indicates that last uDMA transfer caused an| + * | | | error. | + */ +uint32_t +MIV_uDMA_read_status +( + miv_udma_instance_t* this_pdma +); + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_uDMA_H_ */ diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h new file mode 100644 index 0000000..14d0759 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h @@ -0,0 +1,94 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP uDMA module driver. This module is delivered as a part of Mi-V + * extended Sub-System(ESS) MIV_ESS. + */ + +#ifndef MIV_UDMA_APB_REGISTERS +#define MIV_UDMA_APB_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/**************************************************************************//** + * Control start/Reset register details + */ + +#define CONTROL_SR_REG_OFFSET 0x0u + +/* Control start/Reset register bits */ +#define CONTROL_SR_OFFSET 0x00u +#define CONTROL_SR_MASK 0x03u +#define CONTROL_SR_SHIFT 0u + +/* uDMA Control Start Transfer */ + +#define CTRL_START_TX_OFFSET 0x00u +#define CTRL_START_TX_MASK 0x01u +#define CTRL_START_TX_SHIFT 0u + +/* uDMA Control Reset Transfer */ +#define CTRL_RESET_TX_OFFSET 0x00u +#define CTRL_RESET_TX_MASK 0x02u +#define CTRL_RESET_TX_SHIFT 1u + +/**************************************************************************//** + * IRQ Configuration register details + */ +#define IRQ_CFG_REG_OFFSET 0x4u + +/* Control start/Reset register bits */ +#define IRQ_CFG_OFFSET 0x04u +#define IRQ_CFG_MASK 0x01u +#define IRQ_CFG_SHIFT 0u + +/***************************************************************************//** + * Transfer Status register details + */ +#define TX_STATUS_REG_OFFSET 0x08u + +/* Transfer status register bits */ +#define TX_STATUS_OFFSET 0x08u +#define TX_STATUS_MASK 0x03u +#define TX_STATUS_SHIFT 0u + +/***************************************************************************//** + * Source Memory Start Address Register + */ +#define SRC_START_ADDR_REG_OFFSET 0x0cu + +/* Source Memory Start Address Register bits */ +#define SRC_START_ADDR_OFFSET 0x0cu +#define SRC_START_ADDR_MASK 0xFFFFFFFFu +#define SRC_START_ADDR_SHIFT 0u + +/***************************************************************************//** + * Destination Memory Start Address register details + */ +#define DEST_START_ADDR_REG_OFFSET 0x10u + +/* Destination Memory Start Address register bits */ +#define DEST_START_ADDR_OFFSET 0x10u +#define DEST_START_ADDR_MASK 0xFFFFFFFFu +#define DEST_START_ADDR_SHIFT 0x0u + +/***************************************************************************//** + * Block Size register details + */ +#define BLK_SIZE_REG_OFFSET 0x14u + +/* Destination Memory Start Address register bits */ +#define BLK_SIZE_OFFSET 0x14u +#define BLK_SIZE_MASK 0xFFFFFFFFu +#define BLK_SIZE_SHIFT 0x0u + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_UDMA_APB_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c new file mode 100644 index 0000000..525928a --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Mi-V Watchdog Soft IP bare-metal driver. This module is delivered as part of + * Extended Sub System(ESS) MIV_ESS. + * Please refer to miv_watchdog.h file for more information. + */ + +#include "miv_watchdog.h" + +addr_t g_this_wdog; + +/***************************************************************************//* + * Please refer to miv_watchdog.h for more info about this function + */ +void +MIV_WDOG_init +( + addr_t base_addr +) +{ + /* Register the Mi-V Watchdog base address to the driver */ + g_this_wdog = base_addr; +} + +/***************************************************************************//* + * Please refer to miv_watchdog.h for more info about this function + */ +uint8_t MIV_WDOG_configure +( + const miv_wdog_config_t *config +) +{ + uint8_t error = 0u; + + /* check load value and trigger max value */ + if (config->timeout_val <= MIV_WDOG_TRIGGER_MAX) + { + HAL_set_32bit_reg(g_this_wdog, WDOGTRIG,(config->timeout_val)); + } + else + { + error = 1u; + } + + if (config->time_val <= MIV_WDOG_TIMER_MAX) + { + HAL_set_32bit_reg(g_this_wdog, WDOGMSVP,(config->mvrp_val)); + } + else + { + error = 1u; + } + + HAL_set_32bit_reg_field(g_this_wdog, WDOGCNTL_NEXT_ENFORBIDDEN, + config->forbidden_en); + + /* Reload watchdog with new load if it is not in forbidden window */ + if (!(WDOGSTAT_FORBIDDEN_MASK & (HAL_get_32bit_reg(g_this_wdog, WDOGSTAT)))) + { + HAL_set_32bit_reg(g_this_wdog, WDOGRFSH, MIV_WDOG_REFRESH_KEY); + } + else + { + error = 1u; + } + + return (error); +} + +/***************************************************************************//* + * Please refer to miv_watchdog.h for more info about this function + */ +void MIV_WDOG_get_config +( + miv_wdog_config_t *config +) +{ + if (0 != g_this_wdog) + { + + config->time_val = HAL_get_32bit_reg(g_this_wdog, WDOGTIME); + + config->timeout_val = HAL_get_32bit_reg(g_this_wdog, WDOGTRIG); + + config->mvrp_val = HAL_get_32bit_reg(g_this_wdog, WDOGMSVP); + + config->forbidden_en = HAL_get_32bit_reg_field(g_this_wdog, + WDOGCNTL_NEXT_ENFORBIDDEN); + } +} + diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h new file mode 100644 index 0000000..8877e55 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h @@ -0,0 +1,553 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * Watchdog module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(MIV_ESS). + */ +/*=========================================================================*//** + @mainpage MiV Watchdog Bare Metal Driver + + ============================================================================== + Introduction + ============================================================================== + The Mi-V Watchdog module in the MIV_ESS is used to generate a reset for the + system automatically if the software doesn't periodically update or refresh + the timer countdown register. This software driver provides set of functions + for controlling Mi-V Watchdog module as a part of bare metal system where no + operating system is available. The driver can be adapted for use as a part of + an operating system, but the implementation of the adaptation layer between + the driver and the operating system's driver model is outside the scope of the + driver. + + Mi-V Watchdog provides following features: + - Initializing the Mi-V Watchdog + - Reading current value and status of watchdog timer + - Refreshing the watchdog timer value + - Enabling, disabling and clearing timeout and Maximum Value up to which + Refresh is Permitted (MVRP) interrupts. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + The application software should initialize and configure the Mi-V Watchdog + module the the call to the MIV_WDOG_init() and MIV_WDOG_configure() functions. + + No MIV_WDOG hardware configuration parameter are used by the driver, apart + from the MIV_WDOG base address. Hence, no additional configuration files are + required to use the driver. + + ============================================================================== + Theory of Operation + ============================================================================== + The Mi-V Watchdog driver functions are grouped into the following categories: + - Initialization and configuration + - Reading the current value and status of the watchdog timer + - Refreshing the watchdog timer value + - Support for enabling, disabling and clearing time-out and MVRP interrupts. + + -------------------------------- + Initialization and Configuration + -------------------------------- + The MIV_WDOG_init() function stores the base of MIV_WDT module in the MIV_ESS. + This base address is used by rest of the functions to access the Mi-V Watchdog + registers. Please make call this function before calling any other function + from this driver. + Note: The Mi-V Watchdog driver supports only one instance of MIV_WDT in the + hardware. + The Mi-V Watchdog driver provides the MIV_WDOG_configure() function to + configure the MIV_WDOG module with desired configuration values. It also + provides the MIV_WDOG_get_config() to read back the current configuration of + the MIV_WDOG. You can use this function to retrieve the current configurations + and then overwrite them with the application specific values, such as initial + watchdog timer value, Maximum Value (up to which) Refresh (is) Permitted, + watchdog time-out value, enable/disable forbidden region, enable/disable + MVRP interrupt and interrupt type. + + -------------------------------------------- + Reading the Watchdog Timer Value and Status + -------------------------------------------- + Mi-V Watchdog is a down counter. A refresh forbidden window can be created by + configuring the watchdog Maximum Value up to which Refresh is Permitted (MVRP). + When the current value of the watchdog timer is greater than the MVRP value, + refreshing the watchdog is forbidden. Attempting to refresh the watchdog timer + in the forbidden window will assert a timeout interrupt. The + MIV_WDOG_forbidden_status() function can be used to know whether the watchdog + timer is in forbidden window or has crossed it. By default, the forbidden + window is disabled. It can be enabled by providing an appropriate value as + parameter to the MIV_WDOG_configure() function. When the forbidden window is + disabled, any attempt to refresh the watchdog timer is ignored and the counter + keeps on down counting. + + The current value of the watchdog timer can be read using the + MIV_WDOG_current_value() function. This function can be called at any time. + + -------------------------------------------- + Refreshing the Watchdog Timer Value + -------------------------------------------- + The watchdog timer value is refreshed using the MIV_WDOG_reload() function. + The value reloaded into the watchdog timer down-counter is specified at the + configuration time with an appropriate value as parameter to the + MIV_WDOG_get_config() function. + + -------------------------------------------- + Interrupt Control + -------------------------------------------- + The Mi-V Watchdog generates two interrupts, The MVRP interrupt and + the timeout interrupt. + The MVRP interrupt is generated when the watchdog down-counter crosses the + Maximum Value up to which Refresh is Permitted (MVRP). Following functions to + control MVRP interrupt: + - MIV_WDOG_enable_mvrp_irq + - MIV_WDOG_disable_mvrp_irq + - MIV_WDOG_clear_mvrp_irq + + The timeout interrupt is generated when the watchdog down-counter crosses the + watchdog timeout value. The timeout value is a non-zero value and it can be + set to a maximum of MIV_WDOG_TRIGGER_MAX. The non-maskable interrupt is + generated when the watchdog crosses this timeout value, the down counter + keeps on down counting and a reset signal is generated when reaches zero. + Following functions to control timeout interrupt: + - MIV_WDOG_enable_timeout_irq + - MIV_WDOG_disable_timeout_irq + - MIV_WDOG_clear_timeout_irq + +*//*=========================================================================*/ + +#ifndef MIV_WATCHDOG_H_ +#define MIV_WATCHDOG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "miv_watchdog_regs.h" + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#else +#include "hal.h" +#endif + +/****************************************************************************//* + * The following constants can be used to configure the Mi-V Watchdog where a + * zero or non-zero value such as enable or disable is to be provided as a input + * parameter as shown below: + */ +#define MIV_WDOG_ENABLE 1u +#define MIV_WDOG_DISABLE 0u + +/***************************************************************************//** + The miv_wdog_config_t type for the watchdog Configuration structure. This + type is used as a parameter for the MIV_WDOG_configure() and the + MIV_WDOG_get_config() functions. + + Following are the values as part of this structure +| Parameter | Description | +|------------------|-----------------------------------------------------------| +| time_val | The value from which the watchdog timer counts down | +| mvrp_val | The Watchdog MVRP value | +| timeout_val | The watchdog timeout value | +| forbidden_en | Enable/disable the forbidden window | +| | When set, if a refresh occurs in the forbidden window, | +| | the watchdog timeout interrupt will be generated. | + +Time calculation example: + + time_val = 0xFFFFF0u + mvrp_val = 0x989680u + timeout_val = 0x3e8u + + A prescaler = 256 is used. + Considering clock = 50Mhz + + The MVRP interrupt will happen after + (0xFFFFF0 - 0x989680) * ( 1/(50MHz/256)) + mvrp interrupt will happen after 34 sec. after system reset + + (0xFFFFF0 - 0x3e8) * ( 1/(50MHz/256)) + timeout interrupt will happen after 85 sec. after system reset + */ +typedef struct miv_wdog_config +{ + uint32_t time_val; + uint32_t mvrp_val; + uint32_t timeout_val; + uint32_t forbidden_en; + uint32_t intr_type; +}miv_wdog_config_t; + +extern addr_t g_this_wdog; + +/***************************************************************************//* + Internal constants and types +*******************************************************************************/ + +/// @cond private +#define MIV_WDOG_TRIGGER_MAX 4095u +#define MIV_WDOG_TIMER_MAX 16777200u +/// @endcond + +/*-------------------------------------------------------------------------*//* +MIV_WDOG_REFRESH_KEY +===================== + +The MIV_WDOG_REFRESH_KEY macro holds the magic value which will cause a +reload of the watchdog's down counter when written to the watchdog's +WDOGREFRESH register. +*/ +#define MIV_WDOG_REFRESH_KEY (uint32_t)0xDEADC0DEU + +/*-------------------------------------------------------------------------*//* +MIV_WDOG_FORCE_RESET_KEY +===================== +The MIV_WDOG_FORCE_RESET_KEY macro holds the magic value which will force a +reset if the watchdog is already timeout. Writing any other value or writing +TRIGGER register at other times will trigger the watchdog NMI sequence +(i.e raise a timeout interrupt) + */ +#define MIV_WDOG_FORCE_RESET_KEY (uint32_t)0xDEADU + +/***************************************************************************//** + * The MIV_WDOG_init() is used to register the Mi-V Watchdog module base + * address to the driver. + * + * Note: User should call this function before calling any other Mi-V watchdog + * driver function. + * + * @param base_addr + * The base address of the Mi-V watchdog module. This address is used by + * rest of the watchdog driver functions to access the registers. + * + * @return + * This function does not return any value. + */ +void +MIV_WDOG_init +( + addr_t base_addr +); + +/***************************************************************************//** + * The MIV_WDOG_get_config() function returns the current configurations of the + * Mi-V Watchdog. The Mi-V Watchdog is pre-initialized by the flash + * bits at the design time. When used for the first time before calling the + * MIV_WDOG_configure() function, this function will return the default + * configurations as configured at the design time. + * + * @param config + * The config parameter is used to store the current configuration of the Mi-V + * Watchdog. + * + * Please see the description of miv_wdog_config_t for details. + * + * @return + * This function does not return any value. + * + * Example: + */ +void +MIV_WDOG_get_config +( + miv_wdog_config_t* config +); + +/***************************************************************************//** + * The MIV_WDOG_configure() function configures the watchdog module. The + * Watchdog module is pre-initialized by the flash bits at the design time to the + * default values. You can reconfigure the Watchdog module using + * MIV_WDOG_configure() function. + * + * Note that the MIV_WDOG_configure() function can be used only once, as it + * writes into the TIME register. After a write into the TIME register, the TIME, + * TRIGGER and MSVP register values are frozen and can't be altered again unless + * a system reset happens. + * + * Note also that the Mi-V Watchdog is not enabled at reset, calling this function + * will start the watchdog, it cannot then be disabled and must be refreshed + * periodically. + * + * @param config + * The config parameter is the input parameter in which the configurations to + * be applied to the watchdog module are provided by the application. + * Please see the description of miv_wdog_config_t for details. + * + * @return + * This function returns a zero value when executed successfully. A non-zero + * value is returned when the configuration values are out of bound. + * + * Example: + */ +uint8_t +MIV_WDOG_configure +( + const miv_wdog_config_t * config +); + +/***************************************************************************//** + * The MIV_WDOG_reload() function causes the watchdog to reload its down-counter + * timer with the load value configured through interrupt handler. This function + * must be called regularly to avoid a system reset or a watchdog interrupt. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_reload +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg(g_this_wdog, WDOGRFSH, MIV_WDOG_REFRESH_KEY); + } +} + +/***************************************************************************//** + * The MIV_WDOG_current_value() function returns the current value of the + * watchdog's down-counter. + * + * @param + * Void + * + * @return + * This function returns the current value of the watchdog’s down-counter as + * a 32-bit unsigned integer. + */ +static inline uint32_t +MIV_WDOG_current_value +( + void +) +{ + return (HAL_get_32bit_reg(g_this_wdog, WDOGRFSH)); +} + +/***************************************************************************//** + * The MIV_WDOG_forbidden_status() function returns the refresh status of the + * Mi-V Watchdog. + * + * @param + * Void + * + * @return + * This function returns the refresh status of the watchdog. A value of 1 + * indicates that watchdog's down-counter is within the forbidden window and + * that a reload should not be done. A value of 0 indicates that the watchdog's + * down counter is within the permitted window and that a reload is allowed. + */ +static inline uint32_t +MIV_WDOG_forbidden_status +( + void +) +{ + return (HAL_get_32bit_reg_field(g_this_wdog, WDOGSTAT_FORBIDDEN)); +} + +/***************************************************************************//** + * The MIV_WDOG_enable_mvrp_irq() function enables the MVRP interrupt. + * This interrupt is asserted when the timer countdown register leaves the + * maximum value up to which refresh is permitted (MVRP) window. + * + * @param + * Void + * + * @return + * This function does not return a value. + * + * Example: + */ +static inline void +MIV_WDOG_enable_mvrp_irq +( + void +) +{ + + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGCNTL_NEXT_INTENT_MSVP, 0x01u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_disable_mvrp_irq() function disables the generation of the + * MVRP interrupt. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_disable_mvrp_irq +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGCNTL_NEXT_INTENT_MSVP, 0x0u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_clear_timeout_irq() function clears the watchdog’s timeout + * interrupt which is connected to the MIV-RV32 interrupt. Calling + * MIV_WDOG_clear_timeout_irq() results in clearing the MIV-RV32 interrupt. + * Note: You must call the MIV_WDOG_clear_timeout_irq() function as part of your + * implementation of the interrupt handler in order to prevent the same + * interrupt event re-triggering a call to the timeout ISR. + * + * @param + * Void + * + * @return + * This function does not return any value. + * + */ +static inline void +MIV_WDOG_clear_timeout_irq +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_WDOG_TRIPPED, 0x01u); + /* + * Perform a second write to ensure that the first write completed before + * returning from this function. This is to account for posted writes across + * the AHB matrix. The second write ensures that the first write has + * completed and that the interrupt line has been de-asserted by the time + * the function returns. Omitting the second write may result in a delay + * in the de-assertion of the interrupt line going to the RISC-V and a + * retriggering of the interrupt. + */ + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_WDOG_TRIPPED, 0x01u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_clear_mvrp_irq() function clears the mvrp interrupt. + * + * Note: You must call the MIV_WDOG_clear_mvrp_irq() function as part of your + * implementation of the interrupt service routine (ISR) in order to + * prevent the same interrupt event re-triggering a call to the mvrp ISR. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_clear_mvrp_irq +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_MSVP_TRIPPED, 0x01u); + /* + * Perform a second write to ensure that the first write completed before + * returning from this function. This is to account for posted writes across + * the AHB matrix. The second write ensures that the first write has + * completed and that the interrupt line has been de-asserted by the time + * the function returns. Omitting the second write may result in a delay + * in the de-assertion of the interrupt line going to the RISC-V and a + * re-triggering of the interrupt. + */ + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_MSVP_TRIPPED, 0x01u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_timeout_occured() function reports the occurrence of a timeout + * event. + * + * @param + * Void + * + * @return + * A zero value indicates no watchdog timeout event occurred. A value of 1 + * indicates that a timeout event occurred. + */ +static inline uint32_t +MIV_WDOG_timeout_occured +( + void +) +{ + return (HAL_get_32bit_reg_field(g_this_wdog, WDOGSTAT_TRIGGERED)); +} + +/***************************************************************************//** + * The MIV_WDOG_force_reset() function is used to force an immediate reset + * if the watchdog has already triggered. Writing any value in this condition + * will result in watchdog timeout. + * The time out interrupt WDOG_IRQ will be set to high and watchdog timer + * countdown register updated with watchdog trigger timeout register value. + * If the Watchdog has timed out, a special 16-bit value needs to be written + * to the register to force a reset on CPU_RESETN, 0xDEAD + * Then the Watchdog countdown is reset/updated with the top Watchdog Runtime + * register value. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_force_reset +( + void +) +{ + if (WDOGSTAT_TRIGGERED_MASK == + HAL_get_32bit_reg_field(g_this_wdog, WDOGSTAT_TRIGGERED)) + + { + HAL_set_32bit_reg(g_this_wdog, WDOGFORCE, MIV_WDOG_FORCE_RESET_KEY); + } + + else + { + HAL_set_32bit_reg(g_this_wdog, WDOGFORCE, 0x0u); + } +} + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_WATCHDOG_H_ */ diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h new file mode 100644 index 0000000..2fca983 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h @@ -0,0 +1,122 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP watchdog module driver. This module is delivered as a part of Mi-V + * extended Sub-System(ESS) MIV_ESS. + */ + +#ifndef MIV_WDOG_REGISTERS +#define MIV_WDOG_REGISTERS 1u + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * Refresh register details + */ +#define WDOGRFSH_REG_OFFSET 0x00u + +/* Refresh register bits */ +#define WDOGRFSH_OFFSET 0x00u +#define WDOGRFSH_MASK 0xFFFFFFFFu +#define WDOGRFSH_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Control register details + */ +#define WDOGCNTL_REG_OFFSET 0x04u + +/* Control register next intent msvp bit */ +#define WDOGCNTL_NEXT_INTENT_MSVP_OFFSET 0x04u +#define WDOGCNTL_NEXT_INTENT_MSVP_MASK 0x01u +#define WDOGCNTL_NEXT_INTENT_MSVP_SHIFT 0u + +/* Control register next intent wdog bit */ +#define WDOGCNTL_NEXT_INTENT_WDOG_OFFSET 0x04u +#define WDOGCNTL_NEXT_INTENT_WDOG_MASK 0x02u +#define WDOGCNTL_NEXT_INTENT_WDOG_SHIFT 1u + +/* Control register next enforbidden bit */ +#define WDOGCNTL_NEXT_ENFORBIDDEN_OFFSET 0x04u +#define WDOGCNTL_NEXT_ENFORBIDDEN_MASK 0x10u +#define WDOGCNTL_NEXT_ENFORBIDDEN_SHIFT 4u + +/*------------------------------------------------------------------------------ + * Watchdog status register + */ +#define WDOGSTAT_REG_OFFSET 0x08u + +/* msvp_tripped bit */ +#define WDOGSTAT_MSVP_TRIPPED_OFFSET 0x08u +#define WDOGSTAT_MSVP_TRIPPED_MASK 0x01u +#define WDOGSTAT_MSVP_TRIPPED_SHIFT 0u + +/* WDOG Tripped bit */ +#define WDOGSTAT_WDOG_TRIPPED_OFFSET 0x08u +#define WDOGSTAT_WDOG_TRIPPED_MASK 0x02u +#define WDOGSTAT_WDOG_TRIPPED_SHIFT 1u + +/* Forbidden bit */ +#define WDOGSTAT_FORBIDDEN_OFFSET 0x08u +#define WDOGSTAT_FORBIDDEN_MASK 0x04u +#define WDOGSTAT_FORBIDDEN_SHIFT 2u + +/* Triggered bit */ +#define WDOGSTAT_TRIGGERED_OFFSET 0x08u +#define WDOGSTAT_TRIGGERED_MASK 0x08u +#define WDOGSTAT_TRIGGERED_SHIFT 3u + +/* wdoglocked bit */ +#define WDOGSTAT_WDOGLOCKED_OFFSET 0x08u +#define WDOGSTAT_WDOGLOCKED_MASK 0x10u +#define WDOGSTAT_WDOGLOCKED_SHIFT 4u + +/*------------------------------------------------------------------------------ + * Watchdog runtime register + */ +#define WDOGTIME_REG_OFFSET 0x0Cu + +/* wdogmsvp bit */ +#define WDOGTIME_WDOGVALUE_OFFSET 0x0Cu +#define WDOGTIME_WDOGVALUE_MASK 0xFFFFFFu +#define WDOGTIME_WDOGVALUE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Watchdog MVRP register + */ +#define WDOGMSVP_REG_OFFSET 0x10u + +/* wdogmsvp bit */ +#define WDOGMSVP_OFFSET 0x10u +#define WDOGMSVP_MASK 0xFFFFFFu +#define WDOGMSVP_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Watchdog Trigger Timeout register + */ +#define WDOGTRIG_REG_OFFSET 0x14u + +/* wdogmsvp bit */ +#define WDOGTRIG_WDOGRST_OFFSET 0x14u +#define WDOGTRIG_WDOGRST_MASK 0xFFFFFFu +#define WDOGTRIG_WDOGRST_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Watchdog Force Reset register details + */ +#define WDOGFORCE_REG_OFFSET 0x18u + +/* Refresh register bits */ +#define WDOGFORCE_OFFSET 0x18u +#define WDOGFORCE_MASK 0xFFFFFFFFu +#define WDOGFORCE_SHIFT 0u + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_WATCHDOG_REGS_H_ */ diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/hal/cpu_types.h b/applications/user-crypto/miv-rv32-ccm-services/src/platform/hal/cpu_types.h new file mode 100644 index 0000000..ef8ab20 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/hal/cpu_types.h @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file cpu_types.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Type definitions which can be commonly used by the fabric-ip drivers. + * + */ +#ifndef __CPU_TYPES_H +#define __CPU_TYPES_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned int size_t; + +/*------------------------------------------------------------------------------ + * addr_t: address type. + * Used to specify the address of peripherals present in the processor's memory + * map. + */ +typedef unsigned int addr_t; + +/*------------------------------------------------------------------------------ + * psr_t: processor state register. + * Used by HAL_disable_interrupts() and HAL_restore_interrupts() to store the + * processor's state between disabling and restoring interrupts. + */ +typedef unsigned int psr_t; + +#ifdef __cplusplus +} +#endif + +#endif /* CPU_TYPES_H */ + diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/hal/hal.h b/applications/user-crypto/miv-rv32-ccm-services/src/platform/hal/hal.h new file mode 100644 index 0000000..7eec17a --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/hal/hal.h @@ -0,0 +1,235 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file hal.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware abstraction layer functions for peripheral register accesses. + * + */ +#ifndef __HAL_H +#define __HAL_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include "cpu_types.h" +#include "hw_reg_access.h" +#include "hal_assert.h" +/***************************************************************************//** + * Enable all interrupts at the processor level. + */ +void HAL_enable_interrupts( void ); + +/***************************************************************************//** + * Disable all interrupts at the processor core level. + * Return the interrupts enable state before disabling occurred so that it can + * later be restored. + */ +psr_t HAL_disable_interrupts( void ); + +/***************************************************************************//** + * Restore the interrupts enable state at the processor core level. + * This function is normally passed the value returned from a previous call to + * HAL_disable_interrupts(). + */ +void HAL_restore_interrupts( psr_t saved_psr ); + +/***************************************************************************//** + */ +#define FIELD_OFFSET(FIELD_NAME) (FIELD_NAME##_OFFSET) +#define FIELD_SHIFT(FIELD_NAME) (FIELD_NAME##_SHIFT) +#define FIELD_MASK(FIELD_NAME) (FIELD_NAME##_MASK) + +/***************************************************************************//** + * The macro HAL_set_32bit_reg() allows writing a 32 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint32_t containing the value to write. + */ +#define HAL_set_32bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_32bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_32bit_reg() is used to read the value of a 32 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint32_t value. + */ +#define HAL_get_32bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_32bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)) )) + +/***************************************************************************//** + * The macro HAL_set_32bit_reg_field() is used to write a field within a + * 32 bits wide register. The field written can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * VALUE: A variable of type uint32_t containing the field value to write. + */ +#define HAL_set_32bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_32bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_32bit_reg_field() is used to read a register field from + * within a 32 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint32_t value. + */ +#define HAL_get_32bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_32bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +/***************************************************************************//** + * The macro HAL_set_16bit_reg() allows writing a 16 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint_fast16_t containing the value to write. + */ +#define HAL_set_16bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_16bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_16bit_reg() is used to read the value of a 16 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint16_t value. + */ +#define HAL_get_16bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_16bit_reg( (BASE_ADDR) + (REG_NAME##_REG_OFFSET) )) + +/***************************************************************************//** + * The macro HAL_set_16bit_reg_field() is used to write a field within a + * 16 bits wide register. The field written can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * VALUE: A variable of type uint16_t containing the field value to write. + */ +#define HAL_set_16bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_16bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_16bit_reg_field() is used to read a register field from + * within a 8 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint16_t value. + */ +#define HAL_get_16bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_16bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +/***************************************************************************//** + * The macro HAL_set_8bit_reg() allows writing a 8 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint_fast8_t containing the value to write. + */ +#define HAL_set_8bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_8bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_8bit_reg() is used to read the value of a 8 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint8_t value. + */ +#define HAL_get_8bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_8bit_reg( (BASE_ADDR) + (REG_NAME##_REG_OFFSET) )) + +/***************************************************************************//** + */ +#define HAL_set_8bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_8bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_8bit_reg_field() is used to read a register field from + * within a 8 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint8_t value. + */ +#define HAL_get_8bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_8bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +#ifdef __cplusplus +} +#endif + +#endif /*HAL_H*/ + diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/hal/hal_assert.h b/applications/user-crypto/miv-rv32-ccm-services/src/platform/hal/hal_assert.h new file mode 100644 index 0000000..1e18b54 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/hal/hal_assert.h @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hal_assert.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief HAL assert functions + */ +#ifndef __HAL_ASSERT_HEADER +#define __HAL_ASSERT_HEADER 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Disable assertions if we do not recognize the compiler. */ +#if defined ( __GNUC__ ) +#if defined(NDEBUG) +/***************************************************************************//** + * HAL_ASSERT() is defined out when the NDEBUG symbol is used. + ******************************************************************************/ +#define HAL_ASSERT(CHECK) + +#else + +/***************************************************************************//** + * Default behavior for HAL_ASSERT() macro: + *------------------------------------------------------------------------------ + The behavior is toolchain specific and project setting specific. + ******************************************************************************/ +#define HAL_ASSERT(CHECK)\ + do { \ + if (!(CHECK)) \ + { \ + __asm__ volatile ("ebreak"); \ + }\ + } while(0); + +#endif /* NDEBUG */ +#endif /*__GNUC__*/ + +#ifdef __cplusplus +} +#endif +#endif /* __HAL_ASSERT_HEADER */ + diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/hal/hal_irq.c b/applications/user-crypto/miv-rv32-ccm-services/src/platform/hal/hal_irq.c new file mode 100644 index 0000000..95a0775 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/hal/hal_irq.c @@ -0,0 +1,45 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hal_irq.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Legacy interrupt control functions for the Microchip driver library + * hardware abstraction layer. + * + */ +#include "hal.h" +#include "miv_rv32_hal/miv_rv32_hal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * + */ +void HAL_enable_interrupts(void) { + MRV_enable_interrupts(); +} + +/*------------------------------------------------------------------------------ + * + */ +psr_t HAL_disable_interrupts(void) { + psr_t psr; + psr = read_csr(mstatus); + MRV_disable_interrupts(); + return(psr); +} + +/*------------------------------------------------------------------------------ + * + */ +void HAL_restore_interrupts(psr_t saved_psr) { + write_csr(mstatus, saved_psr); +} + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/hal/hw_macros.h b/applications/user-crypto/miv-rv32-ccm-services/src/platform/hal/hw_macros.h new file mode 100644 index 0000000..189609c --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/hal/hw_macros.h @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hw_macros.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware registers access macros. + * + * THE MACROS DEFINED IN THIS FILE ARE DEPRECATED. DO NOT USE FOR NEW + * DEVELOPMENT. + * + * These macros are used to access peripheral registers. They allow access to + * 8, 16 and 32 bit wide registers. All accesses to peripheral registers should + * be done through these macros in order to ease porting across different + * processors/bus architectures. + * + * Some of these macros also allow access to a specific register field. + * + */ +#ifndef __HW_REGISTER_MACROS_H +#define __HW_REGISTER_MACROS_H 1 +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * 32 bits registers access: + */ +#define HW_get_uint32_reg(BASE_ADDR, REG_OFFSET) (*((uint32_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint32_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint32_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint32_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint32_t) \ + ( \ + (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint32_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint32_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 32 bits memory access: + */ +#define HW_get_uint32(BASE_ADDR) (*((uint32_t volatile *)(BASE_ADDR))) + +#define HW_set_uint32(BASE_ADDR, VALUE) (*((uint32_t volatile *)(BASE_ADDR)) = (VALUE)) + +/*------------------------------------------------------------------------------ + * 16 bits registers access: + */ +#define HW_get_uint16_reg(BASE_ADDR, REG_OFFSET) (*((uint16_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint16_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint16_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint16_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint16_t) \ + ( \ + (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint16_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint16_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 8 bits registers access: + */ +#define HW_get_uint8_reg(BASE_ADDR, REG_OFFSET) (*((uint8_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint8_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint8_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint8_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint8_t) \ + ( \ + (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint8_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint8_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 8 bits memory access: + */ +#define HW_get_uint8(BASE_ADDR) (*((uint8_t volatile *)(BASE_ADDR))) + +#define HW_set_uint8(BASE_ADDR, VALUE) (*((uint8_t volatile *)(BASE_ADDR)) = (VALUE)) + +#ifdef __cplusplus +extern "C" { +#endif + +#endif /* __HW_REGISTER_MACROS_H */ + diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/hal/hw_reg_access.S b/applications/user-crypto/miv-rv32-ccm-services/src/platform/hal/hw_reg_access.S new file mode 100644 index 0000000..dd29223 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/hal/hw_reg_access.S @@ -0,0 +1,215 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hw_reg_access.S + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware registers access functions. + * The implementation of these function is platform and toolchain specific. + * The functions declared here are implemented using assembler as part of the + * processor/toolchain specific HAL. This implementation is for the combination + * of the 32 bit RISC-V processors and GNU tool chain. + * + */ + +.section .text + .globl HW_set_32bit_reg + .globl HW_get_32bit_reg + .globl HW_set_32bit_reg_field + .globl HW_get_32bit_reg_field + .globl HW_set_16bit_reg + .globl HW_get_16bit_reg + .globl HW_set_16bit_reg_field + .globl HW_get_16bit_reg_field + .globl HW_set_8bit_reg + .globl HW_get_8bit_reg + .globl HW_set_8bit_reg_field + .globl HW_get_8bit_reg_field + + +/***************************************************************************//** + * HW_set_32bit_reg is used to write the content of a 32 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint32_t value + */ +HW_set_32bit_reg: + sw a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_32bit_reg is used to read the content of a 32 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + + * @return 32 bits value read from the peripheral register. + */ +HW_get_32bit_reg: + lw a0, 0(a0) + ret + +/***************************************************************************//** + * HW_set_32bit_reg_field is used to set the content of a field in a 32 bits + * wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint32_t mask + * a3: uint32_t value + */ +HW_set_32bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lw t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sw t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_32bit_reg_field is used to read the content of a field out of a + * 32 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint32_t mask + * + * @return 32 bits value containing the register field value specified + * as parameter. + */ +HW_get_32bit_reg_field: + lw a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +/***************************************************************************//** + * HW_set_16bit_reg is used to write the content of a 16 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint_fast16_t value + */ +HW_set_16bit_reg: + sh a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_16bit_reg is used to read the content of a 16 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + + * @return 16 bits value read from the peripheral register. + */ +HW_get_16bit_reg: + lh a0, (a0) + ret + +/***************************************************************************//** + * HW_set_16bit_reg_field is used to set the content of a field in a 16 bits + * wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast16_t mask + * a3: uint_fast16_t value + * @param value Value to be written in the specified field. + */ +HW_set_16bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lh t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sh t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_16bit_reg_field is used to read the content of a field from a + * 16 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast16_t mask + * + * @return 16 bits value containing the register field value specified + * as parameter. + */ +HW_get_16bit_reg_field: + lh a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +/***************************************************************************//** + * HW_set_8bit_reg is used to write the content of a 8 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint_fast8_t value + */ +HW_set_8bit_reg: + sb a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_8bit_reg is used to read the content of a 8 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + + * @return 8 bits value read from the peripheral register. + */ +HW_get_8bit_reg: + lb a0, 0(a0) + ret + +/***************************************************************************//** + * HW_set_8bit_reg_field is used to set the content of a field in a 8 bits + * wide peripheral register. + * + * a0: addr_t reg_addr, + * a1: int_fast8_t shift + * a2: uint_fast8_t mask + * a3: uint_fast8_t value + */ +HW_set_8bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lb t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sb t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_8bit_reg_field is used to read the content of a field from a + * 8 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast8_t mask + * + * @return 8 bits value containing the register field value specified + * as parameter. + */ +HW_get_8bit_reg_field: + lb a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +.end diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/hal/hw_reg_access.h b/applications/user-crypto/miv-rv32-ccm-services/src/platform/hal/hw_reg_access.h new file mode 100644 index 0000000..1a24309 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/hal/hw_reg_access.h @@ -0,0 +1,239 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hw_reg_access.S + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware registers access functions. + * The implementation of these function is platform and tool-chain specific. + * The functions declared here are implemented using assembler as part of the + * processor/tool-chain specific HAL. This implementation is for the combination + * of the 32 bit RISC-V processors and GNU tool chain. + * + */ +#ifndef __HW_REG_ACCESS +#define __HW_REG_ACCESS +#ifdef __cplusplus +extern "C" { +#endif + +#include "cpu_types.h" +/***************************************************************************//** + * HW_set_32bit_reg is used to write the content of a 32 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_32bit_reg +( + addr_t reg_addr, + uint32_t value +); + +/***************************************************************************//** + * HW_get_32bit_reg is used to read the content of a 32 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 32 bits value read from the peripheral register. + */ +uint32_t +HW_get_32bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_32bit_reg_field is used to set the content of a field in a 32 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void +HW_set_32bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint32_t mask, + uint32_t value +); + +/***************************************************************************//** + * HW_get_32bit_reg_field is used to read the content of a field out of a + * 32 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 32 bits value containing the register field value specified + * as parameter. + */ +uint32_t +HW_get_32bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint32_t mask +); + +/***************************************************************************//** + * HW_set_16bit_reg is used to write the content of a 16 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_16bit_reg +( + addr_t reg_addr, + uint_fast16_t value +); + +/***************************************************************************//** + * HW_get_16bit_reg is used to read the content of a 16 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 16 bits value read from the peripheral register. + */ +uint16_t +HW_get_16bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_16bit_reg_field is used to set the content of a field in a 16 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void HW_set_16bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast16_t mask, + uint_fast16_t value +); + +/***************************************************************************//** + * HW_get_16bit_reg_field is used to read the content of a field from a + * 16 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 16 bits value containing the register field value specified + * as parameter. + */ +uint16_t HW_get_16bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast16_t mask +); + +/***************************************************************************//** + * HW_set_8bit_reg is used to write the content of a 8 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_8bit_reg +( + addr_t reg_addr, + uint_fast8_t value +); + +/***************************************************************************//** + * HW_get_8bit_reg is used to read the content of a 8 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 8 bits value read from the peripheral register. + */ +uint8_t +HW_get_8bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_8bit_reg_field is used to set the content of a field in a 8 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void HW_set_8bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast8_t mask, + uint_fast8_t value +); + +/***************************************************************************//** + * HW_get_8bit_reg_field is used to read the content of a field from a + * 8 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 8 bits value containing the register field value specified + * as parameter. + */ +uint8_t HW_get_8bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast8_t mask +); + +#ifdef __cplusplus +} +#endif + +#endif /* __HW_REG_ACCESS */ + diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld b/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld new file mode 100644 index 0000000..474eb43 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld @@ -0,0 +1,154 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-execute-in-place.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * image executing from a one address space whereas the data, sdata and stack + * sections are placed in another address space. This could be used in cases such + * as: + * 1) When using MIV_RV32, the reset vector points to the LSRAM at address + * 0x80000000 and the data, sdata, bss and stack sections are placed in the + * TCM region. + * + * 2) Executing from a Non Volatile memory. The actual memory will depend on + * the FPGA platform. For exameple, it could be the eNVM on SmartFusion2, + * Igloo2 or on-board non-volatile memory which supports code execution. + * + * NOTE: Modify the memory section addresses and the sizes according to your + * Libero design. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + + +MEMORY +{ + rom (rx) : ORIGIN = 0x80000000, LENGTH = 16k + ram (rwx) : ORIGIN = 0x80004000, LENGTH = 16k +} + +STACK_SIZE = 1k; /* needs to be calculated for your application */ +HEAP_SIZE = 1k; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > rom + + .text : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.text.entry))) + . = ALIGN(0x10); + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } >rom + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } >ram AT>rom + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } >ram AT>rom + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram +} + diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv-rv32-ram.ld b/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv-rv32-ram.ld new file mode 100644 index 0000000..53076a0 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv-rv32-ram.ld @@ -0,0 +1,150 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-ram.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * debug image executing in SRAM. + * + * This linker script assumes that a RAM is connected at on Mi-V soft processor + * memory space pointed by the reset vector address. + * + * NOTE : Modify the memory section address and the size according to your + * Libero design. + * For example: + * 1) If you want to download and step debug at a different RAM memory address in + * your design (For example TCM base address) than the one provided in this file. + * 2) The MIV_RV32, when used with MIV_ESS IP, provides ways to copy the executable + * HEX file from external Non-Volatile memory into the TCM at reset. In this + * case your executable must be linked to the TCM address. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +MEMORY +{ + ram (rwx) : ORIGIN = 0x80000000, LENGTH = 32k +} + +STACK_SIZE = 2k; /* needs to be calculated for your application */ +HEAP_SIZE = 1k; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > ram + + .text : ALIGN(0x10) + { + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } > ram + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } > ram + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } > ram + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram +} + diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv_rv32_assert.h b/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv_rv32_assert.h new file mode 100644 index 0000000..b3912ed --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv_rv32_assert.h @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * MIV_RV32 HAL Embedded Software + * + */ +#ifndef MIV_RV32_ASSERT_HEADER +#define MIV_RV32_ASSERT_HEADER + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + * ASSERT() implementation. + ******************************************************************************/ +/* Disable assertions if we do not recognize the compiler. */ +#if defined ( __GNUC__ ) +#if defined(NDEBUG) +#define ASSERT(CHECK) +#else +#define ASSERT(CHECK)\ + do { \ + if (!(CHECK)) \ + { \ + __asm__ volatile ("ebreak"); \ + }\ + } while(0); + +#endif /* NDEBUG check */ +#endif /* compiler check */ + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_RV32_ASSERT_HEADER */ + diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv_rv32_entry.S b/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv_rv32_entry.S new file mode 100644 index 0000000..0ea3172 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv_rv32_entry.S @@ -0,0 +1,590 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_entry.S + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor vectors, trap handling and startup code. + * + */ +#ifndef ENTRY_S +#define ENTRY_S + +#define A_EXTENSION_MASK 0x00000001u +#define MTVEC_MODE_BIT_MASK 0x00000003u +#define MTVEC_VECTORED_MODE_VAL 0x00000001u + +#define MTIMEH_ADDR 0x200BFFCu + + +#if __riscv_xlen == 64 +# define LREG ld +# define SREG sd +# define REGBYTES 8 +#else +# define LREG lw +# define SREG sw +# define REGBYTES 4 +#endif + +#if defined(MIV_FP_CONTEXT_SAVE) && defined(__riscv_flen) +#define SP_SHIFT_OFFSET 64 +#else +#define SP_SHIFT_OFFSET 32 +#endif + +.macro STORE_CONTEXT + addi sp, sp, -SP_SHIFT_OFFSET*REGBYTES + SREG x1, 0 * REGBYTES(sp) + SREG x1, 0 * REGBYTES(sp) + SREG x2, 1 * REGBYTES(sp) + SREG x3, 2 * REGBYTES(sp) + SREG x4, 3 * REGBYTES(sp) + SREG x5, 4 * REGBYTES(sp) + SREG x6, 5 * REGBYTES(sp) + SREG x7, 6 * REGBYTES(sp) + SREG x8, 7 * REGBYTES(sp) + SREG x9, 8 * REGBYTES(sp) + SREG x10, 9 * REGBYTES(sp) + SREG x11, 10 * REGBYTES(sp) + SREG x12, 11 * REGBYTES(sp) + SREG x13, 12 * REGBYTES(sp) + SREG x14, 13 * REGBYTES(sp) + SREG x15, 14 * REGBYTES(sp) + SREG x16, 15 * REGBYTES(sp) + SREG x17, 16 * REGBYTES(sp) + SREG x18, 17 * REGBYTES(sp) + SREG x19, 18 * REGBYTES(sp) + SREG x20, 19 * REGBYTES(sp) + SREG x21, 20 * REGBYTES(sp) + SREG x22, 21 * REGBYTES(sp) + SREG x23, 22 * REGBYTES(sp) + SREG x24, 23 * REGBYTES(sp) + SREG x25, 24 * REGBYTES(sp) + SREG x26, 25 * REGBYTES(sp) + SREG x27, 26 * REGBYTES(sp) + SREG x28, 27 * REGBYTES(sp) + SREG x29, 28 * REGBYTES(sp) + SREG x30, 29 * REGBYTES(sp) + SREG x31, 30 * REGBYTES(sp) + + #ifdef __riscv_flen + #ifdef MIV_FP_CONTEXT_SAVE + fsw f0, 31*REGBYTES(sp) + fsw f1, 32*REGBYTES(sp) + fsw f2, 33*REGBYTES(sp) + fsw f3, 34*REGBYTES(sp) + fsw f4, 35*REGBYTES(sp) + fsw f5, 36*REGBYTES(sp) + fsw f6, 37*REGBYTES(sp) + fsw f7, 38*REGBYTES(sp) + fsw f8, 39*REGBYTES(sp) + fsw f9, 40*REGBYTES(sp) + fsw f10, 41*REGBYTES(sp) + fsw f11, 42*REGBYTES(sp) + fsw f12, 43*REGBYTES(sp) + fsw f13, 44*REGBYTES(sp) + fsw f14, 45*REGBYTES(sp) + fsw f15, 46*REGBYTES(sp) + fsw f16, 47*REGBYTES(sp) + fsw f17, 48*REGBYTES(sp) + fsw f18, 49*REGBYTES(sp) + fsw f19, 50*REGBYTES(sp) + fsw f20, 51*REGBYTES(sp) + fsw f21, 52*REGBYTES(sp) + fsw f22, 53*REGBYTES(sp) + fsw f23, 54*REGBYTES(sp) + fsw f24, 55*REGBYTES(sp) + fsw f25, 56*REGBYTES(sp) + fsw f26, 57*REGBYTES(sp) + fsw f27, 58*REGBYTES(sp) + fsw f28, 59*REGBYTES(sp) + fsw f29, 60*REGBYTES(sp) + fsw f30, 61*REGBYTES(sp) + fsw f31, 62*REGBYTES(sp) + #endif /* __riscv_flen */ + #endif /* MIV_FP_CONTEXT_SAVE */ +.endm + + .section .entry, "ax" + .globl _start + +_start: + j handle_reset + +/* Some of the Mi-V soft IP cores support compressed 'C' extension. If the Mi-V + core in your design doesn't support 'C' extension and you enable 'C' extension + in firmware project compiler options, then it would result in a trap. For this + case, we are avoiding compressed instruction here so you can put a breakpoint + at the jump and you can at least look at mcause, mepc and get some hints + about the crash. */ +trap_entry: +.option push +.option norvc +j generic_trap_handler +.option pop + .word 0 + .word 0 + +sw_trap_entry: + j vector_sw_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + +tmr_trap_entry: + j vector_tmr_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + +ext_trap_entry: + j vector_ext_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + .word 0 + +#ifndef MIV_LEGACY_RV32 +MGEUI_trap_entry: + j vector_MGEUI_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MGECI_trap_entry: + j vector_MGECI_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + .word 0 + +#ifndef MIV_RV32_V3_0 +MSYS_MIE22_trap_entry: +#ifndef MIV_RV32_V3_0 + j vector_SUBSYSR_IRQHandler +#endif /*MIV_RV32_V3_0*/ +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE23_trap_entry: + j vector_SUBSYS_IRQHandler +#ifdef __riscv_compressed + .2byte 0 +#endif +#endif /*MIV_RV32_V3_0*/ + +MSYS_MIE24_trap_entry: + j vector_MSYS_EI0_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE25_trap_entry: + j vector_MSYS_EI1_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE26_trap_entry: + j vector_MSYS_EI2_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE27_trap_entry: + j vector_MSYS_EI3_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE28_trap_entry: + j vector_MSYS_EI4_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE29_trap_entry: + j vector_MSYS_EI5_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE30_trap_entry: +#ifndef MIV_RV32_V3_0 + j vector_MSYS_EI6_trap_handler +#else + j vector_SUBSYS_IRQHandler +#endif +#ifdef __riscv_compressed + .2byte 0 +#endif + +#ifndef MIV_RV32_V3_0 +MSYS_MIE31_trap_entry: + j vector_MSYS_EI7_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif +#endif /* MIV_RV32_V3_0 */ +#endif /* MIV_LEGACY_RV32 */ + +.align 4 +generic_trap_handler: + STORE_CONTEXT + csrr a0, mcause + csrr a1, mepc + jal handle_trap + j generic_restore + +vector_sw_trap_handler: + STORE_CONTEXT + jal handle_m_soft_interrupt + j generic_restore + +vector_tmr_trap_handler: + STORE_CONTEXT + jal handle_m_timer_interrupt + j generic_restore + +vector_ext_trap_handler: + STORE_CONTEXT +#ifdef MIV_LEGACY_RV32 + jal handle_m_ext_interrupt +#else + jal External_IRQHandler +#endif /* MIV_LEGACY_RV32 */ + j generic_restore + +#ifndef MIV_LEGACY_RV32 +vector_MGEUI_trap_handler: + STORE_CONTEXT + jal MGEUI_IRQHandler + j generic_restore + +vector_MGECI_trap_handler: + STORE_CONTEXT + jal MGECI_IRQHandler + j generic_restore + +vector_MSYS_EI0_trap_handler: + STORE_CONTEXT + jal MSYS_EI0_IRQHandler + j generic_restore + +vector_MSYS_EI1_trap_handler: + STORE_CONTEXT + jal MSYS_EI1_IRQHandler + j generic_restore + +vector_MSYS_EI2_trap_handler: + STORE_CONTEXT + jal MSYS_EI2_IRQHandler + j generic_restore + +vector_MSYS_EI3_trap_handler: + STORE_CONTEXT + jal MSYS_EI3_IRQHandler + j generic_restore + +vector_MSYS_EI4_trap_handler: + STORE_CONTEXT + jal MSYS_EI4_IRQHandler + j generic_restore + +vector_MSYS_EI5_trap_handler: + STORE_CONTEXT + jal MSYS_EI5_IRQHandler + j generic_restore + +vector_SUBSYS_IRQHandler: + STORE_CONTEXT + jal SUBSYS_IRQHandler + j generic_restore + +#ifndef MIV_RV32_V3_0 +vector_MSYS_EI6_trap_handler: + STORE_CONTEXT + jal MSYS_EI6_IRQHandler + j generic_restore + +vector_MSYS_EI7_trap_handler: + STORE_CONTEXT + jal MSYS_EI7_IRQHandler + j generic_restore + + +vector_SUBSYSR_IRQHandler: + STORE_CONTEXT + jal SUBSYSR_IRQHandler + j generic_restore + +#endif /*MIV_RV32_V3_0*/ +#endif /* MIV_LEGACY_RV32 */ + +generic_restore: + LREG x1, 0 * REGBYTES(sp) + LREG x2, 1 * REGBYTES(sp) + LREG x3, 2 * REGBYTES(sp) + LREG x4, 3 * REGBYTES(sp) + LREG x5, 4 * REGBYTES(sp) + LREG x6, 5 * REGBYTES(sp) + LREG x7, 6 * REGBYTES(sp) + LREG x8, 7 * REGBYTES(sp) + LREG x9, 8 * REGBYTES(sp) + LREG x10, 9 * REGBYTES(sp) + LREG x11, 10 * REGBYTES(sp) + LREG x12, 11 * REGBYTES(sp) + LREG x13, 12 * REGBYTES(sp) + LREG x14, 13 * REGBYTES(sp) + LREG x15, 14 * REGBYTES(sp) + LREG x16, 15 * REGBYTES(sp) + LREG x17, 16 * REGBYTES(sp) + LREG x18, 17 * REGBYTES(sp) + LREG x19, 18 * REGBYTES(sp) + LREG x20, 19 * REGBYTES(sp) + LREG x21, 20 * REGBYTES(sp) + LREG x22, 21 * REGBYTES(sp) + LREG x23, 22 * REGBYTES(sp) + LREG x24, 23 * REGBYTES(sp) + LREG x25, 24 * REGBYTES(sp) + LREG x26, 25 * REGBYTES(sp) + LREG x27, 26 * REGBYTES(sp) + LREG x28, 27 * REGBYTES(sp) + LREG x29, 28 * REGBYTES(sp) + LREG x30, 29 * REGBYTES(sp) + LREG x31, 30 * REGBYTES(sp) + + #ifdef __riscv_flen + #ifdef MIV_FP_CONTEXT_SAVE + flw f0, 0 * REGBYTES(sp) + flw f1, 1 * REGBYTES(sp) + flw f2, 2 * REGBYTES(sp) + flw f3, 3 * REGBYTES(sp) + flw f4, 4 * REGBYTES(sp) + flw f5, 5 * REGBYTES(sp) + flw f6, 6 * REGBYTES(sp) + flw f7, 7 * REGBYTES(sp) + flw f8, 8 * REGBYTES(sp) + flw f9, 9 * REGBYTES(sp) + flw f10, 10 * REGBYTES(sp) + flw f11, 11 * REGBYTES(sp) + flw f12, 12 * REGBYTES(sp) + flw f13, 13 * REGBYTES(sp) + flw f14, 14 * REGBYTES(sp) + flw f15, 15 * REGBYTES(sp) + flw f16, 16 * REGBYTES(sp) + flw f17, 17 * REGBYTES(sp) + flw f18, 18 * REGBYTES(sp) + flw f19, 19 * REGBYTES(sp) + flw f20, 20 * REGBYTES(sp) + flw f21, 21 * REGBYTES(sp) + flw f22, 22 * REGBYTES(sp) + flw f23, 23 * REGBYTES(sp) + flw f24, 24 * REGBYTES(sp) + flw f25, 25 * REGBYTES(sp) + flw f26, 26 * REGBYTES(sp) + flw f27, 27 * REGBYTES(sp) + flw f28, 28 * REGBYTES(sp) + flw f29, 29 * REGBYTES(sp) + flw f30, 30 * REGBYTES(sp) + flw f31, 31 * REGBYTES(sp) + #endif /* __riscv_flen */ + #endif /* MIV_FP_CONTEXT_SAVE */ + + addi sp, sp, SP_SHIFT_OFFSET*REGBYTES + mret + + .section .text, "ax" +handle_reset: +/* Ensure instructions are not relaxed, since gp is not yet set */ +.option push +.option norelax + +#ifndef MIV_RV32_V3_0 + csrwi mstatus, 0 + csrwi mie, 0 + la ra, _start + +/* Clearnig this to be on safer side as RTL doesnt seem to clear it on reset. */ +#ifndef MIV_LEGACY_RV32 + li t0, MTIMEH_ADDR + sw x0, 0(t0) +#endif + + csrr t0, misa + andi t0, t0, A_EXTENSION_MASK + bnez t0, ima_cores_setup /* Jump to IMA core handling */ + + +/* For MIV_RV32 cores the mtvec exception base address is fixed at Reset vector + address + 0x4. Check the mode bits. */ +/* In the MIV_RV32 v3.1, the MTVEC exception base address is WARL, and can be + configured by the user at runtime */ + + csrr t0, mtvec + andi t0, t0, MTVEC_MODE_BIT_MASK + li t1, MTVEC_VECTORED_MODE_VAL + bne t0, t1, ima_cores_setup /* Jump to IMA core handling */ + + /* When mode = 1 => this is vectored mode on MIV_RV32 core. + Verify that the trap_handler address matches the configuration in MTVEC */ + csrr t0, mtvec + andi t0, t0, 0xFFFFFFFC + la t1, trap_entry + bne t0, t1, vector_address_not_matching + j generic_reset_handling + +#else /* MIV_RV32_V3_0 */ + +/* Clearnig this to be on safer side as RTL doesnt seem to clear it on reset. */ +#ifndef MIV_LEGACY_RV32 + li t0, MTIMEH_ADDR + sw x0, 0(t0) +#endif + +/* In the MIV_RV32 v3.1, the MTVEC exception base address is WARL, and can be + configured by the user at runtime */ + csrr t0, mtvec + andi t0, t0, MTVEC_MODE_BIT_MASK + li t1, MTVEC_VECTORED_MODE_VAL + bne t0, t1, ima_cores_setup /* Jump to IMA core handling */ + +/* When mode = 1 => this is vectored mode on MIV_RV32 core. + Verify that the trap_handler address matches the configuration in MTVEC */ + csrr t0, mtvec + andi t0, t0, 0xFFFFFFFC + la t1, trap_entry + bne t0, t1, vector_address_not_matching + j generic_reset_handling +#endif /*MIV_RV32_V3_0*/ + +ima_cores_setup: + la t0, trap_entry + +#ifdef MIV_LEGACY_RV32_VECTORED_INTERRUPTS + addi t0, t0, 0x01 /* Set the mode bit for IMA cores. + For both MIV_RV32 v3.1 and v3.0 cores this is done by configurator. */ +#endif + csrw mtvec, t0 + +generic_reset_handling: +/* Copy sdata section first so that the gp is set and linker relaxation can be + used */ + la a4, __sdata_load + la a5, __sdata_start + la a6, __sdata_end + beq a4, a5, 1f /* Exit if source and dest are same */ + beq a5, a6, 1f /* Exit if section start and end addresses are same */ + call block_copy + +1: + /* initialize global pointer */ + la gp, __global_pointer$ + +.option pop + +/* Floating point support configuration */ +#ifdef __riscv_flen + csrr t0, mstatus + lui t1, 0xffffa + addi t1, t1, -1 + and t0, t0, t1 + lui t1, 0x4 + or t1, t0, t1 + csrw mstatus, t1 + + lui t0, 0x0 + fscsr t0 +#endif + call initializations + /* Initialize stack pointer */ + la sp, __stack_top + + /* Jump into C code */ + j _init + +/* Error: trap_entry is not at the expected address of reset_vector+mtvec offset + as configured in the MIV_RV32 core vectored mode */ +vector_address_not_matching: + ebreak + +initializations: +/* Initialize the .bss section */ + mv t0, ra /* Store ra for future use */ + la a5, __bss_start + la a6, __bss_end + beq a5, a6, 1f /* Section start and end address are the same */ + call zeroize_block + +1: +/* Initialize the .sbss section */ + la a5, __sbss_start + la a6, __sbss_end + beq a5, a6, 1f /* Section start and end address are the same */ + call zeroize_block + +/* Clear heap */ + la a5, __heap_start + la a6, __heap_end + beq a5, a6, 1f /* Section start and end address are the same */ + call zeroize_block + +1: +/* Copy data section */ + la a4, __data_load + la a5, __data_start + la a6, __data_end + beq a4, a5, 1f /* Exit early if source and dest are same */ + beq a5, a6, 1f /* Section start and end addresses are the same */ + call block_copy + +1: + mv ra, t0 /* Retrieve ra */ + ret + +zeroize_block: + bltu a6, a5, block_copy_error /* Error. End address is less than start */ + or a7, a6, a5 /* Check if start or end is unalined */ + andi a7, a7, 0x03u + bgtz a7, block_copy_error /* Unaligned addresses error*/ +zeroize_loop: + sw x0, 0(a5) + add a5, a5, __SIZEOF_POINTER__ + blt a5, a6, zeroize_loop + ret + +block_copy: + bltu a6, a5, block_copy_error /* Error. End address is less than start */ + or a7, a6, a5 /* Check if start or end is unalined */ + andi a7, a7, 0x03u + bgtz a7, block_copy_error /* Unaligned addresses error*/ +block_copy_loop: + lw a7, 0(a4) + sw a7, 0(a5) + addi a5, a5, 0x04 + addi a4, a4, 0x04 + blt a5, a6, block_copy_loop + j block_copy_exit + +block_copy_error: + j block_copy_error + +block_copy_exit: + ret + +#endif /*ENTRY_S*/ diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv_rv32_hal.c b/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv_rv32_hal.c new file mode 100644 index 0000000..a112821 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv_rv32_hal.c @@ -0,0 +1,410 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_hal.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Implementation of Hardware Abstraction Layer for Mi-V soft processors + * + */ +#include +#include "miv_rv32_hal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SUCCESS 0U +#define ERROR 1U +#define MASK_32BIT 0xFFFFFFFFu + +/*------------------------------------------------------------------------------ + * Write in a sequence recommended by privileged spec to avoid spurious + * interrupts + + # New comparand is in a1:a0. + li t0, -1 + sw t0, mtimecmp # No smaller than old value. + sw a1, mtimecmp+4 # No smaller than new value. + sw a0, mtimecmp # New value. + */ +#ifndef MIV_RV32_EXT_TIMECMP +#define WRITE_MTIMECMP(value) MTIMECMPH = MASK_32BIT; \ + MTIMECMP = value & MASK_32BIT;\ + MTIMECMPH = (value >> 32u) & MASK_32BIT; +#else +#define WRITE_MTIMECMP(value) +#endif + +#ifndef MIV_RV32_EXT_TIMER +#define WRITE_MTIME(value) MTIME = value & MASK_32BIT;\ + MTIMEH = (value >> 32u) & MASK_32BIT; +#else +#define WRITE_MTIME(value) +#endif + +extern void Software_IRQHandler(void); + +#ifdef MIV_LEGACY_RV32 +#define MTIME_PRESCALER 100UL +/*------------------------------------------------------------------------------ + * + */ +uint8_t Invalid_IRQHandler(void); +uint8_t External_1_IRQHandler(void); +uint8_t External_2_IRQHandler(void); +uint8_t External_3_IRQHandler(void); +uint8_t External_4_IRQHandler(void); +uint8_t External_5_IRQHandler(void); +uint8_t External_6_IRQHandler(void); +uint8_t External_7_IRQHandler(void); +uint8_t External_8_IRQHandler(void); +uint8_t External_9_IRQHandler(void); +uint8_t External_10_IRQHandler(void); +uint8_t External_11_IRQHandler(void); +uint8_t External_12_IRQHandler(void); +uint8_t External_13_IRQHandler(void); +uint8_t External_14_IRQHandler(void); +uint8_t External_15_IRQHandler(void); +uint8_t External_16_IRQHandler(void); +uint8_t External_17_IRQHandler(void); +uint8_t External_18_IRQHandler(void); +uint8_t External_19_IRQHandler(void); +uint8_t External_20_IRQHandler(void); +uint8_t External_21_IRQHandler(void); +uint8_t External_22_IRQHandler(void); +uint8_t External_23_IRQHandler(void); +uint8_t External_24_IRQHandler(void); +uint8_t External_25_IRQHandler(void); +uint8_t External_26_IRQHandler(void); +uint8_t External_27_IRQHandler(void); +uint8_t External_28_IRQHandler(void); +uint8_t External_29_IRQHandler(void); +uint8_t External_30_IRQHandler(void); +uint8_t External_31_IRQHandler(void); + + +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for external interrupts. + */ +uint8_t (* const mrv_ext_irq_handler_table[32])(void) = +{ + + Invalid_IRQHandler, + External_1_IRQHandler, + External_2_IRQHandler, + External_3_IRQHandler, + External_4_IRQHandler, + External_5_IRQHandler, + External_6_IRQHandler, + External_7_IRQHandler, + External_8_IRQHandler, + External_9_IRQHandler, + External_10_IRQHandler, + External_11_IRQHandler, + External_12_IRQHandler, + External_13_IRQHandler, + External_14_IRQHandler, + External_15_IRQHandler, + External_16_IRQHandler, + External_17_IRQHandler, + External_18_IRQHandler, + External_19_IRQHandler, + External_20_IRQHandler, + External_21_IRQHandler, + External_22_IRQHandler, + External_23_IRQHandler, + External_24_IRQHandler, + External_25_IRQHandler, + External_26_IRQHandler, + External_27_IRQHandler, + External_28_IRQHandler, + External_29_IRQHandler, + External_30_IRQHandler, + External_31_IRQHandler +}; + +#else +/*------------------------------------------------------------------------------ + * Interrupt handlers as mapped into the MIE register of the MIV_RV32 + */ +extern void Reserved_IRQHandler(void); +extern void External_IRQHandler(void); +extern void MGEUI_IRQHandler(void); +extern void MGECI_IRQHandler(void); +extern void MSYS_EI0_IRQHandler(void); +extern void MSYS_EI1_IRQHandler(void); +extern void MSYS_EI2_IRQHandler(void); +extern void MSYS_EI3_IRQHandler(void); +extern void MSYS_EI4_IRQHandler(void); +extern void MSYS_EI5_IRQHandler(void); +extern void SUBSYS_IRQHandler(void); + +#ifndef MIV_RV32_V3_0 /*For MIV_RV32 v3.1*/ +extern void MSYS_EI6_IRQHandler(void); +extern void MSYS_EI7_IRQHandler(void); +extern void SUBSYSR_IRQHandler(void); // @suppress("Unused function declaration") +#endif /*MIV_RV32_V3_0*/ + +#endif /* MIV_LEGACY_RV32 */ + +/*------------------------------------------------------------------------------ + * Increment value for the mtimecmp register in order to achieve a system tick + * interrupt as specified through the MRV_systick_config() function. + */ +static uint64_t g_systick_increment = 0U; +static uint64_t g_systick_cmp_value = 0U; + +/*------------------------------------------------------------------------------ + * Configure the machine timer to generate an interrupt. + */ +uint32_t MRV_systick_config(uint64_t ticks) +{ + uint32_t ret_val = ERROR; + uint64_t remainder = ticks; + g_systick_increment = 0U; + g_systick_cmp_value = 0U; + + while (remainder >= MTIME_PRESCALER) + { + remainder -= MTIME_PRESCALER; + g_systick_increment++; + } + + g_systick_cmp_value = g_systick_increment + MRV_read_mtime(); + + if (g_systick_increment > 0U) + { + WRITE_MTIMECMP(g_systick_cmp_value); + set_csr(mie, MIP_MTIP); + MRV_enable_interrupts(); + ret_val = SUCCESS; + } + + return ret_val; +} + +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for machine timer interrupts. + */ +void handle_m_timer_interrupt(void) +{ + clear_csr(mie, MIP_MTIP); + + uint64_t mtime_at_irq = MRV_read_mtime(); + +#ifndef NDEBUG + static volatile uint32_t d_tick = 0u; +#endif + + while(g_systick_cmp_value < (mtime_at_irq + MTIME_DELTA)) { + g_systick_cmp_value = g_systick_cmp_value + g_systick_increment; + +#ifndef NDEBUG + d_tick += 1; +#endif + } +/***************************************************************************//** + /* + * Note: If d_tick > 1 it means, that a system timer interrupt has been + * missed. + * Please ensure that interrupt handlers are as short as possible to prevent + * them stopping other interrupts from being handled. For example, if a + * system timer interrupt occurs during a software interrupt, the system + * timer interrupt will not be handled until the software interrupt handling + * is complete. If the software interrupt handling time is more than one + * systick interval, it will result in d_tick > 1. + * If you are running the program using the debugger and halt the CPU at a + * breakpoint, MTIME will continue to increment and interrupts will be + * missed; resulting in d_tick > 1. + */ + + WRITE_MTIMECMP(g_systick_cmp_value); + + SysTick_Handler(); + + set_csr(mie, MIP_MTIP); +} + +void handle_m_soft_interrupt(void) +{ + Software_IRQHandler(); + MRV_clear_soft_irq(); +} +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for software interrupts. + */ +#ifdef MIV_LEGACY_RV32 +void handle_m_ext_interrupt(void) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; + uint8_t disable = EXT_IRQ_KEEP_ENABLED; + + if (0u !=int_num) + { + disable = mrv_ext_irq_handler_table[int_num](); + + PLIC->TARGET[hart_id].CLAIM_COMPLETE = int_num; + + if(EXT_IRQ_DISABLE == disable) + { + MRV_PLIC_disable_irq((IRQn_Type)int_num); + } + } +} +#else + +/*------------------------------------------------------------------------------ + * MSYS local interrupts table + */ +void (* const local_irq_handler_table[16])(void) = +{ +#ifndef MIV_RV32_V3_0 + MGEUI_IRQHandler, + MGECI_IRQHandler, + SUBSYS_IRQHandler, + SUBSYSR_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + MSYS_EI0_IRQHandler, + MSYS_EI1_IRQHandler, + MSYS_EI2_IRQHandler, + MSYS_EI3_IRQHandler, + MSYS_EI4_IRQHandler, + MSYS_EI5_IRQHandler, + MSYS_EI6_IRQHandler, + MSYS_EI7_IRQHandler +#else + MGEUI_IRQHandler, + MGECI_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + MSYS_EI0_IRQHandler, + MSYS_EI1_IRQHandler, + MSYS_EI2_IRQHandler, + MSYS_EI3_IRQHandler, + MSYS_EI4_IRQHandler, + MSYS_EI5_IRQHandler, + SUBSYS_IRQHandler, + Reserved_IRQHandler, +#endif +}; + +/*------------------------------------------------------------------------------ + * Jump to interrupt table containing local interrupts + */ +void handle_local_ei_interrupts(uint8_t irq_no) +{ + uint64_t mhart_id = read_csr(mhartid); + ASSERT(irq_no <= MIV_LOCAL_IRQ_MAX) + ASSERT(irq_no >= MIV_LOCAL_IRQ_MIN) + + uint8_t ei_no = (uint8_t)(irq_no - MIV_LOCAL_IRQ_MIN); + (*local_irq_handler_table[ei_no])(); +} +#endif /* MIV_LEGACY_RV32 */ + + +/*------------------------------------------------------------------------------ + * Trap handler. This function is invoked in the non-vectored mode. + */ +void handle_trap(uintptr_t mcause, uintptr_t mepc) +{ + uint64_t is_interrupt = mcause & MCAUSE_INT; + + if (is_interrupt) + { +#ifndef MIV_LEGACY_RV32 + if (((mcause & MCAUSE_CAUSE) >= MIV_LOCAL_IRQ_MIN) && ((mcause & MCAUSE_CAUSE) <= MIV_LOCAL_IRQ_MAX)) + { + handle_local_ei_interrupts((uint8_t)(mcause & MCAUSE_CAUSE)); + } + else if ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT) +#else + if ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT) +#endif + { +#ifndef MIV_LEGACY_RV32 + External_IRQHandler(); +#else + handle_m_ext_interrupt(); +#endif + } + else if ((mcause & MCAUSE_CAUSE) == IRQ_M_SOFT) + { + handle_m_soft_interrupt(); + } + else if ((mcause & MCAUSE_CAUSE) == IRQ_M_TIMER) + { + handle_m_timer_interrupt(); + } + } + else + { +#ifndef NDEBUG + /* + Arguments supplied to this function are mcause, mepc (exception PC) and + stack pointer. + Based on privileged-isa specification mcause values and meanings are: + + 0 Instruction address misaligned (mtval/mtval is the address) + 1 Instruction access fault (mtval/mtval is the address) + 2 Illegal instruction (mtval/mtval contains the + offending instruction opcode) + 3 Breakpoint + 4 Load address misaligned (mtval/mtval is the address) + 5 Load address fault (mtval/mtval is the address) + 6 Store/AMO address fault (mtval/mtval is the address) + 7 Store/AMO access fault (mtval/mtval is the address) + 8 Environment call from U-mode + 9 Environment call from S-mode + A Environment call from M-mode + B Instruction page fault + C Load page fault (mtval/mtval is the address) + E Store page fault (mtval/mtval is the address) + + # Please note: mtval is the newer name for register mbadaddr + # If you get a compile failure here, use the older name. + # At this point, both are supported in latest compiler, older compiler + # versions only support mbadaddr. + # See: https://github.com/riscv/riscv-gcc/issues/133 + */ + + /* interrupt pending */ + uintptr_t mip = read_csr(mip); + + /* additional info and meaning depends on mcause */ + uintptr_t mtval = read_csr(mtval); + + /* trap vector */ + uintptr_t mtvec = read_csr(mtvec); + + /* temporary, sometimes might hold temporary value of a0 */ + uintptr_t mscratch = read_csr(mscratch); + + /* status contains many smaller fields: */ + uintptr_t mstatus = read_csr(mstatus); + + /* PC value when the exception was taken*/ + uintptr_t mmepc = read_csr(mepc); + + /* breakpoint */ + __asm__("ebreak"); +#else + _exit(1 + mcause); +#endif /* NDEBUG */ + } +} + +#ifdef __cplusplus +} +#endif + diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv_rv32_hal.h b/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv_rv32_hal.h new file mode 100644 index 0000000..9ce9ef6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv_rv32_hal.h @@ -0,0 +1,773 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_hal.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware Abstraction Layer functions for Mi-V soft processors + * + */ + +/*=========================================================================*//** + @mainpage MIV_RV32 Hardware Abstraction Layer + + ============================================================================== + Introduction + ============================================================================== + This document describes the Hardware Abstraction Layer (HAL) for the MIV_RV32 + Soft IP Core. This release of the HAL corresponds to the Soft IP core MIV_RV32 + v3.1 release. It also supports earlier versions of the MIV_RV32 as well as the + legacy RV32 IP cores. + The preprocessor macros provided with the MIV_RV32 HAL are used to customize + it to target the Soft Processor IP version being used in your project. + + The term "MIV_RV32" represents following two cores: + - MIV_RV32 v3.0 and later (the latest and greatest Mi-V soft processor) + - MIV_RV32IMC v2.1 (MIV_RV32 v3.0 is a drop in replacement for this core) + It is highly recommended to migrate your design to MIV_RV32 v3.1 + + The term, Legacy RV32 IP cores, represents following IP cores: + - MIV_RV32IMA_L1_AHB + - MIV_RV32IMA_L1_AXI + - MIV_RV32IMAF_L1_AHB + + These legacy RV32 IP cores are deprecated. It is highly recommended to migrate + your designs to MIV_RV32 v3.1 (and subsequent IP releases) for the latest + enhancements, bug fixes, and support. + + -------------------------------- + MIV_RV32 V3.1 + -------------------------------- + This is the latest release of the MIV_RV32 Soft IP core. For more details, + refer to the MIV_RV32 User [Guide](https://www.microchip.com/en-us/products/fpgas-and-plds/ip-core-tools/miv-rv32) + + The MIV_RV32 Core as well as this document use the terms defined below: + + -------------------------------- + - SUBSYS - Processor Subsystem for RISC-V + - OPSRV - Offload Processor Subsystem for RISC-V + - GPR - General Purpose Registers + - MGECIE - Machine GPR ECC Correctable Interrupt Enable + - MGEUIE - Machine GPR ECC Uncorrectable Interrupt Enable + - MTIE - Machine Timer Interrupt Enable + - MEIE - Machine External Interrupt Enable + - MSIE - Machine Software Interrupt Enable + - ISR - Interrupt Service Routine + + ============================================================================== + Customizing MIV_RV32 HAL + ============================================================================== + To use the HAL with older releases of MIV_RV32, preprocessor macros have been + provided. Using these macros, any of the IP version is targeted. + The HAL is used to target any of the mentioned platforms by adding the + following macros in the way : + Project Properties > C/C++ Build > Settings > Preprocessor in Assembler and + Compiler settings. + The table below shows the macros corresponding to the MIV Core being used in + your libero project. By default, the HAL targets v3.1 of the IP core and no + macros need to be set for this configutation. + + | Libero MI-V Soft IP Version | SoftConsole Macro | + |-----------------------------|-------------------| + | MIV_RV32 v3.1 | no macro required | + | MIV_RV32 v3.0 | MIV_CORE_V3_0 | + | Legacy RV32 Cores | MIV_LEGACY_RV32 | + + -------------------------------- + Interrupt Handling + -------------------------------- + The MIE Register is defined as a enum in the HAL, and the table below is used + as a reference when the vectored interrupts are enabled in the GUI core + configurator. + + The MIE register is a RISC-V Control and Status Register (CSR), which stands + for the Machine Interrupt Enable. This is used to enable the machine mode + interrupts in the MIV_RV32 hart. Refer to the RISC-V Priv spec for more details. + + The following table shows the trap entry addresses when an interrupt occurs and + the vectored interrupts are enabled in the GUI configurator. + + | MIE Register Bit | Interrupt Enable | Vector Address | + |-------------------|------------------|----------------| + | 31 | MSYS_IE7 | mtvec.BASE + 0x7C | + | 30 | MSYS_IE6 | mtvec.BASE + 0x78 | + | 29 | MSYS_IE5 | mtvec.BASE + 0x74 | + | 28 | MSYS_IE4 | mtvec.BASE + 0x70 | + | 27 | MSYS_IE3 | mtvec.BASE + 0x6C | + | 26 | MSYS_IE2 | mtvec.BASE + 0x68 | + | 25 | MSYS_IE1 | mtvec.BASE + 0x64 | + | 24 | MSYS_IE0 | mtvec.BASE + 0x60 | + | 23 | SUBSYS_EI | mtvec.BASE + 0x5C | + | 22 | SUBSYSR | mtvec.BASE + 0x58 | + | 17 | MGECIE | mtvec.BASE + 0x44 | + | 16 | MGEUIE | mtvec.BASE + 0x40 | + | 11 | MEIE | mtvec.BASE + 0x2C | + | 7 | MTIE | mtvec.BASE + 0x1C | + | 3 | MSIE | mtvec.BASE + 0x0C | + + + For changes in MIE register map, see the [MIE Register Map for MIV_RV32 v3.0] + (#mie-register-map-for-miv_rv32-v3.0) section. + + SUBSYSR is currently not being used by the core and is Reserved for future use. + + The mtvec.BASE field corresponds to the bits [31:2], where mtvec stands for + Machine Trap Vector, and all traps set the PC to the the value stored in the + mtvec.BASE field when in Non-Vectored mode. In this case, a generic trap + handler is as an interrupt service routine. + + When Vectored interrupts are enabled, use this formula to calculate the trap + address: (mtvec.BASE + 4*cause), where cause comes from the mcause CSR. The + mcause register is written with a code indicating the event that caused the trap. + For more details, see the RISC-V priv specification. + + The MIV_RV32 Soft IP core does not contain a Platfrom Level Interrup Controller + (PLIC). It is advised to use the PLIC contained within the MIV_ESS sub-system. + Connect the PLIC interrupt output of the MIV_ESS to the EXT_IRQ pin on the + MIV_RV32. + + The following table is the MIE register map for the MIV_RV32 Core V3.0. It only + highlights the differences between the V3.0 and V3.1 of the core. + + -------------------------------- + MIE Register Map for MIV_RV32 V3.0 + -------------------------------- + + | MIE Register Bit | Target Interrupt | Vector Address | + |-------------------|------------------|----------------| + | 31 | Not in use | top table | + | 30 | SUBSYS_EI | addr + 0x78 | + | 23 | Not in use | Not in use | + | 22 | Not in use | Not in use | + + Other interrupt bit postions like the MGEUIE and MSYS_IE5 to MSYS_IE0 remain + unchanged. + + -------------------------------- + Floating Point Interrupt Support + -------------------------------- + When an interrupt is taken and Floating Point instructions are used in the + ISR, the floating point register context must be saved to resume the application + correctly. To use this feature, enable the provided macro in the + Softconsole build settings. + This feature is turned off by default as it adds overhead which is not required + when the ISR does not used FP insturctions and saving the general purpose + register context is sufficient. + + | Macro Name | Definition | + |--------------------------|-------------------------------------------------| + | MIV_FP_CONTEXT_SAVE | Define to save the FP register file | + + + -------------------------------- + SUBSYS - SubSystem for RISC-V + -------------------------------- + SUBSYS stands for SubSystem for RISC-V. This was previously (MIV_RV32 v3.0) + known as OPSRV, which stands for "Offload Processor Subsystem + for RISC-V". See the earlier versions of the handbook for more details. + In the latest release of the MIV_RV32 IP core v3.1, OPSRV has been renamed to + SUBSYS. The MIV_RV32 HAL now uses SUBSYS instead of OPSRV. + + *//*=========================================================================*/ +#ifndef RISCV_HAL_H +#define RISCV_HAL_H + +#include "miv_rv32_regs.h" +#include "miv_rv32_plic.h" +#include "miv_rv32_assert.h" +#include "miv_rv32_subsys.h" + +#ifndef LEGACY_DIR_STRUCTURE +#include "fpga_design_config/fpga_design_config.h" +#else +#include "hw_platform.h" +#endif /*LEGACY_DIR_STRUCTURE*/ + +#ifdef __cplusplus +extern "C" { +#endif +/*-------------------------------------------------------------------------*//** + SUBSYS Backwards Compatibility + ======================================= + For application code using the older macro names and API functions, these macros + act as a compatibility layer and applications which use OPSRV API features work + due to these macro definitions. However, it is adviced to update your + application code to use the SUBSYS macros and API functions. + + | Macro Name | Now Called | + |-------------------------|--------------------------| + | OPSRV_TCM_ECC_CE_IRQ | SUBSYS_TCM_ECC_CE_IRQ | + | OPSRV_TCM_ECC_UCE_IRQ | SUBSYS_TCM_ECC_UCE_IRQ | + | OPSRV_AXI_WR_RESP_IRQ | SUBSYS_AXI_WR_RESP_IRQ | + | MRV32_MSYS_OPSRV_IRQn | MRV32_SUBSYS_IRQn | + | MRV32_opsrv_enable_irq | MRV32_subsys_enable_irq | + | MRV32_opsrv_disable_irq | MRV32_subsys_disable_irq | + | MRV32_opsrv_clear_irq | MRV32_subsys_clear_irq | + | OPSRV_IRQHandler | SUBSYS_IRQHandler | + */ + +/*-------------------------------------------------------------------------*//** + MTIME Timer Interrupt Constants + ======================================= + These values contain the register addresses for the registers used by the + machine timer interrupt + + MTIME_PRESCALER is not defined on the MIV_RV32IMC v2.0 and v2.1. By using this + definition the system crashes. For those core, use the following definition: + + #define MTIME_PRESCALER 100u + + MTIME and MTIMECMP + -------------------------------- + MIV_RV32 core offers flexibility in terms of generating MTIME and MTIMECMP + registers internal to the core or using external time reference. There four + possible combinations: + + - Internal MTIME and Internal MTIME IRQ enabled Generate the MTIME and MTIMECMP + registers internally. (The only combination available on legacy RV32 cores) + + - Internal MTIME enabled and Internal MTIME IRQ disabled Generate the MTIME + internally and have a timer interrupt input to the core as external pin. In + this case, 1 pin port will be available on MIV_RV32 for timer interrupt. + + - When the internal MTIME is disabled, and the Internal MTIME IRQ is enabled, the + system generates the time value externally and generates the mtimecmp and + interrupt internally (for example, a multiprocessor system with a shared time + between all cores). In this case, a 64-bit port is available on the MIV_RV32 + core as input. + + - Internal MTIME and Internal MTIME IRQ disabled Generate both the time and + timer interrupts externally. In this case a 64 bit port will be available on + the MIV_RV32 core as input, and a 1 pin port will be available for timer + interrupt. + + To handle all these combinations in the firmware, the following constants must + be defined in accordance with the configuration that you have made on your + MIV_RV32 core design. + + MIV_RV32_EXT_TIMER + -------------------------------- + When defined, it means that the MTIME register is not available internal to + the core. In this case, a 64 bit port will be available on the MIV_RV32 core as + input. When this macro is not defined, it means that the MTIME register is + available internally to the core. + + MIV_RV32_EXT_TIMECMP + -------------------------------- + When defined, it means the MTIMECMP register is not available internally to + the core and the Timer interrupt input to the core comes as an external pin. + When this macro is not defined it means the that MTIMECMP register exists + internal to the core and that the timer interrupt is generated internally. + +NOTE: All these macros must not be defined if you are using a MIV_RV32 core. + */ + +#define OPSRV_TCM_ECC_CE_IRQ SUBSYS_TCM_ECC_CE_IRQ +#define OPSRV_TCM_ECC_UCE_IRQ SUBSYS_TCM_ECC_UCE_IRQ +#define OPSRV_AXI_WR_RESP_IRQ SUBSYS_AXI_WR_RESP_IRQ +#define MRV32_MSYS_OPSRV_IRQn MRV32_SUBSYS_IRQn +#define MRV32_opsrv_enable_irq MRV32_subsys_enable_irq +#define MRV32_opsrv_disable_irq MRV32_subsys_disable_irq +#define MRV32_opsrv_clear_irq MRV32_subsys_clear_irq +#define OPSRV_IRQHandler SUBSYS_IRQHandler + +/*-------------------------------------------------------------------------*//** + External IRQ + ======================================= + Return value from External IRQ handler. This is used to disable the + External Interrupt. + + | Macro Name | Value | Description| + |-------------------|--------|----------------| + | EXT_IRQ_KEEP_ENABLED | 0 | Keep external interrupts enabled | + | EXT_IRQ_DISABLE | 1 | Disable external interrupts | + */ +#define EXT_IRQ_KEEP_ENABLED 0U +#define EXT_IRQ_DISABLE 1U + +#define MTIME_DELTA 5 +#ifdef MIV_LEGACY_RV32 +#define MSIP (*(uint32_t*)0x44000000UL) +#define MTIMECMP (*(uint32_t*)0x44004000UL) +#define MTIMECMPH (*(uint32_t*)0x44004004UL) +#define MTIME (*(uint32_t*)0x4400BFF8UL) +#define MTIMEH (*(uint32_t*)0x4400BFFCUL) + +/* To maintain backward compatibility with FreeRTOS config code */ +#define PRCI_BASE 0x44000000UL +#else /* MIV_LEGACY_RV32 */ + +/* To maintain backward compatibility with FreeRTOS config code */ +#define PRCI_BASE 0x02000000UL + +#ifndef MIV_RV32_EXT_TIMECMP +#define MTIMECMP (*(volatile uint32_t*)0x02004000UL) +#define MTIMECMPH (*(volatile uint32_t*)0x02004004UL) +#else +#define MTIMECMP (0u) +#define MTIMECMPH (0u) +#endif + +#define MTIME_PRESCALER (*(volatile uint32_t*)0x02005000UL) + +#ifndef MIV_RV32_EXT_TIMER +#define MTIME (*(volatile uint32_t*)0x0200BFF8UL) +#define MTIMEH (*(volatile uint32_t*)0x0200BFFCUL) + +/***************************************************************************//** + MIMPID Register + The MIMPID register is a RISC-V Control and Status Register In the v3.0 of + MIV_RV32, the value of `MIMPID = 0x000540AD`. In the v3.1 of MIV_RV32, the + value if `MIMPID = 0xE5010301` corresponding to (E)mbedded (5)ystem(01) core + version (03).(01) this terminology will be followed in the subsequent releases + of the core read the csr value and store it in a varible which may be used to + check the MIV_RV32 core version during runtime. + + Future releases of the core will increment the 03 and 01 as major and minor + releases respectively and the register can be read at runtime to find the + Soft IP core version. + + | Core Version | Register | Value | Notes | + |----------------|------------|---------|---------| + | MIV_RV32 V3.1 | mimpid | 0xE5010301 | implimentation ID | + | MIV_RV32 V3.0 | mimpid | 0x000540AD | implimentation ID | + */ +#define MIMPID read_csr(mimpid) + +/*Used as a mask to read and write to mte mtvec.BASE address*/ +#define MTVEC_BASE_ADDR_MASK 0xFFFFFFFC + +#else +#define MTIME (0u) +#define MTIMEH (0u) +#endif /*MIV_RV32_EXT_TIMER*/ + +/*-------------------------------------------------------------------------*//** + RISC-V Specification Interrupts + ======================================= + These definitions are provided for easy identification of the interrupt + in the MIE/MIP registers. + Apart from the standard software, timer, and external interrupts, the names + of the additional interrupts correspond to the names as used in the MIV_RV32 + handbook. Please refer the MIV_RV32 handbook for more details. + + All the interrups, provided by the MIV_RV32 core, follow the interrupt priority + order and register description as mentioned in the RISC-V spec. + + | Macro Name | Value | Description| + |-------------------|--------|----------------| + | MRV32_SOFT_IRQn | MIE_3_IRQn | Software interrupt enable | + | MRV32_TIMER_IRQn | MIE_7_IRQn | Timer interrupt enable | + | MRV32_EXT_IRQn | MIE_11_IRQn | External interrupt enable | + + */ +#define MRV32_SOFT_IRQn MIE_3_IRQn +#define MRV32_TIMER_IRQn MIE_7_IRQn +#define MRV32_EXT_IRQn MIE_11_IRQn + +/***************************************************************************//** + Interrupt numbers: + This enum represents the interrupt enable bits in the MIE register. + */ +enum +{ + MIE_0_IRQn = (0x01u), + MIE_1_IRQn = (0x01u<<1u), + MIE_2_IRQn = (0x01u<<2u), + MIE_3_IRQn = (0x01u<<3u), /*MSIE 0xC*/ + MIE_4_IRQn = (0x01u<<4u), + MIE_5_IRQn = (0x01u<<5u), + MIE_6_IRQn = (0x01u<<6u), + MIE_7_IRQn = (0x01u<<7u), /*MTIE 0x1C*/ + MIE_8_IRQn = (0x01u<<8u), + MIE_9_IRQn = (0x01u<<9u), + MIE_10_IRQn = (0x01u<<10u), + MIE_11_IRQn = (0x01u<<11u), /*MEIE 0x2C*/ + MIE_12_IRQn = (0x01u<<12u), + MIE_13_IRQn = (0x01u<<13u), + MIE_14_IRQn = (0x01u<<14u), + MIE_15_IRQn = (0x01u<<15u), + MIE_16_IRQn = (0x01u<<16u), /*MGEUIE ECC Uncorrectable 0x40*/ + MIE_17_IRQn = (0x01u<<17u), /*MGECIE ECC Correctable 0x44*/ + MIE_18_IRQn = (0x01u<<18u), + MIE_19_IRQn = (0x01u<<19u), + MIE_20_IRQn = (0x01u<<20u), + MIE_21_IRQn = (0x01u<<21u), + MIE_22_IRQn = (0x01u<<22u), /*SUBSYSR 0x58 (R)eserved*/ + MIE_23_IRQn = (0x01u<<23u), /*SUBSYS_IE 0x5C for MIV_RV32 v3.1*/ + MIE_24_IRQn = (0x01u<<24u), /*MSYS_IE0 0x60*/ + MIE_25_IRQn = (0x01u<<25u), /*MSYS_IE1 0x64*/ + MIE_26_IRQn = (0x01u<<26u), /*MSYS_IE2 0x68*/ + MIE_27_IRQn = (0x01u<<27u), /*MSYS_IE3 0x6C*/ + MIE_28_IRQn = (0x01u<<28u), /*MSYS_IE4 0x70*/ + MIE_29_IRQn = (0x01u<<29u), /*MSYS_IE5 0x74*/ + MIE_30_IRQn = (0x01u<<30u), /*MSYS_IE6 0x78, read comment below*/ + MIE_31_IRQn = (0x01u<<31u) /*MSYS_IE7 0x7C*/ +} MRV_LOCAL_IRQn_Type; + +#define MRV32_MGEUIE_IRQn MIE_16_IRQn +#define MRV32_MGECIE_IRQn MIE_17_IRQn +#define MRV32_MSYS_EIE0_IRQn MIE_24_IRQn +#define MRV32_MSYS_EIE1_IRQn MIE_25_IRQn +#define MRV32_MSYS_EIE2_IRQn MIE_26_IRQn +#define MRV32_MSYS_EIE3_IRQn MIE_27_IRQn +#define MRV32_MSYS_EIE4_IRQn MIE_28_IRQn +#define MRV32_MSYS_EIE5_IRQn MIE_29_IRQn +#ifndef MIV_RV32_V3_0 /*For MIV_RV32 v3.1*/ +#define MRV32_SUBSYSR_IRQn MIE_22_IRQn +#define MRV32_SUBSYS_IRQn MIE_23_IRQn +#define MRV32_MSYS_EIE6_IRQn MIE_30_IRQn +#define MRV32_MSYS_EIE7_IRQn MIE_31_IRQn +#else +#define MRV32_SUBSYS_IRQn MIE_30_IRQn +#endif /*MIV_RV32_V3_0*/ + +/*--------------------------------Public APIs---------------------------------*/ + +/***************************************************************************//** + The MRV32_clear_gpr_ecc_errors() function clears single bit ECC errors on the + GPRs. The ECC block does not write back corrected data to memory. Hence, when + ECC is enabled for the GPRs and if that data has a single bit error then the + data coming out of the ECC block is corrected and will not have the error, but + the data source will still have the error. Therefore, if data has a single bit + error, then the corrected data must be written back to prevent the single bit + error from becoming a double bit error. Clear the pending interrupt bit after + this using MRV32_mgeci_clear_irq() function to complete the ECC error handling. + + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline void MRV32_clear_gpr_ecc_errors(void) +{ + uint32_t temp; + + __asm__ __volatile__ ( + "sw x31, %0" + :"=m" (temp)); + + __asm__ volatile ( + "mv x31, x1;" + "mv x1, x31;" + + "mv x31, x2;" + "mv x2, x31;" + + "mv x31, x3;" + "mv x3, x31;" + + "mv x31, x4;" + "mv x4, x31;" + + "mv x31, x5;" + "mv x5, x31;" + + "mv x31, x6;" + "mv x6, x31;" + + "mv x31, x7;" + "mv x7, x31;" + + "mv x31, x8;" + "mv x8, x31;" + + "mv x31, x9;" + "mv x9, x31;" + + "mv x31, x10;" + "mv x10, x31;" + + "mv x31, x11;" + "mv x11, x31;" + + "mv x31, x12;" + "mv x12, x31;" + + "mv x31, x13;" + "mv x13, x31;" + + "mv x31, x14;" + "mv x14, x31;" + + "mv x31, x15;" + "mv x15, x31;" + + "mv x31, x16;" + "mv x16, x31;" + + "mv x31, x17;" + "mv x17, x31;" + + "mv x31, x18;" + "mv x18, x31;" + + "mv x31, x19;" + "mv x19, x31;" + + "mv x31, x20;" + "mv x20, x31;" + + "mv x31, x21;" + "mv x21, x31;" + + "mv x31, x22;" + "mv x22, x31;" + + "mv x31, x23;" + "mv x23, x31;" + + "mv x31, x24;" + "mv x24, x31;" + + "mv x31, x25;" + "mv x25, x31;" + + "mv x31, x26;" + "mv x26, x31;" + + "mv x31, x27;" + "mv x27, x31;" + + "mv x31, x28;" + "mv x28, x31;" + + "mv x31, x29;" + "mv x29, x31;" + + "mv x31, x30;" + "mv x30, x31;"); + + __asm__ __volatile__ ( + "lw x31, %0;" + : + :"m" (temp)); +} + + +/***************************************************************************//** + The MRV32_mgeui_clear_irq() function clears the GPR ECC Uncorrectable + Interrupt. MGEUI interrupt is available only when ECC is enabled in the MIV_RV32 + IP configurator. + + @return + This function does not return any value. + */ +static inline void MRV32_mgeui_clear_irq(void) +{ + clear_csr(mip, MRV32_MGEUIE_IRQn); +} + +/***************************************************************************//** + The MRV32_mgeci_clear_irq() function clears the GPR ECC Correctable Interrupt + MGECI interrupt is available only when ECC is enabled in the MIV_RV32 IP + configurator. + + @return + This function does not return any value. + */ +static inline void MRV32_mgeci_clear_irq(void) +{ + clear_csr(mip, MRV32_MGECIE_IRQn); +} + +/***************************************************************************//** + The MRV_enable_local_irq() function enables the local interrupts. It takes a + mask value as input. For each set bit in the mask value, the corresponding + interrupt bit in the MIE register is enabled. + + MRV_enable_local_irq( MRV32_SOFT_IRQn | MRV32_TIMER_IRQn | MRV32_EXT_IRQn | + MRV32_MSYS_EIE0_IRQn | + MRV32_MSYS_SUBSYS_IRQn); + */ +static inline void MRV_enable_local_irq(uint32_t mask) +{ + set_csr(mie, mask); +} + +/***************************************************************************//** + The MRV_disable_local_irq() function disables the local interrupts. It takes a + mask value as input. For each set bit in the mask value, the corresponding + interrupt bit in the MIE register is disabled. + + MRV_disable_local_irq( MRV32_SOFT_IRQn | MRV32_TIMER_IRQn | MRV32_EXT_IRQn | + MRV32_MSYS_EIE0_IRQn | + MRV32_MSYS_SUBSYS_IRQn); + */ +static inline void MRV_disable_local_irq(uint32_t mask) +{ + clear_csr(mie, mask); +} +#endif /* MIV_LEGACY_RV32 */ + +/***************************************************************************//** + The MRV_enable_interrupts() function enables all interrupts by setting the + machine mode interrupt enable bit in MSTATUS register. + + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline void MRV_enable_interrupts(void) +{ + set_csr(mstatus, MSTATUS_MIE); +} + +/***************************************************************************//** + The MRV_disable_interrupts() function disables all interrupts by clearing the + machine mode interrupt enable bit in MSTATUS register. + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline void MRV_disable_interrupts(void) +{ + clear_csr(mstatus, MSTATUS_MPIE); + clear_csr(mstatus, MSTATUS_MIE); +} + +/***************************************************************************//** + The MRV_read_mtvec_base() function reads the mtvec base value, which is the + addr used when an interrupt/trap occurs. In the mtvec register, [31:2] is the + BASE address. NOTE: The BASE address must be aligned on a 4B boundary. + + @param + The function does not take any parameters. + + @return + The function returns the value of the BASE field [31:2] as an unsigned 32-bit + value. + */ + +#ifndef MIV_LEGACY_RV32 +#ifndef MIV_RV32_v3_0 +static inline uint32_t MRV_read_mtvec_base (void) +{ + uint32_t mtvec_addr_base = read_csr(mtvec); + return mtvec_addr_base & MTVEC_BASE_ADDR_MASK; +} + +/***************************************************************************//** + The MRV_set_mtvec_base() function takes the mtvec_base address as a unsigned int + and writes the value into the BASE field [31:2] in the mtvec CSR, MODE[1:0] + is Read-only. BASE is 4B aligned, so the lowest 2 bits of mtvec_base are + ignored. + + @param mtvec_base + Any legal value is passed into the function, and it is used as the trap_entry + for interrupts. The PC jumps to this address provided when an interrupt occurs. + In case of vectored interrupts, the address value mentioned in the vector + table under the MIE Register Map is updated to the value passed to this + function parameter. + + @return + This function does not return any value. + */ +static inline void MRV_set_mtvec_base (uint32_t mtvec_base) +{ + mtvec_base = mtvec_base & MTVEC_BASE_ADDR_MASK; + write_csr(mtvec, mtvec_base); +} +#endif /*MIV_RV32_v3_0*/ +#endif /*MIV_LEGACY_RV32*/ + +/***************************************************************************//** + The MRV_read_mtime() function returns the current MTIME register value. + */ +static inline uint64_t MRV_read_mtime(void) +{ + volatile uint32_t hi = 0u; + volatile uint32_t lo = 0u; + + /* when mtime lower word is 0xFFFFFFFF, there will be rollover and + * returned value could be wrong. */ + do { + hi = MTIMEH; + lo = MTIME; + } while(hi != MTIMEH); + + return((((uint64_t)MTIMEH) << 32u) | lo); +} + +/***************************************************************************//** + The MRV_raise_soft_irq() function raises a synchronous software interrupt + by writing into the MSIP register. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV_raise_soft_irq(void) +{ + set_csr(mie, MIP_MSIP); /* Enable software interrupt bit */ + +#ifdef MIV_LEGACY_RV32 + /* You need to make sure that the global interrupt is enabled */ + MSIP = 0x01; /* raise soft interrupt */ +#else + /* Raise soft IRQ on MIV_RV32 processor */ + SUBSYS->soft_reg |= SUBSYS_SOFT_IRQ; +#endif +} + +/***************************************************************************//** + The MRV_clear_soft_irq() function clears a synchronous software interrupt + by clearing the MSIP register. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV_clear_soft_irq(void) +{ +#ifdef MIV_LEGACY_RV32 + MSIP = 0x00u; /* clear soft interrupt */ +#else + /* Clear soft IRQ on MIV_RV32 processor */ + SUBSYS->soft_reg &= ~SUBSYS_SOFT_IRQ; +#endif +} + +/***************************************************************************//** + System tick handler. This handler function gets called when the Machine + timer interrupt asserts. An implementation of this function must be provided + by the application to implement the application specific machine timer + interrupt handling. If application does not provide such implementation, the + weakly linked handler stub function implemented in riscv_hal_stubs.c gets + linked. + */ +void SysTick_Handler(void); + +/***************************************************************************//** + System timer tick configuration. + Configures the machine timer to generate a system tick interrupt at regular + intervals. Takes the number of system clock ticks between interrupts. + + Though this function can take any valid ticks value as parameter, we expect + that, for all practical purposes, a small tick value (to generate periodic + interrupts every few miliseconds) is passed. If you need to generate periodic + events in the range of seconds or more, you may use the SysTick_Handler() to + further count the number of interrupts and hence the larger time intervals. + + @param ticks + This is the number of ticks or clock cycles which are counted down from the + interrupt to be triggered. + + @return + Returns 0 if successful. + Returns 1 if the interrupt interval is not achieved. + */ +uint32_t MRV_systick_config(uint64_t ticks); + +#ifdef __cplusplus +} +#endif +#endif /* RISCV_HAL_H */ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv_rv32_hal_version.h b/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv_rv32_hal_version.h new file mode 100644 index 0000000..4922bf2 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv_rv32_hal_version.h @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_hal_version.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware Abstraction Layer functions for Mi-V soft processors + * + */ + +#ifndef MIV_RV32_HAL_VERSION_H +#define MIV_RV32_HAL_VERSION_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MIV_RV32_HAL_VERSION_MAJOR 4 +#define MIV_RV32_HAL_VERSION_MINOR 2 +#define MIV_RV32_HAL_VERSION_PATCH 100 + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv_rv32_init.c b/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv_rv32_init.c new file mode 100644 index 0000000..85f8aca --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv_rv32_init.c @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_init.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor memory section initializations and start-up code. + * + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern void main(void); + +void _init(void) +{ + /* This function is a placeholder for the case where some more hardware + * specific initializations are required before jumping into the application + * code. You can implement it here. */ + + /* Jump to the application code after all initializations are completed */ + main(); +} + +/* Function called after main() finishes */ +void +_fini(void) +{ +} + +#ifdef __cplusplus +} +#endif + diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv_rv32_plic.h b/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv_rv32_plic.h new file mode 100644 index 0000000..3fd4103 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv_rv32_plic.h @@ -0,0 +1,214 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_plic.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V legacy RV32 soft processor PLIC access data structures and + * functions. + * Legacy RV32 soft processors are DEPRICATED. + * Migrate to MIV_RV32 v3.0 or later. + * + */ +#ifndef RISCV_PLIC_H +#define RISCV_PLIC_H + +#include +#include "miv_rv32_regs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================== + * Interrupt numbers: + */ +#ifdef MIV_LEGACY_RV32 +typedef enum +{ + MRV_NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + External_3_IRQn = 3, + External_4_IRQn = 4, + External_5_IRQn = 5, + External_6_IRQn = 6, + External_7_IRQn = 7, + External_8_IRQn = 8, + External_9_IRQn = 9, + External_10_IRQn = 10, + External_11_IRQn = 11, + External_12_IRQn = 12, + External_13_IRQn = 13, + External_14_IRQn = 14, + External_15_IRQn = 15, + External_16_IRQn = 16, + External_17_IRQn = 17, + External_18_IRQn = 18, + External_19_IRQn = 19, + External_20_IRQn = 20, + External_21_IRQn = 21, + External_22_IRQn = 22, + External_23_IRQn = 23, + External_24_IRQn = 24, + External_25_IRQn = 25, + External_26_IRQn = 26, + External_27_IRQn = 27, + External_28_IRQn = 28, + External_29_IRQn = 29, + External_30_IRQn = 30, + External_31_IRQn = 31 +} IRQn_Type; + +#define EXT_INTR_SOURCES 31 + +/*============================================================================== + * PLIC: Platform Level Interrupt Controller + */ +#define PLIC_BASE_ADDR 0x40000000UL + +typedef struct +{ + volatile uint32_t PRIORITY_THRESHOLD; + volatile uint32_t CLAIM_COMPLETE; + volatile uint32_t reserved[1022]; +} MRV_IRQ_Target_Type; + +typedef struct +{ + volatile uint32_t ENABLES[32]; +} MRV_Target_Enables_Type; + +typedef struct +{ + /*-------------------- Source Priority --------------------*/ + volatile uint32_t SOURCE_PRIORITY[1024]; + + /*-------------------- Pending array --------------------*/ + volatile const uint32_t PENDING_ARRAY[32]; + volatile uint32_t RESERVED1[992]; + + /*-------------------- Target enables --------------------*/ + volatile MRV_Target_Enables_Type TARGET_ENABLES[15808]; + + volatile uint32_t RESERVED2[16384]; + + /*--- Target Priority threshold and claim/complete---------*/ + MRV_IRQ_Target_Type TARGET[15872]; + +} PLIC_Type; + +#define PLIC ((PLIC_Type *)PLIC_BASE_ADDR) + +/*============================================================================== + * The function MRV_PLIC_init() initializes the PLIC controller and enables + * the global external interrupt bit. + */ +static inline void MRV_PLIC_init(void) +{ + uint32_t inc; + unsigned long hart_id = read_csr(mhartid); + + /* Disable all interrupts for the current hart. */ + for(inc = 0; inc < ((EXT_INTR_SOURCES + 32u) / 32u); ++inc) + { + PLIC->TARGET_ENABLES[hart_id].ENABLES[inc] = 0; + } + + /* Set priorities to zero. */ + for(inc = 0; inc < EXT_INTR_SOURCES; ++inc) + { + PLIC->SOURCE_PRIORITY[inc] = 0; + } + + /* Set the threshold to zero. */ + PLIC->TARGET[hart_id].PRIORITY_THRESHOLD = 0; + + /* Enable machine external interrupts. */ + set_csr(mie, MIP_MEIP); +} + +/*============================================================================== + * The function MRV_PLIC_enable_irq() enables the external interrupt for the + * interrupt number indicated by the parameter IRQn. + */ +static inline void MRV_PLIC_enable_irq(IRQn_Type IRQn) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t current = PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32]; + current |= (uint32_t)1 << (IRQn % 32); + PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32] = current; +} + +/*============================================================================== + * The function MRV_PLIC_disable_irq() disables the external interrupt for + * the interrupt number indicated by the parameter IRQn. + + * NOTE: + * This function can be used to disable the external interrupt from outside + * external interrupt handler function. + * This function MUST NOT be used from within the External Interrupt handler. + * If you wish to disable the external interrupt while the interrupt handler + * for that external interrupt is executing then you must use the return value + * EXT_IRQ_DISABLE to return from the extern interrupt handler. + */ +static inline void MRV_PLIC_disable_irq(IRQn_Type IRQn) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t current = PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32]; + + current &= ~((uint32_t)1 << (IRQn % 32)); + + PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32] = current; +} + +/*============================================================================== + * The function MRV_PLIC_set_priority() sets the priority for the external + * interrupt for the interrupt number indicated by the parameter IRQn. + */ +static inline void MRV_PLIC_set_priority(IRQn_Type IRQn, uint32_t priority) +{ + PLIC->SOURCE_PRIORITY[IRQn] = priority; +} + +/*============================================================================== + * The function MRV_PLIC_get_priority() returns the priority for the external + * interrupt for the interrupt number indicated by the parameter IRQn. + */ +static inline uint32_t MRV_PLIC_get_priority(IRQn_Type IRQn) +{ + return PLIC->SOURCE_PRIORITY[IRQn]; +} + +/***************************************************************************//** + * MRV_PLIC_clear_pending_irq(void) + * This is only called by the startup hart and only once + * Clears any pending interrupts as PLIC can be in unknown state on startup + */ +static inline void MRV_PLIC_clear_pending_irq(void) +{ + unsigned long hart_id = read_csr(mhartid); + volatile uint32_t int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; + volatile int32_t wait_possible_int; + + while (MRV_NoInterrupt_IRQn != int_num) + { + PLIC->TARGET[hart_id].CLAIM_COMPLETE = int_num; + wait_possible_int = 0xFU; + while (wait_possible_int) + { + wait_possible_int--; + } + + int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; + } +} + +#endif /* MIV_LEGACY_RV32 */ + +#ifdef __cplusplus +} +#endif + +#endif /* RISCV_PLIC_H */ diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv_rv32_regs.h b/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv_rv32_regs.h new file mode 100644 index 0000000..07d58e7 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv_rv32_regs.h @@ -0,0 +1,520 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor register bit mask and shift constants encodings. + * + */ +#ifndef MIV_RV32_REGS_H +#define MIV_RV32_REGS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MSTATUS_UIE 0x00000001UL +#define MSTATUS_SIE 0x00000002UL +#define MSTATUS_HIE 0x00000004UL +#define MSTATUS_MIE 0x00000008UL +#define MSTATUS_UPIE 0x00000010UL +#define MSTATUS_SPIE 0x00000020UL +#define MSTATUS_HPIE 0x00000040UL +#define MSTATUS_MPIE 0x00000080UL +#define MSTATUS_SPP 0x00000100UL +#define MSTATUS_HPP 0x00000600UL +#define MSTATUS_MPP 0x00001800UL +#define MSTATUS_FS 0x00006000UL +#define MSTATUS_XS 0x00018000UL +#define MSTATUS_MPRV 0x00020000UL +#define MSTATUS_SUM 0x00040000UL +#define MSTATUS_MXR 0x00080000UL +#define MSTATUS_TVM 0x00100000UL +#define MSTATUS_TW 0x00200000UL +#define MSTATUS_TSR 0x00400000UL +#define MSTATUS_RES 0x7F800000UL +#define MSTATUS32_SD 0x80000000UL +#define MSTATUS64_SD 0x8000000000000000UL + +#define MCAUSE32_CAUSE 0x7FFFFFFFUL +#define MCAUSE64_CAUSE 0x7FFFFFFFFFFFFFFFUL +#define MCAUSE32_INT 0x80000000UL +#define MCAUSE64_INT 0x8000000000000000UL + +#define MIP_SSIP (1u << IRQ_S_SOFT) +#define MIP_HSIP (1u << IRQ_H_SOFT) +#define MIP_MSIP (1u << IRQ_M_SOFT) +#define MIP_STIP (1u << IRQ_S_TIMER) +#define MIP_HTIP (1u << IRQ_H_TIMER) +#define MIP_MTIP (1u << IRQ_M_TIMER) +#define MIP_SEIP (1u << IRQ_S_EXT) +#define MIP_HEIP (1u << IRQ_H_EXT) +#define MIP_MEIP (1u << IRQ_M_EXT) + +#define PRV_M 3U + +#define VM_MBARE 0U +#define VM_MBB 1U +#define VM_MBBID 2U +#define VM_SV32 8U +#define VM_SV39 9U +#define VM_SV48 10U + +#define IRQ_S_SOFT 1U +#define IRQ_H_SOFT 2U +#define IRQ_M_SOFT 3U +#define IRQ_S_TIMER 5U +#define IRQ_H_TIMER 6U +#define IRQ_M_TIMER 7U +#define IRQ_S_EXT 9U +#define IRQ_H_EXT 10U +#define IRQ_M_EXT 11U + +#define DEFAULT_RSTVEC 0x00001000 +#define DEFAULT_NMIVEC 0x00001004 +#define DEFAULT_MTVEC 0x00001010 +#define CONFIG_STRING_ADDR 0x0000100C +#define EXT_IO_BASE 0x40000000 +#define DRAM_BASE 0x80000000 + +#ifdef __riscv + +#if __riscv_xlen == 64 +# define MSTATUS_SD MSTATUS64_SD +# define SSTATUS_SD SSTATUS64_SD +# define MCAUSE_INT MCAUSE64_INT +# define MCAUSE_CAUSE MCAUSE64_CAUSE +# define RISCV_PGLEVEL_BITS 9 +#else +# define MSTATUS_SD MSTATUS32_SD +# define SSTATUS_SD SSTATUS32_SD +# define RISCV_PGLEVEL_BITS 10 +# define MCAUSE_INT MCAUSE32_INT +# define MCAUSE_CAUSE MCAUSE32_CAUSE +#endif + +#define RISCV_PGSHIFT 12U +#define RISCV_PGSIZE (1U << RISCV_PGSHIFT) + +#ifndef __ASSEMBLER__ + +#ifdef __GNUC__ + +#define read_csr(reg) ({ unsigned long __tmp; \ + __asm__ volatile ("csrr %0, " #reg : "=r"(__tmp)); \ + __tmp; }) + +#define write_csr(reg, val) ({ \ + __asm__ volatile ("csrw " #reg ", %0" :: "rK"(val)); }) + +#define swap_csr(reg, val) ({ unsigned long __tmp; \ + __asm__ volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "rK"(val)); \ + __tmp; }) + +#define set_csr(reg, bit) ({ unsigned long __tmp; \ + __asm__ volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ + __tmp; }) + +#define clear_csr(reg, bit) ({ unsigned long __tmp; \ + __asm__ volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ + __tmp; }) + +#ifdef __riscv_atomic + +#define MASK(nr) (1UL << nr) +#define MASK_NOT(nr) (~(1UL << nr)) + +/** + * atomic_read - read atomic variable + * @v: pointer of type int + * + * Atomically reads the value of @v. + */ +static inline int atomic_read(const int *v) +{ + return *((volatile int *)(v)); +} + +/** + * atomic_set - set atomic variable + * @v: pointer of type int + * @i: required value + * + * Atomically sets the value of @v to @i. + */ +static inline void atomic_set(int *v, int i) +{ + *v = i; +} + +/** + * atomic_add - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v. + */ +static inline void atomic_add(int i, int *v) +{ + __asm__ __volatile__ ( + "amoadd.w zero, %1, %0" + : "+A" (*v) + : "r" (i)); +} + +static inline int atomic_fetch_add(unsigned int mask, int *v) +{ + int out; + + __asm__ __volatile__ ( + "amoadd.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_sub - subtract integer from atomic variable + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v. + */ +static inline void atomic_sub(int i, int *v) +{ + atomic_add(-i, v); +} + +static inline int atomic_fetch_sub(unsigned int mask, int *v) +{ + int out; + + __asm__ __volatile__ ( + "amosub.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_add_return - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v and returns the result + */ +static inline int atomic_add_return(int i, int *v) +{ + register int c; + __asm__ __volatile__ ( + "amoadd.w %0, %2, %1" + : "=r" (c), "+A" (*v) + : "r" (i)); + return (c + i); +} + +/** + * atomic_sub_return - subtract integer from atomic variable + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v and returns the result + */ +static inline int atomic_sub_return(int i, int *v) +{ + return atomic_add_return(-i, v); +} + +/** + * atomic_inc - increment atomic variable + * @v: pointer of type int + * + * Atomically increments @v by 1. + */ +static inline void atomic_inc(int *v) +{ + atomic_add(1, v); +} + +/** + * atomic_dec - decrement atomic variable + * @v: pointer of type int + * + * Atomically decrements @v by 1. + */ +static inline void atomic_dec(int *v) +{ + atomic_add(-1, v); +} + +static inline int atomic_inc_return(int *v) +{ + return atomic_add_return(1, v); +} + +static inline int atomic_dec_return(int *v) +{ + return atomic_sub_return(1, v); +} + +/** + * atomic_sub_and_test - subtract value from variable and test result + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v and returns + * true if the result is zero, or false for all + * other cases. + */ +static inline int atomic_sub_and_test(int i, int *v) +{ + return (atomic_sub_return(i, v) == 0); +} + +/** + * atomic_inc_and_test - increment and test + * @v: pointer of type int + * + * Atomically increments @v by 1 + * and returns true if the result is zero, or false for all + * other cases. + */ +static inline int atomic_inc_and_test(int *v) +{ + return (atomic_inc_return(v) == 0); +} + +/** + * atomic_dec_and_test - decrement and test + * @v: pointer of type int + * + * Atomically decrements @v by 1 and + * returns true if the result is 0, or false for all other + * cases. + */ +static inline int atomic_dec_and_test(int *v) +{ + return (atomic_dec_return(v) == 0); +} + +/** + * atomic_add_negative - add and test if negative + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v and returns true + * if the result is negative, or false when + * result is greater than or equal to zero. + */ +static inline int atomic_add_negative(int i, int *v) +{ + return (atomic_add_return(i, v) < 0); +} + +static inline int atomic_xchg(int *v, int n) +{ + register int c; + __asm__ __volatile__ ( + "amoswap.w %0, %2, %1" + : "=r" (c), "+A" (*v) + : "r" (n)); + return c; +} + +/** + * atomic_and - Atomically clear bits in atomic variable + * @mask: Mask of the bits to be retained + * @v: pointer of type int + * + * Atomically retains the bits set in @mask from @v + */ +static inline void atomic_and(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoand.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_and(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoand.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_or - Atomically set bits in atomic variable + * @mask: Mask of the bits to be set + * @v: pointer of type int + * + * Atomically sets the bits set in @mask in @v + */ +static inline void atomic_or(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoor.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_or(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoor.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_xor - Atomically flips bits in atomic variable + * @mask: Mask of the bits to be flipped + * @v: pointer of type int + * + * Atomically flips the bits set in @mask in @v + */ +static inline void atomic_xor(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoxor.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_xor(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoxor.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * test_and_set_bit - Set a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_set_bit(int nr, volatile unsigned long *addr) +{ + unsigned long __res, __mask; + __mask = MASK(nr); + __asm__ __volatile__ ( \ + "amoor.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to clear + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_clear_bit(int nr, volatile unsigned long *addr) +{ + unsigned long __res, __mask; + __mask = MASK_NOT(nr); + __asm__ __volatile__ ( \ + "amoand.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * test_and_change_bit - Change a bit and return its old value + * @nr: Bit to change + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_change_bit(int nr, volatile unsigned long *addr) +{ + + unsigned long __res, __mask; + __mask = MASK(nr); + __asm__ __volatile__ ( \ + "amoxor.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * set_bit - Atomically set a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * This function is atomic and may not be reordered. + */ + +static inline void set_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOOR.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK(nr))); +} + +/** + * clear_bit - Clears a bit in memory + * @nr: Bit to clear + * @addr: Address to start counting from + * + * clear_bit() is atomic and may not be reordered. + */ +static inline void clear_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOAND.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK_NOT(nr))); +} + +/** + * change_bit - Toggle a bit in memory + * @nr: Bit to change + * @addr: Address to start counting from + * + * change_bit() is atomic and may not be reordered. + */ +static inline void change_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOXOR.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK(nr))); +} + +#endif /* __riscv_atomic */ + +#endif /* __GNUC__ */ + +#endif /* __ASSEMBLER__ */ + +#endif /* __riscv */ + +#ifdef __cplusplus +} +#endif + +#endif /* RISCV_REGS_H */ diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv_rv32_stubs.c b/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv_rv32_stubs.c new file mode 100644 index 0000000..e26ecfc --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv_rv32_stubs.c @@ -0,0 +1,243 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_stubs.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Stubs for the Mi-V soft processor Interrupt handler. + * + * The functions below will only be linked with the application code if the user + * does not provide an implementation for these functions. These functions are + * defined with weak linking so that they can be overridden by a function with + * same prototype in the user's application code. + * + */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +__attribute__((weak)) void Software_IRQHandler(void) +{ + _exit(10); +} + +__attribute__((weak)) void SysTick_Handler(void) +{ + /* Default handler */ +} + +#ifdef MIV_LEGACY_RV32 +__attribute__((weak)) uint8_t Invalid_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_1_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_2_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_3_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_4_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_5_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_6_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_7_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_8_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_9_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_10_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_11_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_12_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_13_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_14_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_15_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_16_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_17_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_18_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_19_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_20_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_21_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_22_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_23_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_24_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_25_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_26_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_27_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_28_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_29_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_30_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_31_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +#else +__attribute__((weak)) void External_IRQHandler(void) +{ +} +__attribute__((weak)) void MGECI_IRQHandler(void) +{ +} +__attribute__((weak)) void MGEUI_IRQHandler(void) +{ +} +__attribute__((weak)) void SUBSYS_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI0_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI1_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI2_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI3_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI4_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI5_IRQHandler(void) +{ +} +__attribute__((weak)) void Reserved_IRQHandler(void) +{ + _exit(10); +} +#ifndef MIV_RV32_V3_0 /* For MIV_RV32 v3.0 */ +__attribute__((weak)) void MSYS_EI6_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI7_IRQHandler(void) +{ +} +__attribute__((weak)) void SUBSYSR_IRQHandler(void) +{ +} +#endif /* MIV_RV32_V3_0 */ +#endif /* MIV_LEGACY_RV32 */ + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv_rv32_subsys.h b/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv_rv32_subsys.h new file mode 100644 index 0000000..509f13b --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv_rv32_subsys.h @@ -0,0 +1,293 @@ +/******************************************************************************* + * Copyright 2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_subsys.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor SUBSYS regsiter description and API fuctions. + * + */ +#ifndef MIV_RV32_SUBSYS_H +#define MIV_RV32_SUBSYS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef MIV_LEGACY_RV32 +#define MGEUI 16U +#define MGECI 17U +#define MSYS_EI0 24U +#define MSYS_EI1 25U +#define MSYS_EI2 26U +#define MSYS_EI3 27U +#define MSYS_EI4 28U +#define MSYS_EI5 29U + +#define MGEUI_MEIP (1u << MGEUI) +#define MGECI_MEIP (1u << MGECI) +#define MSYS_EI0IP (1u << MSYS_EI0) +#define MSYS_EI1IP (1u << MSYS_EI1) +#define MSYS_EI2IP (1u << MSYS_EI2) +#define MSYS_EI3IP (1u << MSYS_EI3) +#define MSYS_EI4IP (1u << MSYS_EI4) +#define MSYS_EI5IP (1u << MSYS_EI5) + +#define MIV_LOCAL_IRQ_MIN 16 +#ifndef MIV_RV32_V3_0 /*For MIV_RV32 v3.1*/ +#define SUBSYSR 22U +#define SUBSYS_EI 23U +#define MSYS_EI6 30U +#define MSYS_EI7 31U +#define MIV_SUBSYSR (1u << SUBSYSR) +#define MIV_SUBSYS (1u << SUBSYS_EI) +#define MSYS_EI6IP (1u << MSYS_EI6) +#define MSYS_EI7IP (1u << MSYS_EI7) +#define MIV_LOCAL_IRQ_MAX 31 + +#else /* MIV_RV32_V3_0 */ +#define MIV_LOCAL_IRQ_MAX 29 +#define SUBSYS_EI 30U +#define MIP_SUBSYS_REG (1u << SUBSYS_EI) + +#endif /* MIV_RV32_V3_0 */ +#endif /* MIV_LEGACY_RV32 */ + +#ifdef MIV_LEGACY_RV32 +#define MIV_LOCAL_IRQ_MAX 0U +#define MIV_LOCAL_IRQ_MIN 0U +#endif /* MIV_LEGACY_RV32 */ + +#ifdef __cplusplus +} +#endif + +/*-------------------------------------------------------------------------*//** + SUBSYS Register Configuration + ======================================= + For the SUBSYS registers configutation, the following definitions are used in + the SUBSUS API functions. For example, to raise soft interrupts, enable parity + checks, soft reset, and so on. + + | Configuration | Value | Description | + |--------------------------|-------|------------------------------------------------| + | SUBSYS_SOFT_REG_GRP_DED | 0x04 | Mask for the Core GPR DED Reset Register | + | SUBSYS_CFG_PARITY_CHECK | 0x01 | Use to set or clear the parity check on the TCM | + | SUBSYS_SOFT_RESET | 0x01 | Use the SUBSYS soft reset the MIV_RV32 IP core | + | SUBSYS_SOFT_IRQ | 0x02 | Use to raise a software interrupt through SUBSYS| + */ +/*Mask for the Core GPR DED Reset Register*/ +#define SUBSYS_SOFT_REG_GRP_DED 0x04U + +/*Use to set or clear the parity check on the TCM*/ +#define SUBSYS_CFG_PARITY_CHECK 0x01U + +/*Use the SUBSYS soft reset the MIV_RV32 IP core*/ +#define SUBSYS_SOFT_RESET 0x01U + +/*Use to raise a software interrupt through SUBSYS*/ +#define SUBSYS_SOFT_IRQ 0x02U + +/*-------------------------------------------------------------------------*//** + SUBSYS Interrupt Request Masks + ======================================= + The following values correspond to the bit value of the SUBSYS interrupt + enable and interrupt pending register. + + | Interrupt Mask | Value | Description | + |----------------------------|---------|-------------------------------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | TCM ECC controllable error irq enable | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | TCM ECC uncontrollable error irq enable | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | AXI write response error irq enable | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | Icache ECC Correctable error irq | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | Icache ECC Uncorrectable error irq | + | SUBSYS_BASE_ADDR | 0x6000u | Base address of the SUBSYS | + */ +/* TCM ECC correctable error irq enable mask value */ +#define SUBSYS_TCM_ECC_CE_IRQ 0x01u + +/* TCMECC uncorrectable error irq enable */ +#define SUBSYS_TCM_ECC_UCE_IRQ 0x02u + +/* AXI write response error irq enable */ +#define SUBSYS_AXI_WR_RESP_IRQ 0x10u + +/*Icache ECC Correctable error irq*/ +#define SUBSYS_ICACHE_ECC_CE_IRQ 0x40u + +/*Icache ECC Uncorrectable error irq*/ +#define SUBSYS_ICACHE_ECC_UCE_IRQ 0x80u + +/*Base address of the SUBSYS*/ +#define SUBSYS_BASE_ADDR 0x00006000UL + +/***************************************************************************//** + Subsys contains interrupt enable, interrupt pending and Subsys registers + which can be used to enable SUBSYS specific features such as ECC for vaious + memories. For more available features refer to the MIV_RV32 User Guide +*/ +typedef struct +{ + volatile uint32_t cfg; /*Parity is not supported by MIV_RV32 v3.1 and MIV_RV32 v3.0.100*/ + volatile uint32_t reserved0[3]; + volatile uint32_t irq_en; /*offset 0x10*/ + volatile uint32_t irq_pend; + volatile uint32_t reserved1[2]; + volatile uint32_t soft_reg; /*offset 0x20*/ +} SUBSYS_Type; + +#define SUBSYS ((SUBSYS_Type *)SUBSYS_BASE_ADDR) + +/***************************************************************************//** + The MRV32_subsys_enable_irq() function initializes the SUBSYS interrupts. It + takes the logical OR of the following defined IRQ masks as a parameter. + + @param irq_mask + | irq_mask | Value | + |------------------------|------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | + Use logical OR values of one or more interrupts to enable them in the SUBSYS + @return + This function does not return any value. + */ +static inline void MRV32_subsys_enable_irq(uint32_t irq_mask) +{ + SUBSYS->irq_en |= irq_mask; +} + +/***************************************************************************//** + The MRV32_subsys_disable_irq() function disables the SUBSYS interrupts. It + takes the logical OR of the following defined IRQ masks as a parameter. + + @param irq_mask + | irq_mask | Value | + |------------------------|------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | + Use logical OR values of one or more interrupts to disable them in the SUBSYS + @return + This function does not return any value. + */ +static inline void MRV32_subsys_disable_irq(uint32_t irq_mask) +{ + SUBSYS->irq_en &= ~irq_mask; +} + +/***************************************************************************//** + The MRV32_subsys_clear_irq() function clears the SUBSYS interrupts, which was + triggered. It takes the logical OR of the following defined IRQ masks as a + parameter. + @param irq_mask + | irq_mask | Value | + |------------------------|------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | + Use logical OR values of one or more interrupts to disable them in the SUBSYS + @return + This function does not return any value. + */ +static inline void MRV32_subsys_clear_irq(uint32_t irq_mask) +{ + SUBSYS->irq_pend |= irq_mask; +} + +/***************************************************************************//** + The MRV32_subsys_irq_cause() function returns the irq_pend register value which + is present in the SUBSYS. This is be used to check which irq_mask value + caused the SUBSYS interrupt to occur. + @param + This function does not take any parameters + + @return + This function returns the irq_pend regsiter value. +*/ +static inline uint32_t MRV32_subsys_irq_cause() +{ + return SUBSYS->irq_pend; +} + +/***************************************************************************//** + The MRV32_is_gpr_ded() function returns the core_gpr_ded_reset_reg bit value. + When ECC is enabled, the core_gpr_ded_reset_reg is set when the core was + reset due to GPR DED error. + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline uint32_t MRV32_is_gpr_ded(void) +{ + return((SUBSYS->soft_reg & SUBSYS_SOFT_REG_GRP_DED) >> 0x02u); +} + +/***************************************************************************//** + The MRV32_clear_gpr_ded() function must be used to clear the + core_gpr_ded_reset_reg bit. When ECC is enabled, the core_gpr_ded_reset_reg is + set when the core was previously reset due to GPR DED error. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV32_clear_gpr_ded(void) +{ + SUBSYS->soft_reg &= ~SUBSYS_SOFT_REG_GRP_DED; +} + +/***************************************************************************//** + The MRV32_enable_parity_check() function is used to enable parity check on + the TCM and it's interface transactions. This feature is not available on + MIV_RV32 v3.1 and MIV_RV32 v3.0.100 + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV32_enable_parity_check(void) +{ + SUBSYS->cfg |= SUBSYS_CFG_PARITY_CHECK; +} + +/***************************************************************************//** + The MRV32_disable_parity_check() function is used to disable parity check on + the TCM and it's interface transactions. + @param + This function does not take any parameters + + @return + This function does not return any value. + + */ +static inline void MRV32_disable_parity_check(void) +{ + SUBSYS->cfg &= ~SUBSYS_CFG_PARITY_CHECK; +} + +/***************************************************************************//** + The MRV32_cpu_soft_reset() function is used to cause a soft cpu reset on + the MIV_RV32 soft processor core. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV32_cpu_soft_reset(void) +{ + SUBSYS->soft_reg |= SUBSYS_SOFT_RESET; +} +#endif /* MIV_RV32_SUBSYS_H */ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv_rv32_syscall.c b/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv_rv32_syscall.c new file mode 100644 index 0000000..bd2f881 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/miv_rv32_syscall.c @@ -0,0 +1,364 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_syscall.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Stubs for system calls. + * + */ +#include +#include +#include +#include +#include "miv_rv32_hal.h" + +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +#include + +#ifndef LEGACY_DIR_STRUCTURE +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" +#else +#include "core_uart_apb.h" +#endif + +#endif /*MSCC_STDIO_THRU_CORE_UART_APB*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + +/*------------------------------------------------------------------------------ + * CoreUARTapb instance data for the CoreUARTapb instance used for standard + * output. + */ +static UART_instance_t g_stdio_uart; + +/*============================================================================== + * Flag used to indicate if the UART driver needs to be initialized. + */ +static int g_stdio_uart_init_done = 0; + +/* + * Disable semihosting apis + */ +#pragma import(__use_no_semihosting_swi) + +/*============================================================================== + * sendchar() + */ +int sendchar(int ch) +{ + /*-------------------------------------------------------------------------- + * Initialize the UART driver if it is the first time this function is + * called. + */ + if ( !g_stdio_uart_init_done ) + { + /****************************************************************************** + * Baud value: + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + UART_init( &g_stdio_uart, + MSCC_STDIO_UART_BASE_ADDR, + ((SYS_CLK_FREQ/(16 * MSCC_STDIO_BAUD_VALUE))-1), + (DATA_8_BITS | NO_PARITY)); + + g_stdio_uart_init_done = 1; + } + + /*-------------------------------------------------------------------------- + * Output text to the UART. + */ + UART_send( &g_stdio_uart, (uint8_t *)&ch, 1 ); + + return (ch); +} + +/*============================================================================== + * getachar() + */ +int getachar(void) +{ + uint8_t rx_size; + uint8_t rx_byte; + + if ( !g_stdio_uart_init_done ) + { + /****************************************************************************** + * Baud value: + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + UART_init( &g_stdio_uart, + MSCC_STDIO_UART_BASE_ADDR, + ((SYS_CLK_FREQ/(16 * MSCC_STDIO_BAUD_VALUE))-1), + (DATA_8_BITS | NO_PARITY)); + + g_stdio_uart_init_done = 1; + } + + do + { + rx_size = UART_get_rx(&g_stdio_uart, &rx_byte, 1); + } while(0u == rx_size); + + return rx_byte; +} + +#endif /*MSCC_STDIO_THRU_CORE_UART_APB*/ + +#undef errno +static int errno; + +static char *__env[1] = { 0 }; +char **environ = __env; + +void write_hex(int fd, uint32_t hex) +{ + char towrite; + + write( fd , "0x", 2U ); + + for (uint32_t ii = 8U ; ii > 0U; ii--) + { + uint32_t jj = ii-1U; + uint8_t digit = ((hex & (0xFU << (jj*4U))) >> (jj*4U)); + towrite = digit < 0xAU ? (0x48U + digit) : (0x65U + (digit - 0xAU)); + write( fd, &towrite, 1U); + } +} + + +#ifdef GDB_TESTING +void __attribute__((optimize("O0"))) _exit(int code) +#else +void _exit(int code) +#endif +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + const char * message = "\nProgam has exited with code:"; + + write(STDERR_FILENO, message, strlen(message)); + write_hex(STDERR_FILENO, code); +#endif + + while (1){}; +} + +void *_sbrk(ptrdiff_t incr) +{ + extern char _end; + extern char _heap_end; + extern char __heap_start; + extern char __heap_end; + static char *curbrk = &_end; + void * ret = NULL; + + /* + * Did we allocated memory for the heap in the linker script? + * You need to set HEAP_SIZE to a non-zero value in your linker script if + * the following assertion fires. + */ + ASSERT(&__heap_end > &__heap_start); + + if (((curbrk + incr) < &_end) || ((curbrk + incr) > &_heap_end)) + { + errno = ENOMEM; + ret = ((char *) - 1); + } + else + { + curbrk += incr; + ret = curbrk - incr; + } + + /* + * Did we run out of heap? + * You need to increase the heap size in the linker script if the following + * assertion fires. + * */ + ASSERT(curbrk <= &__heap_end); + + return(ret); +} + +int _isatty(int fd) +{ + int ret = 0; + + if (fd <= 2) /* one of stdin, stdout, stderr */ + { + ret = 1; + } + else + { + errno = EBADF; + ret = 0; + } + + return(ret); +} + +static int stub(int err) +{ + errno = err; + return -1; +} + +int _open(const char* name, int flags, int mode) +{ + return stub(ENOENT); +} + +int _openat(int dirfd, const char* name, int flags, int mode) +{ + return stub(ENOENT); +} + +int _close(int fd) +{ + return stub(EBADF); +} + +int _execve(const char* name, char* const argv[], char* const env[]) +{ + return stub(ENOMEM); +} + +int _fork(void) +{ + return stub(EAGAIN); +} + +int _fstat(int fd, struct stat *st) +{ + int ret = 0; + + if (isatty(fd)) + { + st->st_mode = S_IFCHR; + ret = 0; + } + else + { + ret = stub(EBADF); + } + + return ret; +} + +int _getpid(void) +{ + return 1; +} + +int _kill(int pid, int sig) +{ + return stub(EINVAL); +} + +int _link(const char *old_name, const char *new_name) +{ + return stub(EMLINK); +} + +off_t _lseek(int fd, off_t ptr, int dir) +{ + off_t ret = 0; + if (_isatty(fd)) + { + ret = 0; + } + else + { + ret = stub(EBADF); + } + + return ret; +} + +ssize_t _read(int fd, void* ptr, size_t len) +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + + char* ptr1 = (char*)ptr; + + if (_isatty(fd)) + { + int count; + + for (count = 0; count < len; count++) + { + ptr1[count] = getachar(); + sendchar(ptr1[count]); + + /* Return partial buffer if we get EOL */ + if (('\r' == ptr1[count])||('\n' == ptr1[count])) + { + ptr1[count] = '\n'; + return count; + } + } + + return count; /* Filled the buffer */ + } +#endif + + return stub(EBADF); +} + +int _stat(const char* file, struct stat* st) +{ + return stub(EACCES); +} + +clock_t _times(struct tms* buf) +{ + return stub(EACCES); +} + +int _unlink(const char* name) +{ + return stub(ENOENT); +} + +int _wait(int* status) +{ + return stub(ECHILD); +} + +ssize_t _write(int fd, const void* ptr, size_t len) +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + int count_out; + char* ptr1 = (char*)ptr; + + /*-------------------------------------------------------------------------- + * Output text to the UART. + */ + count_out = 0; + while(len--) + { + sendchar(ptr1[count_out]); + count_out++; + } + + errno = 0; + return count_out; + +#else /* MSCC_STDIO_THRU_CORE_UART_APB */ + + return stub(EBADF); + +#endif /* MSCC_STDIO_THRU_CORE_UART_APB */ + +} + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/sample_fpga_design_config.h b/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/sample_fpga_design_config.h new file mode 100644 index 0000000..a380d96 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ccm-services/src/platform/miv_rv32_hal/sample_fpga_design_config.h @@ -0,0 +1,167 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file sample_fpga_design_config.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Sample design configuration settings + * + */ + /*========================================================================*//** + @mainpage + Example file detailing how the fpga_design_config.h should be constructed + for the SoftConsole project targeted for Mi-V processors. + + @section intro_sec Introduction + The SoftConsole project targeted for Mi-V processors now have an improved + folder structure. Detailed description of the folder structure is available + at https://github.com/Mi-V-Soft-RISC-V/miv-rv32-documentation. + + The fpga_design_config.h must be stored as shown below + /boards//fpga_design_config.h + + Currently this file must be hand crafted when using the Mi-V Soft Processor. + In future, all the design and soft IP configurations will be automatically + generated from the Libero design description data. + + You can use this sample file as an example. + Rename this file from sample_fpga_design_config.h to fpga_design_config.h + and then customize it per your hardware design. + + @section Project configuration Instructions + 1. Change SYS_CLK_FREQ define to frequency of Mi-V Soft processor clock + 2 Add all the soft IP core BASE addresses + 3. Add the peripheral Core Interrupts to Mi-V Soft processor IRQ number + mappings + 4. Define MSCC_STDIO_UART_BASE_ADDR if you want a CoreUARTapb mapped to + STDIO + + **NOTE** + In the legacy folder structures, the file hw_config.h as was used at the + root of the project folder. This file is now depricated. + +*//*=========================================================================*/ + +#ifndef FPGA_DESIGN_CONFIG_H_ +#define FPGA_DESIGN_CONFIG_H_ + +/***************************************************************************//** + * Soft-processor clock definition + * This is the only clock brought over from the Mi-V Libero design. + */ +#ifndef SYS_CLK_FREQ +#define SYS_CLK_FREQ 50000000UL +#endif + +/***************************************************************************//** + * Peripheral base addresses. + * Format of define is: + * __BASE_ADDR + * The field is optional if there is only one instance of the core + * in the design + * MIV_ESS is an extended peripheral subsystem IP core with peripherals + * connections as defined below. + * The system can be further extended by attaching APB peripherals to the + * empty APB slots. + */ +#define MIV_ESS_PLIC_BASE_ADDR 0x70000000UL +#define COREUARTAPB0_BASE_ADDR 0x71000000UL +#define MIV_MTIMER_BASE_ADDR 0x72000000UL +#define MIV_ESS_APBSLOT3_BASE_ADDR 0x73000000UL +#define MIV_ESS_APBSLOT4_BASE_ADDR 0x74000000UL +#define COREGPIO_OUT_BASE_ADDR 0x75000000UL +#define CORESPI_BASE_ADDR 0x76000000UL +#define MIV_ESS_uDMA_BASE_ADDR 0x78000000UL +#define MIV_ESS_WDOG_BASE_ADDR 0x79000000UL +#define MIV_ESS_I2C_BASE_ADDR 0x7A000000UL +#define MIV_ESS_APBSLOTB_BASE_ADDR 0x7B000000UL +#define MIV_ESS_APBSLOTC_BASE_ADDR 0x7C000000UL +#define MIV_ESS_APBSLOTD_BASE_ADDR 0x7D000000UL +#define MIV_ESS_APBSLOTE_BASE_ADDR 0x7E000000UL +#define MIV_ESS_APBSLOTF_BASE_ADDR 0x7F000000UL + +/***************************************************************************//** + * Peripheral Interrupts are mapped to the corresponding Mi-V Soft processor + * interrupt in the Libero design. + * + * On the legacy RV32 cores, there can be up to 31 external interrupts (IRQ[30:0] + * pins). The legacy RV32 Soft processor external interrupts are defined in the + miv_rv32_plic.h + * + * These are of the form + * typedef enum +{ + NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + . + . + . + External_31_IRQn = 31 +} IRQn_Type; + + On the legacy RV32 processors, the PLIC identifies the interrupt and passes it + on to the processor core. The interrupt 0 is not used. The pin IRQ[0] should + map to External_1_IRQn likewise IRQ[30] should map to External_31_IRQn + +e.g + +#define TIMER0_IRQn External_30_IRQn +#define TIMER1_IRQn External_31_IRQn + + The MIV_RV32 soft processor has up to six optional system interrupts, MSYS_EI[n] + in addition to one EXT_IRQ. + The MIV_RV32 does not have an inbuilt PLIC and all the interrupts are directly + delivered to the processor core, hence unlike legacy RV32 cores, no interrupt + number mapping is necessary on MIV_RV32 core. + */ + +/**************************************************************************** + * Baud value to achieve a 115200 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ +#define BAUD_VALUE_115200 ((SYS_CLK_FREQ / (16 * 115200)) - 1) + +/****************************************************************************** + * Baud value to achieve a 57600 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + #define BAUD_VALUE_57600 ((SYS_CLK_FREQ / (16 * 57600)) - 1) + +/***************************************************************************//** + * Define MSCC_STDIO_THRU_CORE_UART_APB in the project settings if you want the + * standard IOs to be redirected to a terminal via UART. + */ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +/* + * A base address mapping for the STDIO printf/scanf mapping to CortUARTapb + * must be provided if it is being used + * + * e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR + */ +#define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB0_BASE_ADDR + +#ifndef MSCC_STDIO_UART_BASE_ADDR +#error MSCC_STDIO_UART_BASE_ADDR not defined- e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR +#endif + +#ifndef MSCC_STDIO_BAUD_VALUE +/* + * The MSCC_STDIO_BAUD_VALUE define should be set in your project's settings to + * specify the baud value used by the standard output CoreUARTapb instance for + * generating the UART's baud rate if you want a different baud rate from the + * default of 115200 baud + */ +#define MSCC_STDIO_BAUD_VALUE 115200 +#endif /*MSCC_STDIO_BAUD_VALUE*/ + +#endif /* end of MSCC_STDIO_THRU_CORE_UART_APB */ +/******************************************************************************* + * End of user edit section + */ +#endif /* FPGA_DESIGN_CONFIG_H_ */ diff --git a/applications/user-crypto/miv-rv32-dsa-services/.cproject b/applications/user-crypto/miv-rv32-dsa-services/.cproject new file mode 100755 index 0000000..442ce3b --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/.cproject @@ -0,0 +1,332 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-dsa-services/.gitignore b/applications/user-crypto/miv-rv32-dsa-services/.gitignore new file mode 100755 index 0000000..f1b6b72 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/.gitignore @@ -0,0 +1,3 @@ +/.settings/ +/*miv-rv32-imc-debug*/ +/*miv-rv32-imc-release*/ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-dsa-services/.project b/applications/user-crypto/miv-rv32-dsa-services/.project new file mode 100755 index 0000000..7c876b8 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/.project @@ -0,0 +1,26 @@ + + + miv-rv32-dsa-services + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/applications/user-crypto/miv-rv32-dsa-services/README.md b/applications/user-crypto/miv-rv32-dsa-services/README.md new file mode 100755 index 0000000..5022f8a --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/README.md @@ -0,0 +1,164 @@ +PolarFire User Crypto ECDSA Services example +================================================================================ +This Example Project demonstrates the usage of the User Crypto hardware block for +the signature generation and verification using DSA service functions. It uses + + - CALDSASignHash() is used to generate digital signature. + - CALDSAVerifyHash() is used to verify the digital signature. + +There are two different build configurations provided with this project which +configure this SoftConsole project for RISC-V IMC instruction extension. +The following configurations are provided with the example: + + - miv-rv32-imc-debug + - miv-rv32-imc-release + +Mi-V Soft Processor +-------------------------------------------------------------------------------- +This example uses Mi-V SoftProcessor MiV_RV32.The design is built for debugging +MiV_RV32 through the PolarFire FPGA programming JTAG port using a FlashPro5. +To achieve this the CoreJTAGDebug IP is used to connect to the JTAG port of the +MiV_RV32. + +All the platform/design specific definitions such as peripheral base addresses, +system clock frequency etc. are included in fpga_design_config.h. The +fpga_design_config.h is located at the root folder of this project. + +The Mi-V Soft Processor MiV_RV32 firmware projects needs the miv_rv32_hal and +the hal firmware(RISC-V HAL). + +The RISC-V HAL is available at GitHub [Mi-V-Soft-RISC-V](https://mi-v-ecosystem.github.io/redirects/platform). + +How to use this example +-------------------------------------------------------------------------------- +This example project is targeted at a MIV_RV32 design running on a PolarFire-Eval-Kit +connected via a USB-UART serial cable to a host PC running a terminal emulator +such as TeraTerm or Putty configured as follows: + + - 115200 baud + - 8 data bits + - 1 stop bit + - no parity + - no flow control. + +Run the example project using a debugger. A greeting message will appear over the +UART terminal followed by a menu system and instructions. + +This program displays the return data from User Crypto processor for digital +signature generation and verification services. + +fpga_design_config (formerly known as hw_config.h) +-------------------------------------------------------------------------------- +The SoftConsole project targeted for Mi-V processors now use an improved +directory structure. The fpga_design_config.h must be stored as shown below + +` + /boards//fpga_design_config/fpga_design_config.h +` + +Currently, this file must be hand crafted when using the Mi-V Soft Processor. +In future, all the design and soft IP configurations will be automatically +generated from the Libero design description data. + +You can use the sample file provided with MIV_RV32 HAL as an example. Rename it +from sample_fpga_design_config.h to fpga_design_config.h and then customize it +per your hardware design such as SYS_CLK_FREQ, peripheral BASE addresses, +interrupt numbers, definition of MSCC_STDIO_UART_BASE_ADDR if you want a +CoreUARTapb mapped to STDIO, etc. + +### Generate digital signature + +Select option '1' to generate a digital signature for DSA public-key cryptographic service. +The signature generation function take following parameters as an input. +1. *msg* -: message string +2. *G* -: A generator point +3. *K* -: A random per message parameter. +4. *modulus P* -: A prime number P +4. *modulus Q* -: A prime number Q +5. *private_key X* -: private key to encrypt the message. + +The **CALDSASignHash()** function performs signature generation and after the +successful generation program displays a success message along with +generated signature set {R,S} on the UART terminal. + +### Verify digital signature + +Select *2* to verify the digital signature set {R,S} generated by DSA public key +cryptographic services. The program takes a public key to verify the message signature +along with other domain parameters. +The **CALDSAVerifyHash()** function performs DSA signature verification and after +successful completion it returns the result of verification process,an +appropriate message will be displayed on the UART terminal based on the returned result. + +**NOTE:** +The DSA signature Generation operation should be executed before executing +ECDSA signature verification operation. + +### Configurations + +The CAL library needs a config_user.h containing the configuration data. +This application provides following settings as per CAL requirement + 1. A variable which provides the base address of the User Crypto hardware block + is defined in main.c + + `uint32_t g_user_crypto_base_addr = 0x62000000UL;` + + 2. A symbol INC_STDINT_H is defined in project preprocessor setting. + For more detail, please refer to caltypes.h file present in CAL folder. + +**NOTE:** + 1. If you try to enter data values other than 0 - 9, a - f, A - F, an error + message will be displayed on the serial terminal. + +### Test script + +A test script is provided with this example which automatically enters the NIST +vectors and associated data to verify the functionality. You can use +dsa_services.ttl Tera Term Macro script present in project directory for +testing DSA Signature Services example project. + +**NOTE:** +1. Tera Term Macros don’t work with Windows 10 build 14393.0. You should update + to Windows 10 build 14393.0.105 or [later.](https://osdn.net/ticket/browse.php?group_id=1412&tid=36526) +2. Before running Tera Term Macro script, set language as English + (Setup->General->Language). Also setup transmit delay in (Setup->Serial port) + to 5msec/char and 5msec/line. +3. By default, Tera Term log will be stored in Tera Term installation Directory. + +## Target hardware + +This project was tested on PolarFire-Eval-Kit with CFG4 configuration of the +MIV_RV32 design available [here](https://github.com/Mi-V-Soft-RISC-V/PolarFire-Eval-Kit/tree/main/Libero_Projects) + +All the design specific definitions such as peripheral base addresses, system +clock frequency etc. are included in fpga_design_config.h. + +The firmware projects needs the HAL and the MIV_RV32 HAL firmware components. + +This example project can be used with another design using a different hardware +configurations. This can be achieved by overwriting the content of this example +project's "fpga_design_config.h" file with the correct data per your Libero design. + +### Booting the system + +Currently the example project is configured to use FlashPro debugger to execute +from LSRAM in both Debug and Release mode. + +In the release mode build configuration, following setting is used +`--change-section-lma *-0x80000000` under +Tool Settings > Cross RISCV GNU Create Flash Image > General > Other flags. + +This will allow you to attach the release mode executable as the memory +initialization client in Libero when you want to execute it from non-volatile memory. + +## Silicon revision dependencies + +This example is tested on PolarFire MPF300TS device. + +### CAL library src + +To obtain the CAL source code and a SoftConsole project to generate the CAL +library archive file (*.a) refer [SoftConsole Documentation](https://mi-v-ecosystem.github.io/SoftConsole-Documentation/SoftConsole-v2021.3/using_softconsole/other.html#crypto-application-library). +The CAL source code is bound by license agreement and it will be available as +part of the SoftConsole installation if the CAL specific license was agreed +while installing it. diff --git a/applications/user-crypto/miv-rv32-dsa-services/dsa_services.ttl b/applications/user-crypto/miv-rv32-dsa-services/dsa_services.ttl new file mode 100755 index 0000000..94db886 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/dsa_services.ttl @@ -0,0 +1,249 @@ +; Tera Term Setting: +; 1. Before running Tera Term Macro script, you should set language as English +; and transmit delay in Serial port setup to 5msec/char and 5msec/line. +; 2. By default, Tera Term log will be stored in Tera Term installation Directory. + +changedir '.' +logopen "DSA_service.log" 0 0 0 1 + +settitle 'PolarFire SoC MSS User Crypto DSA service' + +setsync 1 + +;Clear screen +clearscreen 0 + +; Set baud rate to 115200 +setbaud 115200 + +; local echo off +setecho 0 + +; ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +; Test Case 1 +; INPUT +; P = +; a410d23ed9ad9964d3e401cb9317a25213f75712acbc5c12191abf3f1c0e723e2333b49eb1f95b0f9748d952f04a5ae35885 +; 9d384403ce364aa3f58dd9769909b45048548c55872a6afbb3b15c54882f96c20df1b2df164f0bac849ca17ad2df63abd75c +; 881922e79a5009f00b7d631622e90e7fa4e980618575e1d6bd1a72d5b6a50f4f6a68b793937c4af95fc11541759a1736577 +; d9448b87792dff07232415512e933755e12250d466e9cc8df150727d747e51fea7964158326b1365d580cb190f451829159 +; 8221fdf36c6305c8b8a8ed05663dd7b006e945f592abbecae460f77c71b6ec649d3fd5394202ed7bbbd040f7b8fd57cb06a +; 99be254fa25d71a3760734046c2a0db383e02397913ae67ce65870d9f6c6f67a9d00497be1d763b21937cf9cbf9a24ef97b +; bcaa07916f8894e5b7fb03258821ac46140965b23c5409ca49026efb2bf95bce025c4183a5f659bf6aaeef56d7933bb2969 +; 7d7d541348c871fa01f869678b2e34506f6dc0a4c132b689a0ed27dc3c8d53702aa584877 +; Q = abc67417725cf28fc7640d5de43825f416ebfa80e191c42ee886303338f56045 +; G = +; 867d5fb72f5936d1a14ed3b60499662f3124686ef108c5b3da6663a0e86197ec2cc4c9460193a74ff16028ac9441b0c7d27 +; c2272d483ac7cd794d598416c4ff9099a61679d417d478ce5dd974bf349a14575afe74a88b12dd5f6d1cbd3f91ddd597ed6 +; 8e79eba402613130c224b94ac28714a1f1c552475a5d29cfcdd8e08a6b1d65661e28ef313514d1408f5abd3e06ebe3a7d81 +; 4d1ede316bf495273ca1d574f42b482eea30db53466f454b51a175a0b89b3c05dda006e719a2e6371669080d768cc038cdf +; b8098e9aad9b8d83d4b759f43ac9d22b353ed88a33723550150de0361b7a376f37b45d437f71cb711f2847de671ad105951 +; 6a1d45755224a15d37b4aeada3f58c69a136daef0636fe38e3752064afe598433e80089fda24b144a462734bef8f7763884 +; 5b00e59ce7fa4f1daf487a2cada11eaba72bb23e1df6b66a183edd226c440272dd9b06bec0e57f1a0822d2e00212064b6db +; a64562085f5a75929afa5fe509e0b78e630aaf12f91e4980c9b0d6f7e059a2ea3e23479d930 + +;Msg = +; ed9a64d3109ef8a9292956b946873ca4bd887ce624b81be81b82c69c67aaddf5655f70fe4768114db2834c71787f858e516 +; 5da1a7fa961d855ad7e5bc4b7be31b97dbe770798ef7966152b14b86ae35625a28aee5663b9ef3067cbdfbabd87197e5c84 +; 2d3092eb88dca57c6c8ad4c00a19ddf2e1967b59bd06ccaef933bc28e7 +;X = 6d4c934391b7f6fb6e19e3141f8c0018ef5726118a11064358c7d35b37737377 +;Y = +; 1f0a5c75e7985d6e70e4fbfda51a10b925f6accb600d7c6510db90ec367b93bb069bd286e8f979b22ef0702f717a8755c18 +; 309c87dae3fe82cc3dc8f4b7aa3d5f3876f4d4b3eb68bfe910c43076d6cd0d39fc88dde78f09480db55234e6c8ca59fe270 +; 0efec04feee6b4e8ee2413721858be7190dbe905f456edcab55b2dc2916dc1e8731988d9ef8b619abcf8955aa960ef02b3f +; 02a8dc649369222af50f1338ed28d667f3f10cae2a3c28a3c1d08df639c81ada13c8fd198c6dae3d62a3fe9f04c985c65f6 +; 10c06cb8faea68edb80de6cf07a8e89c00218185a952b23572e34df07ce5b4261e5de427eb503ee1baf5992db6d438b4743 +; 4c40c22657bc163e7953fa33eff39dc2734607039aadd6ac27e4367131041f845ffa1a13f556bfba2307a5c78f2ccf11298 +; c762e08871968e48dc3d1569d09965cd09da43cf0309a16af1e20fee7da3dc21b364c4615cd5123fa5f9b23cfc4ffd9cfdc +; ea670623840b062d4648d2eba786ad3f7ae337a4284324ace236f9f7174fbf442b99043002f +;K = 40b5cc685c3d1f59072228af9551683b5b8c8ff65240114ad2dacfccf3928057 + +; OUTPUT +;R = 7695698a14755db4206e850b4f5f19c540b07d07e08aac591e20081646e6eedc +;S = 3dae01154ecff7b19007a953f185f0663ef7f2537f0b15e04fb343c961f36de2 +; ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +; Signature Generation +;------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +;select signature generation +send '1' +pause 1 + +; Msg +pause 1 +send 'ed9a64d3109ef8a9292956b946873ca4bd887ce624b81be81b82c69c67aaddf5655f70fe4768114db2834c71787f858e516' +send '5da1a7fa961d855ad7e5bc4b7be31b97dbe770798ef7966152b14b86ae35625a28aee5663b9ef3067cbdfbabd87197e5c84' +send '2d3092eb88dca57c6c8ad4c00a19ddf2e1967b59bd06ccaef933bc28e7' +pause 1 + +;G +pause 4 +send '867d5fb72f5936d1a14ed3b60499662f3124686ef108c5b3da6663a0e86197ec2cc4c9460193a74ff16028ac9441b0c7d27c' +send '2272d483ac7cd794d598416c4ff9099a61679d417d478ce5dd974bf349a14575afe74a88b12dd5f6d1cbd3f91ddd597ed68e' +send '79eba402613130c224b94ac28714a1f1c552475a5d29cfcdd8e08a6b1d65661e28ef313514d1408f5abd3e06ebe3a7d814d1' +pause 4 +send 'ede316bf495273ca1d574f42b482eea30db53466f454b51a175a0b89b3c05dda006e719a2e6371669080d768cc038cdfb809' +send '8e9aad9b8d83d4b759f43ac9d22b353ed88a33723550150de0361b7a376f37b45d437f71cb711f2847de671ad1059516a1d4' +send '5755224a15d37b4aeada3f58c69a136daef0636fe38e3752064afe598433e80089fda24b144a462734bef8f77638845b00e5' +send '9ce7fa4f1daf487a2cada11eaba72bb23e1df6b66a183edd226c440272dd9b06bec0e57f1a0822d2e00212064b6dba645620' +send '85f5a75929afa5fe509e0b78e630aaf12f91e4980c9b0d6f7e059a2ea3e23479d930' +pause 4 + +;K +send '40b5cc685c3d1f59072228af9551683b5b8c8ff65240114ad2dacfccf3928057' +pause 2 + +;X +send '6d4c934391b7f6fb6e19e3141f8c0018ef5726118a11064358c7d35b37737377' + +pause 4 + +;P +send 'a410d23ed9ad9964d3e401cb9317a25213f75712acbc5c12191abf3f1c0e723e2333b49eb1f95b0f9748d952f04a5ae35885' +send '9d384403ce364aa3f58dd9769909b45048548c55872a6afbb3b15c54882f96c20df1b2df164f0bac849ca17ad2df63abd75c' +pause 4 +send '881922e79a5009f00b7d631622e90e7fa4e980618575e1d6bd1a72d5b6a50f4f6a68b793937c4af95fc11541759a1736577d' +send '9448b87792dff07232415512e933755e12250d466e9cc8df150727d747e51fea7964158326b1365d580cb190f45182915982' +send '21fdf36c6305c8b8a8ed05663dd7b006e945f592abbecae460f77c71b6ec649d3fd5394202ed7bbbd040f7b8fd57cb06a99b' +send 'e254fa25d71a3760734046c2a0db383e02397913ae67ce65870d9f6c6f67a9d00497be1d763b21937cf9cbf9a24ef97bbcaa' +send '07916f8894e5b7fb03258821ac46140965b23c5409ca49026efb2bf95bce025c4183a5f659bf6aaeef56d7933bb29697d7d5' +send '41348c871fa01f869678b2e34506f6dc0a4c132b689a0ed27dc3c8d53702aa584877' +pause 4 + +;Q +send 'abc67417725cf28fc7640d5de43825f416ebfa80e191c42ee886303338f56045' + +pause 4 +; send dummy +send '1' +pause 3 + +; ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +; Signature verification +;------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +;select verification +send '2' +pause 1 + +; send option 1 to automatically generate the public key +send '1' +pause 5 + +; ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +; Test Case 2 +; INPUT +; P = +; a410d23ed9ad9964d3e401cb9317a25213f75712acbc5c12191abf3f1c0e723e2333b49eb1f95b0f9748d952f04a5ae35885 +; 9d384403ce364aa3f58dd9769909b45048548c55872a6afbb3b15c54882f96c20df1b2df164f0bac849ca17ad2df63abd75c +; 881922e79a5009f00b7d631622e90e7fa4e980618575e1d6bd1a72d5b6a50f4f6a68b793937c4af95fc11541759a1736577 +; d9448b87792dff07232415512e933755e12250d466e9cc8df150727d747e51fea7964158326b1365d580cb190f451829159 +; 8221fdf36c6305c8b8a8ed05663dd7b006e945f592abbecae460f77c71b6ec649d3fd5394202ed7bbbd040f7b8fd57cb06a +; 99be254fa25d71a3760734046c2a0db383e02397913ae67ce65870d9f6c6f67a9d00497be1d763b21937cf9cbf9a24ef97b +; bcaa07916f8894e5b7fb03258821ac46140965b23c5409ca49026efb2bf95bce025c4183a5f659bf6aaeef56d7933bb2969 +; 7d7d541348c871fa01f869678b2e34506f6dc0a4c132b689a0ed27dc3c8d53702aa584877 +; Q = +; abc67417725cf28fc7640d5de43825f416ebfa80e191c42ee886303338f56045 +; G = +; 867d5fb72f5936d1a14ed3b60499662f3124686ef108c5b3da6663a0e86197ec2cc4c9460193a74ff16028ac9441b0c7d27 +; c2272d483ac7cd794d598416c4ff9099a61679d417d478ce5dd974bf349a14575afe74a88b12dd5f6d1cbd3f91ddd597ed6 +; 8e79eba402613130c224b94ac28714a1f1c552475a5d29cfcdd8e08a6b1d65661e28ef313514d1408f5abd3e06ebe3a7d81 +; 4d1ede316bf495273ca1d574f42b482eea30db53466f454b51a175a0b89b3c05dda006e719a2e6371669080d768cc038cdf +; b8098e9aad9b8d83d4b759f43ac9d22b353ed88a33723550150de0361b7a376f37b45d437f71cb711f2847de671ad105951 +; 6a1d45755224a15d37b4aeada3f58c69a136daef0636fe38e3752064afe598433e80089fda24b144a462734bef8f7763884 +; 5b00e59ce7fa4f1daf487a2cada11eaba72bb23e1df6b66a183edd226c440272dd9b06bec0e57f1a0822d2e00212064b6db +; a64562085f5a75929afa5fe509e0b78e630aaf12f91e4980c9b0d6f7e059a2ea3e23479d930 +; Msg = +; c737d5ae248a96062d6afa8dcacc0384c5fbfb9d8b6052b52493c60d3edfc524b567b1f896e7447d0e24019403ed83e4889 +; c0c4de57c70fada6c8b5a09904350a44dfaf77d60af62de3edfd8760d077473f26df2837cfc2015f227dd7d351a5350f142 +; 8f2699fd3f518326fea8aef98fc4ea673130c8079fac3895fe856c77f8 +; X = +; 40dbd496fc4644be7ccb24d9dc55895c1b923a05f4da5610589d564ee8aac33f +; Y = +; 6112d3cd3191d17dee7788f568815a0aab50006002c9de2bd1a9bba245ba02894b02e9247517ace698ae0a05176b62b3a02 +; 5a563dda8deb7f2fc3e177ae3477448d39ae4ebe7ae8ec65a4421f754667fd6d7c2eb93f1a18d3d1a6235736bcdb74746f4 +; 6d88e65dc07c2591e1f95dda5e5e20e105ee8b4ddcaaf36021290d6b6493671d8aafae145d9b90bec3cc60179bb8fc30f14 +; 3c575d5d861623721b6547d3aaaade455f05fef9318abcd29bd19b12c35ca756de5108c185ece4aa1bf1a8e38809797067b +; d1f52b6cf2c415e73f9246bd5bfadd7b9a9d2b5369701e72147e22da7e092d9b578fb0c044a36effcbd709258500a00cff2 +; 30962c44225712fc43f9e802baead7f9cb46ab4931f663c6e3ed4082d59610f01741b5f24566b01b3e3933b29e028c54bd2 +; fc75b549fd05e64c58c9ae0ba417a9e98581db77be75233a42f771c99f0a49b494f0955202b19d6c740e866066104e463e6 +; 5e4bad9a081636d05367426153f04bcb2712186dca6834388e82520d34efd8a89313b2c7e60 +; K = +; aa63e91cb3fa545c447a8b8309a569d48104e14d5d05b8951033ac8a7d711c3f + +; OUTPUT +;R = 0041b1c756dd2e42714f9ee7edce21ea33ef49dbf452ccd9357d5f45ffab08f9 +;S = 102c6eaad38d39c0d036335ae19dd0d75e8dcabae59b120f69cbd2b5cf48abdb +; ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +; Signature Generation +;------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +send '5' +pause 1 + +;select signature generation +send '1' +pause 1 + +; Msg +pause 1 +send 'c737d5ae248a96062d6afa8dcacc0384c5fbfb9d8b6052b52493c60d3edfc524b567b1f896e7447d0e24019403ed83e4889' +send 'c0c4de57c70fada6c8b5a09904350a44dfaf77d60af62de3edfd8760d077473f26df2837cfc2015f227dd7d351a5350f142' +send '8f2699fd3f518326fea8aef98fc4ea673130c8079fac3895fe856c77f8' +pause 1 + +;G +pause 4 +send '867d5fb72f5936d1a14ed3b60499662f3124686ef108c5b3da6663a0e86197ec2cc4c9460193a74ff16028ac9441b0c7d27' +send 'c2272d483ac7cd794d598416c4ff9099a61679d417d478ce5dd974bf349a14575afe74a88b12dd5f6d1cbd3f91ddd597ed6' +send '8e79eba402613130c224b94ac28714a1f1c552475a5d29cfcdd8e08a6b1d65661e28ef313514d1408f5abd3e06ebe3a7d81' +pause 4 +send '4d1ede316bf495273ca1d574f42b482eea30db53466f454b51a175a0b89b3c05dda006e719a2e6371669080d768cc038cdf' +send 'b8098e9aad9b8d83d4b759f43ac9d22b353ed88a33723550150de0361b7a376f37b45d437f71cb711f2847de671ad105951' +send '6a1d45755224a15d37b4aeada3f58c69a136daef0636fe38e3752064afe598433e80089fda24b144a462734bef8f7763884' +send '5b00e59ce7fa4f1daf487a2cada11eaba72bb23e1df6b66a183edd226c440272dd9b06bec0e57f1a0822d2e00212064b6db' +send 'a64562085f5a75929afa5fe509e0b78e630aaf12f91e4980c9b0d6f7e059a2ea3e23479d930' +pause 4 + +;K +send 'aa63e91cb3fa545c447a8b8309a569d48104e14d5d05b8951033ac8a7d711c3f' +pause 2 + +;X +send '40dbd496fc4644be7ccb24d9dc55895c1b923a05f4da5610589d564ee8aac33f' + +pause 4 + +;P +send 'a410d23ed9ad9964d3e401cb9317a25213f75712acbc5c12191abf3f1c0e723e2333b49eb1f95b0f9748d952f04a5ae35885' +send '9d384403ce364aa3f58dd9769909b45048548c55872a6afbb3b15c54882f96c20df1b2df164f0bac849ca17ad2df63abd75c' +pause 4 +send '881922e79a5009f00b7d631622e90e7fa4e980618575e1d6bd1a72d5b6a50f4f6a68b793937c4af95fc11541759a1736577d' +send '9448b87792dff07232415512e933755e12250d466e9cc8df150727d747e51fea7964158326b1365d580cb190f45182915982' +send '21fdf36c6305c8b8a8ed05663dd7b006e945f592abbecae460f77c71b6ec649d3fd5394202ed7bbbd040f7b8fd57cb06a99b' +send 'e254fa25d71a3760734046c2a0db383e02397913ae67ce65870d9f6c6f67a9d00497be1d763b21937cf9cbf9a24ef97bbcaa' +send '07916f8894e5b7fb03258821ac46140965b23c5409ca49026efb2bf95bce025c4183a5f659bf6aaeef56d7933bb29697d7d5' +send '41348c871fa01f869678b2e34506f6dc0a4c132b689a0ed27dc3c8d53702aa584877' +pause 4 + +;Q +send 'abc67417725cf28fc7640d5de43825f416ebfa80e191c42ee886303338f56045' + +pause 4 +; send dummy +send '1' +pause 3 + +; ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +; Signature verification +;------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +;select verification +send '2' +pause 1 + +; send option 1 to automatically generate the public key +send '1' +pause 5 + +logclose \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-dsa-services/miv-rv32-dsa-services hw Debug.launch b/applications/user-crypto/miv-rv32-dsa-services/miv-rv32-dsa-services hw Debug.launch new file mode 100755 index 0000000..be235fe --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/miv-rv32-dsa-services hw Debug.launch @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/user-crypto/miv-rv32-dsa-services/miv-rv32-dsa-services hw attach.launch b/applications/user-crypto/miv-rv32-dsa-services/miv-rv32-dsa-services hw attach.launch new file mode 100644 index 0000000..3a05909 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/miv-rv32-dsa-services hw attach.launch @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/application/helper.c b/applications/user-crypto/miv-rv32-dsa-services/src/application/helper.c new file mode 100755 index 0000000..3be82f2 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/application/helper.c @@ -0,0 +1,303 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file helper.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Helper function for PolarFire User Crypto- Cryptography service example. + * + */ +#include +#include +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" +#include "helper.h" + +static const uint8_t g_separator[] = +"\r\n\ +------------------------------------------------------------------------------"; +static const uint8_t hex_chars[16] = { '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + +/*============================================================================== + Function to clear local variable and array. + */ +static void clear_variable(uint8_t *p_var, uint16_t size) +{ + uint16_t inc; + + for(inc = 0; inc < size; inc++) + { + *p_var = 0x00; + p_var++; + } +} + +/*============================================================================== + Function to get the input data from user. + */ +uint16_t get_input_data +( + uint8_t* location, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +) +{ + uint16_t count = 0u; + + /* Clear the memory location. */ + clear_variable(location, size); + + /* Read data from UART terminal. */ + count = get_data_from_uart(location, size, msg, msg_size); + + return count; +} + +/*============================================================================== + Function to get the key from user. + */ +void get_key +( + uint8_t key_type, + uint8_t* location, + uint8_t size, + const uint8_t* msg, + uint8_t msg_size +) +{ + uint8_t status = 0u; + const uint8_t invalid_ms[] = "\r\n Invalid key type. "; + + if(status == VALID) + { + /* Read the 16 bytes of input data from UART terminal. */ + get_input_data(location, size, msg, msg_size); + } + else + { + UART_send(&g_uart, invalid_ms, sizeof( invalid_ms)); + } +} + +/*============================================================================== + Convert ASCII value to hex value. + */ +uint8_t convert_ascii_to_hex(uint8_t* dest, const uint8_t* src) +{ + uint8_t error_flag = 0u; + + if((*src >= '0') && (*src <= '9')) + { + *dest = (*src - '0'); + } + else if((*src >= 'a') && (*src <= 'f')) + { + *dest = (*src - 'a') + 10u; + } + else if((*src >= 'A') && (*src <= 'F')) + { + *dest = (*src - 'A') + 10u; + } + else if(*src != 0x00u) + { + UART_send(&g_uart, (const uint8_t *)"\r\n Invalid data.", sizeof("\r\n Invalid data.")); + error_flag = 1u; + } + return error_flag; +} + +/*============================================================================== + Validate the input hex value . + */ +uint8_t validate_input(uint8_t ascii_input) +{ + uint8_t valid_key = 0u; + + if(((ascii_input >= 'A') && (ascii_input <= 'F')) || \ + ((ascii_input >= 'a') && (ascii_input <= 'f')) || \ + ((ascii_input >= '0') && (ascii_input <= '9'))) + { + valid_key = 1u; + } + else + { + valid_key = 0u; + } + return valid_key; +} + +/*============================================================================== + Display content of buffer passed as parameter as hex values. + */ +void display_output +( + uint8_t* in_buffer, + uint32_t byte_length, + uint8_t reverse_buffer +) +{ + + uint32_t inc; + + + uint8_t byte = 0; + + UART_send(&g_uart, (const uint8_t*)" ", sizeof(" ")); + + + if(reverse_buffer == 0) + { + for(inc = 0; inc < byte_length; ++inc) + { + + + if((inc > 1u) &&(0u == (inc % 16u))) + { + UART_send(&g_uart, (const uint8_t*)"\r\n ", sizeof("\r\n ")); + } + + byte = in_buffer[inc]; + UART_send(&g_uart, &hex_chars[((byte & 0xF0) >> 4) ], 1); + UART_send(&g_uart, &hex_chars[(byte & 0x0F)], 1); + } + } + /* if reverse_byte is true */ + else + { + for(inc = byte_length ; inc > 0; inc -= 1) + { + if((inc < byte_length) &&(0u == (inc % 16u))) + { + UART_send(&g_uart, (const uint8_t*)"\r\n ", sizeof("\r\n ")); + } + + byte = in_buffer[inc - 1]; + UART_send(&g_uart, &hex_chars[((byte & 0xF0) >> 4) ], 1); + UART_send(&g_uart, &hex_chars[(byte & 0x0F)], 1); + } + } +} + +/*============================================================================== + Function to read data from UART terminal and stored it. + */ +uint16_t get_data_from_uart +( + uint8_t* src_ptr, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +) +{ + uint8_t complete = 0u; + uint8_t rx_buff[1]; + uint8_t rx_size = 0u; + uint16_t count = 0u; + uint16_t ret_size = 0u; + uint8_t first = 0u; + uint16_t src_ind = 0u; + uint8_t prev = 0; + uint8_t curr = 0; + uint8_t temp = 0; + uint8_t next_byte = 0; + uint16_t read_data_size = 0; + + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, msg, msg_size); + + if(size != 1) + { + read_data_size = size * 2; + } + else + { + read_data_size = size; + } + + /* Read the key size sent by user and store it. */ + count = 0u; + while(!complete) + { + rx_size = UART_get_rx(&g_uart, rx_buff, sizeof(rx_buff)); + if(rx_size > 0u) + { + /* Is it to terminate from the loop */ + if(ENTER == rx_buff[0]) + { + complete = 1u; + } + /* Is entered key valid */ + else if(validate_input(rx_buff[0]) != 1u) + { + UART_send(&g_uart, rx_buff, sizeof(rx_buff)); + UART_send(&g_uart, (const uint8_t *)"\r\n Invalid input.", + sizeof("\r\n Invalid input.")); + UART_send(&g_uart, msg, msg_size); + complete = 0u; + count = 0u; + first = 0u; + } + else + { + if(next_byte == 0) + { + convert_ascii_to_hex(&src_ptr[src_ind], &rx_buff[0]); + prev = src_ptr[src_ind]; + next_byte = 1; + } + else + { + convert_ascii_to_hex(&curr, &rx_buff[0]); + temp = ((prev << 4) & 0xF0); + src_ptr[src_ind] = (temp | curr); + next_byte = 0; + src_ind++; + } + + + /* Switching to next line after every 8 bytes */ + if(((count % 32u) == 0x00u) && (count > 0x00u) && (complete != 0x01u)) + { + UART_send(&g_uart, (const uint8_t *)"\n\r", sizeof("\n\r")); + first = 0u; + } + + if(first == 0u) + { + UART_send(&g_uart, (const uint8_t *)" ", sizeof(" ")); + first++; + } + UART_send(&g_uart, rx_buff, sizeof(rx_buff)); + count++; + if(read_data_size == count) + { + complete = 1u; + } + } + } + } + + if((count % 2) == 0) + { + ret_size = count / 2; + } + else + { + if(size != 1) + { + temp = src_ptr[src_ind]; + src_ptr[src_ind] = ((temp << 4) & 0xF0); + + ret_size = (count / 2) + 1; + } + else + { + ret_size = 1; + } + } + + return ret_size; +} + diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/application/helper.h b/applications/user-crypto/miv-rv32-dsa-services/src/application/helper.h new file mode 100755 index 0000000..0a2effe --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/application/helper.h @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file helper.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Helper function public API. + * + */ +#ifndef __HELPER_H_ +#define __HELPER_H_ 1 + +/****************************************************************************** + * Maximum buffer size. + *****************************************************************************/ +#define MAX_RX_DATA_SIZE 256 +#define MASTER_TX_BUFFER 10 +#define DATA_LENGTH_32_BYTES 32 + +/*============================================================================== + Macro + */ +#define VALID 0U +#define INVALID 1U +#define ENTER 13u + +/****************************************************************************** + * CoreUARTapb instance data. + *****************************************************************************/ +extern UART_instance_t g_uart; + +uint16_t get_input_data +( + uint8_t* location, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +); +void get_key +( + uint8_t key_type, + uint8_t* location, + uint8_t size, + const uint8_t* msg, + uint8_t msg_size +); +uint16_t get_data_from_uart +( + uint8_t* src_ptr, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +); +void display_output +( + uint8_t* in_buffer, + uint32_t byte_length, + uint8_t reverse_buffer +); +#endif /* __HELPER_H_ */ diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/application/main.c b/applications/user-crypto/miv-rv32-dsa-services/src/application/main.c new file mode 100644 index 0000000..165865e --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/application/main.c @@ -0,0 +1,416 @@ + +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file main.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Application demonstrating the DSA cryptography service. Please see the + * Readme.md for more details. + * + */ +#include +#include +#include "cal/calpolicy.h" +#include "cal/pk.h" +#include "cal/pkx.h" +#include "cal/pkxlib.h" +#include "cal/calini.h" +#include "cal/utils.h" +#include "cal/hash.h" +#include "cal/drbgf5200.h" +#include "cal/drbg.h" +#include "cal/nrbg.h" +#include "cal/sym.h" +#include "cal/shaf5200.h" +#include "cal/calenum.h" +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" +#include "fpga_design_config/fpga_design_config.h" +#include "miv_rv32_hal/miv_rv32_hal.h" +#include "helper.h" + + +#define KEY_SIZE 32 +#define DATA_LENGTH_32_BYTES 32 +#define REVERSE_FALSE 0 +#define REVERSE_TRUE 1 + +/*flag to verify that DSA Signature has been generated before verification */ +#define SIG_GEN_TRUE 1 +#define SIG_GEN_FALSE 0 +#define PARAM_WORD_SIZE 12 +/****************************************************************************** + * User Crypto base address. This will be used in config_user.h in CAL. + *****************************************************************************/ +uint32_t g_user_crypto_base_addr = 0x62000000UL; + +/****************************************************************************** + * CoreUARTapb instance data. + *****************************************************************************/ +UART_instance_t g_uart; + +/*============================================================================== + Messages displayed over the UART. + */ + +const uint8_t g_greeting_msg[] = +"\r\n\r\n\ +******************************************************************************\r\n\ +************* PolarFire User Crypto DSA Service Example Project **************\r\n\ +******************************************************************************\r\n\ + This example project demonstrates the use of the DSA service to calculate\r\n\ + a DSA signature on a provided message and also verifies the generated message\r\n\ +signature. \r\n"; +const uint8_t g_select_operation_msg[] = +"\r\n\ +------------------------------------------------------------------------------\r\n\ + Select the Cryptographic operation to perform:\r\n\ + Press Key '1' to perform DSA signature generation \r\n\ + Press Key '2' to perform DSA signature verification \r\n\ +------------------------------------------------------------------------------\r\n"; +const uint8_t dsa_generation_msg[] = +"\r\n\ +******************************************************************************\r\n\ + DSA Signature Generation\r\n\ +******************************************************************************\r\n" ; +const uint8_t dsa_verification_msg[] = +"\r\n\ +******************************************************************************\r\n\ + DSA Signature verification\r\n\ +******************************************************************************\r\n"; +const uint8_t select_private_key_msg[] = +"\r\n\ +------------------------------------------------------------------------------\r\n\ + Select one of the following options:\r\n\ + Press Key '1' to generate private key through CALECKeyPairGen() function \r\n\ + Press Key '2' to get private key from the terateram macro. \r\n\ +------------------------------------------------------------------------------\r\n"; + +const uint8_t select_public_key_msg[] = +"\r\n\ +------------------------------------------------------------------------------\r\n\ + Select one of the following options:\r\n\ + Press Key '1' to generate public key through entered private_key \r\n\ + Press Key '2' to get public key from the terateram macro. \r\n\ +------------------------------------------------------------------------------\r\n"; + +static const uint8_t g_separator[] = +"\r\n\ +------------------------------------------------------------------------------"; +static const uint8_t msg[] = + "\r\n Enter message (max size : 12 words): \r\n"; +static const uint8_t read_private_key[] = + "\r\n Enter private key x (max size : 12 words):\r\n"; +static const uint8_t read_public_key[] = + "\r\n Enter public key y (max size : 12 words):\r\n"; +static const uint8_t msg_gen_success[] = "\r\n\ +------------------------------------------------------------------------------\r\n\ + \r DSA signature generation successful \r\n"; +static const uint8_t msg_gen_fail[] = "\r\n\ +------------------------------------------------------------------------------\r\n\ + \r\n DSA signature generation fail \r\n"; +static const uint8_t msg_ver_success[] = "\r\n\ +------------------------------------------------------------------------------\r\n\ + \r DSA signature verification successful \r\n"; +static const uint8_t msg_ver_fail[] = "\r\n\ +------------------------------------------------------------------------------\r\n\ + \r\n DSA signature verification fail \r\n"; +static const uint8_t read_g[] = + "\r\n Enter the g parameter \r\n"; + +static const uint8_t read_k[] = + "\r\n Enter the random value k (exactly 8 words ):\r\n"; +static const uint8_t read_p[] = + "\r\n Enter the prime number p (exactly 96 words):\r\n"; +static const uint8_t read_q[] = + "\r\n Enter the prime number q (exactly 96 words):\r\n"; +/*============================================================================== + Global Variables. + */ + uint32_t __attribute__ ((section (".crypto_data"))) msg_g[32] = { 0x00 }; + uint32_t __attribute__ ((section (".crypto_data"))) k_g[8] = { 0x00 }; + uint32_t __attribute__ ((section (".crypto_data"))) p_g[96] = { 0x00 }; + uint32_t __attribute__ ((section (".crypto_data"))) pmu_g[97] = { 0x00 }; + uint32_t __attribute__ ((section (".crypto_data"))) r_g[8] = { 0x00 }; + uint32_t __attribute__ ((section (".crypto_data"))) s_g[8] = { 0x00 }; + uint32_t __attribute__ ((section (".crypto_data"))) g_g[96] = { 0x00 }; + uint32_t __attribute__ ((section (".crypto_data"))) x_g[8] = { 0x00 }; + uint32_t __attribute__ ((section (".crypto_data"))) y_g[96] = { 0x00 }; + uint32_t __attribute__ ((section (".crypto_data"))) q_g[8] = { 0x00 }; + uint32_t __attribute__ ((section (".crypto_data"))) qmu_g[9] = { 0x00 }; + uint32_t __attribute__ ((section (".crypto_data"))) qlen_g = 0; + uint32_t __attribute__ ((section (".crypto_data"))) plen_g = 0; + uint16_t __attribute__ ((section (".crypto_data"))) msg_len = 0; + uint32_t __attribute__ ((section (".crypto_data"))) buffer[] = {0x00}; + +/*============================================================================== + Local functions. + */ +static void dsa_sign(void); +static void display_greeting(void); +static void dsa_verify(void); + +/*============================================================================== + Performs signature generation for ECDSA public-key cryptography. + */ + void dsa_verify(void) + { + SATR result; + uint8_t opt ; + + get_input_data((uint8_t*)&opt, sizeof(opt),select_public_key_msg, + sizeof(select_public_key_msg)); + if (opt == 1) + { + /* generate private and public key pair */ + result = CALExpo(g_g, x_g, p_g, pmu_g, 8, plen_g/4, y_g); + + if(SATR_SUCCESS == result) + { + CALPKTrfRes(SAT_TRUE); + + /* display the generated public key */ + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_polled_tx_string(&g_uart,(uint8_t*)"\r\n Public key generation successful \r\n" ); + UART_send(&g_uart, (const uint8_t *)"\r\n public_key value : \r\n\r\n", + sizeof("\r\n public_key value : \r\n")); + display_output((uint8_t*)&y_g[0], sizeof(y_g),REVERSE_TRUE); + } + } + else + { + /* get public key y point */ + get_input_data((uint8_t*)&y_g[0], sizeof(y_g), read_public_key, + sizeof(read_public_key)); + /* adjust endianness */ + CALWordReverse(y_g, sizeof(y_g)); + CALByteReverseWord(y_g, sizeof(y_g)); + } + /* generate public key*/ + result = CALExpo(g_g, x_g, p_g, pmu_g, 8, plen_g/4, y_g); + + result = CALPKTrfRes(SAT_TRUE); + + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_polled_tx_string(&g_uart, (uint8_t*)"\r\n Public key Generated y = g^x mod p \r\n "); + + + result = CALDSAVerifyHash(&msg_g[0], SATHASHTYPE_SHA384, msg_len, &g_g[0], + &y_g[0], &r_g[0], &s_g[0], &p_g[0], &pmu_g[0],q_g, + qmu_g, qlen_g/4, plen_g/4, SAT_TRUE, + X52CCR_DEFAULT); + if(SATR_SUCCESS == result) + { + result = CALPKTrfRes(SAT_TRUE); + switch(result) + { + case SATR_SUCCESS: + + UART_polled_tx_string(&g_uart, (uint8_t*)msg_ver_success); + break; + case SATR_VERPARMR: + + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_polled_tx_string(&g_uart, (uint8_t*)"\r\n Signature R parameter must be in range [1,Q-1] "); + break ; + case SATR_VERPARMS: + + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_polled_tx_string(&g_uart, (uint8_t*)"\r\n Signature S parameter must be in range [1,Q-1] "); + break ; + case SATR_VERIFYFAIL: + + UART_polled_tx_string(&g_uart, (uint8_t*)msg_ver_fail); + break ; + } + } + } + + +void dsa_sign(void) +{ + SATR result; + + /* Read message value. */ + msg_len = get_input_data((uint8_t*)&msg_g, sizeof(msg_g), msg, sizeof(msg)); + + /* Read DSA value G parameter. */ + get_input_data((uint8_t*)&g_g, sizeof(g_g), read_g, + sizeof(read_g)); + + /* Read random per-message value K parameter. */ + get_input_data((uint8_t*)&k_g, sizeof(k_g), read_k, + sizeof(read_k)); + + /* Read Private key X parameter. */ + get_input_data((uint8_t*)&x_g, sizeof(x_g), read_private_key, + sizeof(read_private_key)); + + /* Read module value P. */ + plen_g = get_input_data((uint8_t*)&p_g, sizeof(p_g), read_p, + sizeof(read_p)); + + /* Read module value Q. */ + qlen_g = get_input_data((uint8_t*)&q_g, sizeof(q_g), read_q, + sizeof(read_q)); + + /* Change the endianness of received parameter from UART terminal.*/ + CALWordReverse((uint32_t*)&g_g, (sizeof(g_g)/4)); + CALByteReverseWord((uint32_t*)&g_g, (sizeof(g_g)/4)); + CALWordReverse((uint32_t*)&k_g, (sizeof(k_g)/4)); + CALByteReverseWord((uint32_t*)&k_g,(sizeof(k_g)/4)); + CALWordReverse((uint32_t*)&x_g, (sizeof(x_g)/4)); + CALByteReverseWord((uint32_t*)&x_g, (sizeof(x_g)/4)); + CALWordReverse((uint32_t*)&p_g, (sizeof(p_g)/4)); + CALByteReverseWord((uint32_t*)&p_g, (sizeof(p_g)/4)); + CALWordReverse((uint32_t*)&q_g, (sizeof(q_g)/4)); + CALByteReverseWord((uint32_t*)&q_g, (sizeof(q_g)/4)); + + /* Initiate generation of pre-compute value for P. */ + result = CALPreCompute((uint32_t*)&p_g[0], (uint32_t*)&pmu_g[0], 96u); + if(SATR_SUCCESS == result) + { + CALPKTrfRes(SAT_TRUE); + } + + /* Initiate generation of pre-compute value for Q. */ + result = CALPreCompute((uint32_t*)&q_g[0], (uint32_t*)&qmu_g[0], 8u); + if(SATR_SUCCESS == result) + { + CALPKTrfRes(SAT_TRUE); + } + + /* Calculates a DSA signature with SCA countermeasures. */ + result = CALDSASignHash(&msg_g[0], SATHASHTYPE_SHA384, msg_len, &g_g[0], + &k_g[0], &x_g[0], &p_g[0], &pmu_g[0], &q_g[0], + &qmu_g[0], qlen_g/4, plen_g/4, r_g, s_g, SAT_TRUE, + X52CCR_DEFAULT); + + /* Display the generated signature. */ + if(SATR_SUCCESS == result) + { + CALPKTrfRes(SAT_TRUE); + switch(result) + { + case SATR_SUCCESS: + + /* Display the generated signature in hex format. */ + UART_send(&g_uart, msg_gen_success, sizeof(msg_gen_success)); + UART_polled_tx_string(&g_uart,(uint8_t*)"\r\n R value:\r\n\r\n"); + display_output((uint8_t*)&r_g[0],sizeof(r_g),REVERSE_TRUE); + UART_polled_tx_string(&g_uart,(uint8_t*)"\r\n S value:\r\n\r\n"); + display_output((uint8_t*)&s_g[0],sizeof(s_g),REVERSE_TRUE); + break; + case SATR_SIGNPARMK: + + UART_polled_tx_string(&g_uart, (uint8_t*)"\r\n\n k parameter must be in [1,q-1] \r\n"); + UART_send(&g_uart, msg_gen_fail, sizeof(msg_gen_fail)); + break ; + + case SATR_SIGNFAIL : + UART_send(&g_uart, msg_gen_fail, sizeof(msg_gen_fail)); + break ; + } + + } + else + { + UART_send(&g_uart, msg_gen_fail, sizeof(msg_gen_fail)); + } +} +/*============================================================================== + Display greeting message when application is started. + */ +static void display_greeting(void) +{ + UART_send(&g_uart, g_greeting_msg,sizeof(g_greeting_msg)); +} + +/*============================================================================== + Display the choice of cryptographic operation to perform. + */ +static void display_operation_choices(void) +{ + UART_send(&g_uart, g_select_operation_msg, sizeof(g_select_operation_msg)); +} + +/*============================================================================== + Display the Option to continue. + */ +static void display_option(void) +{ + uint8_t rx_size; + uint8_t rx_buff[1]; + + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, (const uint8_t*)"\r\n Press any key to continue.\r\n", + sizeof("\r\n Press any key to continue.\r\n")); + do + { + rx_size = UART_get_rx(&g_uart, rx_buff, sizeof(rx_buff)); + } while(0u == rx_size); +} + +/*============================================================================== + * Perform DSA signature and verification sequentially + */ +/* Main function */ +void main(void) +{ + uint8_t rx_buff[1]; + uint8_t rx_size = 0; + uint8_t sig_gen_success = SIG_GEN_FALSE ; + + UART_init(&g_uart, COREUARTAPB0_BASE_ADDR, BAUD_VALUE_115200, + (DATA_8_BITS | NO_PARITY)); + + /* Initializes the Athena Processor */ + CALIni(); + + /* Display greeting message. */ + display_greeting(); + + /* Select cryptographic operation to perform */ + display_operation_choices(); + + for(;;) + { + /* Read inputs from UART terminal. */ + rx_size = UART_get_rx(&g_uart, rx_buff, sizeof(rx_buff)); + if(rx_size > 0) + { + switch(rx_buff[0]) + { + case '1': + /* Performs signature generation for DSA */ + UART_send(&g_uart, dsa_generation_msg, sizeof(dsa_generation_msg)); + dsa_sign(); + sig_gen_success = SIG_GEN_TRUE ; + display_option(); + display_operation_choices(); + break; + + case '2': + /* Performs signature verification for DSA */ + UART_send(&g_uart, dsa_verification_msg, sizeof(dsa_verification_msg)); + if(sig_gen_success == SIG_GEN_TRUE) + { + dsa_verify(); + } + else + { + UART_polled_tx_string(&g_uart,(uint8_t*)"\r\n Please perform DSA signature Generation at least once before DSA verification \r\n "); + } + display_option(); + display_operation_choices(); + break; + + default: + break; + } + } + } + + return; +} diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h b/applications/user-crypto/miv-rv32-dsa-services/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h new file mode 100644 index 0000000..3fd1438 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h @@ -0,0 +1,156 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file fpga_design_config.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Sample design configuration settings. + * + */ + /*========================================================================*//** + @mainpage + Example file detailing how the fpga_design_config.h should be constructed + for the SoftConsole project targeted for Mi-V processors. + + @section intro_sec Introduction + The SoftConsole project targeted for Mi-V processors now have an improved + folder structure. Detailed description of the folder structure is available + at https://github.com/Mi-V-Soft-RISC-V/miv-rv32-documentation. + + The fpga_design_config.h must be stored as shown below + /boards//fpga_design_config.h + + Currently this file must be hand crafted when using the Mi-V Soft Processor. + In future, all the design and soft IP configurations will be automatically + generated from the Libero design description data. + + You can use this sample file as an example. + Rename this file from sample_fpga_design_config.h to fpga_design_config.h + and then customize it per your hardware design. + + @section Project configuration Instructions + 1. Change SYS_CLK_FREQ define to frequency of Mi-V Soft processor clock + 2 Add all the soft IP core BASE addresses + 3. Add the peripheral Core Interrupts to Mi-V Soft processor IRQ number + mappings + 4. Define MSCC_STDIO_UART_BASE_ADDR if you want a CoreUARTapb mapped to + STDIO + + **NOTE** + In the legacy folder structures, the file hw_config.h as was used at the + root of the project folder. This file is now depricated. + +*//*=========================================================================*/ + +#ifndef FPGA_DESIGN_CONFIG_H_ +#define FPGA_DESIGN_CONFIG_H_ + +/***************************************************************************//** + * Soft-processor clock definition + * This is the only clock brought over from the Mi-V Libero design. + */ +#ifndef SYS_CLK_FREQ +#define SYS_CLK_FREQ 83000000UL +#endif + +/***************************************************************************//** + * Peripheral base addresses. + * Format of define is: + * __BASE_ADDR + * The field is optional if there is only one instance of the core + * in the design + * MIV_ESS is an extended peripheral subsystem IP core with peripherals + * connections as defined below. + * The system can be further extended by attaching APB peripherals to the + * empty APB slots. + */ +#define COREUARTAPB0_BASE_ADDR 0x70000000UL +#define COREGPIO_OUT_BASE_ADDR 0x70001000UL +#define CORESPI_BASE_ADDR 0x70002000UL +#define CORESYS_SERV_BASE_ADDR 0x70003000UL + +/***************************************************************************//** + * Peripheral Interrupts are mapped to the corresponding Mi-V Soft processor + * interrupt in the Libero design. + * + * On the legacy RV32 cores, there can be up to 31 external interrupts (IRQ[30:0] + * pins). The legacy RV32 Soft processor external interrupts are defined in the + miv_rv32_plic.h + * + * These are of the form + * typedef enum +{ + NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + . + . + . + External_31_IRQn = 31 +} IRQn_Type; + + On the legacy RV32 processors, the PLIC identifies the interrupt and passes it + on to the processor core. The interrupt 0 is not used. The pin IRQ[0] should + map to External_1_IRQn likewise IRQ[30] should map to External_31_IRQn + +e.g + +#define TIMER0_IRQn External_30_IRQn +#define TIMER1_IRQn External_31_IRQn + + The MIV_RV32 soft processor has up to six optional system interrupts, MSYS_EI[n] + in addition to one EXT_IRQ. + The MIV_RV32 does not have an inbuilt PLIC and all the interrupts are directly + delivered to the processor core, hence unlike legacy RV32 cores, no interrupt + number mapping is necessary on MIV_RV32 core. + */ + +/**************************************************************************** + * Baud value to achieve a 115200 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ +#define BAUD_VALUE_115200 ((SYS_CLK_FREQ / (16 * 115200)) - 1) + +/****************************************************************************** + * Baud value to achieve a 57600 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + #define BAUD_VALUE_57600 ((SYS_CLK_FREQ / (16 * 57600)) - 1) + +/***************************************************************************//** + * Define MSCC_STDIO_THRU_CORE_UART_APB in the project settings if you want the + * standard IOs to be redirected to a terminal via UART. + */ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +/* + * A base address mapping for the STDIO printf/scanf mapping to CortUARTapb + * must be provided if it is being used + * + * e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR + */ +#define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB0_BASE_ADDR + +#ifndef MSCC_STDIO_UART_BASE_ADDR +#error MSCC_STDIO_UART_BASE_ADDR not defined- e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR +#endif + +#ifndef MSCC_STDIO_BAUD_VALUE +/* + * The MSCC_STDIO_BAUD_VALUE define should be set in your project's settings to + * specify the baud value used by the standard output CoreUARTapb instance for + * generating the UART's baud rate if you want a different baud rate from the + * default of 115200 baud + */ +#define MSCC_STDIO_BAUD_VALUE 115200 +#endif /*MSCC_STDIO_BAUD_VALUE*/ + +#endif /* end of MSCC_STDIO_THRU_CORE_UART_APB */ +/******************************************************************************* + * End of user edit section + */ +#endif /* FPGA_DESIGN_CONFIG_H_ */ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld b/applications/user-crypto/miv-rv32-dsa-services/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld new file mode 100755 index 0000000..8541db6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld @@ -0,0 +1,160 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-ram.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * debug image executing in SRAM. + * + * This linker script assumes that a RAM is connected at on Mi-V soft processor + * memory space pointed by the reset vector address. + * + * NOTE : Modify the memory section address and the size according to your + * Libero design. + * For example: + * 1) If you want to download and step debug at a different RAM memory address in + * your design (For example TCM base address) than the one provided in this file. + * 2) The MIV_RV32, when used with MIV_ESS IP, provides ways to copy the executable + * HEX file from external Non-Volatile memory into the TCM at reset. In this + * case your executable must be linked to the TCM address. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +MEMORY +{ + ram (rwx) : ORIGIN = 0x80000000, LENGTH = 64k + crypto_ram (rw) : ORIGIN = 0x61000000, LENGTH = 32k +} + +RAM_START_ADDRESS = 0x80000000; /* Must be the same value MEMORY region ram ORIGIN above. */ +RAM_SIZE = 64k; /* Must be the same value MEMORY region ram LENGTH above. */ +STACK_SIZE = 2k; /* needs to be calculated for your application */ +HEAP_SIZE = 0k; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > ram + + .text : ALIGN(0x10) + { + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } > ram + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } > ram + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } > ram + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram + + . = 0x61000000; + .crypto_data : ALIGN(0x10) + { + . = ALIGN(0x10); + *(.crypto_data) + } > crypto_ram +} + diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/aesf5200.h b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/aesf5200.h new file mode 100755 index 0000000..889dddd --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/aesf5200.h @@ -0,0 +1,104 @@ +/* ------------------------------------------------------------------- + $Rev: 1293 $ $Date: 2017-07-27 14:09:14 -0400 (Thu, 27 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for F5200 AES function hardware implementation for + CAL. + ------------------------------------------------------------------- */ + +#ifndef AESF5200_H +#define AESF5200_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef AESF5200_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATR aesf5200aes (SATSYMTYPE eSymType, SATSYMMODE eMode, + void *pIV, SATBOOL bLoadIV, const void *pSrc, void *pDest, SATUINT32_t uiLen, + SATBOOL bDecrypt); + +extern SATR aesf5200aesk (SATSYMTYPE eSymType, const SATUINT32_t *puiKey); + +extern SATR aesf5200gcm (SATSYMTYPE eSymType, SATSYMMODE eMode, void *pIV, + const void *pSrc, void *pDest, SATUINT32_t uiEncLen, + const void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, SATUINT32_t uiMACLen, + SATBOOL bDecrypt); + +extern SATR aesf5200gcmdma(SATSYMTYPE eSymType, SATSYMMODE eMode, void *pIV, + const void *pSrc, void *pDest, SATUINT32_t uiEncLen, const void *pAuth, + SATUINT32_t uiAuthLen, void *pMAC, SATUINT32_t uiMACLen, SATBOOL bDecrypt, + SATUINT32_t uiDMAChConfig); + +extern SATR aesf5200kw(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR aesf5200kwp(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR aesf5200kr(SATSYMTYPE eSymType, SATSYMMODE eMode, + const SATUINT32_t *puiKey, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKrf, SATBOOL bDecrypt); + +extern SATR aesf5200dma(SATSYMTYPE eSymType, SATSYMMODE eMode, void *pIV, + SATBOOL bLoadIV, const void *pExtSrc, void *pExtDest, SATUINT32_t uiLen, + SATUINT32_t uiDMAChConfig, SATBOOL bDecrypt); + +extern SATR aesf5200krdma(SATSYMTYPE eSymType, SATSYMMODE eMode, + const SATUINT32_t *puiKey, void *pIV, SATBOOL bLoadIV, const void *pExtSrc, + void *pExtDest, SATUINT32_t uiLen, SATUINT32_t uiKrf, + SATUINT32_t uiDMAChConfig, SATBOOL bDecrypt); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/calcontext.h b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/calcontext.h new file mode 100755 index 0000000..fc408c2 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/calcontext.h @@ -0,0 +1,88 @@ +/* ------------------------------------------------------------------- + $Rev: 1298 $ $Date: 2017-08-04 13:04:19 -0400 (Fri, 04 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL context management functions. + ------------------------------------------------------------------- */ + +#ifndef CALCONTEXT_H +#define CALCONTEXT_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* Function resource handle. */ +/* ----- ------ ------- ---- */ +#define SATRES_DEFAULT (SATRESHANDLE)0U +#define SATRES_CALSW (SATRESHANDLE)1U + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ +typedef struct{ + SATUINT32_t uiBase; + SATRESCONTEXTPTR pContext; + }SATRESHANDLESTRUCT; + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALCONTEXT_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATRESCONTEXTPTR CALContextCurrent(const SATRESHANDLE hResource); + +extern SATR CALContextLoad(const SATRESHANDLE hResource, + const SATRESCONTEXTPTR pContext); + +extern SATR CALContextRemove(const SATRESHANDLE hResource); + +extern SATR CALContextUnload(const SATRESHANDLE hResource); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern void init_reshandles(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/calenum.h b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/calenum.h new file mode 100755 index 0000000..6281f3f --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/calenum.h @@ -0,0 +1,289 @@ +/* ------------------------------------------------------------------- + $Rev: 1566 $ $Date: 2018-09-14 11:04:30 -0400 (Fri, 14 Sep 2018) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + This file defines common types in the CAL. + + Most CAL types and constants are defined with the "SAT" prefix to + reduce the chance of name space collisions with other users. + ------------------------------------------------------------------- */ + +#ifndef CALENUM_H +#define CALENUM_H + +/* -------- */ +/* Includes */ +/* -------- */ + +/* CAL base types. */ +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ +/* NULL definitions. */ +#define SAT_NULL 0 + +/* Boolean definitions. */ +#define SAT_TRUE ((SATBOOL)1) +#define SAT_FALSE ((SATBOOL)0) + + +/* Major cipher key/SSP type. */ +/* ----- ------ ------- ----- */ +#define SATSSPTYPE_NULL (SATSSPTYPE)0 +#define SATSSPTYPE_SYMKEY (SATSSPTYPE)1 +#define SATSSPTYPE_ASYMKEY (SATSSPTYPE)2 +/* Special marker for end of list. */ +#define SATSSPTYPE_LAST (SATSSPTYPE)3 + + +/* Asymmetric Ciphers */ +/* ---------- ------- */ +#define SATASYMTYPE_NULL (SATASYMTYPE)0U +#define SATASYMTYPE_DSA_SIGN (SATASYMTYPE)1U +#define SATASYMTYPE_DSA_VERIFY (SATASYMTYPE)2U +#define SATASYMTYPE_RSA_ENCRYPT (SATASYMTYPE)3U +#define SATASYMTYPE_RSA_DECRYPT (SATASYMTYPE)4U +#define SATASYMTYPE_DH (SATASYMTYPE)5U +#define SATASYMTYPE_ECDSA_SIGN (SATASYMTYPE)6U +#define SATASYMTYPE_ECDSA_VERIFY (SATASYMTYPE)7U +#define SATASYMTYPE_ECDH (SATASYMTYPE)8U +#define SATASYMTYPE_RSA_SIGN (SATASYMTYPE)9U +#define SATASYMTYPE_RSA_VERIFY (SATASYMTYPE)10U +/* Special marker for end of list. */ +#define SATASYMTYPE_LAST (SATASYMTYPE)11U + + +/* Encoding Types */ +/* -------- ----- */ +#define SATRSAENCTYPE_NULL (SATRSAENCTYPE)0U +#define SATRSAENCTYPE_PKCS (SATRSAENCTYPE)1U +#define SATRSAENCTYPE_ANSI (SATRSAENCTYPE)2U +#define SATRSAENCTYPE_PSS (SATRSAENCTYPE)3U +/* Special marker for end of list. */ +#define SATRSAENCTYPE_LAST (SATRSAENCTYPE)4U + + +/* Symmetric Ciphers */ +/* --------- ------- */ + +/* Cipher Type. */ +#define SATSYMTYPE_NULL (SATSYMTYPE)0U +#define SATSYMTYPE_AES128 (SATSYMTYPE)1U +#define SATSYMTYPE_AES192 (SATSYMTYPE)2U +#define SATSYMTYPE_AES256 (SATSYMTYPE)3U +#define SATSYMTYPE_AESKS128 (SATSYMTYPE)4U +#define SATSYMTYPE_AESKS192 (SATSYMTYPE)5U +#define SATSYMTYPE_AESKS256 (SATSYMTYPE)6U +/* Special marker for end of list. */ +#define SATSYMTYPE_LAST (SATSYMTYPE)7U + +/* Names for common cipher key lengths, in bits. */ +#define SATSYMKEYSIZE_AES128 (SATSYMKEYSIZE)128U +#define SATSYMKEYSIZE_AES192 (SATSYMKEYSIZE)192U +#define SATSYMKEYSIZE_AES256 (SATSYMKEYSIZE)256U +#define SATSYMKEYSIZE_AESKS128 (SATSYMKEYSIZE)256U +#define SATSYMKEYSIZE_AESKS192 (SATSYMKEYSIZE)384U +#define SATSYMKEYSIZE_AESKS256 (SATSYMKEYSIZE)512U + +/* Cipher Mode. */ +#define SATSYMMODE_NULL (SATSYMMODE)0U +#define SATSYMMODE_ECB (SATSYMMODE)1U +#define SATSYMMODE_CBC (SATSYMMODE)2U +#define SATSYMMODE_CFB (SATSYMMODE)3U +#define SATSYMMODE_OFB (SATSYMMODE)4U +#define SATSYMMODE_CTR (SATSYMMODE)5U +#define SATSYMMODE_GCM (SATSYMMODE)6U +#define SATSYMMODE_GHASH (SATSYMMODE)8U +/* Special marker for end of list. */ +#define SATSYMMODE_LAST (SATSYMMODE)9U + + +/* Hashes */ +/* ------ */ +#define SATHASHTYPE_NULL (SATHASHTYPE)0U +#define SATHASHTYPE_SHA1 (SATHASHTYPE)1U +#define SATHASHTYPE_SHA224 (SATHASHTYPE)2U +#define SATHASHTYPE_SHA256 (SATHASHTYPE)3U +#define SATHASHTYPE_SHA384 (SATHASHTYPE)4U +#define SATHASHTYPE_SHA512 (SATHASHTYPE)5U +#define SATHASHTYPE_SHA512_224 (SATHASHTYPE)6U +#define SATHASHTYPE_SHA512_256 (SATHASHTYPE)7U +/* Special marker for end of list. */ +#define SATHASHTYPE_LAST (SATHASHTYPE)8U + +/* Hash sizes defined in bits */ +#define SATHASHSIZE_NULL (SATHASHSIZE)0U +#define SATHASHSIZE_SHA1 (SATHASHSIZE)160U +#define SATHASHSIZE_SHA224 (SATHASHSIZE)224U +#define SATHASHSIZE_SHA256 (SATHASHSIZE)256U +#define SATHASHSIZE_SHA384 (SATHASHSIZE)384U +#define SATHASHSIZE_SHA512 (SATHASHSIZE)512U +#define SATHASHSIZE_SHA512_224 (SATHASHSIZE)224U +#define SATHASHSIZE_SHA512_256 (SATHASHSIZE)256U + +#define SATHASHSIZE_HASH160 (SATHASHSIZE)160U +#define SATHASHSIZE_HASH192 (SATHASHSIZE)192U +#define SATHASHSIZE_HASH224 (SATHASHSIZE)224U +#define SATHASHSIZE_HASH256 (SATHASHSIZE)256U +#define SATHASHSIZE_HASH320 (SATHASHSIZE)320U +#define SATHASHSIZE_HASH384 (SATHASHSIZE)384U +#define SATHASHSIZE_HASH512 (SATHASHSIZE)512U +#define SATHASHSIZE_HASH521 (SATHASHSIZE)521U + + +/* Message Authentication Codes */ +/* ------- -------------- ----- */ + +/* Message Authentication Types */ +#define SATMACTYPE_NULL (SATMACTYPE)0U +#define SATMACTYPE_SHA1 (SATMACTYPE)1U +#define SATMACTYPE_SHA224 (SATMACTYPE)2U +#define SATMACTYPE_SHA256 (SATMACTYPE)3U +#define SATMACTYPE_SHA384 (SATMACTYPE)4U +#define SATMACTYPE_SHA512 (SATMACTYPE)5U +#define SATMACTYPE_SHA512_224 (SATMACTYPE)6U +#define SATMACTYPE_SHA512_256 (SATMACTYPE)7U +#define SATMACTYPE_AESCMAC128 (SATMACTYPE)10U +#define SATMACTYPE_AESCMAC192 (SATMACTYPE)11U +#define SATMACTYPE_AESCMAC256 (SATMACTYPE)12U +#define SATMACTYPE_AESGMAC (SATMACTYPE)13U +/* Special marker for end of list. */ +#define SATMACTYPE_LAST (SATMACTYPE)14U + + +/* Message Authentication Flags */ +#define SATMACFLAG_OP (SATMACTYPEFLAG)0U +#define SATMACFLAG_FIRSTPASS (SATMACTYPEFLAG)1U +#define SATMACFLAG_FINALPASS (SATMACTYPEFLAG)2U +#define SATMACFLAG_IKEYFINAL (SATMACTYPEFLAG)4U +#define SATMACFLAG_OKEYFINAL (SATMACTYPEFLAG)8U + + +/* Non-deterministic Random Bit Generator */ +/* ------- -------------- ----- */ + +/* NRBG register write enables */ +#define SATNRBGCONFIG_NONE 0x0 +#define SATNRBGCONFIG_RNG_CSR 0x1 +#define SATNRBGCONFIG_RNG_CNTLIM 0x2 +#define SATNRBGCONFIG_RNG_VOTIMER 0X4 +#define SATNRBGCONFIG_RNG_FMSK 0X8 + +/* RNG_CSR access defines */ +#define SATNRBGCONFIG_CSR_RODIS 0x0 +#define SATNRBGCONFIG_CSR_ROEN 0x1 +#define SATNRBGCONFIG_CSR_ROFATAL 0x2 +#define SATNRBGCONFIG_CSR_ROFATALCLR 0X4 + +/* RNG_FMSK mask values */ +#define SATNRBGCONFIG_FMSK_ROOSCF 0xFF +#define SATNRBGCONFIG_FMSK_MONOBITF 0x10000 +#define SATNRBGCONFIG_FMSK_POKERF 0x20000 +#define SATNRBGCONFIG_FMSK_RUNSF 0x40000 +#define SATNRBGCONFIG_FMSK_LRUNSF 0x80000 +#define SATNRBGCONFIG_FMSK_F1401 0xF0000 +#define SATNRBGCONFIG_FMSK_REPCNTF 0x100000 +#define SATNRBGCONFIG_FMSK_APROPF 0x200000 +#define SATNRBGCONFIG_FMSK_SP800 0x300000 + +/* RNG_ROHEALTH mask values */ +#define SATNRBGCONFIG_HLTH_ROOSCF 0x3FC0 +#define SATNRBGCONFIG_HLTH_APROPF 0x20 +#define SATNRBGCONFIG_HLTH_REPCNTF 0x10 +#define SATNRBGCONFIG_HLTH_LRUNSF 0x8 +#define SATNRBGCONFIG_HLTH_RUNSF 0x4 +#define SATNRBGCONFIG_HLTH_POKERF 0x2 +#define SATNRBGCONFIG_HLTH_MONOBITF 0x1 + + +/* Return Codes */ +/* ------ ----- */ +#define SATR_SUCCESS (SATR)0U +#define SATR_FAIL (SATR)1U +#define SATR_BADPARAM (SATR)2U +#define SATR_VERIFYFAIL (SATR)3U +#define SATR_KEYSFULL (SATR)4U +#define SATR_BUSY (SATR)5U +#define SATR_ROFATAL (SATR)6U +#define SATR_PARITYFLUSH (SATR)7U +#define SATR_SIGNFAIL (SATR)8U +#define SATR_VALIDATEFAIL (SATR)9U +#define SATR_PAF (SATR)10U +#define SATR_VALPARMX (SATR)11U +#define SATR_VALPARMY (SATR)12U +#define SATR_VALPARMB (SATR)13U +#define SATR_DCMPPARMX (SATR)14U +#define SATR_DCMPPARMB (SATR)15U +#define SATR_DCMPPARMP (SATR)16U +#define SATR_SIGNPARMD (SATR)17U +#define SATR_SIGNPARMK (SATR)18U +#define SATR_VERPARMR (SATR)19U +#define SATR_VERPARMS (SATR)20U +#define SATR_MSBICV1 (SATR)21U +#define SATR_MSBICV2 (SATR)22U +#define SATR_PADLEN (SATR)23U +#define SATR_LSB0PAD (SATR)24U +#define SATR_BADLEN (SATR)25U +#define SATR_BADHASHTYPE (SATR)26U +#define SATR_BADTYPE (SATR)27U +#define SATR_BADMODE (SATR)28U +#define SATR_BADCONTEXT (SATR)29U +#define SATR_BADHASHLEN (SATR)30U +#define SATR_BADMACTYPE (SATR)31U +#define SATR_BADMACLEN (SATR)32U +#define SATR_BADHANDLE (SATR)33U +#define SATR_FNP (SATR)34U +#define SATR_HFAULT (SATR)35U +#define SATR_NOPEND (SATR)36U +#define SATR_BADRSAENC (SATR)37U +#define SATR_BADMOD (SATR)38U +/* Special marker for end of list. */ +#define SATR_LAST (SATR)39U + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* See caltypes.h for type definitions associated with defines above. */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALENUM_C +#ifdef __cplusplus +extern "C" { +#endif + +/* NOTE: this header file does not have an associated C file. */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/calini.h b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/calini.h new file mode 100755 index 0000000..62461d1 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/calini.h @@ -0,0 +1,69 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL initialization + ------------------------------------------------------------------- */ + +#ifndef CALINI_H +#define CALINI_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALINI_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALIni(void); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/calpolicy.h b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/calpolicy.h new file mode 100755 index 0000000..2a43445 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/calpolicy.h @@ -0,0 +1,183 @@ +/* ------------------------------------------------------------------- + $Rev: 1293 $ $Date: 2017-07-27 14:09:14 -0400 (Thu, 27 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file defining CAL policy for endianess, HW/SW, etc. + ------------------------------------------------------------------- */ + +#ifndef CALPOLICY_H +#define CALPOLICY_H + +/* -------- */ +/* Includes */ +/* -------- */ + +/* The following include provides a custom configuration header file when + CALCONFIGH is defined +*/ +#ifdef CALCONFIGH +# include CALCONFIGH +#else +# error "CALCONFIGH not defined. CAL requires a custom configuration header \ +defined by CALCONFIGH. Review CAL README." +#endif + +/* ------- */ +/* Defines */ +/* ------- */ + +/* Context switching */ +#ifndef MAXRESHANDLES +# define MAXRESHANDLES 1 +#endif + +/* Little Endian (default) / Big Endian */ +#ifndef SAT_LITTLE_ENDIAN +# define SAT_LITTLE_ENDIAN 1 +#endif + +/* PK SW Point Validate Checking */ +#ifndef PKSWCHKVALPT +# define PKSWCHKVALPT 1 +#endif + +/* DMA */ +#ifndef USE_X52EXEC_DMA +# define USE_X52EXEC_DMA 0 +#endif + +/* SHA */ +#define MAXHASHLEN 512 +#define MAXHMACKEYLEN 512 + +/* RNG */ +#define NRBGSIMNUMRO 16 +#define ENTROPYMEMBLOCKS 7 +#define BUFMEMBLOCKS 3 +#ifndef RNXBLKLEN +#define RNXBLKLEN 32 +#endif +#ifndef RNXBLKOUTLEN +#define RNXBLKOUTLEN 4 +#endif + +#ifndef USENRBGSW +# define USENRBGSW 0 +#endif + +/* PK */ +#ifndef PKX0_BASE +# define PKX0_BASE 0xE0000000u +#endif + +#if USEPKSW +# ifndef MAXMODSIZE +# define MAXMODSIZE 8192 +# endif +# ifndef PKSWBUFSIZE +# define PKSWBUFSIZE 15*(MAXMODSIZE/32) +# endif +#else +# define USEPKSW 0 +#endif + +/* Set default values for X52 configuration defines. */ +#ifndef X52_CFG_OPT +# define X52_CFG_OPT 0 +#endif +#ifndef X52_LIR_LEN +# define X52_LIR_LEN 0x800 +#endif +#ifndef X52_BER_LEN +# define X52_BER_LEN 0x400 +#endif +#ifndef X52_MMR_LEN +# define X52_MMR_LEN 0x400 +#endif +#ifndef X52_TSR_LEN +# define X52_TSR_LEN 0x400 +#endif +#ifndef X52_FPR_LEN +# define X52_FPR_LEN 0x400 +#endif +#if X52_LIR_ROM_LEN>0 && X52_LIR_LEN>X52_LIR_ROM_LEN +# define PKX_OFFSET 2048 +#else +# define PKX_OFFSET 0 +#endif + +/* X52 Configuration Options */ +#define AESPKX (X52_CFG_OPT&0x00000001u) +#define AESPKXGCM (X52_CFG_OPT&0x00000008u) +#define AESPKXFASTKEY (X52_CFG_OPT&0x01000000u) +#define SHAPKXOPT1 (X52_CFG_OPT&0x00000020u) +#define SHAPKXOPT224 (X52_CFG_OPT&0x00000040u) +#define SHAPKXOPT256 (X52_CFG_OPT&0x00000080u) +#define SHAPKXOPT384 (X52_CFG_OPT&0x00000100u) +#define SHAPKXOPT512 (X52_CFG_OPT&0x00000200u) +#define SHAPKXOPT5124 (X52_CFG_OPT&0x00400000u) +#define SHAPKXOPT5126 (X52_CFG_OPT&0x00800000u) + +/* Define the maximum number of return values that may be handled using + CAL*TrfRes() function(s). +*/ +#define CAL_MAXTRFS 4 + +/* Volatile pointer operations */ +/* These access macros are designed so that they may be redefined by a + user compiling CAL. +*/ +#ifndef CALREAD32 +# define CALREAD32(ptr) ( *(ptr) ) +#endif +#ifndef CALWRITE32 +# define CALWRITE32(ptr, val) ( *(ptr)=val ) +#endif +#ifndef CALPOLL32 +# define CALPOLL32(ptr, val, mask) while ((*(ptr) & (mask)) != (val)); +#endif + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +#ifndef CALPOLICY_C +#ifdef __cplusplus +extern "C" { +#endif + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +/* NOTE: this header file does not have an associated C file. */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/caltypes.h b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/caltypes.h new file mode 100755 index 0000000..3b2fe0b --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/caltypes.h @@ -0,0 +1,328 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + This file defines common types in the CAL. + + Since support for the C99 stdint.h integer types is not universal, + these are defined herein and may require customization from compiler + to compiler, or use of the stdint.h header, if present (recommended). + + C99 supports 64-bit types; however, support in older compilers is + spotty. For those that do not support it, the macro NO64BITINT may be + defined by the user to prevent defintion of 64-bit types. This is + generally safe with CAL-PK and CAL-SYM; however, this is incompatible + with CAL-SW. + + Most CAL types and constants are defined with the "SAT" prefix to + reduce the chance of name space collisions with other users. + ------------------------------------------------------------------- */ + +#ifndef CALTYPES_H +#define CALTYPES_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* Base Types */ +/* ---- ----- */ + +/* The user may compile using stdint.h instead of the definitions below + by defining the macro INC_STDINT_H. */ +#ifdef INC_STDINT_H +#include +#endif + +/* Integer type abstraction layer. */ +#ifndef INC_STDINT_H + +typedef unsigned char uint8_t; +typedef signed char int8_t; + +typedef unsigned short uint16_t; +typedef signed short int16_t; + +typedef unsigned int uint32_t; +typedef int int32_t; + +/* stdint.h is a C99 feature, and C99 supports 64-bit ints, so this is + immune to the macro used to disable 64-bit int support. +*/ +typedef unsigned long long uint64_t; +typedef long long int64_t; + +typedef long uintptr_t; + +#endif + +/* Boolean type. */ +typedef uint8_t SATBOOL; + +/* Unsigned integer type */ +typedef uint8_t SATUINT8_t; +typedef uint16_t SATUINT16_t; +typedef uint32_t SATUINT32_t; +#ifdef INC_STDINT_H +typedef uint64_t SATUINT64_t; +#else +#ifndef NO64BITINT +typedef uint64_t SATUINT64_t; +#endif +#endif + +/* Integer type */ +typedef int8_t SATINT8_t; +typedef int16_t SATINT16_t; +typedef int32_t SATINT32_t; +#ifdef INC_STDINT_H +typedef int64_t SATINT64_t; +#else +#ifndef NO64BITINT +typedef int64_t SATINT64_t; +#endif +#endif + +typedef uintptr_t SATUINTPTR_t; + +/* Major cipher key/SSP type. */ +/* ----- ------ ------- ----- */ +typedef uint8_t SATSSPTYPE; +typedef SATSSPTYPE * SATSSPTYPEPTR; + + +/* Asymmetric Ciphers */ +/* ---------- ------- */ + +/* Cipher type. */ +typedef uint8_t SATASYMTYPE; +typedef SATASYMTYPE * SATASYMTYPEPTR; + +/* Cipher size type. */ +typedef uint16_t SATASYMSIZE; +typedef SATASYMSIZE * SATASYMSIZEPTR; + +/* Cipher encoding */ +typedef uint8_t SATRSAENCTYPE; +typedef SATRSAENCTYPE * SATRSAENCTYPEPTR; + +/* DSA public/private key. */ +typedef struct { + uint16_t ui16PLen; /* Length of modulus p. */ + uint16_t ui16QLen; /* Length of prime divisor q. */ + uint32_t *pui32P; /* Prime modulus p. */ + uint32_t *pui32Q; /* Prime divisor q. */ + uint32_t *pui32G; /* Generator g, length==p. */ + uint32_t *pui32X; /* Private key x, length==p. */ + uint32_t *pui32Y; /* Private key y, length==q. */ +} SATASYMDSADOMAIN; +typedef SATASYMDSADOMAIN * SATASYMDSADOMAINPTR; + + +/* Symmetric Ciphers */ +/* --------- ------- */ + +/* Cipher type. */ +typedef uint8_t SATSYMTYPE; +typedef SATSYMTYPE * SATSYMTYPEPTR; + +/* Cipher key size type (in bits). */ +typedef uint16_t SATSYMKEYSIZE; +typedef SATSYMKEYSIZE * SATSYMKEYSIZEPTR; + +/* Cipher mode type. */ +typedef uint8_t SATSYMMODE; +typedef SATSYMMODE * SATSYMMODEPTR; + +/* Cipher key object. */ +/* Other fields are only valid when sstCipher!=SATSYMTYPE_NULL. */ +typedef struct { + SATSYMTYPE sstCipher; + SATSYMKEYSIZE ssksKeyLen; + uint32_t *pui32Key; +} SATSYMKEY; +typedef SATSYMKEY * SATSYMKEYPTR; + + +/* Hashes */ +/* ------ */ + +/* Hash type. */ +typedef uint8_t SATHASHTYPE; +typedef SATHASHTYPE * SATHASHTYPEPTR; + +/* Hash size type (in bits). */ +typedef uint16_t SATHASHSIZE; +typedef SATHASHSIZE * SATHASHSIZEPTR; + + +/* Context switching. */ +/* ----- ------ ------- ----- */ + +typedef uint32_t SATRESHANDLE; +typedef SATRESHANDLE * SATRESHANDLEPTR; + +typedef struct { + SATHASHTYPE sshashtype; + uint32_t uiRunLen; + uint32_t uiHash[MAXHASHLEN/32]; /* holds intermed hash */ +} SHACTX; + +typedef struct { + SATHASHTYPE sshashtype; + uint32_t uiRunLen; + uint32_t uiKeyLen; + uint32_t uiHash[MAXHASHLEN/32]; /* holds intermed hash */ + uint32_t uiKey[MAXHMACKEYLEN/32]; /* holds intermed key */ +} SHAHMACCTX; + +typedef struct { + uint8_t uiContextType; + union{ + SHACTX ctxSHA; + SHAHMACCTX ctxMAC; + }CTXUNION; +} SATRESCONTEXT; +typedef SATRESCONTEXT * SATRESCONTEXTPTR; + + +/* Message Authentication Codes */ +/* ------- -------------- ----- */ + +/* MAC type. */ +typedef uint8_t SATMACTYPE; +typedef SATMACTYPE * SATMACTYPEPTR; +typedef uint8_t SATMACTYPEFLAG; + + +/* Random Number Generator */ +/* ------ ------ --------- */ +typedef union { + uint32_t u32[4]; + uint8_t u8[16]; +} uint128_t; + +typedef struct { + uint128_t ui128V; + uint128_t ui128K[2]; + uint32_t uiReseedCnt; + uint32_t uiReseedLim; + uint32_t uiEntropyFactor; + SATSYMKEYSIZE eStrength; + SATBOOL bTesting; + +} DRBGCTX; + +typedef DRBGCTX * DRBGCTXPTR; + + +/* Function Return Code */ +/* -------- ------ ---- */ +typedef uint16_t SATR ; +typedef SATR * SATRPTR ; + + +/* Transfer Results */ +/* -------- ------- */ +typedef struct { + SATUINT32_t uiLen; + volatile SATUINT32_t* vpuiSrc; + void* pDest; +} SATDATATRF; + +typedef struct { + SATUINT32_t uiResType; + SATUINT32_t uiNumDataTrf; + SATDATATRF dtrfArray[CAL_MAXTRFS]; +} SATRESULT; + + +/* EC Ultra Structs */ +/* -- ----- ------- */ +typedef uint32_t SATECTYPE; + +typedef struct { + SATUINT32_t uiLen; + SATUINT32_t* puiX; + SATUINT32_t* puiY; +} SATECPOINT; + +typedef struct { + SATUINT32_t uiLen; + SATUINT32_t* puiMod; + SATUINT32_t* puiMontPrecompute; + SATUINT32_t* puiRSqd; +} SATECMONTMOD; + +typedef struct { + SATUINT32_t uiCurveSize; + SATECTYPE eCurveType; + SATECPOINT* pBasePoint; + SATECMONTMOD* pModP; + SATECMONTMOD* pModN; + SATUINT32_t* puiA; + SATUINT32_t* puiB; +} SATECCURVE; + +typedef struct { + SATUINT32_t uiLen; + SATUINT32_t* puiSigR; + SATUINT32_t* puiSigS; + SATUINT32_t* puiSigX; + SATUINT32_t* puiSigY; +} SATECDSASIG; + +typedef struct { + SATHASHSIZE sHashLen; + SATUINT32_t* puiHash; +} SATHASH; + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALTYPES_C +#ifdef __cplusplus +extern "C" { +#endif + +/* NOTE: this header file does not have an associated C file. */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/config_user.h b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/config_user.h new file mode 100755 index 0000000..3728565 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/config_user.h @@ -0,0 +1,44 @@ +/* ------------------------------------------------------------------- + $Rev: 727 $ $Date: 2017-10-20 16:50:53 -0400 (Fri, 20 Oct 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + + User configuration file to include/exclude CAL components. + ------------------------------------------------------------------- */ + +#ifndef CALCONFIG_F5200_H +#define CALCONFIG_F5200_H + +#include "x52cfg_user.h" +#include + +extern uint32_t g_user_crypto_base_addr; + +#define SAT_LITTLE_ENDIAN 1 +#define PKX0_BASE (g_user_crypto_base_addr) +#define USEPKX 1 +#define USEAESPKX 1 +#define USESHAPKX 1 +#define USEDRBGPKX 1 +#define USENRBGPKX 1 +#define USECALCTX 1 + +#endif diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/drbg.h b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/drbg.h new file mode 100755 index 0000000..dba16f7 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/drbg.h @@ -0,0 +1,91 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for DRBG functions for CAL + ------------------------------------------------------------------- */ + +#ifndef DRBG_H +#define DRBG_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ +#define CALDRBGENTROPYFACTOR 2 + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef DRBG_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALDRBGInstantiate(const SATUINT32_t *puiNonce, + SATUINT32_t uiNonceLen, const SATUINT32_t *puiPzStr, + SATUINT32_t uiPzStrLen, SATSYMKEYSIZE eStrength, + SATUINT32_t uiEntropyFactor, SATUINT32_t uiReseedLim, SATBOOL bTesting); + +extern SATR CALDRBGReseed(const SATUINT32_t *puiAddIn, SATUINT32_t uiAddInLen); + +extern SATR CALDRBGGenerate(const SATUINT32_t *puiAddIn, SATUINT32_t uiAddInLen, + SATBOOL bPredResist, SATUINT32_t *puiOut, SATUINT32_t uiOutBlocks); + +extern SATR CALDRBGUninstantiate(void); + +extern SATR CALDRBGGetCtx(DRBGCTXPTR drbgCtxExt); + +extern SATR CALDRBGLoadCtx(DRBGCTXPTR drbgCtxExt); + +extern SATR CALDRBGGetbInst(void); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +extern SATR CALDrbgTrfRes(SATBOOL bBlock); + +extern void CALDrbgIni(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/drbgf5200.h b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/drbgf5200.h new file mode 100755 index 0000000..d7f6c4c --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/drbgf5200.h @@ -0,0 +1,120 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for F5200 DRBG function hardware implementations + in CAL. + ------------------------------------------------------------------- */ + +#ifndef DRBGF5200_H +#define DRBGF5200_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ +#define RNXEFACTOR (X52BER+2) +#define RNXIRLEN (X52BER+2) +#define RNXKEYORD (X52BER+3) +#define RNXRESPRED (X52BER+4) +#define RNXTESTSEL (X52BER+5) +#define RNXBADDIN (X52BER+6) +#define RNXPPSTR (X52BER+7) +#define RNXPCTX (X52BER+8) +#define RNXPRENT (X52BER+13) +#define RNXITMP3 (X52BER+20) +#define RNXPCTX2 (X52BER+22) +/* These use same locs as tb generator, but can change */ +#define RNXRDATA (X52BER_ENDIAN+0x24) +#define RNXAIDATAOFF 0x0062 +#define RNXAIDATA (X52BER_ENDIAN+RNXAIDATAOFF) +#define RNXCTXOFF 0x0094 +#define RNXCTX (X52FPR+RNXCTXOFF) +#define RNXCTXV (X52FPR_ENDIAN+RNXCTXOFF+6) +#define RNXCTXVMMR (X52MMR_ENDIAN+RNXCTXOFF+6) +#define RNXTESTENT (X52TSR_ENDIAN+8) + +#define RNXCTXWORDS 18 +#define RNXBLENLOC (RNXCTX+RNXCTXWORDS) +#define RNXBOUTLENLOC (RNXCTX+RNXCTXWORDS+1) + +#define RNXMAXTESTENT32 512 +#define CALDRBGMAXADDINLEN X52_BER_LEN-RNXAIDATAOFF-4 +#define CALDRBGMAXPSNONCELEN X52_BER_LEN-RNXAIDATAOFF-4 + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef DRBGF5200_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATR drbgf5200Ini(void); + +extern SATR drbgf5200TrfRes(SATBOOL bBlock); + +extern SATR drbgf5200instantiate(const SATUINT32_t *puiNonce, + SATUINT32_t uiNonceLen, const SATUINT32_t *puiPzStr, SATUINT32_t uiPzStrLen, + SATSYMKEYSIZE eStrength, SATUINT32_t uiEntropyFactor, + SATUINT32_t uiReseedLim, SATBOOL bTesting); + +extern SATR drbgf5200reseed(const SATUINT32_t *puiAddIn, + SATUINT32_t uiAddInLen); + +extern SATR drbgf5200generate(const SATUINT32_t *puiAddIn, + SATUINT32_t uiAddInLen, SATBOOL bPredResist, SATUINT32_t uiReqLen, + SATUINT32_t *puiOut); + +extern SATR drbgf5200uninstantiate(void); + +extern SATR drbgf5200getctx(DRBGCTXPTR drbgCtxExt); + +extern SATR drbgf5200loadctx(DRBGCTXPTR drbgCtxExt); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/hash.h b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/hash.h new file mode 100755 index 0000000..f3fd6d4 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/hash.h @@ -0,0 +1,102 @@ +/* ------------------------------------------------------------------- + $Rev: 1293 $ $Date: 2017-07-27 14:09:14 -0400 (Thu, 27 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL hash functions. + ------------------------------------------------------------------- */ + +#ifndef HASH_H +#define HASH_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ +extern const SATHASHSIZE uiHashWordLen[SATHASHTYPE_LAST]; + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef HASH_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALHash(SATHASHTYPE eHashType, const void *pMsg, + SATUINT32_t uiMsgLen, void *pHash); + +extern SATR CALHashDMA(SATHASHTYPE eHashType, const void *pMsg, + SATUINT32_t uiMsgLen, void *pHash, SATUINT32_t uiDMAChConfig); + +extern SATR CALHashCtx(const SATRESHANDLE hResource, + const SATRESCONTEXTPTR pContext, const void *pMsg, SATUINT32_t uiMsgLen, + void *pHash, const SATBOOL bFinal); + +extern SATR CALHashCtxIni(const SATRESCONTEXTPTR pContext, + const SATHASHTYPE eHashType); + +extern SATR CALHashIni(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen); + +extern SATR CALHashWrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR CALHashRead(void *pHash); + +extern SATR CALKeyTree(SATBOOL bPathSizeSel, const SATUINT32_t* puiKey, + SATUINT8_t uiOpType, const SATUINT32_t* puiPath, SATUINT32_t* puiKeyOut); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATUINT32_t iGetHashLen(SATHASHTYPE eHashType); + +extern SATUINT32_t iGetBlockLen(SATHASHTYPE eHashType); + +extern SATR CALHashCtxLoad(const SATRESHANDLE hResource, + SATRESCONTEXTPTR const pContext, SATUINT32_t uiRunLen); + +extern SATUINT32_t iGetRunLen(SATRESCONTEXTPTR const pContext); + +extern SATR CALHashTypeIni(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/mac.h b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/mac.h new file mode 100755 index 0000000..acdc767 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/mac.h @@ -0,0 +1,95 @@ +/* ------------------------------------------------------------------- + $Rev: 1296 $ $Date: 2017-08-01 13:54:48 -0400 (Tue, 01 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL MAC functions. + ------------------------------------------------------------------- */ + +#ifndef MAC_H +#define MAC_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef MAC_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALMAC(SATMACTYPE eMACType, const SATUINT32_t *pKey, SATUINT32_t uiKeyLen, + const void *pMsg, SATUINT32_t uiMsgLen, void *pMAC); + +extern SATR CALMACDMA(SATMACTYPE eMACType, const SATUINT32_t *pKey, + SATUINT32_t uiKeyLen, const void *pMsg, SATUINT32_t uiMsgLen, + const void *pMAC, SATUINT32_t uiDMAChConfig); + +extern SATR CALMACIni(SATMACTYPE eMACType, const SATUINT32_t *pKey, + SATUINT32_t uiKeyLen, SATUINT32_t uiMsgLen); + +extern SATR CALMACCtx(const SATRESHANDLE hResource, + const SATRESCONTEXTPTR pContext, const void *pMsg, SATUINT32_t uiMsgLen, + void *pHash, const SATUINT8_t uiFlag); + +extern SATR CALMACCtxIni(const SATRESCONTEXTPTR pContext, const SATHASHTYPE eHashType, + const SATUINT32_t *pKey, SATUINT32_t uiKeyLen); + +extern SATR CALMACWrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR CALMACRead(void *pMAC); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATUINT32_t iGetMACKeyLen(SATMACTYPE eMACType); + +extern SATR CALMACCtxLoad(const SATRESHANDLE hResource, + SATRESCONTEXTPTR const pContext, SATUINT32_t uiRunLen); + +extern SATUINT32_t iGetMACRunLen(SATRESCONTEXTPTR const pContext); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/miv-rv32i-user-crypto-lib.a b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/miv-rv32i-user-crypto-lib.a new file mode 100755 index 0000000..5fda638 Binary files /dev/null and b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/miv-rv32i-user-crypto-lib.a differ diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/miv-rv32imc-user-crypto-lib.a b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/miv-rv32imc-user-crypto-lib.a new file mode 100755 index 0000000..ee7bcf4 Binary files /dev/null and b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/miv-rv32imc-user-crypto-lib.a differ diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/nrbg.h b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/nrbg.h new file mode 100755 index 0000000..d517065 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/nrbg.h @@ -0,0 +1,83 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for NRBG functions for CAL. + ------------------------------------------------------------------- */ + +#ifndef NRBG_H +#define NRBG_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef NRBG_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALNRBGSetTestEntropy(SATUINT32_t * puiEntropy, + SATUINT32_t uiEntLen32); + +extern SATR CALNRBGGetEntropy(SATUINT32_t * puiEntropy, SATUINT32_t uiEntLen32, + SATBOOL bTesting); + +extern SATR CALNRBGConfig(SATUINT32_t uiWriteEn, SATUINT32_t uiCSR, + SATUINT32_t uiCntLim, SATUINT32_t uiVoTimer, SATUINT32_t uiFMsk, + SATUINT32_t* puiStatus); + +extern SATUINT32_t CALNRBGHealthStatus(void); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATUINT32_t CALNRBGGetTestEntLen(void); + +extern SATR nrbgpkxgetentropy(SATUINT32_t * puiEntropy, + SATUINT32_t uiEntLen32); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/pk.h b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/pk.h new file mode 100755 index 0000000..5983d9a --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/pk.h @@ -0,0 +1,302 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for for CAL PK. + ------------------------------------------------------------------- */ + +#ifndef PK_H +#define PK_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef PK_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALPKTrfRes(SATBOOL bBlock); + +extern SATR CALDSASign(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALDSASignCM(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALDSASignHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, const SATUINT32_t* puiK, + const SATUINT32_t* puiX, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, SATUINT32_t uiN, + SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALDSASignHashCM(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, const SATUINT32_t* puiK, + const SATUINT32_t* puiX, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, SATUINT32_t uiN, + SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALDSAVerify(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiY, const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, + const SATUINT32_t* puiQMu, SATUINT32_t uiN, SATUINT32_t uiL); + +extern SATR CALDSAVerifyHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, const SATUINT32_t* puiY, + const SATUINT32_t* puiR, const SATUINT32_t* puiS, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALECDHC(const SATUINT32_t* puiS, const SATUINT32_t* puiWx, + const SATUINT32_t* puiWy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t* puiK, const SATUINT32_t* puiR, + const SATUINT32_t* puiRMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiZ); + +extern SATR CALECDSASign(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALECDSASignTwist(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALECDSASignCM(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALECDSASignTwistCM(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALECDSASignHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiK, const SATUINT32_t* puiD, const SATUINT32_t* puiB, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSASignHashCM(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiK, const SATUINT32_t* puiD, const SATUINT32_t* puiB, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSASignTwistHash(const SATUINT32_t* puiMsg, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSAVerify(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS,const + SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress); + +extern SATR CALECDSAVerifyTwist(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALECDSAVerifyHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSAVerifyTwistHash(const SATUINT32_t* puiMsg, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALECMult(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECMultCM(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t* puiN, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress, SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECMultTwist(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiLen, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECMultTwistCM(const SATUINT32_t* puiMul, + const SATUINT32_t* puiPx, const SATUINT32_t* puiPy, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiMod,const SATUINT32_t* puiMu, + const SATUINT32_t* puiN, SATUINT32_t uiLen, SATUINT32_t* puiRx, + SATUINT32_t* puiRy); + +extern SATR CALECMultAdd(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiB, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen, SATUINT32_t uiPtPCompress, SATUINT32_t uiPtQCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECPtValidate(const SATUINT32_t* puiPx, const SATUINT32_t* puiPy, + const SATUINT32_t* puiB, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen); + +extern SATR CALECKeyPairGen(const SATUINT32_t* puiC, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + const SATUINT32_t* puiNM1, const SATUINT32_t* puiNM1Mu, const SATUINT32_t* puiB, + SATUINT32_t* puiD, SATUINT32_t* puiQx, SATUINT32_t* puiQy, SATUINT32_t uiLen); + +extern SATR CALExpo(const SATUINT32_t* puiBase, const SATUINT32_t* puiExpo, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALExpoCM(const SATUINT32_t* puiBase, const SATUINT32_t* puiExpo, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALMMult(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALMMultAdd(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiC, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALModRed(const SATUINT32_t* puiA, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiALen, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPreCompute(const SATUINT32_t* puiMod, SATUINT32_t* puiMu, + SATUINT32_t uiModLen); + +extern SATR CALRSACRT(const SATUINT32_t* puiCipher, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ,const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiLen, SATUINT32_t* puiPlain); + +extern SATR CALRSACRTCM(const SATUINT32_t* puiCipher, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t * puiE, const SATUINT32_t* puiP, + const SATUINT32_t* puiQ, const SATUINT32_t * puiN, + const SATUINT32_t * puiNMu, SATUINT32_t uiLen, SATUINT32_t uiELen, + SATUINT32_t* puiPlain); + +extern SATR CALRSACRTSign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + const SATUINT32_t* puiN, SATUINT32_t uiLen, SATUINT32_t* puiSig); + +extern SATR CALRSACRTSignCM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, const SATUINT32_t* puiQ, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSig); + +extern SATR CALRSACRTSignHash(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ,const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + const SATUINT32_t* puiN, SATUINT32_t uiMsgLen, SATUINT32_t uiModLen, + SATUINT32_t* puiSig, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALRSACRTSignHashCM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, const SATUINT32_t* puiQ, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, SATUINT32_t* puiSig, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALRSASign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiD, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, SATUINT32_t* puiSig); + +extern SATR CALRSASignHash(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiD, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, SATUINT32_t uiModLen, + SATUINT32_t* puiSig, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALRSAVerify(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, + const SATUINT32_t* puiSig); + +extern SATR CALRSAVerifyHash(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiE, SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, const SATUINT32_t* puiSig, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPurge52(SATBOOL bVerify); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/pkx.h b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/pkx.h new file mode 100755 index 0000000..c23dda4 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/pkx.h @@ -0,0 +1,409 @@ +/* ------------------------------------------------------------------- + $Rev: 1298 $ $Date: 2017-08-04 13:04:19 -0400 (Fri, 04 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for for CAL PK. + ------------------------------------------------------------------- */ + +#ifndef PKX_H +#define PKX_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* X5200 Addressing */ +#define X52BER ((volatile SATUINT32_t *) (PKX0_BASE + 0x00000000u)) +#define X52MMR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00001000u)) +#define X52TSR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00002000u)) +#define X52FPR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00003000u)) +#define X52LIR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00004000u)) +#define X52CSR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00007F80u)) +#define X52CSRMERRS ((volatile SATUINT32_t *) (PKX0_BASE + 0x00007F8Cu)) +#define X52CSRMERRT0 ((volatile SATUINT32_t *) (PKX0_BASE + 0x00007F94u)) + +#if SAT_LITTLE_ENDIAN +#define X52BER_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00008000u)) +#define X52MMR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00009000u)) +#define X52TSR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x0000A000u)) +#define X52FPR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x0000B000u)) +#define X52DMACONFIG_ENDIAN 0x8 +#else +#define X52BER_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00000000u)) +#define X52MMR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00001000u)) +#define X52TSR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00002000u)) +#define X52FPR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00003000u)) +#define X52DMACONFIG_ENDIAN 0x0 +#endif + +/* X5200 Macros */ +#define X52GO(x) (0x10 | ((x)<<8)) + +/* Counter Measures */ +#define RANDLEN 4 + +/* X5200 CSRMAIN bit field masks. */ +#define X52CSRMAINRST 1 +#define X52CSRMAINCCMPLT 2 +#define X52CSRMAINCMPLT 4 +#define X52CSRMAINBUSY 8 +#define X52CSRMAINGO 0x10 +#define X52CSRMAINPURGE 0x20 +#define X52CSRMAINECDIS 0x40 +#define X52CSRMAINALARM 0x80 +#define X52CSRMAINLIRA ((0xFFF) << 8) +#define X52CSRMERRSSEC ((0x2) << 24) +#define X52CSRMERRSA 0x1FFF + +/* Address pointers for ROM'd P-curve moduli */ +#define P192_MOD (&uiROMMods[0]) +#define P224_MOD (&uiROMMods[1]) +#define P256_MOD (&uiROMMods[2]) +#define P384_MOD (&uiROMMods[3]) +#define P521_MOD (&uiROMMods[4]) + +/* X5200 Addressing Flags */ +#define X52BYTEREVERSE_FLAG 1 +#define X52WORDREVERSE_FLAG 2 +#define X52BYTEREVERSE 0x00002000 +#define X52WORDREVERSE 0x00004000 +#define X52ADDRESSRANGE 0x2000 + +/* X5200 DMA channel configuration constants. */ +#define X52CCR_DEFAULT 0 /* BSIZE=auto, ESWP=none, PROT=user, INC=inc */ +#define X52CCR_BSIZEAUTO 0 /* BSIZE=auto */ +#define X52CCR_BSIZEBYTE 0x10 /* BSIZE=byte */ +#define X52CCR_BSIZEHWORD 0x20 /* BSIZE=half word */ +#define X52CCR_BSIZEWORD 0x30 /* BSIZE=word */ +#define X52CCR_ESWPNONE 0 /* ESWP=none */ +#define X52CCR_ESWPWORD 0x8 /* ESWP=swap bytes in word [0123]->[3210] */ +#define X52CCR_PROTUSER 0 /* PROT=user */ +#define X52CCR_PROTPRIV 0x2 /* PROT=priv */ +#define X52CCR_INCADDR 0 /* INC=inc */ +#define X52CCR_NOINCADDR 0x1 /* INC=non-inc */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef PKX_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern void CALPKXIni(void); + +extern void CALPKMem32Load(volatile SATUINT32_t * puiDst, + const SATUINT32_t * puiSrc, SATUINT32_t uiNum ); + +extern SATR CALPKXTrfRes(SATBOOL bBlock); + +extern SATR CALPKXPreCompute(const SATUINT32_t* puiMod, SATUINT32_t* puiMu, + SATUINT32_t uiModLen); + +extern SATR CALPKXExpo(const SATUINT32_t* puiBase, const SATUINT32_t* puiExpo, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALPKXExpoCM(const SATUINT32_t* puiBase, + const SATUINT32_t* puiExpo, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPKXDSASign(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXDSASignCM(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXDSASHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATUINT32_t uiDMAChConfig, const SATBOOL bCM); + +extern SATR CALPKXDSAVerify(const SATUINT32_t *puiHash, + const SATUINT32_t *puiG, const SATUINT32_t *puiY, + const SATUINT32_t *puiSigR, const SATUINT32_t *puiSigS, + const SATUINT32_t *puiP, const SATUINT32_t *puiPMu, + const SATUINT32_t *puiQ, const SATUINT32_t *puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL); + +extern SATR CALPKXDSAVHDMA(const SATUINT32_t *puiExtInput, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t *puiG, const SATUINT32_t *puiY, + const SATUINT32_t *puiSigR, const SATUINT32_t *puiSigS, + const SATUINT32_t *puiP, const SATUINT32_t *puiPMu, const SATUINT32_t *puiQ, + const SATUINT32_t *puiQMu, SATUINT32_t uiN, SATUINT32_t uiL, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXModRed(const SATUINT32_t* puiA, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiALen, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPKXMMult(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPKXMMultAdd(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiC, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALPKXECMult(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECMultTwist(const SATUINT32_t* puiMul, + const SATUINT32_t* puiPx,const SATUINT32_t* puiPy, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen, SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECMultCM(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t * puiN, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress, SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECMultTwistCM(const SATUINT32_t* puiMul, + const SATUINT32_t* puiPx, const SATUINT32_t* puiPy, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + const SATUINT32_t * puiN, SATUINT32_t uiLen, SATUINT32_t* puiRx, + SATUINT32_t* puiRy); + +extern SATR CALPKXECMultAdd(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiB, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen, SATUINT32_t uiPtPCompress, SATUINT32_t uiPtQCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECDSASign(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASignTwist(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx,const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASignCM(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASignTwistCM(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASH(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + const SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASHCM(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + const SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, SATUINT32_t uiDMAChConfig, + const SATBOOL bCM); + +extern SATR CALPKXECDSASTwistH(const SATUINT32_t* puiHash, + const SATHASHTYPE eHashType, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiK, const SATUINT32_t* puiD, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, const SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASTwistHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECDSAVerify(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVerifyTwist(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVH(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB,const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + const SATUINT32_t uiLen, const SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB,const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECDSAVTwistH(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, const SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVTwistHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECDHC(const SATUINT32_t* puiS, const SATUINT32_t* puiWx, + const SATUINT32_t* puiWy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t* puiK, const SATUINT32_t* puiR, + const SATUINT32_t* puiRMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiZ); + +extern SATR CALPKXRSACRT(const SATUINT32_t* puiCipher, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, SATUINT32_t uiLen, + SATUINT32_t* puiPlain); + +extern SATR CALPKXRSACRTCM(const SATUINT32_t* puiCipher, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiE, + const SATUINT32_t* puiP, const SATUINT32_t* puiQ, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, const SATUINT32_t uiLen, const SATUINT32_t uiELen, + SATUINT32_t* puiPlain); + +extern SATR CALPKXRSACRTSign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiCipher, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, + const SATUINT32_t* puiQMu, const SATUINT32_t* puiN, SATUINT32_t uiLen, + SATUINT32_t* puiS); + +extern SATR CALPKXRSACRTSignCM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, + const SATUINT32_t* puiP, const SATUINT32_t* puiQ, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSig); + +extern SATR CALPKXRSACRTSHDMA(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + const SATUINT32_t* puiN, SATUINT32_t uiMsgLen, SATUINT32_t uiModLen, + SATUINT32_t* puiSig, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXRSACRTSHDMACM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, + const SATUINT32_t* puiP, const SATUINT32_t* puiQ, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, SATUINT32_t uiLen, + SATUINT32_t* puiSig, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXRSASign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiD, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, SATUINT32_t* puiSig); + +extern SATR CALPKXRSASHDMA(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiD, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, SATUINT32_t* puiSig, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXRSAVerify(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, + const SATUINT32_t* puiS); + +extern SATR CALPKXRSAVHDMA(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiE,SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, const SATUINT32_t* puiS, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECPtValidate(const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiLen); + +extern SATR CALPKXECKeyPairGen(const SATUINT32_t* puiC, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + const SATUINT32_t* puiNM1, const SATUINT32_t* puiNM1Mu, const SATUINT32_t* puiB, + SATUINT32_t* puiD, SATUINT32_t* puiQx, SATUINT32_t* puiQy, SATUINT32_t uiLen); + +extern SATR CALPKXPurge52(SATBOOL bVerify); + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ +extern SATRESULT SATResults; + +/* -------- ------ --------- */ +/* External Global Constants */ +/* -------- ------ --------- */ +extern const SATUINT32_t uiROMMods[]; + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/pkxlib.h b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/pkxlib.h new file mode 100755 index 0000000..fb4c0fc --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/pkxlib.h @@ -0,0 +1,95 @@ +/* ------------------------------------------------------------------- + $Rev: 1434 $ $Date: 2017-10-20 16:46:16 -0400 (Fri, 20 Oct 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for PKX-5200 Library. + ------------------------------------------------------------------- */ + +#ifndef PKXLIB_H +#define PKXLIB_H + +#include "caltypes.h" +#include "calpolicy.h" + +#define PKX_JMP_NONE (0xFFFFu + PKX_OFFSET) + +/* jump table entry points: starting PC value */ +#define PKX_JMP_RECIP_PRECOMPUTE (0x0000 + PKX_OFFSET) +#define PKX_JMP_MOD_EXP (0x0002 + PKX_OFFSET) +#define PKX_JMP_RSA_CRT (0x0004 + PKX_OFFSET) +#define PKX_JMP_EC_PTMUL (0x0006 + PKX_OFFSET) +#define PKX_JMP_EC_DSA_SIGN (0x0008 + PKX_OFFSET) +#define PKX_JMP_EC_DSA_VERIFY (0x000A + PKX_OFFSET) +#define PKX_JMP_DSA_SIGN (0x000C + PKX_OFFSET) +#define PKX_JMP_DSA_VERIFY (0x000E + PKX_OFFSET) +#define PKX_JMP_MOD_MULT (0x0010 + PKX_OFFSET) +#define PKX_JMP_MOD_RED (0x0012 + PKX_OFFSET) +#define PKX_JMP_EC_PTDECOMP (0x0014 + PKX_OFFSET) +#define PKX_JMP_EC_DHC (0x0016 + PKX_OFFSET) +#define PKX_JMP_MOD_MULT_ADD (0x0018 + PKX_OFFSET) +#define PKX_JMP_EC_PTMUL_ADD (0x001A + PKX_OFFSET) +#define PKX_JMP_EC_PTVALIDATE (0x001C + PKX_OFFSET) +#define PKX_JMP_F5200_SHA (0x001E + PKX_OFFSET) +#define PKX_JMP_F5200_AES (0x0020 + PKX_OFFSET) +#define PKX_JMP_F5200_AESK (0x0022 + PKX_OFFSET) +#define PKX_JMP_F5200_GCM (0x0024 + PKX_OFFSET) +#define PKX_JMP_F5200_GHA (0x0026 + PKX_OFFSET) +#define PKX_JMP_F5200_AESKW (0x0028 + PKX_OFFSET) +#define PKX_JMP_F5200_AESKWP (0x002A + PKX_OFFSET) +#define PKX_JMP_RNG_INSTANTIATE (0x002C + PKX_OFFSET) +#define PKX_JMP_RNG_RESEED (0x002E + PKX_OFFSET) +#define PKX_JMP_RNG_GENERATE (0x0030 + PKX_OFFSET) +#define PKX_JMP_RNG_UNINSTANTIATE (0x0032 + PKX_OFFSET) +#define PKX_JMP_RNG_GETENTROPY (0x0034 + PKX_OFFSET) +#define PKX_JMP_F5200_SHA_HMAC (0x0036 + PKX_OFFSET) +#define PKX_JMP_F5200_AES_DMA (0x0038 + PKX_OFFSET) +#define PKX_JMP_RNG_CTRLSTATUS (0x003A + PKX_OFFSET) +#define PKX_JMP_F5200_SHA_DMA (0x003C + PKX_OFFSET) +#define PKX_JMP_SHX_KEYTREE (0x003E + PKX_OFFSET) +#define PKX_JMP_PKX_DSA_DMA (0x0040 + PKX_OFFSET) +#define PKX_JMP_PKX_RSACRT_SIGN (0x0042 + PKX_OFFSET) +#define PKX_JMP_PKX_RSA_SIGN (0x0044 + PKX_OFFSET) +#define PKX_JMP_PKX_RSA_VERIFY (0x0046 + PKX_OFFSET) +#define PKX_JMP_PKX_EC_DSA_DMA (0x0048 + PKX_OFFSET) +#define PKX_JMP_F5200_AES_KEYROLL (0x004A + PKX_OFFSET) +#define PKX_JMP_EXPM (0x004C + PKX_OFFSET) +#define PKX_JMP_RSACRTM (0x004E + PKX_OFFSET) +#define PKX_JMP_EC_PTMULM (0x0050 + PKX_OFFSET) +#define PKX_JMP_DSA_SIGN_M (0x0052 + PKX_OFFSET) +#define PKX_JMP_EC_DSA_SIGN_M (0x0054 + PKX_OFFSET) +#define PKX_JMP_EC_KEYPAIRGEN (0x0056 + PKX_OFFSET) +#define PKX_JMP_RSACRTCM_SIGN (0x0058 + PKX_OFFSET) +#define PKX_JMP_F5200_GCM_NEW (0x005A + PKX_OFFSET) +/* PKX PKRev 2180 */ +/* PKX SHARev 2160 */ +/* PKX AESRev 2135 */ +/* Hex Checksum: 0xd0d79866 */ + +extern const SATUINT32_t uiPKX_Flags; +extern const SATUINT32_t uiPKX_BERWords; +extern const SATUINT32_t uiPKX_LIRWords; +extern const SATUINT32_t uiPKX_Rev; +extern const SATUINT32_t uiPKX_LibSize; +extern const SATUINT32_t uiPKX_LibChksum; +extern const SATUINT32_t uiPKX_Lib[]; +extern SATBOOL bMPF300TS_ES; + +#endif diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/shaf5200.h b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/shaf5200.h new file mode 100755 index 0000000..da598d1 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/shaf5200.h @@ -0,0 +1,101 @@ +/* ------------------------------------------------------------------- + $Rev: 1296 $ $Date: 2017-08-01 13:54:48 -0400 (Tue, 01 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for SHA function hardware implementation for CAL. + ------------------------------------------------------------------- */ + +#ifndef SHAF5200_H +#define SHAF5200_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef SHAF5200_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATR shapkxctx(SATRESCONTEXTPTR const pContext, const void *pBuffer, + SATUINT32_t uiBufLen,void *pHash, const SATBOOL bFinal); + +extern SATR shapkxhmacctx(SATRESCONTEXTPTR const pContext, const void *pBuffer, + SATUINT32_t uiBufLen, void *pHash, const SATUINT8_t uiFlag); + +extern SATR shapkxctxload(SATRESCONTEXTPTR const pContext); + +extern void shapkxctxunload(SATRESCONTEXTPTR const pContext); + +extern SATR shapkxini(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen); + +extern SATR shapkxhmacini(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, + const void *pKey, SATUINT32_t uiKeyLen); + +extern SATR shapkxwrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR shapkxhmacwrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR shapkxread(void *pHash, SATUINT32_t uiRevFlag); + +extern SATR shapkxkeytree(SATBOOL bPathSizeSel, const SATUINT32_t* puiKey, + SATUINT8_t uiOpType, const SATUINT32_t* puiPath, SATUINT32_t* puiKeyOut); + +extern SATR shapkxdma(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, + const void *pExtSrc, const void *pExtDest, SATUINT32_t uiDMAChConfig); + +extern SATR shapkxhmacdma(SATMACTYPE eMACType, const SATUINT32_t *pKey, + SATUINT32_t uiKeyLen, const void *pMsg, SATUINT32_t uiMsgLen, + const void *pMAC, SATUINT32_t uiDMAChConfig); + +extern SATR shapkxhashtypeini(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/sym.h b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/sym.h new file mode 100755 index 0000000..2e07faa --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/sym.h @@ -0,0 +1,129 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for Symmetric Key Cryptography in CAL. + ------------------------------------------------------------------- */ + +#ifndef SYM_H +#define SYM_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef SYM_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALSymTrfRes(SATBOOL bBlock); + +extern SATR CALSymEncrypt(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen); + +extern SATR CALSymDecrypt(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen); + +extern SATR CALSymEncryptDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymDecryptDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymEncryptKR(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF); + +extern SATR CALSymDecryptKR(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF); + +extern SATR CALSymEncryptKRDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymDecryptKRDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymEncAuth(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen); + +extern SATR CALSymDecVerify(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen); + +extern SATR CALSymKw(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR CALSymKwp(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR CALSymEncAuthDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymDecVerifyDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen, SATUINT32_t uiDMAChConfig); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/utils.h b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/utils.h new file mode 100755 index 0000000..91474f0 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/utils.h @@ -0,0 +1,93 @@ +/* ------------------------------------------------------------------- + $Rev: 1300 $ $Date: 2017-08-07 11:36:02 -0400 (Mon, 07 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL utility functions. + ------------------------------------------------------------------- */ + +#ifndef UTILS_H +#define UTILS_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef UTILS_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern void CALMemCopy(void *pDst, const void *pSrc, SATUINT32_t uiNum8); + +extern void CALMemClear( void * pLoc, SATUINT32_t uiNum ); + +extern void CALMemClear32( SATUINT32_t* puiLoc, SATUINT32_t uiLen32 ); + +extern SATBOOL CALMemCmp(const void *pA, const void *pB, SATUINT32_t uiNum); + +extern void CALVol32MemLoad(volatile SATUINT32_t * puiDst, const void * pSrc, + SATUINT32_t uiNum32); + +extern void CALVol32MemRead(void * pDst, volatile SATUINT32_t * puiSrc, + SATUINT32_t uiNum32); + +extern void CALByteReverse(SATUINT32_t* puiArray, SATINT32_t iNumberBytes); + +extern void CALByteReverseWord(SATUINT32_t* puiArray, SATINT32_t iNumberWords); + +extern void CALWordReverse(SATUINT32_t *puiArray, SATINT32_t iNumberWords); + +extern void vAppendNonzero(void *puiArray, SATUINT32_t uiLen, + SATUINT32_t uiBlockSize); + +extern void vAppendZero(void *puiArray, SATUINT32_t uiLen, + SATUINT32_t uiBlockSize); + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/x52cfg_user.h b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/x52cfg_user.h new file mode 100755 index 0000000..c8d8648 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/middleware/cal/x52cfg_user.h @@ -0,0 +1,72 @@ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ +/* X5200 configuration */ +/* $Date: 2015-07-23 14:30:19 -0400 (Thu, 23 Jul 2015) $ $Rev: 2093 $ */ +/* ------------------------------------------------------------------- + Options: + * LIR ROM size : 4096 + * LIR RAM size : 2048 + * BER size : 1024 + * MMR size : 1024 + * TSR size : 1024 + * FPR size : 1024 + * Single error correct, dual error detect (SECDED) memory parity + * DMA enabled + * FPGA multipliers disabled + * AES enabled + - Fast key schedule generation + - GCM/GHASH enabled + - AES countermeasures enabled + * RNG enabled + * External PRNG disabled + * SHA enabled + - Fast SHA enabled + - SHA-1 enabled + - SHA-224 enabled + - SHA-256 enabled + - SHA-384 enabled + - SHA-512 enabled + - SHA-512/224 enabled + - SHA-512/256 enabled + - SHA countermeasures enabled + * P-curves populated in FCR: + - P-192 populated + - P-224 populated + - P-256 populated + - P-384 populated + - P-521 populated + * Data memory scrambling enabled + + ------------------------------------------------------------------- */ + +#ifndef X52CFG_H +#define X52CFG_H + +#define X52_CFG_MODEL 0xf5200 +#define X52_CFG_DATE 0x15072720 +#define X52_CFG_REV 0x0000082e +#define X52_CFG_OPT 0x0fd87ff9 +#define X52_CFG_OPT2 0xc0000000 +#define X52_LIR_LEN 0x1800 +#define X52_LIR_ROM_LEN 0x1000 +#define X52_LIR_RAM_LEN 0x0800 +#define X52_BER_LEN 0x400 +#define X52_MMR_LEN 0x400 +#define X52_TSR_LEN 0x400 +#define X52_FPR_LEN 0x400 + +#endif diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/README.md b/applications/user-crypto/miv-rv32-dsa-services/src/platform/README.md new file mode 100644 index 0000000..f7f6030 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/README.md @@ -0,0 +1,27 @@ +# Mi-V soft processor platform source code + +## Repo organization + +``` + + | + |-- drivers + | |- fpga_ip + | | | CoreGPIO + | | | CoreSysServices_PF + | | | CoreUARTapb + | | + | |- off_chip + | | | . + | | | . + | | + |-- hal + | | + |-- miv_rv32_hal + + +``` + +The drivers published here are compatible with the improved SoftConsole project folder structure being used in the latest [example projects](https://github.com/Mi-V-Soft-RISC-V/miv-rv32-bare-metal-examples). +These drivers can also be used with the legacy folder structure (projects released via Firmware Catalog) by defining the **LEGACY_DIR_STRUCTURE** macro in the SoftConsole project settings. + diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c new file mode 100644 index 0000000..1a0073f --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c @@ -0,0 +1,533 @@ +/******************************************************************************* + * (c) Copyright 2008-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file core_gpio.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreGPIO bare metal driver implementation. + * + */ +#include "coregpio_regs.h" +#include "core_gpio.h" + +/*-------------------------------------------------------------------------*//** + * + */ +#define GPIO_INT_ENABLE_MASK (uint32_t)0x00000008UL +#define OUTPUT_BUFFER_ENABLE_MASK 0x00000004UL + + +#define NB_OF_GPIO 32 + +#define CLEAR_ALL_IRQ32 (uint32_t)0xFFFFFFFF +#define CLEAR_ALL_IRQ16 (uint16_t)0xFFFF +#define CLEAR_ALL_IRQ8 (uint8_t)0xFF + +/*-------------------------------------------------------------------------*//** + * GPIO_init() + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_init +( + gpio_instance_t * this_gpio, + addr_t base_addr, + gpio_apb_width_t bus_width +) +{ + uint8_t i = 0; + addr_t cfg_reg_addr = base_addr; + + this_gpio->base_addr = base_addr; + this_gpio->apb_bus_width = bus_width; + + /* Clear configuration. */ + for( i = 0, cfg_reg_addr = base_addr; i < NB_OF_GPIO; ++i ) + { + HW_set_8bit_reg( cfg_reg_addr, 0 ); + cfg_reg_addr += 4; + } + /* Clear any pending interrupts */ + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, CLEAR_ALL_IRQ32 ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, (uint16_t)CLEAR_ALL_IRQ16 ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, (uint16_t)CLEAR_ALL_IRQ16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, (uint8_t)CLEAR_ALL_IRQ8 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_config + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_config +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint32_t config +) +{ + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + uint32_t cfg_reg_addr = this_gpio->base_addr; + cfg_reg_addr += (port_id * 4); + HW_set_32bit_reg( cfg_reg_addr, config ); + + /* + * Verify that the configuration was correctly written. Failure to read + * back the expected value may indicate that the GPIO port was configured + * as part of the hardware flow and cannot be modified through software. + * It may also indicate that the base address passed as parameter to + * GPIO_init() was incorrect. + */ + HAL_ASSERT( HW_get_32bit_reg( cfg_reg_addr ) == config ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_set_outputs + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_set_outputs +( + gpio_instance_t * this_gpio, + uint32_t value +) +{ + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, GPIO_OUT, value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, GPIO_OUT0, (uint16_t)value ); + HAL_set_16bit_reg( this_gpio->base_addr, GPIO_OUT1, (uint16_t)(value >> 16) ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT0, (uint8_t)value ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT1, (uint8_t)(value >> 8) ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT2, (uint8_t)(value >> 16) ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT3, (uint8_t)(value >> 24) ); + break; + + default: + HAL_ASSERT(0); + break; + } + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( GPIO_get_outputs( this_gpio ) == value ); +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_inputs + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_inputs +( + gpio_instance_t * this_gpio +) +{ + uint32_t gpio_in = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + gpio_in = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_IN ); + break; + + case GPIO_APB_16_BITS_BUS: + gpio_in |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_IN0 ); + gpio_in |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_IN1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + gpio_in |= HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN0 ); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN1 ) << 8); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN2 ) << 16); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return gpio_in; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_outputs + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_outputs +( + gpio_instance_t * this_gpio +) +{ + uint32_t gpio_out = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + gpio_out = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ); + break; + + case GPIO_APB_16_BITS_BUS: + gpio_out |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT0 ); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + gpio_out |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT0 ); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT1 ) << 8); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT2 ) << 16); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return gpio_out; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_set_output + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_set_output +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint8_t value +) +{ + HAL_ASSERT( port_id < NB_OF_GPIO ); + + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + { + uint32_t outputs_state; + + outputs_state = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ); + if ( 0 == value ) + { + outputs_state &= ~(1 << port_id); + } + else + { + outputs_state |= 1 << port_id; + } + HAL_set_32bit_reg( this_gpio->base_addr, GPIO_OUT, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ) == outputs_state ); + } + break; + + case GPIO_APB_16_BITS_BUS: + { + uint16_t outputs_state; + uint32_t gpio_out_reg_addr = this_gpio->base_addr + GPIO_OUT_REG_OFFSET + ((port_id >> 4) * 4); + + outputs_state = HW_get_16bit_reg( gpio_out_reg_addr ); + if ( 0 == value ) + { + outputs_state &= ~(1 << (port_id & 0x0F)); + } + else + { + outputs_state |= 1 << (port_id & 0x0F); + } + HW_set_16bit_reg( gpio_out_reg_addr, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HW_get_16bit_reg( gpio_out_reg_addr ) == outputs_state ); + } + break; + + case GPIO_APB_8_BITS_BUS: + { + uint8_t outputs_state; + uint32_t gpio_out_reg_addr = this_gpio->base_addr + GPIO_OUT_REG_OFFSET + ((port_id >> 3) * 4); + + outputs_state = HW_get_8bit_reg( gpio_out_reg_addr ); + if ( 0 == value ) + { + outputs_state &= ~(1 << (port_id & 0x07)); + } + else + { + outputs_state |= 1 << (port_id & 0x07); + } + HW_set_8bit_reg( gpio_out_reg_addr, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HW_get_8bit_reg( gpio_out_reg_addr ) == outputs_state ); + } + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_drive_inout + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_drive_inout +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + gpio_inout_state_t inout_state +) +{ + uint32_t config; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + switch( inout_state ) + { + case GPIO_DRIVE_HIGH: + /* Set output high */ + GPIO_set_output( this_gpio, port_id, 1 ); + + /* Enable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config |= OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + case GPIO_DRIVE_LOW: + /* Set output low */ + GPIO_set_output( this_gpio, port_id, 0 ); + + /* Enable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config |= OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + case GPIO_HIGH_Z: + /* Disable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config &= ~OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_enable_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_enable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t cfg_value; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + cfg_reg_addr += (port_id * 4); + cfg_value = HW_get_8bit_reg( cfg_reg_addr ); + cfg_value |= GPIO_INT_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, cfg_value ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_disable_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_disable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t cfg_value; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + cfg_reg_addr += (port_id * 4); + cfg_value = HW_get_8bit_reg( cfg_reg_addr ); + cfg_value &= ~GPIO_INT_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, cfg_value ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_clear_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_clear_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t irq_clr_value = ((uint32_t)1) << ((uint32_t)port_id); + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, irq_clr_value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, irq_clr_value >> 16 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, irq_clr_value >> 24 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_irq_sources + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_irq_sources +( + gpio_instance_t * this_gpio +) +{ + uint32_t intr_src = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + intr_src = HAL_get_32bit_reg( this_gpio->base_addr, IRQ ); + break; + + case GPIO_APB_16_BITS_BUS: + intr_src |= HAL_get_16bit_reg( this_gpio->base_addr, IRQ0 ); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + intr_src |= HAL_get_16bit_reg( this_gpio->base_addr, IRQ0 ); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ1 ) << 8); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ2 ) << 16); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return intr_src; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_clear_all_irq_sources + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_clear_all_irq_sources +( + gpio_instance_t * this_gpio, + uint32_t bitmask +) +{ + uint32_t irq_clr_value = bitmask; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, irq_clr_value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, irq_clr_value >> 16 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, irq_clr_value >> 24 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h new file mode 100644 index 0000000..88ba178 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h @@ -0,0 +1,722 @@ +/******************************************************************************* + * (c) Copyright 2008-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file core_gpio.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreGPIO bare metal driver public API. + * + */ + +/*=========================================================================*//** + @mainpage CoreGPIO Bare Metal Driver. + + @section intro_sec Introduction + The CoreGPIO hardware IP includes up to 32 general-purpose input/output GPIOs. + This driver provides a set of functions for controlling the GPIOs as part of a + bare-metal system where no operating system is available. These drivers + can be adapted for use as part of an operating system, but the implementation + of the adaptation layer between this driver and the operating system's driver + model is outside the scope of this driver. + + @section driver_configuration Driver Configuration + The individual IOs of CoreGPIO can be configured either in the hardware flow + or as part of the software application through calls to the GPIO_config() + function. GPIOs configured as part of the hardware are fixed and cannot be + modified using a call to the GPI_config() function. + + @section theory_op Theory of Operation + The CoreGPIO driver uses the Actel Hardware Abstraction Layer (HAL) to access + hardware registers. You must ensure that the Actel HAL is included as part of + your software project. The Actel HAL is available through the Actel Firmware + Catalog. + + The CoreGPIO driver functions are logically grouped into the following groups: + - Initialization + - Configuration + - Reading and writing GPIO state + - Interrupt control + + The CoreGPIO driver is initialized through a call to the GPIO_init() function. + The GPIO_init() function must be called before any other GPIO driver functions + can be called. + + Each GPIO port is individually configured through a call to the + GPIO_config() function. Configuration includes deciding if a GPIO port is + going to be used as input, output, or both. GPIO ports configured as inputs + are further configured to generate interrupts based on the state of input. + Interrupts is either level- or edge-sensitive. + Note that a CoreGPIO hardware instance is generated as part of the hardware + flow with a fixed configuration for some or all of its IOs. + Attempting to modify the configuration of such a hardware-configured IO using + the GPIO_config() function has no effect. + + The state of the GPIO ports can be read and written using the following + functions: + - GPIO_get_inputs() + - GPIO_get_outputs() + - GPIO_set_outputs() + - GPIO_drive_inout() + + Interrupts generated by GPIO ports configured as inputs are controlled using + the following functions: + - GPIO_enable_irq() + - GPIO_disable_irq() + - GPIO_clear_irq() + - GPIO_get_irq_sources() + - GPIO_clear_all_irq_sources() + + *//*=========================================================================*/ +#ifndef CORE_GPIO_H_ +#define CORE_GPIO_H_ + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + The gpio_id_t enumeration is used to identify GPIOs as part of the + parameter to functions: + - GPIO_config(), + - GPIO_drive_inout(), + - GPIO_enable_int(), + - GPIO_disable_int(), + - GPIO_clear_int() + */ +typedef enum __gpio_id_t +{ + GPIO_0 = 0, + GPIO_1 = 1, + GPIO_2 = 2, + GPIO_3 = 3, + GPIO_4 = 4, + GPIO_5 = 5, + GPIO_6 = 6, + GPIO_7 = 7, + GPIO_8 = 8, + GPIO_9 = 9, + GPIO_10 = 10, + GPIO_11 = 11, + GPIO_12 = 12, + GPIO_13 = 13, + GPIO_14 = 14, + GPIO_15 = 15, + GPIO_16 = 16, + GPIO_17 = 17, + GPIO_18 = 18, + GPIO_19 = 19, + GPIO_20 = 20, + GPIO_21 = 21, + GPIO_22 = 22, + GPIO_23 = 23, + GPIO_24 = 24, + GPIO_25 = 25, + GPIO_26 = 26, + GPIO_27 = 27, + GPIO_28 = 28, + GPIO_29 = 29, + GPIO_30 = 30, + GPIO_31 = 31 +} gpio_id_t; + +/*-------------------------------------------------------------------------*//** + Possible width of the APB bus + */ +typedef enum __gpio_apb_width_t +{ + GPIO_APB_8_BITS_BUS = 0, + GPIO_APB_16_BITS_BUS = 1, + GPIO_APB_32_BITS_BUS = 2, + GPIO_APB_UNKNOWN_BUS_WIDTH = 3 +} gpio_apb_width_t; + +/*-------------------------------------------------------------------------*//** + Structure instance holding all data regarding the CoreGPIO + */ +typedef struct __gpio_instance_t +{ + addr_t base_addr; + gpio_apb_width_t apb_bus_width; +} gpio_instance_t; + +/*-------------------------------------------------------------------------*//** + GPIO ports definitions used to identify GPIOs as part of the parameter to + function GPIO_set_outputs(). + These definitions are also be used to identity GPIO through logical operations + on the return value of function GPIO_get_inputs(). + # GPIO_0_MASK + # GPIO_1_MASK + # GPIO_2_MASK + # GPIO_3_MASK + # GPIO_4_MASK + # GPIO_5_MASK + # GPIO_6_MASK + # GPIO_7_MASK + # GPIO_8_MASK + # GPIO_9_MASK + # GPIO_10_MASK + # GPIO_11_MASK + # GPIO_12_MASK + # GPIO_13_MASK + # GPIO_14_MASK + # GPIO_15_MASK + # GPIO_16_MASK + # GPIO_17_MASK + # GPIO_18_MASK + # GPIO_19_MASK + # GPIO_20_MASK + # GPIO_21_MASK + # GPIO_22_MASK + # GPIO_23_MASK + # GPIO_24_MASK + # GPIO_25_MASK + # GPIO_26_MASK + # GPIO_27_MASK + # GPIO_28_MASK + # GPIO_29_MASK + # GPIO_30_MASK + # GPIO_31_MASK + */ +#define GPIO_0_MASK 0x00000001UL +#define GPIO_1_MASK 0x00000002UL +#define GPIO_2_MASK 0x00000004UL +#define GPIO_3_MASK 0x00000008UL +#define GPIO_4_MASK 0x00000010UL +#define GPIO_5_MASK 0x00000020UL +#define GPIO_6_MASK 0x00000040UL +#define GPIO_7_MASK 0x00000080UL +#define GPIO_8_MASK 0x00000100UL +#define GPIO_9_MASK 0x00000200UL +#define GPIO_10_MASK 0x00000400UL +#define GPIO_11_MASK 0x00000800UL +#define GPIO_12_MASK 0x00001000UL +#define GPIO_13_MASK 0x00002000UL +#define GPIO_14_MASK 0x00004000UL +#define GPIO_15_MASK 0x00008000UL +#define GPIO_16_MASK 0x00010000UL +#define GPIO_17_MASK 0x00020000UL +#define GPIO_18_MASK 0x00040000UL +#define GPIO_19_MASK 0x00080000UL +#define GPIO_20_MASK 0x00100000UL +#define GPIO_21_MASK 0x00200000UL +#define GPIO_22_MASK 0x00400000UL +#define GPIO_23_MASK 0x00800000UL +#define GPIO_24_MASK 0x01000000UL +#define GPIO_25_MASK 0x02000000UL +#define GPIO_26_MASK 0x04000000UL +#define GPIO_27_MASK 0x08000000UL +#define GPIO_28_MASK 0x10000000UL +#define GPIO_29_MASK 0x20000000UL +#define GPIO_30_MASK 0x40000000UL +#define GPIO_31_MASK 0x80000000UL + +/*-------------------------------------------------------------------------*//** + * GPIO modes + * # GPIO_INPUT_MODE + * # GPIO_OUTPUT_MODE + * # GPIO_INOUT_MODE + */ +#define GPIO_INPUT_MODE 0x0000000002UL +#define GPIO_OUTPUT_MODE 0x0000000005UL +#define GPIO_INOUT_MODE 0x0000000003UL + +/*-------------------------------------------------------------------------*//** + * Possible GPIO inputs interrupt configurations. + * # GPIO_IRQ_LEVEL_HIGH + * # GPIO_IRQ_LEVEL_LOW + * # GPIO_IRQ_EDGE_POSITIVE + * # GPIO_IRQ_EDGE_NEGATIVE + * # GPIO_IRQ_EDGE_BOTH + */ +#define GPIO_IRQ_LEVEL_HIGH 0x0000000000UL +#define GPIO_IRQ_LEVEL_LOW 0x0000000020UL +#define GPIO_IRQ_EDGE_POSITIVE 0x0000000040UL +#define GPIO_IRQ_EDGE_NEGATIVE 0x0000000060UL +#define GPIO_IRQ_EDGE_BOTH 0x0000000080UL + +/*-------------------------------------------------------------------------*//** + * Possible states for GPIO configured as INOUT + */ +typedef enum gpio_inout_state +{ + GPIO_DRIVE_LOW = 0, + GPIO_DRIVE_HIGH, + GPIO_HIGH_Z +} gpio_inout_state_t; + +/*-------------------------------------------------------------------------*//** + The GPIO_init() function initializes a CoreGPIO hardware instance and the data + structure associated with the CoreGPIO hardware instance. + Note that a CoreGPIO hardware instance is generated with a fixed configuration + for some or all of its IOs as part of the hardware flow. + Attempting to modify the configuration of such a hardware-configured IO using + the GPIO_config() function has no effect. + + @param this_gpio + Pointer to the gpio_instance_t data structure instance holding all data + regarding the CoreGPIO hardware instance being initialized. A pointer to the + same data structure is used in subsequent calls to the CoreGPIO driver + functions in order to identify the CoreGPIO instance that must perform the + operation implemented by the called driver function. + + @param base_addr + The base_addr parameter is the base address in the memory map of the + processor for the registers of the GPIO instance being initialized. + + @param bus_width + The bus_width parameter informs the driver of the APB bus width selected + during the hardware flow configuration of the CoreGPIO hardware instance. It + indicates to the driver whether the CoreGPIO hardware registers are visible + as 8, 16, or 32-bits registers. Allowed values are: + - GPIO_APB_8_BITS_BUS + - GPIO_APB_16_BITS_BUS + - GPIO_APB_32_BITS_BUS + + @return + none. + + @example + @code + #define COREGPIO_BASE_ADDR 0xC2000000 + + gpio_instance_t g_gpio; + + void system_init( void ) + { + GPIO_init( &g_gpio, COREGPIO_BASE_ADDR, GPIO_APB_32_BITS_BUS ); + } + @endcode + */ +void GPIO_init +( + gpio_instance_t * this_gpio, + addr_t base_addr, + gpio_apb_width_t bus_width +); + +/*-------------------------------------------------------------------------*//** + The GPIO_config() function is used to configure an individual GPIO port. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO port to be configured. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @param config + The config parameter specifies the configuration to be applied to the GPIO + port identified by the first parameter. It is a logical OR of GPIO mode and + interrupt mode. The interrupt mode is only relevant if the GPIO is + configured as an input. + - Possible modes are: + - GPIO_INPUT_MODE, + - GPIO_OUTPUT_MODE, + - GPIO_INOUT_MODE. + - Possible interrupt modes are: + - GPIO_IRQ_LEVEL_HIGH, + - GPIO_IRQ_LEVEL_LOW, + - GPIO_IRQ_EDGE_POSITIVE, + - GPIO_IRQ_EDGE_NEGATIVE, + - GPIO_IRQ_EDGE_BOTH + + @return + none. + + @example + For example, the following call configures GPIO 4 as an input that generates + interrupts on a low-to-high transition of the input: + @code + GPIO_config( &g_gpio, GPIO_4, GPIO_INPUT_MODE | GPIO_IRQ_EDGE_POSITIVE ); + @endcode + */ +void GPIO_config +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint32_t config +); + +/*-------------------------------------------------------------------------*//** + The GPIO_set_outputs() function is used to set the state of the GPIO ports + configured as outputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param value + The value parameter specifies the state of the GPIO ports configured as + outputs. It is a bit mask of the form (GPIO_n_MASK | GPIO_m_MASK), where n + and m are numbers identifying GPIOs. + For example, (GPIO_0_MASK | GPIO_1_MASK | GPIO_2_MASK ) specifies that the + first, second, and third GPIO must be set high and all other outputs set + low. + + @return + none. + + @example + Set GPIO 0 and 8 outputs high and all other GPIO outputs low. + @code + GPIO_set_outputs( &g_gpio, GPIO_0_MASK | GPIO_8_MASK ); + @endcode + + @example + Set GPIO 2 and 4 outputs low without affecting the other GPIO outputs. + @code + uint32_t gpio_outputs; + gpio_outputs = GPIO_get_outputs( &g_gpio ); + gpio_outputs &= ~( GPIO_2_MASK | GPIO_4_MASK ); + GPIO_set_outputs( &g_gpio, gpio_outputs ); + @endcode + + @see GPIO_get_outputs() + */ +void GPIO_set_outputs +( + gpio_instance_t * this_gpio, + uint32_t value +); + +/*-------------------------------------------------------------------------*//** + The GPIO_set_output() function is used to set the state of a single GPIO port + configured as an output. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter specifies the GPIO port that has its output set by a + call to this function. + + @param value + The value parameter specifies the desired state for the GPIO output. A value + of 0 sets the output low, and a value of 1 sets the port high. + + @return + none. + */ +void GPIO_set_output +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint8_t value +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_inputs() function is used to read the state of all GPIOs + configured as inputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @return + This function returns a 32-bit unsigned integer, where each bit represents + the state of an input. The least significant bit represents the state of + GPIO 0, and the most significant bit represents the state of GPIO 31. + */ +uint32_t GPIO_get_inputs +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_outputs() function is used to read the current state of all + GPIO outputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @return + This function returns a 32-bit unsigned integer where each bit represents + the state of an output. The least significant bit represents the state + of GPIO 0, and the most significant bit represents the state of GPIO 31. + */ +uint32_t GPIO_get_outputs +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_drive_inout() function is used to set the output state of a + GPIO configured as INOUT. An INOUT GPIO is in one of three states: + - high + - low + - high impedance + + An INOUT output is typically be used where several devices drive the state of + a signal. The high and low states are equivalent to the high and low states of + a GPIO configured as an output. The high impedance state is used to prevent + the GPIO from driving the state of the output and therefore allow reading the + state of the GPIO as an input. + Note that the GPIO port you wish to use as INOUT through this function + must be configurable through software. Therefore, the GPIO ports used as INOUT + must not have a fixed configuration selected as part of the hardware flow. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO for which this function will + change the output state. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @param inout_state + The inout_state parameter specifies the state of the I/O identified by the + first parameter. Possible states are: + - GPIO_DRIVE_HIGH, + - GPIO_DRIVE_LOW, + - GPIO_HIGH_Z (high impedance) + + @return + none. + + @example + The call to GPIO_drive_inout() below will set the GPIO 7 output to + high impedance state. + @code + GPIO_drive_inout( &g_gpio, GPIO_7, GPIO_HIGH_Z ); + @endcode + */ +void GPIO_drive_inout +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + gpio_inout_state_t inout_state +); + +/*-------------------------------------------------------------------------*//** + The GPIO_enable_irq() function is used to enable an interrupt to be + generated based on the state of the input identified as a parameter. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO input that the call to + GPIO_enable_irq() enables to generate interrupts. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + @example + The call to GPIO_enable_irq() below allows GPIO 8 to generate interrupts. + + @code + GPIO_enable_irq( &g_gpio, GPIO_8 ); + @endcode + */ +void GPIO_enable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_disable_irq() function is used to disable interrupts from being + generated based on the state of the input specified as a parameter. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO input that the call to + GPIO_disable_irq() disables from generating interrupts. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + @example + The call to GPIO_disable_irq() below prevents GPIO 8 from generating + interrupts. + @code + GPIO_disable_irq( &g_gpio, GPIO_8 ); + @endcode + */ +void GPIO_disable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_clear_irq() function is used to clear the interrupt generated by + the GPIO specified as a parameter. The GPIO_clear_irq() function must be + called as part of a GPIO interrupt service routine (ISR) in order to prevent + the same interrupt event from re-triggering a call to the GPIO ISR. + Note that interrupts may also need to be cleared in the processor's + interrupt controller. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO input for which to clear the + interrupt. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + @example + The example below demonstrates the use of the GPIO_clear_irq() function as + part of the GPIO-9 interrupt service routine. + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + GPIO_clear_irq( &g_gpio, GPIO_9 ); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +void GPIO_clear_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_irq_sources() function is used to identify the source of the + interrupt. i.e. to That is the GPIO input line, whose state change triggered + the interrupt. The GPIO_get_irq_sources() function must be called as part of + a GPIO interrupt service routine (ISR) in order to determine the interrupt + source. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @return + This function returns a 32-bit unsigned integer, where each bit represents + the pin number of a GPIO. + + @example + The example below demonstrates the use of the GPIO_get_irq_sources() + function as part of the GPIO-9 interrupt service routine. + + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + GPIO_clear_all_irq_sources(g_p_mygpio, GPIO_get_irq_sources(g_p_mygpio)); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +uint32_t GPIO_get_irq_sources +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_clear_all_irq_sources() function is used to clear all the active + interrupts generated by the GPIO specified as a parameter. The + GPIO_clear_all_irq_sources() function must be called as part of a GPIO + interrupt service routine (ISR) in order to prevent the same interrupt event + from re-triggering a call to the GPIO ISR. + Note that interrupts may also need to be cleared in the processor's + interrupt controller. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param bitmask + This bitmask parameter is a 32-bit unsigned integer where each bit + represents the GPIO pin used to clear the interrupt bit register of the + corresponding GPIO bit. The least significant bit represents the status of + GPIO 0, and the most significant bit represents the status of GPIO 31. + + @return + none. + + @example + The example below demonstrates the use of the GPIO_clear_all_irq_sources() + function as part of the GPIO-9 interrupt service routine. + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + do_interrupt_processing(); + + GPIO_clear_all_irq_sources(g_p_mygpio, GPIO_get_irq_sources(g_p_mygpio)); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +void GPIO_clear_all_irq_sources +( + gpio_instance_t * this_gpio, + uint32_t bitmask +); + +#ifdef __cplusplus +} +#endif + +#endif /* CORE_GPIO_H_ */ diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h new file mode 100644 index 0000000..41f5b7c --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h @@ -0,0 +1,45 @@ +/******************************************************************************* + * (c) Copyright 2008-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file coregpio_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreGPIO register definitions + * + */ + +#ifndef __CORE_GPIO_REGISTERS_H +#define __CORE_GPIO_REGISTERS_H 1 + +/*------------------------------------------------------------------------------ + * + */ +#define IRQ_REG_OFFSET 0x80 + +#define IRQ0_REG_OFFSET 0x80 +#define IRQ1_REG_OFFSET 0x84 +#define IRQ2_REG_OFFSET 0x88 +#define IRQ3_REG_OFFSET 0x8C + +/*------------------------------------------------------------------------------ + * + */ +#define GPIO_IN_REG_OFFSET 0x90 + +#define GPIO_IN0_REG_OFFSET 0x90 +#define GPIO_IN1_REG_OFFSET 0x94 +#define GPIO_IN2_REG_OFFSET 0x98 +#define GPIO_IN3_REG_OFFSET 0x9C + +/*------------------------------------------------------------------------------ + * + */ +#define GPIO_OUT_REG_OFFSET 0xA0 + +#define GPIO_OUT0_REG_OFFSET 0xA0 +#define GPIO_OUT1_REG_OFFSET 0xA4 +#define GPIO_OUT2_REG_OFFSET 0xA8 +#define GPIO_OUT3_REG_OFFSET 0xAC + +#endif /* __CORE_GPIO_REGISTERS_H */ diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c new file mode 100644 index 0000000..1fd3dd6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c @@ -0,0 +1,1495 @@ +/******************************************************************************* + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * CoreI2C software driver implementation. + * + */ + +#include "core_smbus_regs.h" +#include "core_i2c.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * I2C transaction direction. + */ +#define WRITE_DIR 0u +#define READ_DIR 1u + +/* -- TRANSACTIONS TYPES -- */ +#define NO_TRANSACTION 0u +#define MASTER_WRITE_TRANSACTION 1u +#define MASTER_READ_TRANSACTION 2u +#define MASTER_RANDOM_READ_TRANSACTION 3u +#define WRITE_SLAVE_TRANSACTION 4u +#define READ_SLAVE_TRANSACTION 5u + +/* -- SMBUS H/W STATES -- */ +/* -- MASTER STATES -- */ +#define ST_BUS_ERROR 0x00u /* Bus error during MST or selected slave modes */ +#define ST_I2C_IDLE 0xF8u /* No activity and no interrupt either... */ +#define ST_START 0x08u /* start condition sent */ +#define ST_RESTART 0x10u /* repeated start */ +#define ST_SLAW_ACK 0x18u /* SLA+W sent, ack received */ +#define ST_SLAW_NACK 0x20u /* SLA+W sent, nack received */ +#define ST_TX_DATA_ACK 0x28u /* Data sent, ACK'ed */ +#define ST_TX_DATA_NACK 0x30u /* Data sent, NACK'ed */ +#define ST_LOST_ARB 0x38u /* Master lost arbitration */ +#define ST_SLAR_ACK 0x40u /* SLA+R sent, ACK'ed */ +#define ST_SLAR_NACK 0x48u /* SLA+R sent, NACK'ed */ +#define ST_RX_DATA_ACK 0x50u /* Data received, ACK sent */ +#define ST_RX_DATA_NACK 0x58u /* Data received, NACK sent */ +#define ST_RESET_ACTIVATED 0xD0u /* Master reset is activated */ +#define ST_STOP_TRANSMIT 0xE0u /* Stop has been transmitted */ + +/* -- SLAVE STATES -- */ +#define ST_SLAVE_SLAW 0x60u /* SLA+W received */ +#define ST_SLAVE_SLAR_ACK 0xA8u /* SLA+R received, ACK returned */ +#define ST_SLV_LA 0x68u /* Slave lost arbitration */ +#define ST_GCA 0x70u /* GCA received */ +#define ST_GCA_LA 0x78u /* GCA lost arbitration */ +#define ST_RDATA 0x80u /* Data received */ +#define ST_SLA_NACK 0x88u /* Slave addressed, NACK returned */ +#define ST_GCA_ACK 0x90u /* Previously addresses with GCA, data ACKed */ +#define ST_GCA_NACK 0x98u /* GCA addressed, NACK returned */ +#define ST_RSTOP 0xA0u /* Stop received */ +#define ST_SLARW_LA 0xB0u /* Arbitration lost */ +#define ST_RACK 0xB8u /* Byte sent, ACK received */ +#define ST_SLAVE_RNACK 0xC0u /* Byte sent, NACK received */ +#define ST_FINAL 0xC8u /* Final byte sent, ACK received */ +#define ST_SLV_RST 0xD8u /* Slave reset state */ + + +/* I2C Channel base offset */ +#define CHANNEL_BASE_SHIFT 5u +#define CHANNEL_MASK 0x1E0u + +/* + * Maximum address offset length in slave write-read transactions. + * A maximum of two bytes will be interpreted as address offset within the slave + * tx buffer. + */ +#define MAX_OFFSET_LENGTH 2u + +/*------------------------------------------------------------------------------ + * I2C interrupts control functions implemented "i2c_interrupt.c". + * the implementation of these functions depend on the underlying hardware + * design and how the CoreI2C interrupt line is connected to the system's + * interrupt controller. + */ +void I2C_enable_irq( i2c_instance_t * this_i2c ); +void I2C_disable_irq( i2c_instance_t * this_i2c ); +static void enable_slave_if_required(i2c_instance_t * this_i2c); + +/*------------------------------------------------------------------------------ + * I2C_init() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_init +( + i2c_instance_t * this_i2c, + addr_t base_address, + uint8_t ser_address, + i2c_clock_divider_t ser_clock_speed +) +{ + psr_t saved_psr; + uint_fast16_t clock_speed = (uint_fast16_t)ser_clock_speed; + + /* + * We need to disable ints while doing this as there is no guarantee we + * have not been called already and the ISR is active. + */ + saved_psr = HAL_disable_interrupts(); + + /* + * Initialize all items of the this_i2c data structure to zero. This + * initializes all state variables to their init value. It relies on + * the fact that NO_TRANSACTION, I2C_SUCCESS and I2C_RELEASE_BUS all + * have an actual value of zero. + */ + memset(this_i2c, 0, sizeof(i2c_instance_t)); + + /* + * Set base address of I2C hardware used by this instance. + */ + this_i2c->base_address = base_address; + + /* + * Update Serial address of the device + */ + this_i2c->ser_address = ((uint_fast8_t)ser_address << 1u); + + /* + * Configure hardware. + */ + HAL_set_8bit_reg_field(this_i2c->base_address, ENS1, 0x00); /* Reset I2C hardware. */ + HAL_set_8bit_reg_field(this_i2c->base_address, ENS1, 0x01); /* set enable bit */ + HAL_set_8bit_reg_field(this_i2c->base_address, CR2, ( (clock_speed >> 2) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c->base_address, CR1, ( (clock_speed >> 1) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c->base_address, CR0, ( clock_speed & 0x01) ); + + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS, this_i2c->ser_address); + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, this_i2c->ser_address); + + /* + * Finally safe to enable interrupts. + */ + HAL_restore_interrupts( saved_psr ); +} +/*------------------------------------------------------------------------------ + * I2C_channel_init() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_channel_init +( + i2c_instance_t * this_i2c_channel, + i2c_instance_t * this_i2c, + i2c_channel_number_t channel_number, + i2c_clock_divider_t ser_clock_speed +) +{ + psr_t saved_psr; + uint_fast16_t clock_speed = (uint_fast16_t)ser_clock_speed; + + HAL_ASSERT(channel_number < I2C_MAX_CHANNELS); + HAL_ASSERT(I2C_CHANNEL_0 != channel_number); + + /* + * Cannot allow channel 0 in this function as we will trash the hardware + * base address and slave address. + */ + if ((channel_number < I2C_MAX_CHANNELS) && + (I2C_CHANNEL_0 != channel_number)) + { + /* + * We need to disable ints while doing this as the hardware should already + * be active at this stage. + */ + saved_psr = HAL_disable_interrupts(); + + /* + * Initialize channel data. + */ + memset(this_i2c_channel, 0, sizeof(i2c_instance_t)); + + this_i2c_channel->base_address = + ((this_i2c->base_address) & ~((addr_t)CHANNEL_MASK)) + | (((addr_t)channel_number) << CHANNEL_BASE_SHIFT); + + this_i2c_channel->ser_address = this_i2c->ser_address; + + HAL_set_8bit_reg_field(this_i2c_channel->base_address, ENS1, 0x00); /* Reset I2C channel hardware. */ + HAL_set_8bit_reg_field(this_i2c_channel->base_address, ENS1, 0x01); /* set enable bit */ + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR2, ( (clock_speed >> 2) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR1, ( (clock_speed >> 1) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR0, ( clock_speed & 0x01) ); + /* + * Finally safe to enable interrupts. + */ + HAL_restore_interrupts( saved_psr ); + } +} + +/*------------------------------------------------------------------------------ + * I2C_write() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_write +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * write_buffer, + uint16_t write_size, + uint8_t options +) +{ + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + saved_psr = HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_WRITE_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_WRITE_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + this_i2c->dir = WRITE_DIR; + this_i2c->master_tx_buffer = write_buffer; + this_i2c->master_tx_size = write_size; + this_i2c->master_tx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_read() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +) +{ + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + saved_psr = HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_READ_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_READ_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + + this_i2c->dir = READ_DIR; + + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_write_read() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_write_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * addr_offset, + uint16_t offset_size, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +) +{ + HAL_ASSERT(offset_size > 0u); + HAL_ASSERT(addr_offset != (uint8_t *)0); + HAL_ASSERT(read_size > 0u); + HAL_ASSERT(read_buffer != (uint8_t *)0); + + this_i2c->master_status = I2C_FAILED; + + if((read_size > 0u) && (offset_size > 0u)) + { + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + saved_psr = HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_RANDOM_READ_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_RANDOM_READ_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + + this_i2c->dir = WRITE_DIR; + + this_i2c->master_tx_buffer = addr_offset; + this_i2c->master_tx_size = offset_size; + this_i2c->master_tx_idx = 0u; + + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + + HAL_restore_interrupts( saved_psr ); + } +} + +/*------------------------------------------------------------------------------ + * I2C_get_status() + * See "core_i2c.h" for details of how to use this function. + */ +i2c_status_t I2C_get_status +( + i2c_instance_t * this_i2c +) +{ + i2c_status_t i2c_status ; + + i2c_status = this_i2c->master_status ; + + return i2c_status; +} + +/*------------------------------------------------------------------------------ + * I2C_wait_complete() + * See "core_i2c.h" for details of how to use this function. + */ +i2c_status_t I2C_wait_complete +( + i2c_instance_t * this_i2c, + uint32_t timeout_ms +) +{ + i2c_status_t i2c_status; + psr_t saved_psr; + /* + * Because we have no idea of what CPU we are supposed to be running on + * we need to guard this write to the timeout value to avoid ISR/user code + * interaction issues. Checking the status below should be fine as only a + * single byte should change in that. + */ + saved_psr = HAL_disable_interrupts(); + this_i2c->master_timeout_ms = timeout_ms; + HAL_restore_interrupts( saved_psr ); + + /* Run the loop until state returns I2C_FAILED or I2C_SUCESS*/ + do { + i2c_status = this_i2c->master_status; + } while(I2C_IN_PROGRESS == i2c_status); + return i2c_status; +} + +/*------------------------------------------------------------------------------ + * I2C_system_tick() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_system_tick +( + i2c_instance_t * this_i2c, + uint32_t ms_since_last_tick +) +{ + if(this_i2c->master_timeout_ms != I2C_NO_TIMEOUT) + { + if(this_i2c->master_timeout_ms > ms_since_last_tick) + { + this_i2c->master_timeout_ms -= ms_since_last_tick; + } + else + { + psr_t saved_psr; + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + /* + * Mark current transaction as having timed out. + */ + this_i2c->master_status = I2C_TIMED_OUT; + this_i2c->transaction = NO_TRANSACTION; + this_i2c->is_transaction_pending = 0; + + HAL_restore_interrupts( saved_psr ); + + /* + * Make sure we do not incorrectly signal a timeout for subsequent + * transactions. + */ + this_i2c->master_timeout_ms = I2C_NO_TIMEOUT; + } + } +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_tx_buffer() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_tx_buffer +( + i2c_instance_t * this_i2c, + const uint8_t * tx_buffer, + uint16_t tx_size +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + this_i2c->slave_tx_buffer = tx_buffer; + this_i2c->slave_tx_size = tx_size; + this_i2c->slave_tx_idx = 0u; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_rx_buffer() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_rx_buffer +( + i2c_instance_t * this_i2c, + uint8_t * rx_buffer, + uint16_t rx_size +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + this_i2c->slave_rx_buffer = rx_buffer; + this_i2c->slave_rx_size = rx_size; + this_i2c->slave_rx_idx = 0u; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_mem_offset_length() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_mem_offset_length +( + i2c_instance_t * this_i2c, + uint8_t offset_length +) +{ + HAL_ASSERT(offset_length <= MAX_OFFSET_LENGTH); + + /* + * Single byte update, should be interrupt safe + */ + if(offset_length > MAX_OFFSET_LENGTH) + { + this_i2c->slave_mem_offset_length = MAX_OFFSET_LENGTH; + } + else + { + this_i2c->slave_mem_offset_length = offset_length; + } +} + +/*------------------------------------------------------------------------------ + * I2C_register_write_handler() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_register_write_handler +( + i2c_instance_t * this_i2c, + i2c_slave_wr_handler_t handler +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + this_i2c->slave_write_handler = handler; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_enable_slave() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_enable_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register and slave mode flag without the I2C ISR interrupting + * us. + */ + saved_psr = HAL_disable_interrupts(); + + /* Set the Assert Acknowledge bit. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + /* Enable slave mode */ + this_i2c->is_slave_enabled = 1u; + + HAL_restore_interrupts( saved_psr ); + + /* Enable I2C IRQ*/ + I2C_enable_irq( this_i2c ); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_slave() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_disable_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + /* Reset the assert acknowledge bit. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + + /* Disable slave mode with IRQ blocked to make whole change atomic */ + this_i2c->is_slave_enabled = 0u; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * + */ +static void enable_slave_if_required +( + i2c_instance_t * this_i2c +) +{ + /* + * This function is only called from within the ISR and so does not need + * guarding on the register access. + */ + if( 0 != this_i2c->is_slave_enabled ) + { + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x01u ); + } +} +/*------------------------------------------------------------------------------ + * I2C_set_slave_second_addr() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_slave_second_addr +( + i2c_instance_t * this_i2c, + uint8_t second_slave_addr +) +{ + uint8_t second_slave_address; + + /* + This function does not support CoreI2C hardware configured with a fixed + second slave address. The current implementation of the ADDR1[0] register + bit makes it difficult for the driver to support both programmable and + fixed second slave address, so we choose to support programmable only. + With the programmable configuration, ADDR1[0] and ADDR0[0] both control + enable/disable of GCA recognition, as an effective OR of the 2 bit fields. + Therefore we set ADDR1[0] to 0 here, so that only ADDR0[0] controls GCA. + */ + second_slave_address = (uint8_t)((second_slave_addr << 1u) & (~SLAVE1_EN_MASK)); + + /* + * Single byte register write, should be interrupt safe + */ + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, second_slave_address); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_slave_second_addr() + * See "i2c.h" for details of how to use this function. + */ +void I2C_disable_slave_second_addr +( + i2c_instance_t * this_i2c +) +{ + /* + We are disabling the second slave address by setting the value of the 2nd + slave address to the primary slave address. The reason for using this method + of disabling 2nd slave address is that ADDRESS1[0] has different meaning + depending on hardware configuration. Its use would likely interfere with + the intended GCA setting. + */ + /* + * Single byte register write, should be interrupt safe + */ + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, this_i2c->ser_address); +} + +/*------------------------------------------------------------------------------ + * i2C_set_gca() + * See "i2c.h" for details of how to use this function. + */ + +void I2C_set_gca +( + i2c_instance_t * this_i2c +) +{ + /* + * This read modify write access should be interrupt safe as the address + * register is not written to in the ISR. + */ + /* accept GC addressing. */ + HAL_set_8bit_reg_field(this_i2c->base_address, GC, 0x01u); +} + +/*------------------------------------------------------------------------------ + * I2C_clear_gca() + * See "i2c.h" for details of how to use this function. + */ +void I2C_clear_gca +( + i2c_instance_t * this_i2c +) +{ + /* + * This read modify write access should be interrupt safe as the address + * register is not written to in the ISR. + */ + /* Clear GC addressing. */ + HAL_set_8bit_reg_field(this_i2c->base_address, GC, 0x00u); +} + +/*------------------------------------------------------------------------------ + * I2C_isr() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_isr +( + i2c_instance_t * this_i2c +) +{ + volatile uint8_t status; + uint8_t data; + uint8_t hold_bus; + uint8_t clear_irq = 1u; + + status = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + + switch( status ) + { + /************** MASTER TRANSMITTER / RECEIVER *******************/ + + case ST_START: /* start has been xmt'd */ + case ST_RESTART: /* repeated start has been xmt'd */ + HAL_set_8bit_reg_field( this_i2c->base_address, STA, 0x00u); + HAL_set_8bit_reg( this_i2c->base_address, DATA, this_i2c->target_addr); /* write call address */ + HAL_set_8bit_reg_field( this_i2c->base_address, DIR, this_i2c->dir); /* set direction bit */ + if(this_i2c->dir == WRITE_DIR) + { + this_i2c->master_tx_idx = 0u; + } + else + { + this_i2c->master_rx_idx = 0u; + } + + /* + * Clear the pending transaction. This condition will be true if the slave + * has acquired the bus to carry out pending master transaction which + * it had received during its slave transmission or reception mode. + */ + if(this_i2c->is_transaction_pending) + { + this_i2c->is_transaction_pending = 0u; + } + + /* + * Make sure to update proper transaction after master START + * or RESTART + */ + if(this_i2c->transaction != this_i2c->pending_transaction) + { + this_i2c->transaction = this_i2c->pending_transaction; + } + break; + + case ST_LOST_ARB: + /* Set start bit. Let's keep trying! Don't give up! */ + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + break; + + case ST_STOP_TRANSMIT: + /* Stop has been transmitted. Do nothing */ + break; + + /******************* MASTER TRANSMITTER *************************/ + case ST_SLAW_NACK: + /* SLA+W has been transmitted; not ACK has been received - let's stop. */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_FAILED; + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + case ST_SLAW_ACK: + case ST_TX_DATA_ACK: + /* data byte has been xmt'd with ACK, time to send stop bit or repeated start. */ + if (this_i2c->master_tx_idx < this_i2c->master_tx_size) + { + HAL_set_8bit_reg(this_i2c->base_address, DATA, (uint_fast8_t)this_i2c->master_tx_buffer[this_i2c->master_tx_idx++]); + } + else if ( this_i2c->transaction == MASTER_RANDOM_READ_TRANSACTION ) + { + /* We are finished sending the address offset part of a random read transaction. + * It is is time to send a restart in order to change direction. */ + this_i2c->dir = READ_DIR; + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + else /* done sending. let's stop */ + { + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + hold_bus = this_i2c->options & I2C_HOLD_BUS; + + /* Store the information of current I2C bus status in the bus_status*/ + this_i2c->bus_status = hold_bus; + if ( hold_bus == 0u ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); /*xmt stop condition */ + enable_slave_if_required(this_i2c); + } + else + { + I2C_disable_irq( this_i2c ); + clear_irq = 0u; + } + this_i2c->master_status = I2C_SUCCESS; + } + break; + + case ST_TX_DATA_NACK: + /* data byte SENT, ACK to be received + * In fact, this means we've received a NACK (This may not be + * obvious, but if we've rec'd an ACK then we would be in state + * 0x28!) hence, let's send a stop bit + */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u);/* xmt stop condition */ + this_i2c->master_status = I2C_FAILED; + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + /********************* MASTER (or slave?) RECEIVER *************************/ + + /* STATUS codes 08H, 10H, 38H are all covered in MTX mode */ + case ST_SLAR_ACK: /* SLA+R tx'ed. */ + /* Let's make sure we ACK the first data byte received (set AA bit in CTRL) unless + * the next byte is the last byte of the read transaction. + */ + if(this_i2c->master_rx_size > 1u) + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + } + else if(1u == this_i2c->master_rx_size) + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + else /* this_i2c->master_rx_size == 0u */ + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_SUCCESS; + this_i2c->transaction = NO_TRANSACTION; + } + break; + + case ST_SLAR_NACK: /* SLA+R tx'ed; let's release the bus (send a stop condition) */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_FAILED; + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + case ST_RX_DATA_ACK: /* Data byte received, ACK returned */ + /* First, get the data */ + this_i2c->master_rx_buffer[this_i2c->master_rx_idx++] = HAL_get_8bit_reg(this_i2c->base_address, DATA); + if( this_i2c->master_rx_idx >= (this_i2c->master_rx_size - 1u)) + { + /* If we're at the second last byte, let's set AA to 0 so + * we return a NACK at the last byte. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + break; + + case ST_RX_DATA_NACK: /* Data byte received, NACK returned */ + /* Get the data, then send a stop condition */ + this_i2c->master_rx_buffer[this_i2c->master_rx_idx] = HAL_get_8bit_reg(this_i2c->base_address, DATA); + + hold_bus = this_i2c->options & I2C_HOLD_BUS; + + /* Store the information of current I2C bus status in the bus_status*/ + this_i2c->bus_status = hold_bus; + if ( hold_bus == 0u ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); /*xmt stop condition */ + + /* Bus is released, now we can start listening to bus, if it is slave */ + enable_slave_if_required(this_i2c); + } + else + { + I2C_disable_irq( this_i2c ); + clear_irq = 0u; + } + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + this_i2c->master_status = I2C_SUCCESS; + break; + + /******************** SLAVE RECEIVER **************************/ + case ST_GCA_NACK: /* NACK after, GCA addressing */ + case ST_SLA_NACK: /* Re-enable AA (assert ack) bit for future transmissions */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + this_i2c->transaction = NO_TRANSACTION; + this_i2c->slave_status = I2C_SUCCESS; + + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + break; + + case ST_GCA_LA: /* Arbitr. lost (GCA rec'd) */ + case ST_SLV_LA: /* Arbitr. lost (SLA rec'd) */ + /* + * We lost arbitration and either the GCE or our address was the + * one received so pend the master operation we were starting. + */ + this_i2c->is_transaction_pending = 1u; + /* Fall through to normal ST processing as we are now in slave mode */ + + case ST_GCA: /* General call address received, ACK returned */ + case ST_SLAVE_SLAW: /* SLA+W received, ACK returned */ + this_i2c->transaction = WRITE_SLAVE_TRANSACTION; + this_i2c->slave_rx_idx = 0u; + this_i2c->random_read_addr = 0u; + /* + * If Start Bit is set clear it, but store that information since it is because of + * pending transaction + */ + if(HAL_get_8bit_reg_field(this_i2c->base_address, STA)) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + this_i2c->is_transaction_pending = 1u; + } + this_i2c->slave_status = I2C_IN_PROGRESS; +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + /* Fall through to put address as first byte in payload buffer */ +#else + /* Only break from this case if the slave address must NOT be included at the + * beginning of the received write data. */ + break; +#endif + case ST_GCA_ACK: /* DATA received; ACK sent after GCA */ + case ST_RDATA: /* DATA received; must clear DATA register */ + if((this_i2c->slave_rx_buffer != (uint8_t *)0) + && (this_i2c->slave_rx_idx < this_i2c->slave_rx_size)) + { + data = HAL_get_8bit_reg(this_i2c->base_address, DATA); + this_i2c->slave_rx_buffer[this_i2c->slave_rx_idx++] = data; + +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + if((ST_RDATA == status) || (ST_GCA_ACK == status)) + { + /* Ignore the slave address byte in the random read address + computation in the case where INCLUDE_SLA_IN_RX_PAYLOAD + is defined. */ +#endif + this_i2c->random_read_addr = (this_i2c->random_read_addr << 8) + data; +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + } +#endif + } + + if(this_i2c->slave_rx_idx >= this_i2c->slave_rx_size) + { + /* Rx buffer is full. NACK next received byte. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + break; + + case ST_RSTOP: + /* STOP or repeated START occurred. */ + /* We cannot be sure if the transaction has actually completed as + * this hardware state reports that either a STOP or repeated START + * condition has occurred. We assume that this is a repeated START + * if the transaction was a write from the master to this point.*/ + if ( this_i2c->transaction == WRITE_SLAVE_TRANSACTION ) + { + if ( this_i2c->slave_rx_idx == this_i2c->slave_mem_offset_length ) + { + this_i2c->slave_tx_idx = this_i2c->random_read_addr; + } + /* Call the slave's write transaction handler if it exists. */ + if ( this_i2c->slave_write_handler != 0u ) + { + i2c_slave_handler_ret_t h_ret; + h_ret = this_i2c->slave_write_handler( this_i2c, this_i2c->slave_rx_buffer, (uint16_t)this_i2c->slave_rx_idx ); + if ( I2C_REENABLE_SLAVE_RX == h_ret ) + { + /* There is a small risk that the write handler could + * call I2C_disable_slave() but return + * I2C_REENABLE_SLAVE_RX in error so we only enable + * ACKs if still in slave mode. */ + enable_slave_if_required(this_i2c); + } + else + { + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x0u ); + /* Clear slave mode flag as well otherwise in mixed + * master/slave applications, the AA bit will get set by + * subsequent master operations. */ + this_i2c->is_slave_enabled = 0u; + } + } + else + { + /* Re-enable address acknowledge in case we were ready to nack the next received byte. */ + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x01u ); + } + } + else /* A stop or repeated start outside a write/read operation */ + { + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * See if we need to re-enable acknowledgement as some error conditions, such + * as a master prematurely ending a transfer, can see us get here with AA set + * to 0 which will disable slave operation if we are not careful. + */ + enable_slave_if_required(this_i2c); + } + + /* Mark any previous master write transaction as complete. */ + this_i2c->slave_status = I2C_SUCCESS; + + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + + break; + + case ST_SLV_RST: /* SMBUS ONLY: timeout state. must clear interrupt */ + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction. + */ + this_i2c->transaction = NO_TRANSACTION; + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * Clear status to I2C_FAILED only if there was an operation in progress. + */ + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->slave_status = I2C_FAILED; + } + + enable_slave_if_required(this_i2c); /* Make sure AA is set correctly */ + + break; + + /****************** SLAVE TRANSMITTER **************************/ + case ST_SLAVE_SLAR_ACK: /* SLA+R received, ACK returned */ + case ST_SLARW_LA: /* Arbitration lost, and: */ + case ST_RACK: /* Data tx'ed, ACK received */ + if ( status == ST_SLAVE_SLAR_ACK ) + { + this_i2c->transaction = READ_SLAVE_TRANSACTION; + this_i2c->random_read_addr = 0u; + this_i2c->slave_status = I2C_IN_PROGRESS; + /* If Start Bit is set clear it, but store that information since it is because of + * pending transaction + */ + if(HAL_get_8bit_reg_field(this_i2c->base_address, STA)) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + this_i2c->is_transaction_pending = 1u; + } + } + if (this_i2c->slave_tx_idx >= this_i2c->slave_tx_size) + { + /* Ensure 0xFF is returned to the master when the slave specifies + * an empty transmit buffer. */ + HAL_set_8bit_reg(this_i2c->base_address, DATA, 0xFFu); + } + else + { + /* Load the data the data byte to be sent to the master. */ + HAL_set_8bit_reg(this_i2c->base_address, DATA, (uint_fast8_t)this_i2c->slave_tx_buffer[this_i2c->slave_tx_idx++]); + } + /* Determine if this is the last data byte to send to the master. */ + if (this_i2c->slave_tx_idx >= this_i2c->slave_tx_size) /* last byte? */ + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + /* Next read transaction will result in slave's transmit buffer + * being sent from the first byte. */ + this_i2c->slave_tx_idx = 0u; + } + break; + + case ST_SLAVE_RNACK: /* Data byte has been transmitted; not-ACK has been received. */ + case ST_FINAL: /* Last Data byte tx'ed, ACK received */ + /* We assume that the transaction will be stopped by the master. + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. */ + this_i2c->slave_tx_idx = 0u; + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + /* Mark previous state as complete */ + this_i2c->slave_status = I2C_SUCCESS; + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + + break; + + /* Master Reset has been activated Wait 35 ms for interrupt to be set, + * clear interrupt and proceed to 0xF8 state. */ + case ST_RESET_ACTIVATED: + case ST_BUS_ERROR: /* Bus error during MST or selected slave modes */ + default: + /* Some undefined state has encountered. Clear Start bit to make + * sure, next good transaction happen */ + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction. + */ + this_i2c->transaction = NO_TRANSACTION; + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * Clear statuses to I2C_FAILED only if there was an operation in progress. + */ + if(I2C_IN_PROGRESS == this_i2c->master_status) + { + this_i2c->master_status = I2C_FAILED; + } + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->slave_status = I2C_FAILED; + } + + break; + } + + if ( clear_irq ) + { + /* clear interrupt. */ + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + /* Read the status register to ensure the last I2C registers write took place + * in a system built around a bus making use of posted writes. */ + status = HAL_get_8bit_reg( this_i2c->base_address, STATUS); +} + +/*------------------------------------------------------------------------------ + * I2C_smbus_init() + * See "i2c.h" for details of how to use this function. + */ + +/* + * SMBSUS_NO = 1 + * SMBALERT_NO = 1 + * SMBus enable = 1 + */ +#define INIT_AND_ENABLE_SMBUS 0x54u +void I2C_smbus_init +( + i2c_instance_t * this_i2c +) +{ + /* + * Single byte register write, should be interrupt safe + */ + /* Enable SMBUS */ + HAL_set_8bit_reg(this_i2c->base_address, SMBUS, INIT_AND_ENABLE_SMBUS); +} + +/*------------------------------------------------------------------------------ + * I2C_enable_smbus_irq() + * See "i2c.h" for details of how to use this function. + */ +void I2C_enable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + if ( irq_type & I2C_SMBALERT_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_IE, 0x01u); + } + if ( irq_type & I2C_SMBSUS_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_IE, 0x01u); + } + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_smbus_irq() + * See "i2c.h" for details of how to use this function. + */ +void I2C_disable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + if ( irq_type & I2C_SMBALERT_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_IE, 0x00u); + } + if (irq_type & I2C_SMBSUS_IRQ ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_IE, 0x00u); + } + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_suspend_smbus_slave() + * See "i2c.h" for details of how to use this function. + */ +void I2C_suspend_smbus_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_NO_CONTROL, 0x00u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_resume_smbus_slave() + * See "i2c.h" for details of how to use this function. + */ +void I2C_resume_smbus_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_NO_CONTROL, 0x01u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_reset_smbus() + * See "i2c.h" for details of how to use this function. + */ +void I2C_reset_smbus +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + HAL_set_8bit_reg_field(this_i2c->base_address, SMBUS_MST_RESET, 0x01u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_smbus_alert() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_smbus_alert +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_NO_CONTROL, 0x00u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_clear_smbus_alert() + * See "i2c.h" for details of how to use this function. + */ +void I2C_clear_smbus_alert +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_NO_CONTROL, 0x01u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_get_irq_status() + * See "i2c.h" for details of how to use this function. + */ +uint8_t I2C_get_irq_status +( + i2c_instance_t * this_i2c +) +{ + uint8_t status ; + uint8_t irq_type = I2C_NO_IRQ ; + + status = HAL_get_8bit_reg(this_i2c->base_address, SMBUS); + + if( status & (uint8_t)SMBALERT_NI_STATUS_MASK ) + { + irq_type |= I2C_SMBALERT_IRQ ; + } + + if( status & (uint8_t)SMBSUS_NI_STATUS_MASK ) + { + irq_type |= I2C_SMBSUS_IRQ ; + } + + status = HAL_get_8bit_reg(this_i2c->base_address, CONTROL); + + if( status & (uint8_t)SI_MASK ) + { + irq_type |= I2C_INTR_IRQ ; + } + return(irq_type); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_addr2() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_user_data +( + i2c_instance_t * this_i2c, + void * p_user_data +) +{ + this_i2c->p_user_data = p_user_data ; +} + +/*------------------------------------------------------------------------------ + * I2C_get_user_data() + * See "i2c.h" for details of how to use this function. + */ +void * I2C_get_user_data +( + i2c_instance_t * this_i2c +) +{ + return( this_i2c->p_user_data); +} + +#ifdef __cplusplus +} +#endif + diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h new file mode 100644 index 0000000..3891ce0 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h @@ -0,0 +1,2306 @@ +/***************************************************************************//** + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * CoreI2C software driver Application Programming Interface. + * This file contains defines and function declarations allowing to interface + * with the CoreI2C software driver. + * + */ +/*=========================================================================*//** + @mainpage CoreI2C Bare Metal Driver. + The CoreI2C bare metal software driver supports I2C master and slave + operations. + + ============================================================================== + Introduction + ============================================================================== + The CoreI2C driver provides a set of functions for controlling the Microchip + CoreI2C hardware IP. The driver supports up to 16 separate I2C channels per + CoreI2C instance, with common slave address settings shared between channels + on a device. + + Optional features of the CoreI2C allow it to operate with I2C based protocols + such as System Management Bus (SMBus), Power Management Bus (PMBus), and + Intelligent Platform Management Interface (IPMI). This driver provides support + for these features when enabled in the CoreI2C IP. + + The major features provided by CoreI2C driver: + - Provides support to configuring the I2C channels of each CoreI2C peripheral device. + - I2C master operations. + - I2C slave operations. + - SMBus related operations. + + This driver is used as part of a bare metal system where no operating + system is available. The driver gets adapted as a part of an operating system, + but the implementation of the adaptation layer between the driver and the operating + system's driver model is outside the scope of this driver. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + Your application software should configure the CoreI2C driver through + calls to the I2C_init() function for each CoreI2C instance in the + hardware design. The configuration parameters include the CoreI2C hardware + instance base address and other runtime parameters, such as the I2C serial + clock frequency and the I2C device address. + + Once channel 0 of a CoreI2C peripheral has been initialized by I2C_init(), + any additional channels present should be configured by calling + I2C_channel_init() for each of the remaining channels. + + Apart from the CoreI2C hardware instance base address, no CoreI2C hardware configuration + parameters are used by the driver. Hence, no additional configuration files are required + to use the driver. + + -------------------------------- + Interrupt Control + -------------------------------- + The CoreI2C driver has to enable and disable the generation of interrupts by + CoreI2C at various times when it is operating. This enabling and disabling of + interrupts must be done through the system’s interrupt controller. For that + reason, the method of controlling the CoreI2C interrupt is system specific + and it is necessary to customize the I2C_enable_irq() and I2C_disable_irq() + functions. These functions are available in the i2c_interrupt.c file. + The default implementation calls HAL_ASSERT(0) to indicate to the application + developer that a suitable implementations for these functions must be provided. + + The implementation of the I2C_enable_irq() function should permit interrupts + generated by a CoreI2C instance to interrupt the processor. The implementation + of the I2C_disable_irq() function should prevent interrupts generated by a + CoreI2C instance from interrupting the processor. See the provided example + projects for a working implementation of these functions. + + The I2C_register_write_handler() function registers a write handler + function with the CoreI2C driver that calls on completion of an I2C write + transaction by the CoreI2C slave. It is your responsibility to create and + register the implementation of this handler function that processes or + trigger the processing of the received data. + + The SMBSUS and SMBALERT interrupts are related to the SMBus interface and are + enabled and disabled through I2C_enable_smbus_irq() and + I2C_disable_smbus_irq() respectively. It is your responsibility to create + interrupt handler functions in your application to get the desired response + for the SMBus interrupts. + + Note: You must include the path to any application header files that are + included in the i2c_interrupt.c file, as an include path in your + project's compiler settings. The details of how to do this will depend + on your development software. + + -------------------------------- + SMBus Logic Options + -------------------------------- + SMBus related APIs does not have any effect if the "Generate SMBus Logic" + is not enabled in the CoreI2C hardware configuration. Following are API's + that does not give the desired results if SMBus Logic is disabled. + + - I2C_smbus_init() + - I2C_reset_smbus() + - I2C_enable_smbus_irq() + - I2C_disable_smbus_irq() + - I2C_suspend_smbus_slave() + - I2C_resume_smbus_slave() + - I2C_set_smsbus_alert() + - I2C_clear_smsbus_alert() + - I2C_get_irq_status() + + -------------------------------- + Fixed Baud Rate Values + -------------------------------- + The serial clock frequency parameter passed to the I2C_init() and + I2C_channel_init() functions may not have any effect if fixed values were + selected for Baud rate in the hardware configuration of CoreI2C. When fixed + values are selected for these baud rates, the driver cannot overwrite + the fixed values. + + ----------------------------------- + Fixed Slave Address Options Values + ----------------------------------- + The primary slave address parameter passed to the I2C_init() function and + secondary address value passed to the I2C_set_slave_second_addr() function, + may not have the desired effect if fixed values were selected for the slave 0 + address and slave 1 address respectively. Proper operation of this version of + the driver requires the slave addresses to be programmable. + + ============================================================================== + Theory of Operation + ============================================================================== + The CoreI2C software driver is designed to allow the control of multiple + instances of CoreI2C with one or more I2C channels. Each channel in an + instance of CoreI2C in the hardware design is associated with a single + instance of the i2c_instance_t structure in the software. You must allocate + memory for one unique i2c_instance_t structure instance for each channel of + each CoreI2C hardware instance. The contents of these data structures are + initialised by calling I2C_init() and if necessary I2C_channel_init(). + A pointer to the structure is passed to the subsequent driver functions in order + to identify the CoreI2C hardware instance and channel to perform the + requested operation. + + Note: Do not attempt to directly manipulate the contents of i2c_instance_t + structures. These structures are only intended to be modified by the driver + functions. + + The CoreI2C driver functions are grouped into the following categories: + - Initialization and configuration functions + - Interrupt control + - I2C slave addressing functions + - I2C master operations functions to handle write, read, and write-read + transactions + - I2C slave operations functions to handle write, read, and write-read + transactions + - Mixed master-slave operations + - SMBus interface configuration and control + + -------------------------------- + Initialization and Configuration + -------------------------------- + The CoreI2C device is first initialized by calling the I2C_init() + function. Since each CoreI2C peripheral supports up to 16 channels, an + additional function, I2C_channel_init(), is required to initialize the + remaining channels with their own data structures. + + I2C_init() function initializes channel 0 of a CoreI2C and the i2c_instance_t + for channel 0 acts as the basis for further channel initialization as the + hardware base address and I2C serial address are same across all the channels. + Ensure to call I2C_init() function before calling any other I2C driver function + calls. The I2C_init() call for each CoreI2C takes the I2C serial address assigned + to the I2C and the serial clock divider to generate its I2C clock as configuration + parameters. + + I2C_channel_init() function takes as input parameters a pointer to the CoreI2C + i2c_instance_t which has been initialized by calling the I2C_init() and a pointer + to a separate i2c_instance_t which represents this new channel. Another input + parameter which is required by this function is serial clock divider which generates + its I2C clock. + + -------------------------------- + Interrupt Control + -------------------------------- + The CoreI2C driver is interrupt driven and it uses each channels INT + interrupt to drive the state machine which is at the heart of the driver. + The application is responsible for providing the link between the interrupt + generating hardware and the CoreI2C interrupt handler and must ensure that + the I2C_isr() function is called with the correct i2c_instance_t structure + pointer for the CoreI2C channel initiating the interrupt. + + The driver enables and disables the generation of INT interrupts by CoreI2C + at various times when it is operating through the user supplied + I2C_enable_irq() and I2C_disable_irq() functions. + + The I2C_register_write_handler() function is used to register a write + handler function with the CoreI2C driver which is called on completion + of an I2C write transaction by the CoreI2C slave. It is the user + applications responsibility to create and register the implementation of + this handler function that processes or triggers the processing of the + received data. + + The other two interrupt sources in the CoreI2C are related to SMBus + operation and are enabled and disabled through I2C_enable_smbus_irq() and + I2C_disable_smbus_irq() respectively. Due to the application specific + nature of the response to SMBus interrupts, you must design interrupt + handler functions in the application to get the desired behaviour for + SMBus related interrupts. + + If enabled, the SMBA_INT signal from the CoreI2C is asserted if an + SMBALERT condition is signalled on the SMBALERT_NI input for the channel. + + If enabled, the SMBS_INT signal from the CoreI2C is asserted if an + SMBSUSPEND condition is signalled on the SMBSUS_NI input for the channel. + + ## I2C Slave Addressing Functions + A CoreI2C peripheral responds to the following three slave addresses: + - Slave address 0 - This is the primary slave address that accesses + a CoreI2C channel when it acts as a slave in + I2C transactions. You must configure the primary slave + address using I2C_init(). + + - Slave address 1 - This is the secondary slave address which might be + required in certain application specific scenarios. + The secondary slave address is configured by + I2C_set_slave_second_addr() and is disabled by + I2C_disable_slave_second_addr(). + + - General call address - A CoreI2C slave can be configured to respond to + a broadcast command by a master transmitting the + general call address of 0x00. Use the I2C_set_gca() + function to enable the slave to respond to the general + call address. If the CoreI2C slave is not required to + respond to the general call address, disable this + address by calling I2C_clear_gca(). + + Note: All channels on a CoreI2C instance share the same slave address logic. + This means that they cannot have separate slave addresses and rely on + the separate physical I2C bus connections to distinguish them. + + -------------------------------- + Transaction Types + -------------------------------- + The I2C driver is designed to handle three types of I2C transaction: + - Write transactions + - Read transactions + - Write-read transactions + + ## Write Transaction + The master I2C device initiates a write transaction by sending a START bit + as soon as the bus becomes free. The START bit is followed by the 7-bit + serial address of the target slave device followed by the read/write bit + indicating the direction of the transaction. The slave acknowledges the + receipt of it's address with an acknowledge bit. The master sends data one + byte at a time to the slave, which must acknowledge the receipt of each byte + for the next byte to be sent. The master sends a STOP bit to complete the + transaction. The slave can abort the transaction by replying with a + non-acknowledge bit instead of an acknowledge bit. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ## Read Transaction + The master I2C device initiates a read transaction by sending a START bit + as soon as the bus becomes free. The START bit is followed by the 7-bit + serial address of the target slave device followed by the read/write bit + indicating the direction of the transaction. The slave acknowledges the + receipt of it's slave address with an acknowledge bit. The slave sends + data one byte at a time to the master, which must acknowledge the receipt of + each byte for the next byte to be sent. The master sends a non-acknowledge + bit following the last byte it wishes to read followed by a STOP bit. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ## Write-Read Transaction + The write-read transaction is a combination of a write transaction + immediately followed by a read transaction. There is no STOP bit in between + the write and read phases of a write-read transaction. A repeated START + bit is sent between the write and read phases. + + Whilst the write handler is being executed, the slave holds the clock line + low to stretch the clock until the response is ready. + + The write-read transaction is typically used to send a command or offset + in the write transaction specifying the logical data to be transferred + during the read phase. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ## Master Operations + The application can use the I2C_write(), I2C_read(), and I2C_write_read() + functions to initiate an I2C bus transaction. The application can then wait + for the transaction to complete using the I2C_wait_complete() function + or poll the status of the I2C transaction using the I2C_get_status() + function until it returns a value different from I2C_IN_PROGRESS. The + I2C_system_tick() function is used to set a time base for the + I2C_wait_complete() function's time out delay. + + ## Slave Operations + To configure the I2C driver to operate as an I2C slave requires the use + of the following functions: + - I2C_set_slave_tx_buffer() + - I2C_set_slave_rx_buffer() + - I2C_set_slave_mem_offset_length() + - I2C_register_write_handler() + - I2C_enable_slave() + + Use of all functions is not required if the slave I2C does not need to support + all types of I2C read transactions. The subsequent sections list the functions + that must be used to support each transaction type. + + ## Responding to Read Transactions + The following functions are used to configure the CoreI2C driver to + respond to I2C read transactions: + • I2C_set_slave_tx_buffer() + • I2C_enable_slave() + + The I2C_set_slave_tx_buffer() function specifies the data buffer that + is transmitted when the I2C slave is the target of an I2C read + transaction. It is then up to the application to manage the content of + that buffer to control the data that will be transmitted to the I2C + master as a result of the read transaction. + + The I2C_enable_slave() function enables the I2C hardware instance + to respond to the I2C transactions. It must be called after the I2C driver + has been configured to respond to the required transaction types. + + ## Responding to Write Transactions + The following functions are used to configure the I2C driver to respond + to I2C write transactions: + • I2C_set_slave_rx_buffer() + • I2C_register_write_handler() + • I2C_enable_slave() + + The I2C_set_slave_rx_buffer() function specifies the data buffer that + stored the data received by the I2C slave when it targets an I2C write + transaction. + + The I2C_register_write_handler() function specifies the handler function + that must be called on completion of the I2C write transaction. It is this + handler function that processes or triggers the processing of the received + data. + + The I2C_enable_slave() function enables the I2C hardware instance + to respond to I2C transactions. It must be called after the I2C driver + has been configured to respond to the required transaction types. + + ## Responding to Write-Read Transactions + The following functions are used to configure the CoreI2C driver to + respond to write-read transactions: + - I2C_set_slave_mem_offset_length() + - I2C_set_slave_tx_buffer() + - I2C_set_slave_rx_buffer() + - I2C_register_write_handler() + - I2C_enable_slave() + + The I2C_set_slave_mem_offset_length() function specifies the number of + bytes expected by the I2C slave during the write phase of the write-read + transaction. + + The I2C_set_slave_tx_buffer() function specifies the data that is + transmitted to the I2C master during the read phase of the write-read + transaction. The value received by the I2C slave during the write phase of + the transaction will be used as an index into the transmit buffer + specified by this function. It decides which part of the transmit buffer + will be transmitted to the I2C master as part of the read phase of the + write-read transaction. + + The I2C_set_slave_rx_buffer() function specifies the data buffer that + stores the data received by the I2C slave during the write phase of + the write-read transaction. This buffer must be large enough to accommodate + the number of bytes specified through the I2C_set_slave_mem_offset_length() + function. + + The I2C_register_write_handler() function can optionally be used to + specify a handler function that is called on completion of the write phase + of the I2C write-read transaction. If a handler function is registered, it + is responsible for processing the received data in the slave receive + buffer and populating the slave transmit buffer with the data that will be + transmitted to the I2C master as part of the read phase of the write-read + transaction. + + The I2C_enable_slave() function enables the CoreI2C hardware instance to + respond to the I2C transactions. It must be called after configuring the + CoreI2C driver to respond to the required transaction types. + + ## Mixed Master-Slave Operations + The CoreI2C device supports mixed master and slave operations. If the + CoreI2C slave has a transaction in progress and your application attempts to + begin a master mode transaction, the CoreI2C driver queues the master mode + transaction until the bus is released and the CoreI2C can switch to master + mode and acquire the bus. The CoreI2C master then starts the previously + queued master transaction. + + ## SMBus Control + The CoreI2C driver enables the CoreI2C peripheral’s SMBus functionality + using the I2C_smbus_init() function. + + The I2C_suspend_smbus_slave() function is used with a master mode CoreI2C + to force slave devices on the SMBus to enter their Power-Down/Suspend mode. + The I2C_resume_smbus_slave() function is used to end the suspend operation + on the SMBus. + + The I2C_reset_smbus() function is used with a master mode CoreI2C to force + all devices on the SMBus to reset their SMBUs interface. + + The I2C_set_smsbus_alert() function is used by a slave mode CoreI2C to + force communication with the SMBus master. Once communications with the + master is initiated, the I2C_clear_smsbus_alert() function clears the alert + condition. + + The I2C_enable_smbus_irq() and I2C_disable_smbus_irq() functions are used to + enable and disable the SMBSUS and SMBALERT SMBus interrupts. + + *//*=========================================================================*/ + +#ifndef CORE_I2C_H_ +#define CORE_I2C_H_ + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#include "hal_assert.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + I2C_RELEASE_BUS + ======================================= + The I2C_RELEASE_BUS constant is used to specify the options parameter to + functions I2C_read(), I2C_write() and I2C_write_read() to indicate + that a STOP bit must be generated at the end of the I2C transaction to release + the bus. + */ +#define I2C_RELEASE_BUS 0x00u + +/*-------------------------------------------------------------------------*//** + I2C_HOLD_BUS + ======================================= + The I2C_HOLD_BUS constant specify the options parameter to functions I2C_read(), + I2C_write(), and I2C_write_read() to indicate that a STOP bit must not be + generated at the end of the I2C transaction in order to retain the bus ownership. + This causes the next transaction to begin with a repeated START bit and no STOP + bit between the transactions. + */ +#define I2C_HOLD_BUS 0x01u + +/*-------------------------------------------------------------------------*//** + Interrupt Identifier Number + ======================================= + The following constants specify the interrupt identifier number which is + solely used by the driver API. This has nothing to do with hardware interrupt + line. I2C_INTR_IRQ is the primary interrupt signal which drives the state machine + of the CoreI2C driver. The I2C_SMBALERT_IRQ and I2C_SMBSUS_IRQ are used by + SMBus interrupt enable and disable functions. These IRQ numbers are also used + by I2C_get_irq_status(). + + | Constant | Description | + |--------------------|--------------------------------------------------------| + | I2C_NO_IRQ | No interrupt | + | I2C_SMBALERT_IRQ | Used by SMBus interrupt enable functions | + | I2C_SMBSUS_IRQ | Used by SMBus interrupt disable functions | + | I2C_INTR_IRQ | Primary interrupt signal which drives the state machine| + + */ +#define I2C_NO_IRQ 0x00u +#define I2C_SMBALERT_IRQ 0x01u +#define I2C_SMBSUS_IRQ 0x02u +#define I2C_INTR_IRQ 0x04u + +/*-------------------------------------------------------------------------*//** + I2C_NO_TIMEOUT + ======================================= + The I2C_wait_complete() function uses I2C_NO_TIMEOUT constant as a parameter + to indicate that the wait for completion of the transaction should not time out. + */ +#define I2C_NO_TIMEOUT 0u + +/***************************************************************************//** + The i2c_channel_number_t type is used to specify the channel number of a + CoreI2C instance. + */ +typedef enum i2c_channel_number { + I2C_CHANNEL_0 = 0u, + I2C_CHANNEL_1, + I2C_CHANNEL_2, + I2C_CHANNEL_3, + I2C_CHANNEL_4, + I2C_CHANNEL_5, + I2C_CHANNEL_6, + I2C_CHANNEL_7, + I2C_CHANNEL_8, + I2C_CHANNEL_9, + I2C_CHANNEL_10, + I2C_CHANNEL_11, + I2C_CHANNEL_12, + I2C_CHANNEL_13, + I2C_CHANNEL_14, + I2C_CHANNEL_15, + I2C_MAX_CHANNELS = 16u +} i2c_channel_number_t; + +/***************************************************************************//** + The i2c_clock_divider_t type specifies the divider to be applied + to the I2C PCLK or BCLK signal in order to generate the I2C clock. + The I2C_BCLK_DIV_8 value selects a clock frequency based on division of BCLK, + all other values select a clock frequency based on division of PCLK. + */ +typedef enum i2c_clock_divider { + I2C_PCLK_DIV_256 = 0u, + I2C_PCLK_DIV_224, + I2C_PCLK_DIV_192, + I2C_PCLK_DIV_160, + I2C_PCLK_DIV_960, + I2C_PCLK_DIV_120, + I2C_PCLK_DIV_60, + I2C_BCLK_DIV_8 +} i2c_clock_divider_t; + +/***************************************************************************//** + The i2c_status_t type is used to report the status of I2C transactions. + */ +typedef enum i2c_status +{ + I2C_SUCCESS = 0u, + I2C_IN_PROGRESS, + I2C_FAILED, + I2C_TIMED_OUT +} i2c_status_t; + +/***************************************************************************//** + The i2c_slave_handler_ret_t type is used by slave write handler functions + to indicate whether or not the received data buffer should be released. + */ +typedef enum i2c_slave_handler_ret { + I2C_REENABLE_SLAVE_RX = 0u, + I2C_PAUSE_SLAVE_RX = 1u +} i2c_slave_handler_ret_t; + +/***************************************************************************//** + This structure identifies various CoreI2C hardware instances in the system + and the I2C channels within them. The application software should declare + one instance of this structure for each channel of each instance of CoreI2C + in your system. I2C_init() and I2C_channel_init() functions initialize this + structure depending on whether it is channel 0 or one of the additional + channels, respectively. A pointer to an initialized instance of the + structure should be passed as the first parameter to the CoreI2C driver + functions, to identify which CoreI2C hardware instance and channel should + perform the requested operation. + + The contents of this data structure should not be modified or used outside of + the CoreI2C driver. Software using the CoreI2C driver should only need to + create one single instance of this data structure for each channel of each + CoreI2C hardware instance in the system then pass a pointer to these data + structures with each call to the CoreI2C driver in order to identify which + CoreI2C hardware instance to use. + */ +typedef struct i2c_instance i2c_instance_t ; +/***************************************************************************//* + Slave write handler functions prototype +/***************************************************************************//** + This defines the function prototype that must be followed by I2C slave write + handler functions. These functions are registered with the CoreI2C driver + through the I2C_register_write_handler() function. + + Declaring and Implementing Slave Write Handler Functions: + + Slave write handler functions should follow the following prototype: + @code + i2c_slave_handler_ret_t write_handler + ( + i2c_instance_t *instance, uint8_t * data, uint16_t size + ); + @endcode + + The instance parameter is a pointer to the i2c_instance_t for which this + slave write handler has been declared. + + The data parameter is a pointer to a buffer (received data buffer) holding + the data written to the I2C slave. + + Define the INCLUDE_SLA_IN_RX_PAYLOAD macro for the driver to insert the + actual address used to access the slave as the first byte in the buffer. + This allows the applications to tailor their response based on the actual + address used to access the slave (primary address, secondary address, or GCA). + + The size parameter is the number of bytes held in the received data buffer. + Handler functions must return one of the following values: + - I2C_REENABLE_SLAVE_RX + - I2C_PAUSE_SLAVE_RX + + If the handler function returns I2C_REENABLE_SLAVE_RX, the driver releases + the received data buffer and allows further I2C write transactions to the + I2C slave. + + If the handler function returns I2C_PAUSE_SLAVE_RX, the I2C slave responds + to subsequent write requests with a non-acknowledge bit (NACK), until the + received data buffer content gets processed by some other part of the + software application. + + Call the I2C_enable_slave() after returning the I2C_PAUSE_SLAVE_RX to release + the received data buffer in order to store the data received by the subsequent + I2C write transactions. + */ +typedef i2c_slave_handler_ret_t (*i2c_slave_wr_handler_t)(i2c_instance_t *instance, uint8_t *, uint16_t ); + +/***************************************************************************//** + This structure is used to identify the various CoreI2C hardware instances in + your system and the I2C channels within them. Your application software should + declare one instance of this structure for each channel of each instance of + CoreI2C in your system. The functions I2C_init() and I2C_channel_init() + initialize this structure depending on whether it is channel 0 or one of the + additional channels respectively. A pointer to an initialized instance of the + structure should be passed as the first parameter to the CoreI2C driver + functions, to identify which CoreI2C hardware instance and channel should + perform the requested operation. + + The contents of this data structure should not be modified or used outside of + the CoreI2C driver. Software using the CoreI2C driver should only need to + create one single instance of this data structure for each channel of each + CoreI2C hardware instance in the system then pass a pointer to these data + structures with each call to the CoreI2C driver in order to identify the + CoreI2C hardware instance it wishes to use. + */ +struct i2c_instance +{ + addr_t base_address; + uint_fast8_t ser_address; + + /* Transmit related info:*/ + uint_fast8_t target_addr; + + /* Current transaction type (WRITE, READ, RANDOM_READ)*/ + uint8_t transaction; + + uint_fast16_t random_read_addr; + + uint8_t options; + + /* Master TX INFO: */ + const uint8_t * master_tx_buffer; + uint_fast16_t master_tx_size; + uint_fast16_t master_tx_idx; + uint_fast8_t dir; + + /* Master RX INFO: */ + uint8_t * master_rx_buffer; + uint_fast16_t master_rx_size; + uint_fast16_t master_rx_idx; + + /* Master Status */ + volatile i2c_status_t master_status; + uint32_t master_timeout_ms; + + /* Slave TX INFO */ + const uint8_t * slave_tx_buffer; + uint_fast16_t slave_tx_size; + uint_fast16_t slave_tx_idx; + + /* Slave RX INFO */ + uint8_t * slave_rx_buffer; + uint_fast16_t slave_rx_size; + uint_fast16_t slave_rx_idx; + /* Slave Status */ + volatile i2c_status_t slave_status; + + /* Slave data: */ + uint_fast8_t slave_mem_offset_length; + i2c_slave_wr_handler_t slave_write_handler; + uint8_t is_slave_enabled; + + /* user specific data */ + void *p_user_data ; + + /* I2C bus status */ + uint8_t bus_status; + + /* Is transaction pending flag */ + uint8_t is_transaction_pending; + + /* I2C Pending transaction */ + uint8_t pending_transaction; +}; + +/*------------------------Public Function-------------------------------------*/ + +/***************************************************************************//** + The I2C_init() function configures channel 0 of a CoreI2C instance. It sets + the base hardware address which is used to locate the CoreI2C instance + in memory and also used internally by I2C_channel_init() to calculate the + register addresses for any additional channels. The slave serial address set + is shared by all channels on a CoreI2C instance. + + If only one channel is configured in a CoreI2C, the address of the + i2c_instance_t used in I2C_Init() will also be used in subsequent calls to the + CoreI2C driver functions. If more than one channel is configured in the + CoreI2C, I2C_channel_init() will be called after I2C_init(), which initializes + the i2c_instance_t data structure for a specific channel. + + @param this_i2c + Pointer to the i2c_instance_t data structure that holds all the data + related to channel 0 of the CoreI2C instance is initialized. A pointer + to this structure is used in all subsequent calls to the CoreI2C driver + functions which operates on channel 0 of this CoreI2C instance. + + @param base_address + Base address in the processor's memory map of the registers of the CoreI2C + instance being initialized. + + @param ser_address + This parameter sets the primary I2C serial address (SLAVE0 address) for the + CoreI2C to initialize. It is the principal I2C bus address to which the + CoreI2C instance will respond. CoreI2C can operate in master mode or slave + mode and the serial address is significant only in the case of I2C slave + mode. In master mode, CoreI2C does not require a serial address and the + value of this parameter is not important. If you do not intend to use the + CoreI2C device in slave mode, then provide any dummy slave address value + to this parameter. However, in systems where the CoreI2C is expected to + switch from master mode to slave mode, it is advisable to initialize the + CoreI2C device with a valid serial slave address. Call the I2C_init() + function whenever it is required to change the primary slave address as + there is no separate function to set the primary slave address of the + I2C device. The serial address initialized through this function is + basically the primary slave address or slave address0. + I2C_set_slave_second_addr() is used to set the secondary slave address + or slave address 1. + Note : ser_address parameter does not have any affect if fixed slave + address is enabled in CoreI2C hardware design. CoreI2C will + be always addressed with the hardware configured fixed slave + address. + Note : ser_address parameter will not have any affect if the CoreI2C + instance is only used in master mode. + + @param ser_clock_speed + This parameter sets the I2C serial clock frequency. It selects the divider + that generates the serial clock from the APB PCLK or from the BCLK. + It can be one of the following: + - I2C_PCLK_DIV_256 + - I2C_PCLK_DIV_224 + - I2C_PCLK_DIV_192 + - I2C_PCLK_DIV_160 + - I2C_PCLK_DIV_960 + - I2C_PCLK_DIV_120 + - I2C_PCLK_DIV_60 + - I2C_BCLK_DIV_8 + Note: serial_clock_speed value does not have any affect if the fixed baud + rate is enabled in CoreI2C hardware instance configuration dialogue + window. The fixed baud rate divider value overrides the value passed + as parameter in this function. + Note: serial_clock_speed value is not critical for devices that only operate + as slaves and can be set to any of the above values. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void system_init( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + } + @endcode + */ +void I2C_init +( + i2c_instance_t * this_i2c, + addr_t base_address, + uint8_t ser_address, + i2c_clock_divider_t ser_clock_speed +); + +/***************************************************************************//** + The I2C_channel_init() function initializes and configures hardware and data + structures of one of the additional channels of a CoreI2C instance. + I2C_init() must be called before calling this function to set the CoreI2C + instance hardware base address and I2C serial address. I2C_channel_init() also + initializes I2C serial clock divider to set the serial clock baud rate. + The pointer to data structure i2c_instance_t used for a particular channel + is used as an input parameter to subsequent CoreI2C driver functions + which operate on this channel. + + @param this_i2c_channel + Pointer to the i2c_instance_t data structure that holds all data related to + the CoreI2C channel gets initialized. A pointer to the same data structure + is used in subsequent calls to the CoreI2C driver functions in order to + identify the CoreI2C channel instance that should perform the operation + implemented by the called driver function. + + @param this_i2c + This is a pointer to an i2c_instance_t structure, previously initialized by + I2C_init(). It holds information regarding the hardware base address and + I2C serial address for the CoreI2C containing the channel to be + initialized. This information is required by I2C_channel_init() to + initialize the i2c_instance_t structure pointed by this_i2c_channel as + all channels in a CoreI2C instance share the same base address and serial + address. It is very important that the i2c_instance_t structure pointed + by this_i2c must be previously initialized by calling I2C_init(). + + @param channel_number + This parameter of type i2c_channel_number_t identifies the channel to be + initialized. + + @param ser_clock_speed + This parameter sets the I2C serial clock frequency. It selects the divider + that is used to generate the serial clock from the APB PCLK or from + the BCLK. It can be one of the following: + - I2C_PCLK_DIV_256 + - I2C_PCLK_DIV_224 + - I2C_PCLK_DIV_192 + - I2C_PCLK_DIV_160 + - I2C_PCLK_DIV_960 + - I2C_PCLK_DIV_120 + - I2C_PCLK_DIV_60 + - I2C_BCLK_DIV_8 + Note: serial_clock_speed value does not have any affect if the fixed baud + rate is enabled in CoreI2C hardware instance configuration dialogue + window. The fixed baud rate divider value will supersede the value + passed as parameter in this function. + Note: ser_clock_speed value is not critical for devices that only operate + as slaves and can be set to any of the above values. + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_SER_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + i2c_instance_t g_i2c_channel_1_inst; + + uint8_t tx_buffer[DATA_LENGTH]; + uint8_t write_length = DATA_LENGTH; + + void system_init( void ) + { + uint8_t target_slave_addr = 0x12; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize CoreI2C channel 1 with different clock speed + I2C_channel_init( &g_i2c_channel_1_inst, &g_i2c_inst, I2C_CHANNEL_1, + I2C_PCLK_DIV_224 ); + + // Write data to Channel 1 of CoreI2C instance. + I2C_write( &g_i2c_channel_1_inst, target_slave_addr, tx_buffer, + write_length, I2C_RELEASE_BUS ); + } + @endcode + +*/ +void I2C_channel_init +( + i2c_instance_t * this_i2c_channel, + i2c_instance_t * this_i2c, + i2c_channel_number_t channel_number, + i2c_clock_divider_t ser_clock_speed +); + +/***************************************************************************//** + The I2C_isr function is the CoreI2C interrupt service routine. User must + call this function from their application level CoreI2C interrupt handler + function. This function runs the I2C state machine based on previous and + current status. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREINTERRUPT_BASE_ADDR 0xCC000000u + #define COREI2C_SER_ADDR 0x10u + #define I2C_IRQ_NB 2u + + i2c_instance_t g_i2c_inst; + + void core_i2c_isr( void ) + { + I2C_isr( &g_i2c_inst ); + } + + void main( void ) + { + CIC_init( COREINTERRUPT_BASE_ADDR ); + NVIC_init(); + CIC_set_irq_handler( I2C_IRQ_NB, core_i2c_isr ); + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + NVIC_enable_interrupt( NVIC_IRQ_0 ); + } + @endcode + */ +void I2C_isr +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//* + #Master Specific Functions + + The following functions are only used within an I2C master's implementation. +/***************************************************************************//** + This function initiates an I2C master write transaction. This function returns + immediately after initiating the transaction. The content of the write buffer + passed as parameter should not be modified until the write transaction + completes. It also means that the memory allocated for the write buffer should + not be freed or should not go out of scope before the write completes. You can + check for the write transaction completion using the I2C_status() function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr + This parameter specifies the serial address of the target I2C device. + + @param write_buffer + This parameter is a pointer to a buffer holding the data to be written to + the target I2C device. Do not to release the memory used by this buffer + before the write transaction completes. For example, it is not appropriate + to return from a function allocating this buffer as an auto array variable + before the write transaction completes as this would result in the buffer's + memory being de-allocated from the stack when the function returns. This + memory could then be subsequently reused and modified causing unexpected + data to be written to the target I2C device. + + @param write_size + Number of bytes held in the write_buffer to be written to the target I2C + device. + + @param options + The options parameter is used to indicate if the I2C bus should be released + on completion of the write transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the write transaction causing the bus to be released for other I2C + devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the write + transaction, preventing other I2C devices from initiating a bus transaction. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t tx_buffer[DATA_LENGTH]; + uint8_t write_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Write data to Channel 0 of CoreI2C instance. + I2C_write( &g_i2c_inst, target_slave_addr, tx_buffer, write_length, + I2C_RELEASE_BUS ); + + // Wait for completion and record the outcome + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_write +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * write_buffer, + uint16_t write_size, + uint8_t options +); + +/***************************************************************************//** + This function initiates an I2C master read transaction. This function returns + immediately after initiating the transaction. + The contents of the read buffer passed as parameter should not be modified + until the read transaction completes. It also means that the memory allocated + for the read buffer should not be freed or should not go out of scope before + the read completes. You can check for the read transaction completion using + the I2C_status() function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr + This parameter specifies the serial address of the target I2C device. + + @param read_buffer + This is a pointer to a buffer where the data received from the target device + gets stored. Do not to release the memory used by this buffer before the read + transaction completes. For example, it is not appropriate to return from a + function allocating this buffer as an auto array variable before the read + transaction completes as this would result in the buffer's memory being + de-allocated from the stack when the function returns. This memory could + then be subsequently reallocated resulting in the read transaction + corrupting the newly allocated memory. + + @param read_size + This parameter specifies the number of bytes to read from the target device. + This size must not exceed the size of the read_buffer buffer. + + @param options + The options parameter is used to indicate if the I2C bus should be released + on completion of the read transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the read transaction causing the bus to be released for other I2C + devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the read transaction, + preventing other I2C devices from initiating a bus transaction. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t rx_buffer[DATA_LENGTH]; + uint8_t read_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Read data from target slave Channel 0 of CoreI2C instance. + I2C_read( &g_i2c_inst, target_slave_addr, rx_buffer, read_length, + I2C_RELEASE_BUS ); + + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +); + +/***************************************************************************//** + This function initiates an I2C write-read transaction where data is first + written to the target device before issuing a restart condition and changing + the direction of the I2C transaction in order to read from the target device. + + The same warnings about buffer allocation in I2C_write() and I2C_read() + applies to this function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr + This parameter specifies the serial address of the target I2C device. + + @param addr_offset + This parameter is a pointer to the buffer containing the data that is sent + to the slave during the write phase of the write-read transaction. This + data is typically used to specify an address offset specifying to the I2C + slave device what data it must return during the read phase of the + write-read transaction. + + @param offset_size + This parameter specifies the number of offset bytes to be written during the + write phase of the write-read transaction. This is typically the size of the + buffer pointed by the addr_offset parameter. + + @param read_buffer + This parameter is a pointer to the buffer where the data read from the I2C + slave will be stored. + + @param read_size + This parameter specifies the number of bytes to read from the target I2C + slave device. This size must not exceed the size of the buffer pointed by + the read_buffer parameter. + + @param options + The options parameter is used to indicate if the I2C bus should be released + on completion of the write-read transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the write-read transaction causing the bus to be released for other + I2C devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the write-read + transaction, preventing other I2C devices from initiating a bus transaction. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define TX_LENGTH 16u + #define RX_LENGTH 8u + + i2c_instance_t g_i2c_inst; + uint8_t rx_buffer[RX_LENGTH]; + uint8_t read_length = RX_LENGTH; + uint8_t tx_buffer[TX_LENGTH]; + uint8_t write_length = TX_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + I2C_write_read( &g_i2c_inst, target_slave_addr, tx_buffer, write_length, + rx_buffer, read_length, I2C_RELEASE_BUS ); + + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_write_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * addr_offset, + uint16_t offset_size, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +); + +/***************************************************************************//** + This function indicates the current state of a CoreI2C channel. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + The return value indicates the current state of a CoreI2C channel or the + outcome of the previous transaction if no transaction is in progress. + Following are the return values are: + - I2C_SUCCESS + The last I2C transaction has completed successfully. + - I2C_IN_PROGRESS + There is an I2C transaction in progress. + - I2C_FAILED + The last I2C transaction failed. + - I2C_TIMED_OUT + The request has failed to complete in the allotted time. + + @example + @code + i2c_instance_t g_i2c_inst; + + while( I2C_IN_PROGRESS == I2C_get_status( &g_i2c_inst ) ) + { + // Do something useful while waiting for I2C operation to complete + our_i2c_busy_task(); + } + + if( I2C_SUCCESS != I2C_get_status( &g_i2c_inst ) ) + { + // Something went wrong... + our_i2c_error_recovery( &g_i2c_inst ); + } + @endcode + */ +i2c_status_t I2C_get_status +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + This function waits for the current I2C transaction to complete. The return + value indicates whether the last I2C transaction was successful or not. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + @param timeout_ms + The timeout_ms parameter specifies the delay within which the current I2C + transaction should complete. The time out delay is given in + milliseconds. I2C_wait_complete() will return I2C_TIMED_OUT if the current + transaction has not completed after the time out delay has expired. This + parameter can be set to I2C_NO_TIMEOUT to indicate that I2C_wait_complete() + must not time out. + + @return + The return value indicates the outcome of the last I2C transaction. It can + be one of the following: + - I2C_SUCCESS + The last I2C transaction has completed successfully. + - I2C_FAILED + The last I2C transaction failed. + - I2C_TIMED_OUT + The last transaction failed to complete within the time out delay given + as second parameter. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t rx_buffer[DATA_LENGTH]; + uint8_t read_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Read data from Channel 0 of CoreI2C instance. + I2C_read( &g_i2c_inst, target_slave_addr, rx_buffer, read_length, + I2C_RELEASE_BUS ); + + // Wait for completion and record the outcome + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +i2c_status_t I2C_wait_complete +( + i2c_instance_t * this_i2c, + uint32_t timeout_ms +); + +/***************************************************************************//** + This function is used to control the expiration of the time out delay + specified as a parameter to the I2C_wait_complete() function. It must be + called from the interrupt service routine of a periodic interrupt source such + as the SysTick timer interrupt. It takes the period of the interrupt + source as its ms_since_last_tick parameter and uses it as the time base for + the I2C_wait_complete() function's time out delay. + + Note: This function does not need to be called if the I2C_wait_complete() + function is called with a timeout_ms value of I2C_NO_TIMEOUT. + + Note: If this function is not called then the I2C_wait_complete() function + will behave as if its timeout_ms was specified as I2C_NO_TIMEOUT and it + will not time out. + + Note: If this function is being called from an interrupt handler (for example, + SysTick) it is important that the calling interrupt have a lower priority + than the CoreI2C interrupt(s) to ensure any updates to the shared data are + protected. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + @param ms_since_last_tick + The ms_since_last_tick parameter specifies the number of milliseconds that + elapsed since the last call to I2C_system_tick(). This parameter would + typically be a constant specifying the interrupt rate of a timer used to + generate system ticks. + + @return None. + + @example + The following example shows how the I2C_system_tick() function. I2C_system_tick() + is called for each I2C channel from the SysTick timer interrupt service routine. + The following example shows how the SysTick is configured to generate an interrupt + in every 10 milliseconds. + @code + #define SYSTICK_INTERVAL_MS 10 + + void SysTick_Handler(void) + { + I2C_system_tick(&g_core_i2c0, SYSTICK_INTERVAL_MS); + I2C_system_tick(&g_core_i2c2, SYSTICK_INTERVAL_MS); + } + @endcode + */ +void I2C_system_tick +( + i2c_instance_t * this_i2c, + uint32_t ms_since_last_tick +); + +/***************************************************************************//* + #Slave Specific Functions + + The following functions are only used within the implementation of an I2C slave device. + +/***************************************************************************//** + This function specifies the memory buffer holding the data that will be sent + to the I2C master when this CoreI2C channel is the target of an I2C read or + write-read transaction. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param tx_buffer + This parameter is a pointer to the memory buffer holding the data to be + returned to the I2C master when this CoreI2C channel is the target of an + I2C read or write-read transaction. + + @param tx_size + Size of the transmit buffer pointed by the tx_buffer parameter. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Specify the transmit buffer containing the data that will be + // returned to the master during read and write-read transactions. + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + } + @endcode + */ +void I2C_set_slave_tx_buffer +( + i2c_instance_t * this_i2c, + const uint8_t * tx_buffer, + uint16_t tx_size +); + +/***************************************************************************//** + This function specifies the memory buffer that is used by the CoreI2C channel + to receive data when it is a slave. This buffer is the memory where data gets + stored when the CoreI2C channel is the target of an I2C master write + transaction (that is, when it is the slave). + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param rx_buffer + This parameter is a pointer to the memory buffer allocated by the caller + software to be used as a slave receive buffer. + + @param rx_size + Size of the slave receive buffer. This is the amount of memory allocated + to the buffer pointed by rx_buffer. + Note: Indirectly, this buffer size specifies the maximum I2C write + transaction length this CoreI2C channel targets. This is because + this CoreI2C channel responds to further received bytes with + a non-acknowledge bit (NACK) as soon as its receive buffer is + full. This causes the write transaction to fail. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_RX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_rx_buffer[SLAVE_RX_BUFFER_SIZE]; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Specify the buffer used to store the data written by the I2C master. + I2C_set_slave_rx_buffer( &g_i2c_inst, g_slave_rx_buffer, + sizeof(g_slave_rx_buffer) ); + } + @endcode + */ +void I2C_set_slave_rx_buffer +( + i2c_instance_t * this_i2c, + uint8_t * rx_buffer, + uint16_t rx_size +); + +/***************************************************************************//** + This function is used as part of the configuration of a CoreI2C channel to + operate as a slave supporting write-read transactions. It specifies the + number of bytes expected as part of the write phase of a write-read + transaction. The bytes received during the write phase of a write-read + transaction will be interpreted as an offset into the slave's transmit buffer. + This allows random access into the I2C slave transmit buffer from a remote + I2C master. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param offset_length + The offset_length parameter configures the number of bytes to be interpreted + by the CoreI2C slave as a memory offset value during the write phase of + write-read transactions. The maximum value for the offset_length parameter + is two. The value of offset_length has the following effect on the + interpretation of the received data. + • If offset_length is 0, the offset into the transmit buffer is fixed at 0. + • If offset_length is 1, a single byte of received data is interpreted as an + unsigned 8-bit offset value in the range 0 to 255. + • If offset_length is 2, 2 bytes of received data are interpreted as an + unsigned 16-bit offset value in the range 0 to 65535. The first byte + received in this case provides the high order bits of the offset and + the second byte provides the low order bits. + If the number of bytes received does not match the non 0 value of + offset_length, the transmit buffer offset is set to 0. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + I2C_set_slave_mem_offset_length( &g_i2c_inst, 1 ); + } + @endcode + */ +void I2C_set_slave_mem_offset_length +( + i2c_instance_t * this_i2c, + uint8_t offset_length +); + +/***************************************************************************//** + Register the function that is called to process the data written to this + CoreI2C channel when it is the slave in an I2C write transaction. + + Note: If a write handler is registered, it is called on completion of the + write phase of a write-read transaction and responsible for processing + the received data in the slave receive buffer and populating the slave + transmit buffer with the data that is transmitted to the I2C master + as part of the read phase of the write-read transaction. If a write + handler is not registered, the write data of a write-read transaction is + interpreted as an offset into the slave’s transmit buffer and handled by + the driver. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param handler + Pointer to the function that processes the I2C write request. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + // local function prototype + void slave_write_handler + ( + i2c_instance_t * this_i2c, + uint8_t * p_rx_data, + uint16_t rx_size + ); + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + I2C_set_slave_mem_offset_length( &g_i2c_inst, 1 ); + I2C_register_write_handler( &g_i2c_inst, slave_write_handler ); + } + @endcode +*/ +void I2C_register_write_handler +( + i2c_instance_t * this_i2c, + i2c_slave_wr_handler_t handler +); + +/***************************************************************************//** + This function enables slave mode operation for a CoreI2C channel. It enables + the CoreI2C slave to receive data when it is the target of an I2C read, write, + or write-read transaction. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + // Enable I2C slave + I2C_enable_slave( &g_i2c_inst ); + @endcode + */ +void I2C_enable_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + This function disables the slave mode operation for a CoreI2C channel. It stops + the CoreI2C slave that acknowledges the I2C read, write, or write-read + transactions targeted at it. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + // Disable I2C slave + I2C_disable_slave( &g_i2c_inst ); + @endcode + */ +void I2C_disable_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_slave_second_addr() function sets the secondary slave address for + a CoreI2C slave device. This is an additional slave address required in certain + applications, for example, to enable fail-safe operation in a system. As the + CoreI2C device supports 7-bit addressing, the highest value assigned to second + slave address is 127 (0x7F). + + Note: This function does not support CoreI2C hardware configured with a fixed + second slave address. The current implementation of the ADDR1[0] register + bit makes it difficult for the driver to support both programmable and + fixed second slave address, so we choose to support programmable only. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param second_slave_addr + The second_slave_addr parameter is the secondary slave address of the I2C + device. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SECOND_SLAVE_ADDR 0x20u + + i2c_instance_t g_i2c_inst; + void main( void ) + { + // Initialize the CoreI2C driver with its base address, primary I2C + // serial address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_second_addr( &g_i2c_inst, SECOND_SLAVE_ADDR ); + } + @endcode + */ +void I2C_set_slave_second_addr +( + i2c_instance_t * this_i2c, + uint8_t second_slave_addr +); + +/***************************************************************************//** + The I2C_disable_slave_second_addr() function disables the secondary slave + address of the CoreI2C slave device. + + Note: This version of the driver only supports CoreI2C hardware configured + with a programmable second slave address. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + i2c_instance_t g_i2c_inst; + I2C_disable_slave_second_addr( &g_i2c_inst); + @endcode + */ +void I2C_disable_slave_second_addr +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_gca() function is used to set the general call acknowledgement bit + of a CoreI2C slave device. This allows all channels of the CoreI2C slave + device to respond to a general call or broadcast message from an I2C master. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + i2c_instance_t g_i2c_inst; + + // Enable recognition of the General Call Address + I2C_set_gca( &g_i2c_inst ); + @endcode + */ +void I2C_set_gca +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_clear_gca() function is used to clear the general call acknowledgement + bit of a CoreI2C slave device. This will stop all channels of the I2C slave + device responding to any general call or broadcast message from the master. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + i2c_instance_t g_i2c_inst; + + // Disable recognition of the General Call Address + I2C_clear_gca( &g_i2c_inst ); + @endcode + */ + +void I2C_clear_gca +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//* + #I2C SMBUS Specific APIs + +/***************************************************************************//** + The I2C_smbus_init() function enables SMBus timeouts and status logic for a + CoreI2C channel. + + Note: This and any of the other SMBus related functionality will only have an + effect if the CoreI2C was instantiated with the Generate SMBus Logic + option checked. + + Note: If the CoreI2C was instantiated with the Generate IPMI Logic option + checked this function then enables the IPMI 3mS SCL low timeout but + none of the other SMBus functions will have any effect. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void system_init( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst); + } + @endcode + */ +void I2C_smbus_init +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_enable_smbus_irq() function is used to enable the CoreI2C channel’s + SMBSUS and SMBALERT SMBus interrupts. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param irq_type + The irq_type specify the SMBUS interrupt(s) which will be enabled. + The two possible interrupts are: + - I2C_SMBALERT_IRQ + - I2C_SMBSUS_IRQ + To enable both interrupts in one call, use I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ. + + @return + None + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both I2C_SMBALERT_IRQ & I2C_SMBSUS_IRQ interrupts + I2C_enable_smbus_irq( &g_i2c_inst, + (uint8_t)(I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ) ); + } + @endcode + */ +void I2C_enable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +); + +/***************************************************************************//** + The I2C_disable_smbus_irq() function disable the CoreI2C channel’s SMBSUS and + SMBALERT SMBus interrupts. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param irq_type + The irq_type specifies the SMBUS interrupt(s) which are disabled. + The two possible interrupts are: + • I2C_SMBALERT_IRQ + • I2C_SMBSUS_IRQ + To disable both ints in one call, use I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both SMBALERT & SMBSUS interrupts + I2C_enable_smbus_irq( &g_i2c_inst, + (uint8_t)(I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ)); + + ... + + // Disable the SMBALERT interrupt + I2C_disable_smbus_irq( &g_i2c_inst, I2C_SMBALERT_IRQ ); + } + @endcode + */ +void I2C_disable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +); + +/***************************************************************************//** + The I2C_suspend_smbus_slave() function forces any SMBUS slave devices + connected to a CoreI2C channel into Power-Down or Suspend mode by asserting + the channel's SMBSUS signal. The CoreI2C channel is the SMBus master in this + case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // suspend SMBus slaves + I2C_suspend_smbus_slave( &g_i2c_inst ); + + ... + + // Re-enable SMBus slaves + I2C_resume_smbus_slave( &g_i2c_inst ); + } + @endcode + */ +void I2C_suspend_smbus_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_resume_smbus_slave() function de-asserts the CoreI2C channel's SMBSUS + signal to take any connected slave devices out of the Suspend mode. The CoreI2C + channel is the SMBus master in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // suspend SMBus slaves + I2C_suspend_smbus_slave( &g_i2c_inst ); + + ... + + // Re-enable SMBus slaves + I2C_resume_smbus_slave( &g_i2c_inst ); + } + @endcode + */ +void I2C_resume_smbus_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_reset_smbus() function resets the CoreI2C channel's SMBus connection + by forcing SCLK low for 35 mS. The reset that automatically cleares after 35 ms + gets elapsed. The CoreI2C channel is the SMBus master in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Make sure the SMBus channel is in a known state by resetting it + I2C_reset_smbus( &g_i2c_inst ); + } + @endcode + */ +void I2C_reset_smbus +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_smbus_alert() function is used to force master communication with + an I2C slave device by asserting the CoreI2C channel's SMBALERT signal. The + CoreI2C channel is the SMBus slave in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Get the SMBus masters attention + I2C_set_smbus_alert( &g_i2c_inst ); + + ... + + // Once we are happy, drop the alert + I2C_clear_smbus_alert( &g_i2c_inst ); + } + @endcode + */ +void I2C_set_smbus_alert +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_clear_smbus_alert() function is used to de-assert the CoreI2C channel's + SMBALERT signal once a slave device gets a response from the master. The + CoreI2C channel is the SMBus slave in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Get the SMBus masters attention + I2C_set_smbus_alert( &g_i2c_inst ); + + ... + + // Once we are happy, drop the alert + I2C_clear_smbus_alert( &g_i2c_inst ); + } + @endcode + */ +void I2C_clear_smbus_alert +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_get_irq_status function returns information about which interrupts are + currently pending in a CoreI2C channel. + The interrupts supported by CoreI2C are: + • SMBUSALERT + • SMBSUS + • INTR + + The macros I2C_NO_IRQ, I2C_SMBALERT_IRQ, I2C_SMBSUS_IRQ, and I2C_INTR_IRQ are + provided to use with this function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + This function returns the status of the CoreI2C channel's interrupts as a + single byte bitmap where a bit is set to indicate a pending interrupt. + The following are the bit positions associated with each interrupt type: + Bit 0 - SMBUS_ALERT_IRQ + Bit 1 - SMBSUS_IRQ + Bit 2 - INTR_IRQ + It returns 0, if there are no pending interrupts. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + uint8_t irq_to_enable = I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ; + uint8_t pending_irq = 0u; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both I2C_SMBALERT_IRQ & I2C_SMBSUS_IRQ irq + I2C_enable_smbus_irq( &g_i2c_inst, irq_to_enable ); + + // Get I2C IRQ type + pending_irq = I2C_get_irq_status( &g_i2c_inst ); + + // Let's assume, in system, INTR and SMBALERT IRQ is pending. + // So pending_irq will return status of both the IRQs + + if( pending_irq & I2C_SMBALERT_IRQ ) + { + // if true, it means SMBALERT_IRQ is there in pending IRQ list + } + if( pending_irq & I2C_INTR_IRQ ) + { + // if true, it means I2C_INTR_IRQ is there in pending IRQ list + } + } + @endcode + */ +uint8_t I2C_get_irq_status +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_user_data() function allows the association of a block of application + specific data with a CoreI2C channel. The composition of the data block is an + application matter and the driver simply provides the means for the application + to set and retrieve the pointer. For example, this is used to provide additional + channel specific information to the slave write handler. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param p_user_data + The p_user_data parameter is a pointer to the user specific data block for + this channel. It is defined as void * as the driver does not know the actual + type of data being pointed to and simply stores the pointer for later + retrieval by the application. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + app_data_t channel_xdata; + + void main( void ) + { + app_data_t *p_xdata; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Store location of user data in instance structure + I2C_set_user_data( &g_i2c_inst, (void *)&channel_xdata ); + + ... + + // Retrieve location of user data and do some work on it + p_xdata = (app_data_t *)I2C_get_user_data( &g_i2c_inst ); + if( NULL != p_xdata ) + { + p_xdata->foo = 123; + } + } + @endcode + */ +void I2C_set_user_data +( + i2c_instance_t * this_i2c, + void * p_user_data +); + +/***************************************************************************//** + The I2C_get_user_data() function is used to allows the retrieval of the address + of a block of application specific data associated with a CoreI2C channel. + The composition of the data block is an application matter and the driver + simply provides the means for the application to set and retrieve the pointer. + For example, this is used to provide additional channel specific information + to the slave write handler. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + This function returns a pointer to the user specific data block for this + channel. It is defined as void * as the driver does not know the actual type + of data being pointed. If no user data has been registered for this channel + a NULL pointer is returned. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + app_data_t channel_xdata; + + void main( void ) + { + app_data_t *p_xdata; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Store location of user data in instance structure + I2C_set_user_data( &g_i2c_inst, (void *)&channel_xdata ); + + ... + + // Retrieve location of user data and do some work on it + p_xdata = (app_data_t *)I2C_get_user_data( &g_i2c_inst ); + if( NULL != p_xdata ) + { + p_xdata->foo = 123; + } + } + @endcode + */ +void * I2C_get_user_data +( + i2c_instance_t * this_i2c +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h new file mode 100644 index 0000000..b1d872d --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h @@ -0,0 +1,190 @@ +/******************************************************************************* + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + */ + +#ifndef __CORE_SMBUS_REGISTERS +#define __CORE_SMBUS_REGISTERS 1 + +/*------------------------------------------------------------------------------ + * CONTROL register details + */ +#define CONTROL_REG_OFFSET 0x00u + +/* + * CR0 bits. + */ +#define CR0_OFFSET 0x00u +#define CR0_MASK 0x01u +#define CR0_SHIFT 0u + +/* + * CR1 bits. + */ +#define CR1_OFFSET 0x00u +#define CR1_MASK 0x02u +#define CR1_SHIFT 1u + +/* + * AA bits. + */ +#define AA_OFFSET 0x00u +#define AA_MASK 0x04u +#define AA_SHIFT 2u + +/* + * SI bits. + */ +#define SI_OFFSET 0x00u +#define SI_MASK 0x08u +#define SI_SHIFT 3u + +/* + * STO bits. + */ +#define STO_OFFSET 0x00u +#define STO_MASK 0x10u +#define STO_SHIFT 4u + +/* + * STA bits. + */ +#define STA_OFFSET 0x00u +#define STA_MASK 0x20u +#define STA_SHIFT 5u + +/* + * ENS1 bits. + */ +#define ENS1_OFFSET 0x00u +#define ENS1_MASK 0x40u +#define ENS1_SHIFT 6u + +/* + * CR2 bits. + */ +#define CR2_OFFSET 0x00u +#define CR2_MASK 0x80u +#define CR2_SHIFT 7u + +/*------------------------------------------------------------------------------ + * STATUS register details + */ +#define STATUS_REG_OFFSET 0x04u + +/*------------------------------------------------------------------------------ + * DATA register details + */ +#define DATA_REG_OFFSET 0x08u + +/* + * TARGET_ADDR bits. + */ +#define TARGET_ADDR_OFFSET 0x08u +#define TARGET_ADDR_MASK 0xFEu +#define TARGET_ADDR_SHIFT 1u + +/* + * DIR bit. + */ +#define DIR_OFFSET 0x08u +#define DIR_MASK 0x01u +#define DIR_SHIFT 0u + + +/*------------------------------------------------------------------------------ + * ADDRESS register details + */ +#define ADDRESS_REG_OFFSET 0x0Cu + +/* + * GC bits. + */ +#define GC_OFFSET 0x0Cu +#define GC_MASK 0x01u +#define GC_SHIFT 0u + +/* + * ADR bits. + */ +#define OWN_SLAVE_ADDR_OFFSET 0x0Cu +#define OWN_SLAVE_ADDR_MASK 0xFEu +#define OWN_SLAVE_ADDR_SHIFT 1u + +/*------------------------------------------------------------------------------ + * SMBUS register details + */ +#define SMBUS_REG_OFFSET 0x10u + +/* + * SMBALERT_IE bits. + */ +#define SMBALERT_IE_OFFSET 0x10u +#define SMBALERT_IE_MASK 0x01u +#define SMBALERT_IE_SHIFT 0u + +/* + * SMBSUS_IE bits. + */ +#define SMBSUS_IE_OFFSET 0x10u +#define SMBSUS_IE_MASK 0x02u +#define SMBSUS_IE_SHIFT 1u + +/* + * SMB_IPMI_EN bits. + */ +#define SMB_IPMI_EN_OFFSET 0x10u +#define SMB_IPMI_EN_MASK 0x04u +#define SMB_IPMI_EN_SHIFT 2u + +/* + * SMBALERT_NI_STATUS bits. + */ +#define SMBALERT_NI_STATUS_OFFSET 0x10u +#define SMBALERT_NI_STATUS_MASK 0x08u +#define SMBALERT_NI_STATUS_SHIFT 3u + +/* + * SMBALERT_NO_CONTROL bits. + */ +#define SMBALERT_NO_CONTROL_OFFSET 0x10u +#define SMBALERT_NO_CONTROL_MASK 0x10u +#define SMBALERT_NO_CONTROL_SHIFT 4u + +/* + * SMBSUS_NI_STATUS bits. + */ +#define SMBSUS_NI_STATUS_OFFSET 0x10u +#define SMBSUS_NI_STATUS_MASK 0x20u +#define SMBSUS_NI_STATUS_SHIFT 5u + +/* + * SMBSUS_NO_CONTROL bits. + */ +#define SMBSUS_NO_CONTROL_OFFSET 0x10u +#define SMBSUS_NO_CONTROL_MASK 0x40u +#define SMBSUS_NO_CONTROL_SHIFT 6u + +/* + * SMBUS_MST_RESET bits. + */ +#define SMBUS_MST_RESET_OFFSET 0x10u +#define SMBUS_MST_RESET_MASK 0x80u +#define SMBUS_MST_RESET_SHIFT 7u + +/*------------------------------------------------------------------------------ + * SLAVE ADDRESS 1 register details + */ + +#define ADDRESS1_REG_OFFSET 0x1Cu + +/* + * SLAVE1_EN bit of Slave Address 1 . + */ +#define SLAVE1_EN_OFFSET 0x1Cu +#define SLAVE1_EN_MASK 0x01u +#define SLAVE1_EN_SHIFT 0u + +#endif /* __CORE_SMBUS_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c new file mode 100644 index 0000000..12e352d --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * CoreI2C driver interrupt control. + * + */ +#include "core_i2c.h" + +/*------------------------------------------------------------------------------ + * This function must be modified to enable interrupts generated from the + * CoreI2C instance identified as parameter. + */ +void I2C_enable_irq( i2c_instance_t * this_i2c ) +{ + HAL_ASSERT(0) +} + +/*------------------------------------------------------------------------------ + * This function must be modified to disable interrupts generated from the + * CoreI2C instance identified as parameter. + */ +void I2C_disable_irq( i2c_instance_t * this_i2c ) +{ + HAL_ASSERT(0) +} diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.c b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.c new file mode 100644 index 0000000..2e11750 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.c @@ -0,0 +1,1345 @@ +/***************************************************************************//** + * Copyright 2013-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * CoreSPI bare metal driver implementation for CoreSPI. + * + * This Core SPI driver provides functions for implementing SPI master or + * SPI slave operations with the CoreSPI version 4.2.xxx It is not compatible + * with CoreSPI version 3.0.xxx. + * + * @file core_spi.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreSPI software configuration + * + */ + +#include "core_spi.h" +#include "corespi_regs.h" +#include + +/******************************************************************************* + * Null parameters with appropriate type definitions + */ +#define NULL_ADDR ( ( addr_t ) 0u ) +#define NULL_INSTANCE ( ( spi_instance_t * ) 0u ) +#define NULL_BUFF ( ( uint8_t * ) 0u ) +#define NULL_FRAME_HANDLER ( ( spi_frame_rx_handler_t ) 0u ) +#define NULL_BLOCK_HANDLER ( ( spi_block_rx_handler_t ) 0u ) +#define NULL_SLAVE_TX_UPDATE_HANDLER ( ( spi_slave_frame_tx_handler_t ) 0u ) +#define NULL_SLAVE_CMD_HANDLER NULL_BLOCK_HANDLER + +#define SPI_ALL_INTS (0xFFu) /* For clearing all active interrupts */ + +/******************************************************************************* + * Possible states for different register bit fields + */ + +#define DISABLE 0u +#define ENABLE 1u + + +/******************************************************************************* + * Function return values + */ +enum { + FAILURE = 0u, + SUCCESS = 1u +}; + +/******************************************************************************* + * Local function declarations + */ +static void fill_slave_tx_fifo( spi_instance_t * this_spi ); +static void read_slave_rx_fifo( spi_instance_t * this_spi ); +static void recover_from_rx_overflow( const spi_instance_t * this_spi ); + +/******************************************************************************* + * SPI_init() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_init +( + spi_instance_t * this_spi, + addr_t base_addr, + uint16_t fifo_depth +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( NULL_ADDR != base_addr ); + HAL_ASSERT( SPI_MAX_FIFO_DEPTH >= fifo_depth ); + HAL_ASSERT( SPI_MIN_FIFO_DEPTH <= fifo_depth ); + + if( ( NULL_INSTANCE != this_spi ) && ( base_addr != NULL_ADDR ) ) + { + /* + * Initialize all transmit / receive buffers and handlers + * + * Relies on the fact that byte filling with 0x00 will equate + * to 0 for any non byte sized items too. + */ + + /* First fill struct with 0s */ + memset( this_spi, 0, sizeof(spi_instance_t) ); + + /* Configure CoreSPI instance attributes */ + this_spi->base_addr = (addr_t)base_addr; + + /* Store FIFO depth or fall back to minimum if out of range */ + if( ( SPI_MAX_FIFO_DEPTH >= fifo_depth ) && ( SPI_MIN_FIFO_DEPTH <= fifo_depth ) ) + { + this_spi->fifo_depth = fifo_depth; + } + else + { + this_spi->fifo_depth = SPI_MIN_FIFO_DEPTH; + } + /* Make sure the CoreSPI is disabled while we configure it */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Ensure all slaves are deselected */ + HAL_set_8bit_reg( this_spi->base_addr, SSEL, 0u ); + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Ensure RXAVAIL, TXRFM, SSEND and CMDINT are disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, 0u ); + /* + * Enable the CoreSPI in the reset default of master mode + * with TXUNDERRUN, RXOVFLOW and TXDONE interrupts disabled. + * The driver does not currently use interrupts in master mode. + */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL1, ENABLE | CTRL1_MASTER_MASK ); + } +} + +/***************************************************************************//** + * SPI_configure_slave_mode() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_configure_slave_mode +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Don't yet know what slave transfer mode will be used */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_NONE; + + /* Make sure the CoreSPI is disabled while we configure it */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Ensure RXAVAIL, TXRFM, SSEND and CMDINT are disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, 0u ); + /* + * Enable the CoreSPI in slave mode with TXUNDERRUN, RXOVFLOW and TXDONE + * interrupts disabled. The appropriate interrupts will be enabled later + * on when the transfer mode is configured. + */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL1, ENABLE ); + } +} + +/***************************************************************************//** + * SPI_configure_master_mode() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_configure_master_mode +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Disable the CoreSPI for a little while, while we configure the CoreSPI */ + HAL_set_8bit_reg_field(this_spi->base_addr, CTRL1_ENABLE, DISABLE); + + /* Reset slave transfer mode to unknown in case it has been set previously */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_NONE; + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Ensure RXAVAIL, TXRFM, SSEND and CMDINT are disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, 0u ); + + /* Enable the CoreSPI in master mode with TXUNDERRUN, RXOVFLOW and TXDONE interrupts disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL1, ENABLE | CTRL1_MASTER_MASK ); + } +} + +/***************************************************************************//** + * SPI_set_slave_select() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +) +{ + spi_slave_t temp = (spi_slave_t)(0x00u) ; + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( SPI_MAX_NB_OF_SLAVES > slave ); + + if( ( NULL_INSTANCE != this_spi ) && ( SPI_MAX_NB_OF_SLAVES > slave ) ) + { + /* This function is only intended to be used with an SPI master */ + if( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW ) ) + { + recover_from_rx_overflow( this_spi ); + } + /* Set the correct slave select bit */ + temp = (spi_slave_t)( HAL_get_8bit_reg( this_spi->base_addr, SSEL ) | ((uint32_t)1u << (uint32_t)slave) ); + HAL_set_8bit_reg( this_spi->base_addr, SSEL, (uint_fast8_t)temp ); + } + } +} + +/***************************************************************************//** + * SPI_clear_slave_select() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_clear_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +) +{ + spi_slave_t temp = (spi_slave_t) (0x00u) ; + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( SPI_MAX_NB_OF_SLAVES > slave ); + + if( ( NULL_INSTANCE != this_spi ) && ( SPI_MAX_NB_OF_SLAVES > slave ) ) + { + /* This function is only intended to be used with an SPI master. */ + if( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW) ) + { + recover_from_rx_overflow( this_spi ); + } + /* Clear the correct slave select bit */ + temp = (spi_slave_t)( HAL_get_8bit_reg( this_spi->base_addr, SSEL ) & ~((uint32_t)1u << (uint32_t)slave) ); + HAL_set_8bit_reg( this_spi->base_addr, SSEL, (uint_fast8_t)temp ) ; + } + } +} + +/***************************************************************************//** + * SPI_transfer_frame() + * See "core_spi.h" for details of how to use this function. + */ +uint32_t SPI_transfer_frame +( + spi_instance_t * this_spi, + uint32_t tx_bits +) +{ + volatile uint32_t rx_data = 0u; /* Ensure consistent return value if in slave mode */ + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI master. */ + if( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Flush the receive and transmit FIFOs by resetting both */ + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK); + + /* Send frame. */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, tx_bits ); + + /* Wait for frame Tx to complete. */ + while ( ENABLE != HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_DONE ) ) + { + ; + } + + /* Read received frame. */ + rx_data = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + } + } + + /* Finally, return the frame we received from the slave or 0 */ + return( rx_data ); +} + + +/***************************************************************************//** + * SPI_transfer_block() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_transfer_block +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_buffer, + uint16_t rx_byte_size +) +{ + uint32_t transfer_size = 0U; /* Total number of bytes to transfer. */ + uint16_t transfer_idx = 0U; /* Number of bytes transferred so far */ + uint16_t tx_idx = 0u; /* Number of valid data bytes sent */ + uint16_t rx_idx = 0u; /* Number of valid response bytes received */ + uint16_t transit = 0U; /* Number of bytes "in flight" to avoid FIFO errors */ + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI master. */ + if( ( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) && + /* Check for empty transfer as well */ + ( 0u != ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) ) ) + { + /* + * tansfer_size is one less than the real amount as we have to write + * the last frame separately to trigger the slave deselect in case + * the SPS option is in place. + */ + transfer_size = ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) - 1u; + /* Flush the receive and transmit FIFOs */ + HAL_set_8bit_reg(this_spi->base_addr, CMD, (uint32_t)(CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK )); + + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW) ) + { + recover_from_rx_overflow( this_spi ); + } + + /* Disable the Core SPI for a little bit, while we load the TX FIFO */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + while( ( tx_idx < transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out 0s to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + } + ++transit; + ++tx_idx; + } + + /* If room left to put last frame in before the off, then do it */ + if( ( tx_idx == transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data, not expecting any reply this time */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out last 0 to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + } + + ++transit; + ++tx_idx; + } + + /* FIFO is all loaded up so enable Core SPI to start transfer */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + + /* Perform the remainder of the transfer by sending a byte every time a byte + * has been received. This should ensure that no Rx overflow can happen in + * case of an interrupt occurring during this function. + * + * We break the transfer down into stages to minimise the processing in + * each loop as the SPI interface is very demanding at higher clock rates. + * This works well with FIFOs but might be less efficient if there is only + * a single frame buffer. + * + * First stage transfers remaining command bytes (if any). + * At this stage anything in the RX FIFO can be discarded as it is + * not part of a valid response. + */ + while( tx_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + /* Send another byte. */ + if( tx_idx == transfer_size ) /* Last frame is special... */ + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Read and discard. */ + HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now, we are writing dummy bytes to push through the response from + * the slave but we still have to keep discarding any read data that + * corresponds with one of our command bytes. + */ + while( transfer_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + if( tx_idx < transfer_size ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Read and discard. */ + HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now we are now only sending dummy data to push through the + * valid response data which we store in the response buffer. + */ + while( tx_idx < transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received byte. */ + rx_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* If we still need to send the last frame */ + while( tx_idx == transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received byte. */ + rx_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* + * Finally, we are now finished sending data and are only reading + * valid response data which we store in the response buffer. + */ + while( transfer_idx <= transfer_size ) + { + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received byte. */ + rx_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + } + } + } + } +} + +/***************************************************************************//** + * SPI_transfer_block_store_all_resp() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_transfer_block_store_all_resp +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_data_buffer, + uint16_t rx_byte_size, + uint8_t * cmd_response_buffer +) +{ + uint32_t transfer_size = 0U; /* Total number of bytes to transfer. */ + uint16_t transfer_idx = 0U; /* Number of bytes transferred so far */ + uint16_t tx_idx = 0u; /* Number of valid data bytes sent */ + uint16_t rx_idx = 0u; /* Number of valid response bytes received */ + uint16_t transit = 0U; /* Number of bytes "in flight" to avoid FIFO errors */ + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI master. */ + if( ( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) && + /* Check for empty transfer as well */ + ( 0u != ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) ) ) + { + /* + * tansfer_size is one less than the real amount as we have to write + * the last frame separately to trigger the slave deselect in case + * the SPS option is in place. + */ + transfer_size = ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) - 1u; + /* Flush the receive and transmit FIFOs */ + HAL_set_8bit_reg(this_spi->base_addr, CMD, (uint32_t)(CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK )); + + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW) ) + { + recover_from_rx_overflow( this_spi ); + } + + /* Disable the Core SPI for a little bit, while we load the TX FIFO */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + while( ( tx_idx < transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out 0s to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + } + ++transit; + ++tx_idx; + } + + /* If room left to put last frame in before the off, then do it */ + if( ( tx_idx == transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data, not expecting any reply this time */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out last 0 to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + } + + ++transit; + ++tx_idx; + } + + /* FIFO is all loaded up so enable Core SPI to start transfer */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + + /* Perform the remainder of the transfer by sending a byte every time a byte + * has been received. This should ensure that no Rx overflow can happen in + * case of an interrupt occurring during this function. + * + * We break the transfer down into stages to minimise the processing in + * each loop as the SPI interface is very demanding at higher clock rates. + * This works well with FIFOs but might be less efficient if there is only + * a single frame buffer. + * + * First stage transfers remaining command bytes (if any). + * At this stage anything in the RX FIFO can be discarded as it is + * not part of a valid response. + */ + while( tx_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + /* Send another byte. */ + if( tx_idx == transfer_size ) /* Last frame is special... */ + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received command byte. */ + cmd_response_buffer[transfer_idx] = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now, we are writing dummy bytes to push through the response from + * the slave, which we store in the command response buffer. + */ + while( transfer_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + if( tx_idx < transfer_size ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received command byte. */ + cmd_response_buffer[transfer_idx] = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now we are now only sending dummy data to push through the + * valid response data which we store in the data response buffer. + */ + while( tx_idx < transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received data byte. */ + rx_data_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* If we still need to send the last frame */ + while( tx_idx == transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received data byte. */ + rx_data_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* + * Finally, we are now finished sending data and are only reading + * valid response data which we store in the data response buffer. + */ + while( transfer_idx <= transfer_size ) + { + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received data byte. */ + rx_data_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + } + } + } + } +} +/***************************************************************************//** + * SPI_set_frame_rx_handler() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_frame_rx_handler +( + spi_instance_t * this_spi, + spi_frame_rx_handler_t rx_handler +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if(NULL_INSTANCE != this_spi) + { + /* This function is only intended to be used with an SPI slave. */ + if(DISABLE == HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER)) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Disable SSEND and CMD interrupts as we are not doing block transfers */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTSSEND, DISABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + + /* Disable block Rx handler as they are mutually exclusive. */ + this_spi->block_rx_handler = 0U; + + /* Keep a copy of the pointer to the Rx handler function. */ + this_spi->frame_rx_handler = rx_handler; + + if( SPI_SLAVE_XFER_FRAME != this_spi->slave_xfer_mode ) + { + /* + * Either just coming from init or were previously in block mode + * so no tx frame handler is set at this point in time... + * + * Don't allow TXDONE interrupts. + */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXDONE, DISABLE ); + } + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK); + + /* Enable Rx and FIFO error interrupts */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTRXOVFLOW, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXURUN, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTRXDATA, ENABLE ); + + /* Make sure correct mode is selected */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_FRAME; + + /* Finally re-enable the CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } + } +} + +/***************************************************************************//** + * SPI_set_slave_tx_frame() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_slave_tx_frame +( + spi_instance_t * this_spi, + uint32_t frame_value, + spi_slave_frame_tx_handler_t slave_tx_frame_handler +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI slave. */ + if( DISABLE == HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Disable SSEND and CMD interrupts as we are not doing block transfers */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTSSEND, DISABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + + if( SPI_SLAVE_XFER_FRAME != this_spi->slave_xfer_mode ) + { + /* + * Either just coming from init or were previously in block mode + * so no rx frame handler is set at this point in time... + * + * Don't allow RXDATA interrupts. + */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTRXDATA, DISABLE ); + } + + /* Disable slave block tx buffer as it is mutually exclusive with frame + * level handling. */ + this_spi->slave_tx_buffer = NULL_BUFF; + this_spi->slave_tx_size = 0U; + this_spi->slave_tx_idx = 0U; + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK); + + /* Assign the slave frame update handler - NULL_SLAVE_TX_UPDATE_HANDLER for none */ + this_spi->slave_tx_frame_handler = slave_tx_frame_handler; + + /* Keep a copy of the slave Tx frame value. */ + this_spi->slave_tx_frame = frame_value; + + /* Load one frame into Tx data register. */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, this_spi->slave_tx_frame ); + + /* Enable Tx Done interrupt in order to reload the slave Tx frame after each + * time it has been sent. */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXDONE, ENABLE ); + + /* Make sure correct mode is selected */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_FRAME; + + /* Ready to go so enable CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } + } +} + +/***************************************************************************//** + * SPI_set_slave_block_buffers() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_slave_block_buffers +( + spi_instance_t * this_spi, + const uint8_t * tx_buffer, + uint32_t tx_buff_size, + uint8_t * rx_buffer, + uint32_t rx_buff_size, + spi_block_rx_handler_t block_rx_handler +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI slave. */ + if( DISABLE == HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Make sure correct mode is selected */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_BLOCK; + /* + * No command handler should be setup at this stage so fake this + * to ensure 0 padding works. + */ + this_spi->cmd_done = 1u; + + /* Disable frame handlers as they are mutually exclusive with block Rx handler. */ + this_spi->frame_rx_handler = NULL_FRAME_HANDLER; + this_spi->slave_tx_frame_handler = NULL_SLAVE_TX_UPDATE_HANDLER; + + /* Keep a copy of the pointer to the block Rx handler function. */ + this_spi->block_rx_handler = block_rx_handler; + + /* Assign slave receive buffer */ + this_spi->slave_rx_buffer = rx_buffer; + this_spi->slave_rx_size = rx_buff_size; + this_spi->slave_rx_idx = 0U; + + /* Assign slave transmit buffer*/ + this_spi->slave_tx_buffer = tx_buffer; + this_spi->slave_tx_size = tx_buff_size; + this_spi->slave_tx_idx = 0U; + + /* Flush the receive and transmit FIFOs */ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Preload the transmit FIFO. */ + while( !(HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_TXFULL)) && + ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->slave_tx_buffer[this_spi->slave_tx_idx] ); + ++this_spi->slave_tx_idx; + } + /* + * Disable TXDATA interrupt as we will look after transmission in rx handling + * because we know that once we have read a frame it is safe to send another one. + */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTTXDATA, DISABLE ); + + /* Enable Rx, FIFO error and SSEND interrupts */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTRXOVFLOW, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXURUN, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTRXDATA, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTSSEND, ENABLE ); + + /* Disable command handler until it is set explicitly */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + + /* Now enable the CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } + } +} + +/***************************************************************************//** + * SPI_set_cmd_handler() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_cmd_handler +( + spi_instance_t * this_spi, + spi_block_rx_handler_t cmd_handler, + uint32_t cmd_size +) +{ + uint32_t ctrl2 = 0u; + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( NULL_SLAVE_CMD_HANDLER != cmd_handler ); + HAL_ASSERT( 0u < cmd_size ); + + if( ( NULL_INSTANCE != this_spi ) && ( 0u < cmd_size ) && + ( NULL_SLAVE_CMD_HANDLER != cmd_handler ) ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + /* + * Note we don't flush the FIFOs as this has been done already when + * block mode was configured. + * + * Clear this flag so zero padding is disabled until command response + * has been taken care of. + */ + this_spi->cmd_done = 0u; + + /* Assign user handler for Command received interrupt */ + this_spi->cmd_handler = cmd_handler; + + /* Configure the command size and Enable Command received interrupt */ + ctrl2 = HAL_get_8bit_reg( this_spi->base_addr, CTRL2 ); + + /* First clear the count field then insert count and int enables */ + ctrl2 &= ~(uint32_t)CTRL2_CMDSIZE_MASK; + ctrl2 |= (uint32_t)((cmd_size & CTRL2_CMDSIZE_MASK) | CTRL2_INTCMD_MASK | CTRL2_INTRXDATA_MASK); + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, ctrl2 ); + + /* Now enable the CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } +} + +/***************************************************************************//** + * SPI_set_cmd_response() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_cmd_response +( + spi_instance_t * this_spi, + const uint8_t * resp_tx_buffer, + uint32_t resp_buff_size +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( NULL_BUFF != resp_tx_buffer ); + HAL_ASSERT( 0u < resp_buff_size ); + + if( ( NULL_INSTANCE != this_spi ) && ( 0u < resp_buff_size ) && + ( NULL_BUFF != resp_tx_buffer ) ) + { + this_spi->resp_tx_buffer = resp_tx_buffer; + this_spi->resp_buff_size = resp_buff_size; + this_spi->resp_buff_tx_idx = 0u; + + fill_slave_tx_fifo(this_spi); + } +} + + +/***************************************************************************//** + * SPI_enable() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_enable +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } +} + + +/***************************************************************************//** + * SPI_disable() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_disable +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + } +} + + +/***************************************************************************//** + * SPI interrupt service routine. + */ +void SPI_isr +( + spi_instance_t * this_spi +) +{ + uint32_t rx_frame; + int32_t guard; + +/* + * The assert and the NULL check here can be commented out to reduce the interrupt + * latency once you are sure the interrupt vector code is correct. + */ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + if( NULL_INSTANCE != this_spi ) + { + /* Handle receive. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_RXDATA ) ) + { + /* + * Service receive data according to transfer mode in operation. + * + * We check block mode first as this is most likely to have back to back + * transfers with multiple bytes. + * + * Note the order of the checks here will effect interrupt latency and + * for critical timing the mode you are using most often should probably be + * be the first checked. + */ + if( SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode ) /* Block handling mode. */ + { + while( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Read irrespective to clear the RX IRQ */ + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + if( this_spi->slave_rx_idx < this_spi->slave_rx_size ) + { + this_spi->slave_rx_buffer[this_spi->slave_rx_idx] = (uint8_t)rx_frame; + } + ++this_spi->slave_rx_idx; + } + /* + * Now handle updating of tx FIFO to keep the data flowing. + * First see if there is anything in slave_tx_buffer to send. + */ + while( ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) + && ( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->slave_tx_buffer[this_spi->slave_tx_idx] ); + ++this_spi->slave_tx_idx; + } + /* + * Next see if there is anything in resp_tx_buffer to send. + */ + if( this_spi->slave_tx_idx >= this_spi->slave_tx_size ) + { + while( ( this_spi->resp_buff_tx_idx < this_spi->resp_buff_size ) + && ( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->resp_tx_buffer[this_spi->resp_buff_tx_idx] ); + ++this_spi->resp_buff_tx_idx; + } + } + /* + * Lastly, see if we are ready to pad with 0s . + */ + if( this_spi->cmd_done && ( this_spi->slave_tx_idx >= this_spi->slave_tx_size ) && + ( this_spi->resp_buff_tx_idx >= this_spi->resp_buff_size ) ) + { + guard = 1 + ((int32_t)this_spi->fifo_depth / 4); + while( ( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) + && ( 0 != guard ) ) + { + /* + * Pad TX FIFO with 0s for consistent behaviour if the master + * tries to transfer more than we expected. + */ + HAL_set_32bit_reg(this_spi->base_addr, TXDATA, 0x00u); + /* + * We use the guard count to cover the event that we are never + * seeing the TX FIFO full because the data is being pulled + * out as fast as we can stuff it in. In this case we never spend + * more than our allocated time spinning here. + */ + guard--; + } + } + } + else if( SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode ) /* Single frame handling mode. */ + { + while( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + if( NULL_FRAME_HANDLER != this_spi->frame_rx_handler ) + { + this_spi->frame_rx_handler( rx_frame ); + } + } + } + else /* Slave transfer mode not set up so discard anything in RX FIFO */ + { + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_RXFIFORST_MASK ); + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_RXDATA, ENABLE ); + } + + /* Handle transmit. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_TXDONE ) ) + { + /* + * Note, the driver only currently uses the txdone interrupt when + * in frame transmit mode. In block mode all TX handling is done by the + * receive interrupt handling code as we know that for every frame received + * a frame must be placed in the TX FIFO. + */ + if( SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode ) + { + /* Execute the user callback to update the slave_tx_frame */ + if( NULL_SLAVE_TX_UPDATE_HANDLER != this_spi->slave_tx_frame_handler ) + { + this_spi->slave_tx_frame_handler ( this_spi ); + } + + /* Reload slave tx frame into Tx data register. */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, this_spi->slave_tx_frame ); + } + else if( SPI_SLAVE_XFER_BLOCK != this_spi->slave_xfer_mode ) + { + /* Slave transfer mode not set up so discard anything in TX FIFO */ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK ); + } + else + { + /* Nothing to do, no slave mode configured */ + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_TXDONE, ENABLE ); + } + + + /* Handle receive overflow. */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, INTMASK_RXOVERFLOW)) + { + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_RXFIFORST_MASK); + HAL_set_8bit_reg_field(this_spi->base_addr, INTCLR_RXOVERFLOW, ENABLE); + } + + /* Handle transmit under run. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_TXUNDERRUN ) ) + { + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK ); + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_TXUNDERRUN, ENABLE ); + } + + /* Handle command interrupt. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_CMDINT ) ) + { + read_slave_rx_fifo( this_spi ); + + /* + * Call the command handler if one exists. + */ + if( NULL_SLAVE_CMD_HANDLER != this_spi->cmd_handler ) + { + this_spi->cmd_handler( this_spi->slave_rx_buffer, this_spi->slave_rx_idx ); + } + this_spi->cmd_done = 1u; + /* Disable command interrupt until slave select becomes de-asserted to avoid retriggering. */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_CMDINT, ENABLE ); + } + + /* Handle slave select becoming de-asserted. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_SSEND) ) + { + /* Only supposed to do all this if transferring blocks... */ + if(SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode) + { + uint32_t rx_size; + + /* Empty any remaining bytes in RX FIFO */ + read_slave_rx_fifo( this_spi ); + rx_size = this_spi->slave_rx_idx; + /* + * Re-enable command interrupt if required. + * Must be done before re loading FIFO to ensure stale response + * data is not pushed into the FIFO. + */ + if(NULL_SLAVE_CMD_HANDLER != this_spi->cmd_handler) + { + this_spi->cmd_done = 0u; + this_spi->resp_tx_buffer = 0u; + this_spi->resp_buff_size = 0u; + this_spi->resp_buff_tx_idx = 0u; + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_CMDINT, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, ENABLE ); + } + /* + * Reset the transmit index to 0 to restart transmit at the start of the + * transmit buffer in the next transaction. This also requires flushing + * the Tx FIFO and refilling it with the start of Tx data buffer. + */ + this_spi->slave_tx_idx = 0u; + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + fill_slave_tx_fifo( this_spi ); + + /* Prepare to receive next packet. */ + this_spi->slave_rx_idx = 0u; + /* + * Call the receive handler if one exists. + */ + if( NULL_BLOCK_HANDLER != this_spi->block_rx_handler ) + { + this_spi->block_rx_handler( this_spi->slave_rx_buffer, rx_size ); + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_RXDATA, ENABLE ); + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_SSEND, ENABLE ); + } + } +} + +/******************************************************************************* + * Local function definitions + */ + +/***************************************************************************//** + * Fill the transmit FIFO (used for slave block transfers). + */ +static void fill_slave_tx_fifo +( + spi_instance_t * this_spi +) +{ + /* First see if slave_tx_buffer needs transmitting */ + while( ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) && + !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->slave_tx_buffer[this_spi->slave_tx_idx] ); + ++this_spi->slave_tx_idx; + } + + /* Then see if it is safe to look at putting resp_tx_buffer in FIFO? */ + if( this_spi->slave_tx_idx >= this_spi->slave_tx_size ) + { + while( ( this_spi->resp_buff_tx_idx < this_spi->resp_buff_size ) && + !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->resp_tx_buffer[this_spi->resp_buff_tx_idx] ); + ++this_spi->resp_buff_tx_idx; + } + } +} + +/***************************************************************************//** + * + */ +static void read_slave_rx_fifo +( + spi_instance_t * this_spi +) +{ + uint32_t rx_frame; + + if( SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode ) /* Block handling mode. */ + { + while( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); /* Read irresepective to clear the RX IRQ */ + if( this_spi->slave_rx_idx < this_spi->slave_rx_size ) + { + this_spi->slave_rx_buffer[this_spi->slave_rx_idx] = (uint8_t)rx_frame; + } + ++this_spi->slave_rx_idx; + } + } + else if( SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode ) /* Frame handling mode */ + { + while( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Single frame handling mode. */ + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + if( NULL_FRAME_HANDLER != this_spi->frame_rx_handler ) + { + this_spi->frame_rx_handler( rx_frame ); + } + } + } + else /* Slave transfer mode not set up so discard anything in RX FIFO */ + { + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_RXFIFORST_MASK ); + } +} + +/***************************************************************************//** + * This function is to recover the CoreSPI from receiver overflow. + * It temporarily disables the CoreSPI from interacting with external world, flushes + * the transmit and receiver FIFOs, clears all interrupts and then re-enables + * the CoreSPI instance referred by this_spi parameter. + */ +static void recover_from_rx_overflow +( + const spi_instance_t * this_spi +) +{ + /* Disable CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Reset TX and RX FIFOs */ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Enable CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); +} + + diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.h b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.h new file mode 100644 index 0000000..c6873f7 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.h @@ -0,0 +1,1324 @@ +/***************************************************************************//** + * Copyright 2013-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Core SPI bare metal software driver public API. + * + * This Core SPI driver provides functions for implementing SPI master or + * SPI slave operations with the CoreSPI version 4.2.xxx It is not compatible + * with CoreSPI version 3.0.xxx. + * + * The Core SPI driver supports two classes of data transfer operation: + * SPI frame operation or SPI block transfer operations. + * + * Frame operations allow transferring individual SPI frames from 4 to 32-bits + * in length. Block operations allow transferring blocks of data organized as + * 8-bit frames. + * + * @file core_spi.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreSPI prototypes + * + */ + +/*=========================================================================*//** + @mainpage Core SPI Bare Metal Driver. + + ============================================================================== + Introduction + ============================================================================== + CoreSPI is an IP component that implements a full-duplex, synchronous, and + configurable serial peripheral interface (SPI) with frame sizes from 4 to 32 + bits and bus interface sizes of 8-, 16-, or 32-bit. Each CoreSPI instance + communicates with up to eight slave devices. + + This driver provides a set of functions for controlling CoreSPI as part of + the bare metal system where no operating system is available. These drivers + can be adapted to be used as a part of an operating system, but the + implementation of the adaptation layer between driver and the operating + system's driver model is outside the scope of this User's Guide. + + ============================================================================== + Driver Configuration + ============================================================================== + Your application software should configure the CoreSPI driver through calls + to the SPI_init() function for each CoreSPI instance in the hardware design. + This function configures a default set of parameters that include a CoreSPI + hardware instance base address and the depth of the FIFOs for this instance. + + The CoreSPI instance is configured at the time of instantiation in hardware + design for APB width, frame size, FIFO depth, serial clock speed, serial + clock polarity, serial clock phase, and slave select state parameters. + + CoreSPI can communicate with up to eight different slave devices that match + the CoreSPI configuration at the time of hardware instantiation. + + The functions SPI_configure_slave_mode() and SPI_configure_master_mode() are + used to configure the CoreSPI instance as a master or slave as required by + the application. + + When CoreSPI wishes to communicate with a specific slave device, call + the SPI_set_slave_select() function with the slave number as an argument. + This function selects the slave device. A previously selected slave gets + unselected by calling the SPI_clear_slave_select() function. + + ============================================================================== + Theory of Operation + ============================================================================== + The CoreSPI driver functions are grouped into the following categories: + • Initialization + • Configuration for either master or slave operations + • SPI master frame transfer control + • SPI master block transfer control + • SPI slave frame transfer control + • SPI slave block transfer control + + Frame transfers allow CoreSPI to write or read up to 32-bits of data in a + single SPI transaction. For example, a frame transfer of 12-bits might be used + to read the result of an ADC conversion from a SPI analog to digital converter. + + Block transfers allow CoreSPI to write and/or read a number of bytes in a single + SPI transaction. With the driver as is, block transfer transactions allow data + transfers in multiples of 8-bits (8, 16, 24, 32, 40,...) and the CoreSPI instance + has to be configured for 8-bit frames. For other frame sizes, the + SPI_transfer_block() code can act as a template for developing a frame block + transfer function. + Block transfers are typically used with byte oriented devices like SPI + FLASH devices. + + Note: The CoreSPI instance in the hardware design must be configured for + the frame size required by the application; configuration by driver is + not possible. + + -------------------------------- + Initialization + -------------------------------- + The CoreSPI driver is initialized through a call to the SPI_init() function. + The SPI_init() function takes a pointer to the global CoreSPI instance data + structure of type spi_instance_t and the base address of the CoreSPI instance + as defined by the hardware design. The CoreSPI instance global data structure + is used by the driver to store state information for each CoreSPI instance. + A pointer to these data structures is also used as the first parameter to + any of the driver functions to identify which CoreSPI will be used by the + called function. It is the responsibility of the application programmer to + create and maintain these global CoreSPI instance data structures. Any call + to a CoreSPI driver function should be of the form SPI_function_name + ( &g_core_spi0, ... ). + The SPI_init() function resets the transmit and receives FIFOs of CoreSPI + instance being initialized. + The SPI_init() function must be called before any other CoreSPI driver + functions can be called. + + ---------------------------------------------------- + Configuration + ---------------------------------------------------- + A CoreSPI instance can operate either as a master or as a slave SPI device. + There are two distinct functions for configuring a CoreSPI instance for + master or slave operations. + + ## Master Configuration + The SPI_configure_master_mode() function configures the specified CoreSPI + block for operations as an SPI master. This function must be called once + before the CoreSPI block communicates with an SPI slave device. + + ## Slave Configuration + The SPI_configure_slave_mode() function configures the specified CoreSPI + block for operations as a SPI slave. This function must be called after + calling the SPI_init() to configure the CoreSPI instance referred by this_spi + parameter to operate in the slave mode. + + ------------------------------------- + SPI Master Frame Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI master frame transfers: + • SPI_set_slave_select() + • SPI_transfer_frame() + • SPI_clear_slave_select() + + The master must first select the target slave or slaves to be addressed by + calling the SPI_set_slave_select() function. This causes the relevant select + line(s) to become asserted while data is clocked out onto the SPI data line. + + A function call is then made to SPI_transfer_frame() specifying the value + of the data frame to be sent and returning the value read. + + After the transfer is complete, use the SPI_clear_slave_select() function + to prevent this slave select line from being asserted during subsequent SPI + transactions. A call to this function is required only if the master is + communicating with multiple slave devices. + + ------------------------------------- + SPI Master Block Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI master block transfers: + • SPI_set_slave_select() + • SPI_transfer_block() + • SPI_clear_slave_select() + + The master must first select the target slave or slaves by calling + SPI_set_slave_select(). This causes the relevant slave select line(s) to + become asserted while data is clocked out onto the SPI data line. + Alternatively, a general purpose input/output (GPIO) can be used to control + the state of the target slave device's chip select signal. + + A call is then made to the SPI_transfer_block() function. The parameters of + this function specify the following: + • The number of bytes to be transmitted + • A pointer to the buffer containing the data to be transmitted + • The number of bytes to be received + • A pointer to the buffer where the received data gets stored + + The number of bytes to be transmitted can be set to zero to indicate that the + transfer is purely a block read transfer. The number of bytes to be received + can be set to zero to specify that the transfer is purely a block write + transfer. + + Block mode transfers as implemented by the driver are effectively half duplex + as we do not store the values received from the slave device whilst we are + transmitting. If full duplex operation is required, the driver + SPI_transfer_block() function can serve as a starting point for implementing + full duplex block transfers. + + The SPI_clear_slave_select() function can be used after the transfer is + complete to prevent this slave select line from being asserted during + subsequent SPI transactions. A call to this function is only required if + the master is communicating with multiple slave devices. + + ------------------------------------- + SPI Slave Frame Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI slave frame transfers: + • SPI_set_frame_rx_handler() + • SPI_set_slave_tx_frame() + + The SPI_set_frame_rx_handler() function specifies the receive handler + function that is called when a frame of data has been received by the + SPI when it is configured as a slave. The receive handler function specified + through this call processes the frame data written over the SPI bus to the + SPI slave by the remote SPI master. The receive handler function must be + implemented as part of the application. It is only required if the SPI slave + is the target of SPI frame write transactions. + + The SPI_set_slave_tx_frame() function specifies the frame data that is + returned to the SPI master. The frame data specified through this function + is the value that will be read over the SPI bus by the remote SPI master, + when it initiates a transaction. Call the SPI_set_slave_tx_frame() function + only if the SPI slave is the target of SPI read transactions. That is, if + data is meant to be read over CoreSPI. + + If both frame handlers are required, call the SPI_set_frame_rx_handler() + first, otherwise the initial TX frame gets discarded when SPI_set_frame_rx_handler() + clears the FIFOs as part of its initialization. + + ------------------------------------- + SPI Slave Block Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI slave block transfers: + • SPI_set_slave_block_buffers() + • SPI_set_cmd_handler() + • SPI_set_cmd_response() + + The SPI_set_slave_block_buffers() function is used to configure an SPI slave + for block transfer operations. It specifies the following: + • The buffer containing the data that will be returned to the remote SPI + master + • The buffer where data received from the remote SPI master will be + stored + • The optional handler function that will be called after the receive + buffer is filled + + The SPI_set_cmd_handler() function specifies a command handler function that + is called by the driver once a specific number of frames have been + received after the SPI chip select signal becomes active. The number of + bytes making up the command part of the transaction is specified as part of + the parameters to the SPI_set_cmd_handler() function. The command handler + function is implemented as a part of the application making use of the SPI + driver and typically calls the SPI_set_cmd_response() function. + + The SPI_set_cmd_response() function specifies the data that gets returned + to the master. Typically, the SPI_set_slave_block_buffers() function is + called as a part of the system initialisation to specify the data sent to + the master while the command bytes are being received. The transmit buffer + specified through calling the SPI_set_slave_block_buffers() function would + also typically include one or more bytes allowing the turn around time + for the command handler function to execute and call the + SPI_set_cmd_response() function. + + *//*=========================================================================*/ +#ifndef CORE_SPI_H_ +#define CORE_SPI_H_ + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#include "hal_assert.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + SPI FIFO Depth + ======================================= + SPI_MAX_FIFO_DEPTH & SPI_MIN_FIFO_DEPTH constants define the maximum and minimum + FIFO depths allowed for the CoreSPI instance. User need to inform the driver of + the FIFO depth for each CoreSPI instance to ensure that the FIFOs are managed correctly. + + | Constant | Description | + |--------------------|----------------------------------------------------| + | SPI_MAX_FIFO_DEPTH | Maximum FIFO depth allowed for the CoreSPI instance| + | SPI_MIN_FIFO_DEPTH | Minimum FIFO depth allowed for the CoreSPI instance| + + */ +#define SPI_MAX_FIFO_DEPTH 32u +#define SPI_MIN_FIFO_DEPTH 1u + +/***************************************************************************//** + Instances of this structure are used to identify the specific CoreSPI hardware + instances. A pointer to an instance of the spi_instance_t structure is passed + as the first parameter to the CoreSPI driver functions to identify which SPI + performs the requested operation. + */ +typedef struct spi_instance spi_instance_t; + +/***************************************************************************//** + This function pointer type is to assign a callback function for TX interrupt + when slave wants to send the next updated frame. + + Declaring and Implementing Slave Frame Transmit Handler Functions: + Slave transmit frame update handler functions should follow the following + prototype: + void slave_tx_frame_update_handler ( spi_instance_t * this_spi ); + The actual name of the transmit handler is unimportant. You can use any name + of your choice for the frame update handler. + + A common handler function may be used when multiple CoreSPI instances are + configured as slave, as the particular slave device currently requiring + service is indicated by the function parameter. + */ +typedef void (*spi_slave_frame_tx_handler_t)( spi_instance_t * this_spi ); + +/***************************************************************************//** + This defines the function prototype that must be followed by the SPI slave + frame receive handler functions. These functions are registered with the SPI + driver through the SPI_set_frame_rx_handler() function. + + Declaring and Implementing the Slave Frame Receive Handler Functions: + The Slave frame receive handler functions should follow the following + prototype: + void slave_frame_receive_handler(uint32_t rx_frame); + The actual name of the receive handler is unimportant. You can use any name + of your choice for the receive frame handler. The rx_frame parameter contains + the value of the received frame. + + Separate handler functions are required for each slave instance as there is + no indication of the slave requiring service passed to the handler. + + */ +typedef void (*spi_frame_rx_handler_t)( uint32_t rx_frame ); + +/***************************************************************************//** + This defines the function prototype that must be followed by SPI slave + block receive handler functions. These functions are registered with the + SPI driver through the SPI_set_slave_block_buffers() function. + + Declaring and Implementing Slave Block Receive Handler Functions: + Slave block receive handler functions should follow the following prototype: + void spi_block_rx_handler ( uint8_t * rx_buff, uint16_t rx_size ); + The actual name of the receive handler is unimportant. You can use any name + of your choice for the receive frame handler. The rx_buff parameter contains + a pointer to the start of the received block. The rx_size parameter contains + the number of bytes of the received block. + + Separate handler functions are required for each slave instance as there is + no indication of the slave requiring service passed to the handler. + + */ +typedef void (*spi_block_rx_handler_t)( uint8_t * rx_buff, uint32_t rx_size ); + +/***************************************************************************//** + This enumeration is used to select a specific SPI slave device (0 to 7). It is + used as a parameter to the SPI_configure_master_mode(), SPI_set_slave_select(), + and SPI_clear_slave_select() functions. + */ +typedef enum __spi_slave_t +{ + SPI_SLAVE_0 = 0, + SPI_SLAVE_1 = 1, + SPI_SLAVE_2 = 2, + SPI_SLAVE_3 = 3, + SPI_SLAVE_4 = 4, + SPI_SLAVE_5 = 5, + SPI_SLAVE_6 = 6, + SPI_SLAVE_7 = 7, + SPI_MAX_NB_OF_SLAVES = 8 +} spi_slave_t; + +/***************************************************************************//** + This enumeration is used to indicate the current slave mode transfer type so + that we are not relying on buffer comparisons to dictate the logic of the driver. + */ +typedef enum __spi_sxfer_mode_t +{ + SPI_SLAVE_XFER_NONE = 0, /* Not configured yet */ + SPI_SLAVE_XFER_BLOCK = 1, /* Block transfers, with SSEND delimiting end of block */ + SPI_SLAVE_XFER_FRAME = 2 /* Single frame transfers */ +} spi_sxfer_mode_t; + +/***************************************************************************//** + There is one instance of this structure for each of the core SPIs. Instances + of this structure are used to identify a specific SPI. A pointer to an + instance of the spi_instance_t structure is passed as the first parameter to + SPI driver functions to identify which SPI should perform the requested operation. + */ +struct spi_instance{ + + /* Base address in the processor's memory map for the + registers of the CoreSPI instance being initialized */ + addr_t base_addr; /* Base address of SPI hardware instance */ + + uint32_t rx_frame; /* received data */ + + /* Internal transmit state: */ + const uint8_t * slave_tx_buffer; /* Pointer to slave transmit buffer */ + uint32_t slave_tx_size; /* Size of slave transmit buffer */ + uint32_t slave_tx_idx; /* Current index into slave transmit buffer */ + + /* Slave command response buffer: */ + const uint8_t * resp_tx_buffer; + uint32_t resp_buff_size; + uint32_t resp_buff_tx_idx; + spi_block_rx_handler_t cmd_handler; + uint32_t cmd_done; /* Flag which indicates response has been set up and + it is safe to pad with 0s once the response is sent */ + + /* Internal receive state: */ + uint8_t * slave_rx_buffer; /* Pointer to buffer where data received by a slave will be stored */ + uint32_t slave_rx_size; /* Slave receive buffer size */ + uint32_t slave_rx_idx; /* Current index into slave receive buffer */ + + /* Slave received frame handler: */ + spi_frame_rx_handler_t frame_rx_handler; /* Pointer to function that will be called when a frame + is received when the SPI block is configured as slave */ + /* Slave transmitted frame handler: */ + uint32_t slave_tx_frame; /* Value of the data frame that will be transmitted + when the SPI block is configured as slave */ + spi_slave_frame_tx_handler_t slave_tx_frame_handler; /* Callback function pointer to update slave_tx_frame */ + + /* Slave block rx handler: */ + spi_block_rx_handler_t block_rx_handler; /* Pointer to the function that will be called when a data block has been received */ + + /* Per instance specific hardware information that the driver needs to know */ + uint16_t fifo_depth; /* Depth of RX and TX FIFOs in frames */ + + /* How we are expecting to deal with slave transfers */ + spi_sxfer_mode_t slave_xfer_mode; /* Current slave mode transfer configuration */ +}; + +/*------------------------Public Function-------------------------------------*/ + +/***************************************************************************//** + The SPI_init() function initializes the hardware and data structures of a + CoreSPI instance referenced by this_spi parameter. This function must be + called for each CoreSPI instance with a unique this_spi and base_addr + parameter combination. The SPI_init() function must be called before any + other CoreSPI driver functions are called. + + After calling the SPI_init() the CoreSPI is configured as a master, + all interrupt sources will be masked and all the slaves are deselected. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to be initialized. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @param base_addr + The base_addr parameter is the base address in the processor's memory map for + the registers of the CoreSPI instance being initialized. It is assumed that + any non NULL value passed in here points to a valid instance of a CoreSPI as + the driver has no way of verifying this. Failure to pass in a valid address + can result in system instability. + + @param fifo_depth + The fifo_depth parameter specifies the number of frames in the receive + and transmit FIFOs of the CoreSPI instance being initialized. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + @endcode + */ +void SPI_init +( + spi_instance_t * this_spi, + addr_t base_addr, + uint16_t fifo_depth +); + +/***************************************************************************//** + The SPI_configure_slave_mode() function is used when a CoreSPI instance is + to be configured as a SPI slave. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to be configured. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + + int main(void) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_slave_mode ( &g _spi0 ); + } + @endcode + */ +void SPI_configure_slave_mode +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_configure_master_mode() function is used when a CoreSPI instance is + to be configured as a SPI master. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to be configured. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + + int main(void) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_master_mode ( &g _spi0 ); + } + @endcode + */ +void SPI_configure_master_mode +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_set_slave_select() function is used by a CoreSPI master to select a + specific slave. This function causes the relevant slave select signal to be + asserted while data is clocked out onto the SPI data line. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param slave + The slave parameter is one of the spi_slave_t enumerated constants + identifying a slave. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + const uint32_t master_tx_frame = 0x0100A0E1; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0 ); + SPI_transfer_frame( &g_spi0, master_tx_frame ); + SPI_clear_slave_select( &g_spi0, SPI_SLAVE_0 ); + + @endcode + */ +void SPI_set_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +); + +/***************************************************************************//** + The SPI_clear_slave_select() function is used by a CoreSPI master to + deselect a specific slave. This function causes the relevant slave select + signal to be de-asserted. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param slave + The slave parameter is one of the spi_slave_t enumerated constants + identifying a slave. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + const uint32_t master_tx_frame = 0x0100A0E1; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0 ); + SPI_transfer_frame( &g_spi0, master_tx_frame ); + SPI_clear_slave_select( &g_spi0, SPI_SLAVE_0 ); + @endcode + */ +void SPI_clear_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +); + +/***************************************************************************//** + The SPI_transfer_frame() function is used by a SPI master to transmit and + receive a single frame of the size that has been configured at the time of + CoreSPI hardware instantiation. This function is typically used for + transactions with a SPI slave where the number of transmit and receive bits + are not divisible by 8 or where full duplex exchange of frames is required. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param tx_bits + The tx_bits parameter is a 32-bit word containing the value that will be + transmitted. If the frame size configured for the CoreSPI is less than 32-bits, + the upper bits will be ignored. + Note: The bit length of the value to be transmitted to the slave is + set when the CoreSPI is instantiated in the hardware design. + + @return + This function returns a 32-bit word containing the value that is received + from the slave. If the frame size configured for the CoreSPI in question is + less that 32-bits, the upper bits will be 0. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + const uint32_t master_tx_frame = 0x0100A0E1; + uint32_t master_rx; + + SPI_init(&g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ); + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0 ); + master_rx = SPI_transfer_frame( &g_spi0, master_tx_frame ); + SPI_clear_slave_select( &g_spi0, SPI_SLAVE_0 ); + @endcode + */ +uint32_t SPI_transfer_frame +( + spi_instance_t * this_spi, + uint32_t tx_bits +); + +/***************************************************************************//** + The SPI_transfer_block() function is used by the SPI master to transmit and + receive blocks of data organized as a specified number of 8-bit frames. It + can be used for the following: + • Writing a data block to a slave + • Reading a data block from a slave + • Sending a command to a slave followed by reading the outcome of + the command in a single SPI transaction. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param cmd_buffer + The cmd_buffer parameter is a pointer to the buffer that contains the data + sent by the master from the beginning of the transfer. This pointer can be + null (0) if the master does not need to send a command before reading data. + + @param cmd_byte_size + The cmd_byte_size parameter specifies the number of bytes in cmd_buffer that + will be sent. A value ‘0’ indicates that no data needs to be sent to the slave. + + @param rx_buffer + The rx_buffer parameter is a pointer to the buffer that stores the data received + from the slave after sending the command. This pointer can be null (0) if the + master does not receive any data from the slave. + + @param rx_byte_size + The rx_byte_size parameter specifies the number of bytes received from + the slave and stored in the rx_buffer. A value ‘0’ indicates that no data is + to be read from the slave. + + @return + This function does not return any value. + + @example + @code + Polled write transfer example + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + + uint8_t master_tx_buffer[MASTER_TX_BUFFER] = + { + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A + }; + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0) ; + SPI_transfer_block + ( + &g_spi0, + master_tx_buffer, + sizeof(master_tx_buffer), + 0, + 0 + ); + SPI_clear_slave_select(&g_spi0, SPI_SLAVE_0 ); + @endcode + */ +void SPI_transfer_block +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_buffer, + uint16_t rx_byte_size +); + +/***************************************************************************//** + The SPI_transfer_block_store_all_resp() function is used by the SPI master + to transmit and receive blocks of data organized as a specified number + of 8-bit frames. It can be used for the following: + • Writing a data block to a slave + • Reading a data block from a slave + • Sending a command to a slave followed by reading the outcome of + the command in a single SPI transaction + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param cmd_buffer + The cmd_buffer parameter is a pointer to the buffer that contains the data sent by + the master from the beginning of the transfer. This pointer can be null (0) + if the master does not need to send a command before reading data. + + @param cmd_byte_size + The cmd_byte_size parameter specifies the number of bytes contained in + cmd_buffer that will be sent. A value ‘0’ indicates that no data needs + to be sent to the slave. + + @param rx_data_buffer + The rx_data_buffer parameter is a pointer to the buffer that stores the data received + from the slave after sending the command. This pointer can be null (0) if the + master does not receive any data from the slave. + + @param rx_byte_size + The rx_byte_size parameter specifies the number of bytes received from + the slave and stores in the rx_buffer. A value ‘0’ indicates that no data is + to be read from the slave. + + @param cmd_response_buffer + The cmd_response_buffer parameter is a pointer to the buffer which stores the + command response from the slave, while the master is transmitting the number + of bytes indicated by cmd_byte_size parameter. + + @return + This function does not return any value. + + @example + @code + Polled write transfer example + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + + uint8_t master_tx_buffer[MASTER_TX_BUFFER] = + { + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A + }; + + uint8_t cmd_rx_buffer[CMD_RX_BUFFER]={0}; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0) ; + SPI_transfer_block_store_all_resp + ( + &g_spi0, + master_tx_buffer, + sizeof(master_tx_buffer), + 0, + 0, + cmd_response_buffer + ); + SPI_clear_slave_select(&g_spi0, SPI_SLAVE_0 ); + @endcode + */ +void SPI_transfer_block_store_all_resp +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_data_buffer, + uint16_t rx_byte_size, + uint8_t * cmd_response_buffer +); + +/***************************************************************************//** + The SPI_set_frame_rx_handler() function is used by the SPI slaves to specify + the receive handler function that is called by the SPI driver interrupt + handler when a frame of data is received by the SPI slave. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param rx_handler + The rx_handler parameter is a pointer to the frame receive handler that must + be called when a frame is received by the CoreSPI slave. Passing in a NULL + pointer disables the receive handler but does enable the receive interrupt to + ensure the RX FIFO is empty each time a frame is received. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + uint32_t g_slave_rx_frame = 0; + spi_instance_t g_spi0; + + void slave_frame_handler(uint32_t rx_frame) + { + g_slave_rx_frame = rx_frame; + } + int setup_slave( void ) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_slave_mode( &g_spi0 ); + SPI_set_frame_rx_handler( &g_spi0, slave_frame_handler ); + } + @endcode + */ +void SPI_set_frame_rx_handler +( + spi_instance_t * this_spi, + spi_frame_rx_handler_t rx_handler +); + +/***************************************************************************//** + The SPI_set_slave_tx_frame() function is used by the SPI slaves to specify + the frame that gets transmitted when a transaction is initiated by the SPI + master. This function allows you to assign a slave_tx_frame_handler function, + which will be executed upon transmit interrupt when the SPI is in slave mode. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param frame_value + The frame_value parameter contains the value of the frame to be sent to the + master. + Note: The bit length of the value to be transmitted to the master is + set when the CoreSPI is instantiated in the hardware design. + + @param slave_tx_frame_handler + The slave_tx_frame_handler function pointer is executed upon occurrence of + transmit interrupt when CoreSPI is operating in slave mode. This parameter + is optional and if set to NULL it is assumed that the frame value is static or + updated asynchronously. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + const uint32_t slave_tx_frame[2] = { 0x0110F761, 0x0110F671 }; + uint32_t master_rx; + uint32_t slave_frame_idx = 0 ; + + slave_frame_update( spi_instance_t * this_spi ) + { + this_spi->slave_tx_frame = slave_tx_frame[slave_frame_idx++]; + if( slave_frame_idx > 2 ) + slave_frame_idx = 0; + } + main() + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ) ; + SPI_set_slave_tx_frame( &g_spi0, slave_tx_frame[slave_frame_idx++], + &slave_frame_update ); + } + @endcode + */ +void SPI_set_slave_tx_frame +( + spi_instance_t * this_spi, + uint32_t frame_value, + spi_slave_frame_tx_handler_t slave_tx_frame_handler +); + +/***************************************************************************//** + The SPI_set_slave_block_buffers() function is used to configure an SPI slave + for block transfer operations. It specifies one or more of the following: + • The data that is transmitted when accessed by a master. + • The buffer where the data received from a master is stored. + • The handler function that must be called after the receive buffer has + been filled. + • The number of bytes that must be received from the master before calling + the recieve handler function. + These parameters allow the following use cases: + • Slave performing an action after receiving a block of data from a + master containing a command. This action is performed by the + receive handler based on the content of the receive data buffer. + • Slave returning a block of data to the master. The type of information + is always the same but the actual values change over time. For example, + returning the voltage of a predefined set of analog inputs. + • Slave returning data based on a command contained in the first part of + the SPI transaction. For example, reading the voltage of the analog + input specified by the first data byte by the master. This is achieved + by using the SPI_set_slave_block_buffers() function in conjunction with + functions SPI_set_cmd_handler() and SPI_set_cmd_response(). + + See the SPI_set_cmd_handler() function description for details of + this use case. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param tx_buffer + The tx_buffer parameter is a pointer to a buffer containing the data that + will be sent to the master. This parameter can be set to ‘0’ if the SPI + slave is not intended to be the target of SPI read transactions. + + @param tx_buff_size + The tx_buff_size parameter specifies the number of bytes that are + transmitted by the SPI slave. It is the number of bytes contained in the + tx_buffer. This parameter can be set to ‘0’ if the SPI slave is not + intended to be the target of SPI read transactions. The driver returns 0s + to the master if there is no buffer specified or the master reads beyond the + end of the buffer. + Note: If SPI_transfer_block() is used to read from this slave and there is + no command handler involved, the buffer size here must be at least the + combined length of the command and response specified by the master. + On receiving this data, the master discards the data bytes equal to + command length bytes from the start of the received buffer. + + @param rx_buffer + The rx_buffer parameter is a pointer to the buffer where data received + from the master is stored. This parameter can be set to ‘0’ if the + SPI slave is not intended to be the target of SPI write or write-read + transactions. + + @param rx_buff_size + The rx_buff_size parameter specifies the size of the receive buffer. It is + also the number of bytes that must be received before the receive handler + is called, if a receive handler is specified using the block_rx_handler + parameter. Any bytes received in excess of the size specified by the + rx_buff_size parameter are discarded. This parameter can be set to ‘0’ + if the SPI slave is not intended to be the target of SPI write or + write-read transactions. + + @param block_rx_handler + The block_rx_handler parameter is a pointer to a function that is called + when receive buffer has been filled or the slave select has been de-asserted. + This parameter can be set to ‘0’ if the SPI slave is not intended to be the + target of SPI write or write-read transactions. + + @return + This function does not return any value. + + @example + @code + Slave Performing Operation Based on Master Command: + In this example the SPI slave is configured to receive 10 bytes of data + or command from the SPI slave, and process the data received from the master. + + #define SPI0_BASE_ADDR 0xC2000000 + + uint32_t nb_of_rx_handler_calls = 0; + spi_instance_t g_spi0; + + void spi1_block_rx_handler_b + ( + uint8_t * rx_buff, + uint16_t rx_size + ) + { + ++nb_of_rx_handler_calls; + } + + void setup_slave( void ) + { + uint8_t slave_rx_buffer[10] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_slave_mode( &g_spi0 ); + + SPI_set_slave_block_buffers + ( + &g_spi0, + 0, + 0, + slave_rx_buffer, + sizeof( master_tx_buffer ), + spi1_block_rx_handler_b + ); + } + @endcode + */ +void SPI_set_slave_block_buffers +( + spi_instance_t * this_spi, + const uint8_t * tx_buffer, + uint32_t tx_buff_size, + uint8_t * rx_buffer, + uint32_t rx_buff_size, + spi_block_rx_handler_t block_rx_handler +); + +/***************************************************************************//** + The SPI_isr() function is the top level interrupt handler function for the + CoreSPI driver. You must call SPI_isr() from the system level + (CoreInterrupt and NVIC level) interrupt handler assigned to the interrupt + triggered by the CoreSPI SPIINT signal. Your system level interrupt handler + must also clear the system level interrupt triggered by the CoreSPI SPIINT + signal before returning, to prevent a re-assertion of the same interrupt. + + This function supports all types of interrupt triggered by CoreSPI. It is not + a complete interrupt handler by itself; rather, it is a top level wrapper that + abstracts CoreSPI command interrupt and slave mode transmit interrupt handling + by calling lower level handler functions specific to each type of CoreSPI + interrupt. You must create the lower level handler functions to suit your + application and register them with the driver through calling the + SPI_set_cmd_handler(), SPI_set_cmd_response(), and SPI_set_slave_tx_frame() + functions. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + + @example + @code + + Example of configuring a CoreInterrupt connected to the Fabric Interrupt on a + SmartFusion device to handle CoreSPI interrupt. + + #define #define SPI1_INT_IRQ_NB 0 + spi_instance_t g_spi0; + + Void CIC_irq1_handler(void) + { + SPI_isr( &g_spi0 ); + } + + void Fabric_IRQHandler( void ) + { + // Call the CoreInterrupt driver ISR to determine the source of the + // interrupt and call the relevant ISR registered to it. + CIC_irq_handler(); + + // Clear NVIC interrupt status to allow further interrupts + NVIC_ClearPendingIRQ( Fabric_IRQn ); + } + + main() + { + ... + + CIC_init( CIC_BASE_ADDR ); + + // Install handler for SPI IRQ + CIC_set_irq_handler( SPI0_INT_IRQ_NB, CIC_irq1_handler ); + + NVIC_ClearPendingIRQ( Fabric_IRQn ); + NVIC_EnableIRQ( Fabric_IRQn ); + + CIC_enable_irq( SPI1_INT_IRQ_NB ); + + ... + } + @endcode + */ +void SPI_isr +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_set_cmd_handler() function specifies a command handler function that + will be called when the number of bytes received reaches the command size + specified as cmd_size parameter. + + This function is used by the SPI slaves performing block transfers. Its + purpose is to allow an SPI slave to decide the data that will be returned to + the master while an SPI transaction is taking place. Typically, one or more + command bytes are sent by the master to request some specific data. The slave + interprets the command byte(s) while one or more turn-around bytes are + transmitted. The slave adjusts its transmit data buffer based on the command + during the turn around time. + + The following table provides an example of the use of this function where the + SPI slave returns data bytes D0 to D6 based on the value of a command. The + 3 bytes long command is made up of a command opcode byte followed by an + address byte followed by a size byte. The cmd_handler() function specified + through an earlier call to SPI_set_cmd_handler() is called by the CoreSPI + driver once the third byte is received. The cmd_handler() function + interprets the command bytes and calls SPI_set_cmd_response() to set the SPI + slave's response transmit buffer with the data to be transmitted after the + turnaround bytes (T0 to T3). The number of turnaround bytes must be + sufficient to give enough time for the cmd_handler() to execute. The number + of turnaround bytes is specified by the protocol used on top of the SPI + transport layer so that master and slave agree on the number of turn around + bytes. + +|Timestamp| SPI Transaction | Bytes | Comments | +|---------|-------------|----------------------|---------------| +| t0|COMMAND|C A S |C - command opcode byte, A - address byte, S - size byte| +|t1| TURN-AROUND|T0 T1 |cmd_handler() called here (T0 to T3 are TURN-AROUND bytes)| +|t2|TURN-AROUND|T2 T3|SPI_set_cmd_response() called here by implementation of cmd_handler() +|| | |to set the data that will be transmitted by the SPI slave.| +|t3| DATA | D0 D1 D2 D3 D4 D5 D6 |Data transmition (SPI slave return data bytes)| + + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure identifying + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @param cmd_handler + The cmd_handler parameter is a pointer to a function with the prototype: + void cmd_handler(uint8_t * rx_buff, uint32_t rx_size); + It specifies the function that will be called when the number of bytes + specified by the cmd_size parameter has been received. + + @param cmd_size + The cmd_size parameter specifies the number of bytes that must be received + before calling the command handler function specified by the cmd_handler. + The CoreSPI supports cmd_size values in the range 1 to 7. + + @return + This function does not return any value. + + @example + @code + The following example demonstrates how to configure CoreSPI to implement + the protocol given as an example above. The configure_slave() function + configures CoreSPI. It sets receive and transmit buffers. The transmit + buffer specified through the call to SPI_set_slave_block_buffers() function + specifies the data that will be returned to the master in bytes between + t0 and t3. These bytes will be sent to the master while the master transmits + the command and dummy bytes. The spi_slave_cmd_handler() function will be + called by the driver at time t1 after the 3 command bytes have been received. + The spi_block_rx_handler() function will be called by the driver at time t4, + when the transaction completes and the slave select signal becomes + de-asserted. + + #define SPI0_BASE_ADDR 0xC2000000 + #define COMMAND_SIZE 3 + #define NB_OF_DUMMY_BYTES 4 + #define MAX_TRANSACTION_SIZE 16 + + spi_instance_t g_spi0; + uint8_t slave_tx_buffer[COMMAND_SIZE + NB_OF_DUMMY_BYTES]; + uint8_t slave_rx_buffer[MAX_TRANSACTION_SIZE]; + + void configure_slave( void ) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_slave_mode( &g_spi0 ); + SPI_set_slave_block_buffers + ( + &g_spi0, + slave_tx_buffer, + COMMAND_SIZE + NB_OF_DUMMY_BYTES, + slave_rx_buffer, + sizeof(slave_rx_buffer), + spi_block_rx_handler + ); + + SPI_set_cmd_handler + ( + &g_spi0, + spi_slave_cmd_handler, + COMMAND_SIZE + ); + } + + void spi_slave_cmd_handler + ( + uint8_t * rx_buff, + uint32_t rx_size + ) + { + uint8_t command; + uint8_t address; + uint8_t size; + uint8_t * p_response; + uint32_t response_size; + + command = rx_buff[0]; + address = rx_buff[1]; + size = rx_buff[2]; + + p_response = get_response_data( command, address, size, &response_size ); + SPI_set_cmd_response( &g_spi0, p_response, response_size ); + } + + void spi_block_rx_handler + ( + uint8_t * rx_buff, + uint32_t rx_size + ) + { + process_rx_data( rx_buff, rx_size ); + } + @endcode + */ +void SPI_set_cmd_handler +( + spi_instance_t * this_spi, + spi_block_rx_handler_t cmd_handler, + uint32_t cmd_size +); + +/***************************************************************************//** + The SPI_set_cmd_response() function specifies the data that will be returned + to the master. See the description of SPI_set_cmd_handler() for details. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param resp_tx_buffer + The resp_tx_buffer parameter is a pointer to the buffer containing the data + that must be returned to the host in the data phase of an SPI transaction. + + @param resp_buff_size + The resp_buff_size parameter specifies the size of the buffer pointed by the + resp_tx_buffer parameter. + + @return + This function does not return any value. + */ +void SPI_set_cmd_response +( + spi_instance_t * this_spi, + const uint8_t * resp_tx_buffer, + uint32_t resp_buff_size +); + +/***************************************************************************//** + The SPI_enable() function enables the CoreSPI and allows it to respond to the external + signals. It is usually called to re-enable a CoreSPI instance which has been + disabled previously via by calling the SPI_disable() as the normal state of a CoreSPI + after enabling the initialization. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + */ +void SPI_enable +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_disable() function disables the CoreSPI and stops responding to the + external signals. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + */ +void SPI_disable +( + spi_instance_t * this_spi +); + +#ifdef __cplusplus +} +#endif + +#endif /* CORE_SPI_H_*/ diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreSPI/corespi_regs.h b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreSPI/corespi_regs.h new file mode 100644 index 0000000..a3e5b2a --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreSPI/corespi_regs.h @@ -0,0 +1,270 @@ +/***************************************************************************//** + * Copyright 2011-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file corespi_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreSPI memory map + * + */ + +#ifndef CORESPI_REGS_H_ +#define CORESPI_REGS_H_ + +/******************************************************************************* + * Control register 1: + *------------------------------------------------------------------------------ + */ +#define CTRL1_REG_OFFSET 0x00u + +#define CTRL1_ENABLE_OFFSET 0x00u +#define CTRL1_ENABLE_MASK 0x01u +#define CTRL1_ENABLE_SHIFT 0x00 + +#define CTRL1_MASTER_OFFSET 0x00u +#define CTRL1_MASTER_MASK 0x02u +#define CTRL1_MASTER_SHIFT 0x01 + +#define CTRL1_INTRXDATA_OFFSET 0x00u +#define CTRL1_INTRXDATA_MASK 0x04u +#define CTRL1_INTRXDATA_SHIFT 0x02 + +#define CTRL1_INTTXDONE_OFFSET 0x00u +#define CTRL1_INTTXDONE_MASK 0x08u +#define CTRL1_INTTXDONE_SHIFT 0x03 + +#define CTRL1_INTRXOVFLOW_OFFSET 0x00u +#define CTRL1_INTRXOVFLOW_MASK 0x10u +#define CTRL1_INTRXOVFLOW_SHIFT 0x04 + +#define CTRL1_INTTXURUN_OFFSET 0x00u +#define CTRL1_INTTXURUN_MASK 0x20u +#define CTRL1_INTTXURUN_SHIFT 0x05 + +#define CTRL1_FRAMEURUN_OFFSET 0x00u +#define CTRL1_FRAMEURUN_MASK 0x40u +#define CTRL1_FRAMEURUN_SHIFT 0x06 + +#define CTRL1_OENOFF_OFFSET 0x00u +#define CTRL1_OENOFF_MASK 0x80u +#define CTRL1_OENOFF_SHIFT 0x07 + +/******************************************************************************* + * Interrupt clear register: + *------------------------------------------------------------------------------ + */ +#define INTCLR_REG_OFFSET 0x04u + +#define INTCLR_TXDONE_OFFSET 0x04u +#define INTCLR_TXDONE_MASK 0x01u +#define INTCLR_TXDONE_SHIFT 0x00 + +#define INTCLR_RXDONE_OFFSET 0x04u +#define INTCLR_RXDONE_MASK 0x02u +#define INTCLR_RXDONE_SHIFT 0x01 + +#define INTCLR_RXOVERFLOW_OFFSET 0x04u +#define INTCLR_RXOVERFLOW_MASK 0x04u +#define INTCLR_RXOVERFLOW_SHIFT 0x02 + +#define INTCLR_TXUNDERRUN_OFFSET 0x04u +#define INTCLR_TXUNDERRUN_MASK 0x08u +#define INTCLR_TXUNDERRUN_SHIFT 0x03 + +#define INTCLR_CMDINT_OFFSET 0x04u +#define INTCLR_CMDINT_MASK 0x10u +#define INTCLR_CMDINT_SHIFT 0x04 + +#define INTCLR_SSEND_OFFSET 0x04u +#define INTCLR_SSEND_MASK 0x20u +#define INTCLR_SSEND_SHIFT 0x05 + +#define INTCLR_RXDATA_OFFSET 0x04u +#define INTCLR_RXDATA_MASK 0x40u +#define INTCLR_RXDATA_SHIFT 0x06 + +#define INTCLR_TXDATA_OFFSET 0x04u +#define INTCLR_TXDATA_MASK 0x80u +#define INTCLR_TXDATA_SHIFT 0x07 + +/******************************************************************************* + * Receive data register: + *------------------------------------------------------------------------------ + */ +#define RXDATA_REG_OFFSET 0x08u + +/******************************************************************************* + * Transmit data register: + *------------------------------------------------------------------------------ + */ +#define TXDATA_REG_OFFSET 0x0Cu + +/******************************************************************************* + * Masked interrupt status register: + *------------------------------------------------------------------------------ + */ +#define INTMASK_REG_OFFSET 0x10u + +#define INTMASK_TXDONE_OFFSET 0x10u +#define INTMASK_TXDONE_MASK 0x01u +#define INTMASK_TXDONE_SHIFT 0x00 + +#define INTMASK_RXDONE_OFFSET 0x10u +#define INTMASK_RXDONE_MASK 0x02u +#define INTMASK_RXDONE_SHIFT 0x01 + +#define INTMASK_RXOVERFLOW_OFFSET 0x10u +#define INTMASK_RXOVERFLOW_MASK 0x04u +#define INTMASK_RXOVERFLOW_SHIFT 0x02 + +#define INTMASK_TXUNDERRUN_OFFSET 0x10u +#define INTMASK_TXUNDERRUN_MASK 0x08u +#define INTMASK_TXUNDERRUN_SHIFT 0x03 + +#define INTMASK_CMDINT_OFFSET 0x10u +#define INTMASK_CMDINT_MASK 0x10u +#define INTMASK_CMDINT_SHIFT 0x04 + +#define INTMASK_SSEND_OFFSET 0x10u +#define INTMASK_SSEND_MASK 0x20u +#define INTMASK_SSEND_SHIFT 0x05 + +#define INTMASK_RXDATA_OFFSET 0x10u +#define INTMASK_RXDATA_MASK 0x40u +#define INTMASK_RXDATA_SHIFT 0x06 + +#define INTMASK_TXDATA_OFFSET 0x10u +#define INTMASK_TXDATA_MASK 0x80u +#define INTMASK_TXDATA_SHIFT 0x07 + +/******************************************************************************* + * Raw interrupt status register: + *------------------------------------------------------------------------------ + */ +#define INTRAW_REG_OFFSET 0x14u + +#define INTRAW_TXDONE_OFFSET 0x14u +#define INTRAW_TXDONE_MASK 0x01u +#define INTRAW_TXDONE_SHIFT 0x00 + +#define INTRAW_RXDONE_OFFSET 0x14u +#define INTRAW_RXDONE_MASK 0x02u +#define INTRAW_RXDONE_SHIFT 0x01 + +#define INTRAW_RXOVERFLOW_OFFSET 0x14u +#define INTRAW_RXOVERFLOW_MASK 0x04u +#define INTRAW_RXOVERFLOW_SHIFT 0x02 + +#define INTRAW_TXUNDERRUN_OFFSET 0x14u +#define INTRAW_TXUNDERRUN_MASK 0x08u +#define INTRAW_TXUNDERRUN_SHIFT 0x03 + +#define INTRAW_CMDINT_OFFSET 0x14u +#define INTRAW_CMDINT_MASK 0x10u +#define INTRAW_CMDINT_SHIFT 0x04 + +#define INTRAW_SSEND_OFFSET 0x14u +#define INTRAW_SSEND_MASK 0x20u +#define INTRAW_SSEND_SHIFT 0x05 + +#define INTRAW_RXDATA_OFFSET 0x14u +#define INTRAW_RXDATA_MASK 0x40u +#define INTRAW_RXDATA_SHIFT 0x06 + +#define INTRAW_TXDATA_OFFSET 0x14u +#define INTRAW_TXDATA_MASK 0x80u +#define INTRAW_TXDATA_SHIFT 0x07 + +/******************************************************************************* + * Control register 2: + *------------------------------------------------------------------------------ + */ +#define CTRL2_REG_OFFSET 0x18u + +#define CTRL2_CMDSIZE_OFFSET 0x18u +#define CTRL2_CMDSIZE_MASK 0x07u +#define CTRL2_CMDSIZE_SHIFT 0x00 + +#define CTRL2_INTCMD_OFFSET 0x18u +#define CTRL2_INTCMD_MASK 0x10u +#define CTRL2_INTCMD_SHIFT 0x04 + +#define CTRL2_INTSSEND_OFFSET 0x18u +#define CTRL2_INTSSEND_MASK 0x20u +#define CTRL2_INTSSEND_SHIFT 0x05 + +#define CTRL2_INTRXDATA_OFFSET 0x18u +#define CTRL2_INTRXDATA_MASK 0x40u +#define CTRL2_INTRXDATA_SHIFT 0x06 + +#define CTRL2_INTTXDATA_OFFSET 0x18u +#define CTRL2_INTTXDATA_MASK 0x80u +#define CTRL2_INTTXDATA_SHIFT 0x07 + +/******************************************************************************* + * Command register: + *------------------------------------------------------------------------------ + */ +#define CMD_REG_OFFSET 0x1Cu + +#define CMD_RXFIFORST_OFFSET 0x1Cu +#define CMD_RXFIFORST_MASK 0x01u +#define CMD_RXFIFORST_SHIFT 0x00 + +#define CMD_TXFIFORST_OFFSET 0x1Cu +#define CMD_TXFIFORST_MASK 0x02u +#define CMD_TXFIFORST_SHIFT 0x01 + +/******************************************************************************* + * Status register: + *------------------------------------------------------------------------------ + */ +#define STATUS_REG_OFFSET 0x20u + +#define STATUS_FIRSTFRAME_OFFSET 0x20u +#define STATUS_FIRSTFRAME_MASK 0x01u +#define STATUS_FIRSTFRAME_SHIFT 0x00 + +#define STATUS_DONE_OFFSET 0x20u +#define STATUS_DONE_MASK 0x02u +#define STATUS_DONE_SHIFT 0x01 + +#define STATUS_RXEMPTY_OFFSET 0x20u +#define STATUS_RXEMPTY_MASK 0x04u +#define STATUS_RXEMPTY_SHIFT 0x02 + +#define STATUS_TXFULL_OFFSET 0x20u +#define STATUS_TXFULL_MASK 0x08u +#define STATUS_TXFULL_SHIFT 0x03 + +#define STATUS_RXOVFLOW_OFFSET 0x20u +#define STATUS_RXOVFLOW_MASK 0x10u +#define STATUS_RXOVFLOW_SHIFT 0x04 + +#define STATUS_TXUNDERRUN_OFFSET 0x20u +#define STATUS_TXUNDERRUN_MASK 0x20u +#define STATUS_TXUNDERRUN_SHIFT 0x05 + +#define STATUS_SSEL_OFFSET 0x20u +#define STATUS_SSEL_MASK 0x40u +#define STATUS_SSEL_SHIFT 0x06 + +#define STATUS_ACTIVE_OFFSET 0x20u +#define STATUS_ACTIVE_MASK 0x80u +#define STATUS_ACTIVE_SHIFT 0x07 + +/******************************************************************************* + * Slave select register: + *------------------------------------------------------------------------------ + */ +#define SSEL_REG_OFFSET 0x24u + +/******************************************************************************* + * Transmit data last register: + *------------------------------------------------------------------------------ + */ +#define TXLAST_REG_OFFSET 0x28u + + +#endif /*CORESPI_REGS_H_*/ diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.c b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.c new file mode 100644 index 0000000..b8adaed --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.c @@ -0,0 +1,889 @@ +/******************************************************************************* + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * PF_System_Services driver implementation. See file "core_syservices_pf.h" for + * description of the functions implemented in this file. + * + */ + +#include "core_sysservices_pf.h" +#include "coresysservicespf_regs.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define NULL_BUFFER (( uint8_t* ) 0) + +static uint8_t execute_ss_command +( + uint8_t cmd_opcode, + const uint8_t* cmd_data, + uint16_t cmd_data_size, + const uint8_t* p_response, + uint16_t response_size, + uint16_t mb_offset, + uint16_t response_offset +); + +uint32_t g_css_pf_base_addr = 0u; + +/***************************************************************************//** + * SYS_init() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +void +SYS_init +( + uint32_t base_addr +) +{ + g_css_pf_base_addr = base_addr; +} + +/***************************************************************************//** + * SYS_get_serial_number() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_serial_number +( + const uint8_t * p_serial_number, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if (p_serial_number == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(SERIAL_NUMBER_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_serial_number, + SERIAL_NUMBER_RESP_LEN, + mb_offset, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_get_user_code() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_user_code +( + const uint8_t * p_user_code, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_user_code == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(USERCODE_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_user_code, + USERCODE_RESP_LEN, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_get_design_info() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_design_info +( + const uint8_t * p_design_info, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_design_info == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(DESIGN_INFO_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_design_info, + DESIGN_INFO_RESP_LEN, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_get_device_certificate() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_device_certificate +( + const uint8_t * p_device_certificate, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_device_certificate == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(DEVICE_CERTIFICATE_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_device_certificate, + DEVICE_CERTIFICATE_RESP_LEN, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_read_digest() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_read_digest +( + const uint8_t * p_digest, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_digest == NULL_BUFFER) + { + return status; + } + +#ifndef CORESYSSERVICES_MPFS + status = execute_ss_command(READ_DIGEST_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_digest, + READ_DIGEST_RESP_LEN, + mb_offset, + 0u); +#else + status = execute_ss_command(READ_DIGEST_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_digest, + READ_DIGEST_MPFS_RESP_LEN, + mb_offset, + 0u); +#endif + return status; + +} + +/***************************************************************************//** + * SYS_query_security() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_query_security +( + uint8_t * p_security_locks, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint8_t idx = 0u; + + if(p_security_locks == NULL_BUFFER) + { + return status; + } + +#ifndef CORESYSSERVICES_MPFS + uint8_t buf[12] = {0}; + /* Actual QUERY_SECURITY_RESP_LEN is 9 or 33 but PF_System_Services core + * needs number of words instead of number of bytes to be written to or read + * from MailBox */ + status = execute_ss_command(QUERY_SECURITY_REQUEST_CMD, + NULL_BUFFER, + 0u, + buf, + (QUERY_SECURITY_RESP_LEN + 3u), + mb_offset, + 0u); + + for (idx = 0u; idx < 9u; idx++) + { + *(p_security_locks+idx) = buf[idx]; + } + +#else + uint8_t buf[36] = {0}; + + status = execute_ss_command(QUERY_SECURITY_REQUEST_CMD, + NULL_BUFFER, + 0u, + buf, + (QUERY_SECURITY_MPFS_RESP_LEN + 3u), + mb_offset, + 0u); + + for (idx = 0u; idx < 33u; idx++) + { + *(p_security_locks+idx) = buf[idx]; + } + +#endif + + return status; +} + +/***************************************************************************//** + * SYS_read_debug_info() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_read_debug_info +( + const uint8_t * p_debug_info, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_debug_info == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(READ_DEBUG_INFO_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_debug_info, + READ_DEBUG_INFO_RESP_LEN, + mb_offset, + 0u); + return status; +} + +#ifdef CORESYSSERVICES_MPFS +/***************************************************************************//** + * SYS_read_envm_parameter() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_read_envm_parameter +( + uint8_t * p_envm_param, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_envm_param == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(READ_ENVM_PARAM_REQUEST_CMD, + NULL_BUFFER, + 0, + p_envm_param, + READ_ENVM_PARAM_RESP_LEN, + mb_offset, + 0); + return status; +} + +#endif + +/***************************************************************************//** + * SYS_puf_emulation_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_puf_emulation_service +( + const uint8_t * p_challenge, + uint8_t op_type, + uint8_t* p_response, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint8_t mb_format[20] = {0x00}; + uint8_t index = 0u; + + if((p_response == NULL_BUFFER) || (p_challenge == NULL_BUFFER)) + { + return status; + } + + /* Frame the data required for mailbox */ + mb_format[index] = op_type; + + for (index = 4u; index < 20u; index++) + { + mb_format[index] = p_challenge[index - 4u]; + } + + status = execute_ss_command(PUF_EMULATION_SERVICE_REQUEST_CMD, + mb_format, + PUF_EMULATION_SERVICE_CMD_LEN, + p_response, + PUF_EMULATION_SERVICE_RESP_LEN, + mb_offset, + 5u); /* mentioning offset to number of words instead of bytes */ + + return status; +} + +/***************************************************************************//** + * SYS_digital_signature_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_digital_signature_service +( + const uint8_t* p_hash, + uint8_t format, + uint8_t* p_response, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if((p_hash == NULL_BUFFER) || (p_response == NULL_BUFFER)) + { + return status; + } + + if (format == DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD) + { + status = execute_ss_command(DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD, + p_hash, + DIGITAL_SIGNATURE_HASH_LEN, + p_response, + DIGITAL_SIGNATURE_RAW_FORMAT_RESP_SIZE, + mb_offset, + 12u); /* mentioning offset to number of words instead of bytes */ + } + else + { + status = execute_ss_command(DIGITAL_SIGNATURE_DER_FORMAT_REQUEST_CMD, + p_hash, + DIGITAL_SIGNATURE_HASH_LEN, + p_response, + DIGITAL_SIGNATURE_DER_FORMAT_RESP_SIZE, + mb_offset, + 12u); /* mentioning offset to number of words instead of bytes */ + } + + return status; +} + +/***************************************************************************//** + * SYS_secure_nvm_write() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_secure_nvm_write +( + uint8_t format, + uint8_t snvm_module, + const uint8_t* p_data, + const uint8_t* p_user_key, + uint16_t mb_offset +) +{ + uint8_t frame[256] = {0x00}; + uint8_t* p_frame = &frame[0]; + uint16_t index = 0u; + uint8_t status = SYS_PARAM_ERR; + + HAL_ASSERT(!(NULL_BUFFER == p_data)); + HAL_ASSERT(!(snvm_module >= 221u)); + if (format != SNVM_NON_AUTHEN_TEXT_REQUEST_CMD) + { + HAL_ASSERT(!(NULL_BUFFER == p_user_key)); + } + + if ((p_data == NULL_BUFFER) || (snvm_module >= 221)) + { + return status; + } + + if ((format != SNVM_NON_AUTHEN_TEXT_REQUEST_CMD) + && (p_user_key == NULL_BUFFER)) + { + return status; + } + + if ((format != SNVM_NON_AUTHEN_TEXT_REQUEST_CMD) + && (format != SNVM_AUTHEN_TEXT_REQUEST_CMD) + && (format != SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD)) + { + return status; + } + + *p_frame = snvm_module; /* SNVMADDR - SNVM module */ + + p_frame += 4u; /* Next 3 bytes RESERVED - For alignment */ + + /* Copy user key and send the command/data to mailbox. */ + if ((format == SNVM_AUTHEN_TEXT_REQUEST_CMD) || + (format == SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD)) + { + /* Copy user data */ + for (index = 0u; index < (AUTHENTICATED_TEXT_DATA_LEN - USER_SECRET_KEY_LEN - 4u); index++) + { + *p_frame = p_data[index]; + p_frame++; + } + + /* Copy user key */ + for (index = 0u; index < USER_SECRET_KEY_LEN; index++) + { + *p_frame = p_user_key[index]; + p_frame++; + } + + status = execute_ss_command(format, + &frame[0], + AUTHENTICATED_TEXT_DATA_LEN, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + } + else + { + /* Copy user data */ + for (index = 0u; index < (NON_AUTHENTICATED_TEXT_DATA_LEN - 4u); index++) + { + *(p_frame+index) = p_data[index]; + } + + status = execute_ss_command(format, + &frame[0], + NON_AUTHENTICATED_TEXT_DATA_LEN, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + } + + return status; +} + +/***************************************************************************//** + * SYS_secure_nvm_read() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_secure_nvm_read +( + uint8_t snvm_module, + const uint8_t* p_user_key, + uint8_t* p_admin, + uint8_t* p_data, + uint16_t data_len, + uint16_t mb_offset +) +{ + /* Frame the message. */ + uint8_t frame[16] = {0x00u}; + uint8_t* p_frame = &frame[0u]; + uint8_t status = SYS_PARAM_ERR; + uint8_t response[256] = {0x00u}; + uint16_t index = 0u; + + HAL_ASSERT(!(NULL_BUFFER == p_data)); + HAL_ASSERT(!(NULL_BUFFER == p_admin)); + HAL_ASSERT(!(snvm_module > 221u)); + + HAL_ASSERT(data_len == 236u || data_len == 252u); + + if((p_data == NULL_BUFFER) || + (snvm_module >= 221) || + (p_admin == NULL_BUFFER)) + { + return status; + } + + *p_frame = snvm_module; /* SNVMADDR - SNVM module */ + + p_frame += 4u; /* RESERVED - For alignment */ + + /* Copy user key */ + if (236u == data_len) + { + HAL_ASSERT(p_user_key != NULL_BUFFER); + + if(p_user_key == NULL_BUFFER) + { + return status; + } + + for (index = 0u; index < 12u; index++) + { + *p_frame = p_user_key[index]; + p_frame++; + } + } + else + { + p_frame += 12u; + } + + status = execute_ss_command(SNVM_READ_REQUEST_CMD, + &frame[0], + 16u, + response, + (data_len + 4u), + mb_offset, + 4u); /* mentioning offset to number of words instead of bytes */ + + if (SYS_SUCCESS == status) + { + for (index = 0u; index < 4u; index++) + { + *(p_admin+index) = (uint32_t)response[index]; + } + + + /* Copy data into user buffer. */ + for (index = 4u; index < (data_len + 4u); index++) + { + *(p_data + (index - 4u)) = response[index]; + } + } + else + { + ; + } + + return status; +} + +/***************************************************************************//** + * SYS_nonce_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_nonce_service +( + const uint8_t * p_nonce, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if((p_nonce == NULL_BUFFER)) + { + return status; + } + + status = execute_ss_command(NONCE_SERVICE_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_nonce, + NONCE_SERVICE_RESP_LEN, + mb_offset, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_bitstream_authenticate_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_bitstream_authenticate_service +( + uint32_t spi_flash_address, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint32_t l_spi_flash_address = spi_flash_address; + status = execute_ss_command(BITSTREAM_AUTHENTICATE_CMD, + (uint8_t* )&l_spi_flash_address, + 4u, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_IAP_image_authenticate_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_IAP_image_authenticate_service +( + uint8_t spi_idx +) +{ + uint8_t status = SYS_PARAM_ERR; + + HAL_ASSERT(!(spi_idx == 1u)); + + if (spi_idx == 1u) + { + return status; + } + + status = execute_ss_command(IAP_BITSTREAM_AUTHENTICATE_CMD, + NULL_BUFFER, + 0u, + NULL_BUFFER, + 0u, + spi_idx, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_digest_check_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_digest_check_service +( + uint32_t options, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint32_t l_options = options; + + status = execute_ss_command(DIGEST_CHECK_CMD, + (uint8_t* )&l_options, + 4u, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_iap_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_iap_service +( + uint8_t iap_cmd, + uint32_t spiaddr, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint16_t l_mb_offset = 0u; + uint16_t cmd_data_size = 0u; + uint8_t* cmd_data = NULL_BUFFER; + bool invalid_param = false; + + if (((IAP_PROGRAM_BY_SPIIDX_CMD == iap_cmd) + || (IAP_VERIFY_BY_SPIIDX_CMD == iap_cmd)) + && (1u == spiaddr)) + { + invalid_param = true; + HAL_ASSERT(!invalid_param); + } + + if (!invalid_param) + { + switch(iap_cmd) + { + case IAP_PROGRAM_BY_SPIIDX_CMD: + case IAP_VERIFY_BY_SPIIDX_CMD: + /*In SPI_IDX based program and verify commands, + * Mailbox is not Required. Instead of mailbox offset + * SPI_IDX is passed as parameter.*/ + l_mb_offset = (uint16_t)(0xFFu & spiaddr); + break; + + case IAP_PROGRAM_BY_SPIADDR_CMD: + case IAP_VERIFY_BY_SPIADDR_CMD: + /*In SPI_ADDR based program and verify commands, + * Mailbox is Required*/ + l_mb_offset = mb_offset; + /*command data size is four bytes holding the + * SPI Address in it.*/ + cmd_data_size = 4u; + cmd_data = (uint8_t*)&spiaddr; + break; + + case IAP_AUTOUPDATE_CMD: + /*In auto update command Mailbox is not Required*/ + l_mb_offset = 0u; + break; + + default: + l_mb_offset = 0u; + + } + + status = execute_ss_command( + (uint8_t)iap_cmd, + cmd_data, + cmd_data_size, + NULL_BUFFER, + 0, + (uint16_t)l_mb_offset, + 0); + } + + return status; +} + +/***************************************************************************//** + Internal functions. +*/ +/* +This function executes the SS command. If Mailbox input data is required by the +it will first load it from cmd_data into the Mailbox. If the service requires +the response data to be read from mailbox, it will do so and store it in p_response. +*/ +static uint8_t execute_ss_command +( + uint8_t cmd_opcode, + const uint8_t* cmd_data, + uint16_t cmd_data_size, + const uint8_t* p_response, + uint16_t response_size, + uint16_t mb_offset, + uint16_t response_offset +) +{ + /* Pointer used during Writing to Mailbox memory. */ + uint32_t status = 0u; + uint16_t idx = 0u; + uint16_t ss_command = 0u; + uint32_t* word_buf; + uint16_t timeout_count = SS_TIMEOUT_COUNT; + + /* making sure that the system controller is not executing any service i.e. + SS_USER_BUSY is gone 0 */ + + while (1u == HAL_get_32bit_reg_field(g_css_pf_base_addr, SS_USER_BUSY)) + { + --timeout_count; + + if (timeout_count == 0) + { + return SS_USER_BUSY_TIMEOUT; + } + } + + /* Form the SS command: bit 0to6 is the opcode, bit 7to15 is the Mailbox offset + For some services this field has another meaning + (e.g. for IAP bitstream auth. it means spi_idx) */ + ss_command = ((mb_offset << 7u) | (cmd_opcode & 0x7Fu)); + + /* Load the command register with the SS request command code*/ + HAL_set_32bit_reg(g_css_pf_base_addr, SS_CMD, ss_command); + + if (cmd_data_size > 0u) + { + HAL_ASSERT(!(NULL_BUFFER == cmd_data)); + HAL_ASSERT(!(cmd_data_size % 4u)); + + /* Load the MBX_WCNT register with number of words */ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_WCNT, (cmd_data_size/4u)); + + /* Load the MBX_WADDR register with offset of input data (write to Mailbox) + For all the services this offset remains either 0 or Not applicable + for the services in which no Mailbox write is required.*/ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_WADDR, (0x00u + mb_offset)); + + } + + if (response_size > 0u) + { + HAL_ASSERT(!(NULL_BUFFER == p_response)); + HAL_ASSERT(!(response_size % 4u)); + + /* + Load the MBX_RWCNT register with number of words to be read from Mailbox + */ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_RCNT, (response_size/4u)); + + /* + Load the MBX_RADRDESC register with offset address within the mailbox + format for that particular service. + It will be 0 for the services where there is no output data from G5CONTROL + is expected. + This function assumes that this value is pre-calculated by service specific + functions as this value is fixed for each service. + */ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_RADDR, (response_offset + mb_offset)); + } + + /*Set the request bit in SYS_SERV_REQ register to start the service*/ + HAL_set_32bit_reg_field(g_css_pf_base_addr, SS_REQ_REQ, 0x01u); + + if (cmd_data_size > 0u) + { + word_buf = (uint32_t*)cmd_data; + + /* Write the user data into mail box. */ + for (idx = 0u; idx < (cmd_data_size/4u); idx++) + { + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_WDATA, word_buf[idx]); + } + } + + timeout_count = SS_TIMEOUT_COUNT; + if (response_size > 0u) + { + word_buf = (uint32_t*)p_response; + + for (idx = 0u; idx < (response_size/4u); idx++) + { + while (0u == HAL_get_32bit_reg_field(g_css_pf_base_addr, + SS_USER_RDVLD)) + { + --timeout_count; + + if (timeout_count == 0) + { + return SS_USER_RDVLD_TIMEOUT; + } + } + word_buf[idx] = HAL_get_32bit_reg(g_css_pf_base_addr, MBX_RDATA); + } + } + + timeout_count = SS_TIMEOUT_COUNT; + /* make sure that service is complete i.e. SS_USER_BUSY is gone 0 */ + while (1u == HAL_get_32bit_reg_field(g_css_pf_base_addr, SS_USER_BUSY)) + { + --timeout_count; + + if (timeout_count == 0) + { + return SS_USER_RDVLD_TIMEOUT; + } + } + + /* Read the status returned by System Controller */ + status = HAL_get_32bit_reg(g_css_pf_base_addr, SS_STAT); + + return (uint8_t)status; +} + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h new file mode 100644 index 0000000..8e0ebb6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h @@ -0,0 +1,1249 @@ +/******************************************************************************* + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the + * CoreSysServices_PF bare metal driver. + */ +/*=========================================================================*//** + @mainpage CoreSysServices_PF Bare Metal Driver. + + @section intro_sec Introduction + The PolarFire System Services (PF_SYSTEM_SERVICES) SgCore enables executing + the system services on the PolarFire and PolarFire SoC device. The system services + are the system controller actions initiated by the System Controller's System + Service Interface (SSI). The PolarFire System Services "SgCore" provides a + method to initiate these system services. The PF_SYSTEM_SERVICES interacts + with the system controller on SSI and Mailbox interface to initiate system + services, exchange data required for that services, and to know the successful + completion or error status. + + The PF_SYSTEM_SERVICES provides an APB interface for controlling the registers + functions for controlling the PF_SYSTEM_SERVICES as part of a bare metal system + register implemented within it. This software driver provides a set of where no + part of an operating system but the implementation of the adaptation layer + operating system is available. This driver is adapted for use in + between this driver and the operating system's driver model is outside the + scope of this driver. + + ## Features + The CoreSysServices_PF driver provides the following features: + - Executing device and design information services + - Executing design services + - Executing data security services + - Executing Fabric services + + The CoreSysServices_PF driver is provided as C source code. + + @section Driver Configuration + The application software should configure the CoreSysServices_PF driver through + calling the SYS_init() function. Only one instance of PF_SYSTEM_SERVICES SgCore is + supported. No additional configuration files are required to use the driver. + If using this driver on RT PolarFire device FPGA, define RT_DEVICE_FAMILY + macro in application. + + @section theory_op Theory of Operation + The CoreSysServices_PF driver provides access to the PolarFire system services. + These system services are grouped into the following categories: + + Device and Design Information Service + - Serial Number Service + - USERCODE Service + - Design Info Service + - Device Certificate Services + - Read Digests + - Query Security + - Read Debug Info + - Read eNVM param + + Design Services + - Bitstream authentication service + - IAP bitstream authentication service + + Data Security Services + - Digital Signature Service + - Secure NVM (SNVM) Functions + - PUF Emulation Service + - Nonce Service + + Fabric Services + - Digest Check Service + - In Application programming(IAP)/Auto-Update service + + Initialization and Configuration + + The CoreSysServices_PF driver is initialized by calling the SYS_init() + function. The SYS_init() function must be called before calling any other + CoreSysServices_PF driver functions. + + Device and Design Information Services + + The CoreSysServices_PF driver is used to read information about the device + and the design using the following functions: + - SYS_get_serial_number() + - SYS_get_user_code() + - SYS_get_design_info() + - SYS_get_device_certificate() + - SYS_read_digest() + - SYS_query_security() + - SYS_read_debug_info() + + Design Authentication Services + + The CoreSysServices_PF driver is used to execute design services using the + following functions: + - SYS_bitstream_authenticate_service() + - SYS_IAP_image_authenticate_service() + + Data Security Services + + The CoreSysServices_PF driver is used to execute data security services + using the following functions: + - SYS_digital_signature_service() + - SYS_secure_nvm_write() + - SYS_secure_nvm_read() + - SYS_puf_emulation_service () + - SYS_nonce_service () + + Executing Fabric Services + + The CoreSysServices_PF driver is used to execute fabric services using the + following functions: + - SYS_digest_check_service() + - SYS_iap_service() + + All the service execution functions return the 8-bit status, which is returned + by the system controller on executing the given service. A '0' value indicates + successful execution of that service. A non-zero value indicates error. + The error codes for each service are different. See individual function + description to know the exact meanings of the error codes for each service. + + The function descriptions in this file mainly focus on the details required + by the user to use the APIs provided by this driver to execute the services. + To know the complete details of the system services, see the + PolarFire FPGA and PolarFire SoC FPGA System Services [document](https://onlinedocs.microchip.com/pr/GUID-1409CF11-8EF9-4C24-A94E-70979A688632-en-US-3/index.html) + + *//*=========================================================================*/ +#ifndef __CORE_SYSSERV_PF_H +#define __CORE_SYSSERV_PF_H 1 + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#include "hal_assert.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** +* # Service Execution Success and Error Status Codes +* +* The following status codes are the return values from the system service functions. +* For any service, a return value '0' indicates that the service was executed +* successfully. A non-zero return value indicates that the service was not +* executed successfully. For all the services, the return value represents the +* status code returned by the system controller for the respective service, +* except the values SYS_PARAM_ERR, SS_USER_BUSY_TIMEOUT, and SS_USER_RDVLD_TIMEOUT. +* These three values indicate the error conditions detected by this driver and +* they do not overlap with the status code returned by the system controller for +* any of the system service. +* +* SYS_SUCCESS +* System service executed successfully +* +* SYS_PARAM_ERR +* System service cannot be executed as one or more parameters are not as +* expected by this driver. No read/write access is performed with the +* IP. +* +* SS_USER_BUSY_TIMEOUT +* The System service request is initiated and the driver timed-out while +* waiting for the system service to complete. The System Service +* completion is indicated by de-assertion of the SS_USER_BUSY bit by the +* IP. +* +* SS_USER_RDVLD_TIMEOUT +* The System service request is initiated and the driver timed-out while +* waiting for SS_USER_RDVLD bit, which indicates availability of data to +* be read from the mailbox, to become active. +*/ +#define SYS_SUCCESS 0u +#define SYS_PARAM_ERR 0xFFu +#define SS_USER_BUSY_TIMEOUT 0xFAu +#define SS_USER_RDVLD_TIMEOUT 0xFBu + +/** +* # System Service Timeout Count +* +* The SS_TIMEOUT_COUNT value is used by the driver as a timeout count +* while waiting for either the SS_USER_BUSY or SS_USER_RDVLD. This empirical +* value is sufficiently large so that the operations are falsely +* timeout in the normal circumstance. It is provided as a way to provide +* more debug information to the application in case there are some +* unforeseen issues. You may change this value for your need based on your +* system design. +*/ +#define SS_TIMEOUT_COUNT 40000u +/* + * SYS_DCF_DEVICE_MISMATCH + * Public key or FSN do not match device + * + * + * SYS_DCF_INVALID_SIGNATURE + * Certificate signature is invalid + * + * SYS_DCF_SYSTEM_ERROR + * PUF or storage failure + */ +#define SYS_DCF_DEVICE_MISMATCH 1u +#define SYS_DCF_INVALID_SIGNATURE 2u +#define SYS_DCF_SYSTEM_ERROR 3u + +/* + * SYS_NONCE_PUK_FETCH_ERROR + * Error fetching PUK + * + * SYS_NONCE_SEED_GEN_ERROR + * Error generating seed + */ +#define SYS_NONCE_PUK_FETCH_ERROR 1u +#define SYS_NONCE_SEED_GEN_ERROR 2u + +/** + * # Secure Nvm Write Error Codes + * + * SNVM_WRITE_INVALID_SNVMADDR + * Illegal page address + * + * SNVM_WRITE_FAILURE + * PNVM program/verify failed + * + * SNVM_WRITE_SYSTEM_ERROR + * PUF or storage failure + * + * SNVM_WRITE_NOT_PERMITTED + * Write is not permitted + */ +#define SNVM_WRITE_INVALID_SNVMADDR 1u +#define SNVM_WRITE_FAILURE 2u +#define SNVM_WRITE_SYSTEM_ERROR 3u +#define SNVM_WRITE_NOT_PERMITTED 4u + +/** + * # Secure Nvm Read Error Codes + * + * SNVM_READ_INVALID_SNVMADDR + * Illegal page address + * + * SNVM_READ_AUTHENTICATION_FAILURE + * Storage corrupt or incorrect USK + * + * SNVM_READ_SYSTEM_ERROR + * PUF or storage failure + * + */ +#define SNVM_READ_INVALID_SNVMADDR 1u +#define SNVM_READ_AUTHENTICATION_FAILURE 2u +#define SNVM_READ_SYSTEM_ERROR 3u + +/** + * # Digital Signature Service Error Codes + * + * DIGITAL_SIGNATURE_FEK_FAILURE_ERROR + * Error retrieving FEK + * + * DIGITAL_SIGNATURE_DRBG_ERROR + * Failed to generate nonce + * + * DIGITAL_SIGNATURE_ECDSA_ERROR + * ECDSA failed + */ +#define DIGITAL_SIGNATURE_FEK_FAILURE_ERROR 1u +#define DIGITAL_SIGNATURE_DRBG_ERROR 2u +#define DIGITAL_SIGNATURE_ECDSA_ERROR 3u + +/** + * # Digest Check Error Codes + * + * NOTE: When these error occur, the DIGEST tamper flag is triggered. + * + * DIGEST_CHECK_FABRICERR + * Fabric digest check error + * + * DIGEST_CHECK_CCERR + * UFS Fabric Configuration (CC) segment digest check error + * + * DIGEST_CHECK_SNVMERR + * ROM digest in SNVM segment digest check error + * + * DIGEST_CHECK_ULERR + * UFS UL segment digest check error + * + * DIGEST_CHECK_UK0ERR + * UKDIGEST0 in User Key segment digest check error + * + * DIGEST_CHECK_UK1ERR + * UKDIGEST1 in User Key segment digest check error + * + * DIGEST_CHECK_UK2ERR + * UKDIGEST2 in User Key segment (UPK1) digest check error + * + * DIGEST_CHECK_UK3ERR + * UKDIGEST3 in User Key segment (UK1) digest check error + * + * DIGEST_CHECK_UK4ERR + * UKDIGEST4 in User Key segment (DPK) digest check error + * + * DIGEST_CHECK_UK5ERR + * UKDIGEST5 in User Key segment (UPK2) digest check error + * + * DIGEST_CHECK_UK6ERR + * UKDIGEST6 in User Key segment (UK2) digest check error + * + * DIGEST_CHECK_UPERR + * UFS Permanent Lock (UPERM) segment digest check error + * + * DIGEST_CHECK_SYSERR + * M3 ROM, Factory and Factory Key Segments digest check error + * + */ +#define DIGEST_CHECK_FABRICERR 0x00u +#define DIGEST_CHECK_CCERR 0x01u +#define DIGEST_CHECK_SNVMERR 0x02u +#define DIGEST_CHECK_ULERR 0x03u +#define DIGEST_CHECK_UK0ERR 0x04u +#define DIGEST_CHECK_UK1ERR 0x05u +#define DIGEST_CHECK_UK2ERR 0x06u +#define DIGEST_CHECK_UK3ERR 0x07u +#define DIGEST_CHECK_UK4ERR 0x08u +#define DIGEST_CHECK_UK5ERR 0x09u +#define DIGEST_CHECK_UK6ERR 0x10u +#define DIGEST_CHECK_UPERR 0x11u +#define DIGEST_CHECK_SYSERR 0x12u + +/** + * # Bitstream Authentication and Iap Bitstream Authentication Return Status + * + * BSTREAM_AUTH_CHAINING_MISMATCH_ERR + * Validator or hash chaining mismatch. Incorrectly constructed bitstream or + * wrong key used. + * + * BSTREAM_AUTH_UNEXPECTED_DATA_ERR + * Unexpected data received. + * Additional data received after end of EOB component. + * + * BSTREAM_AUTH_INVALID_ENCRY_KEY_ERR + * Invalid/corrupt encryption key. + * The requested key mode is disabled or the key could not be read/reconstructed. + * + * BSTREAM_AUTH_INVALID_HEADER_ERR + * Invalid component header + * + * BSTREAM_AUTH_BACK_LEVEL_NOT_SATISFIED_ERR + * Back level not satisfied + * + * BSTREAM_AUTH_ILLEGAL_BITSTREAM_MODE_ERR + * Illegal bitstream mode. + * Requested bitstream mode is disabled by user security. + * + * BSTREAM_AUTH_DNS_BINDING_MISMATCH_ERR + * DSN binding mismatch + * + * BSTREAM_AUTH_ILLEGAL_COMPONENT_SEQUENCE_ERR + * Illegal component sequence + * + * BSTREAM_AUTH_INSUFF_DEVICE_CAPAB_ERR + * Insufficient device capabilities + * + * BSTREAM_AUTH_INCORRECT_DEVICEID_ERR + * Incorrect DEVICEID + * + * BSTREAM_AUTH_PROTOCOL_VERSION_ERR + * Unsupported bitstream protocol version (regeneration required) + * + * BSTREAM_AUTH_VERIFY_ERR + * Verify not permitted on this bitstream + * + * BSTREAM_AUTH_INVALID_DEV_CERT_ERR + * Invalid Device Certificate. + * Device SCAC is invalid or not present. + * + * BSTREAM_AUTH_INVALID_DIB_ERR + * Invalid DIB + * + * BSTREAM_AUTH_SPI_NOT_MASTER_ERR + * Device not in SPI Master Mode. + * Error may occur only when bitstream is executed through IAP mode. + * + * BSTREAM_AUTH_AUTOIAP_NO_VALID_IMAGE_ERR + * No valid images found. + * Error may occur when bitstream is executed through Auto Update mode. + * Occurs when no valid image pointers are found. + * + * BSTREAM_AUTH_INDEXIAP_NO_VALID_IMAGE_ERR + * No valid images found. + * Error may occur when bitstream is executed through IAP mode via Index Mode. + * Occurs when No valid image pointers are found. + * + * BSTREAM_AUTH_NEWER_DESIGN_VERSION_ERR + * Programmed design version is newer than AutoUpdate image found. + * Error may occur when bitstream is executed through Auto Update mode. + * + * BSTREAM_AUTH_INVALID_IMAGE_ERR + * Selected image was invalid and no recovery was performed due to valid design + * in device. + * Error may occur only when bitstream is executed through Auto Update or IAP mode + * (This error is here for completeness but only can be observed by running the + * READ_DEBUG_INFO instruction and looking at IAP Error code field). + * + * BSTREAM_AUTH_IMAGE_PROGRAM_FAILED_ERR + * Selected and Recovery image failed to program. + * Error may occur only when bitstream is executed through Auto Update or + * IAP mode + * (This error is here for completeness but only can be observed by running the + * READ_DEBUG_INFO instruction and looking at IAP Error code field). + * + * BSTREAM_AUTH_ABORT_ERR + * Abort. + * Non-bitstream instruction executed during bitstream loading. + * + * BSTREAM_AUTH_NVMVERIFY_ERR + * Fabric/UFS verification failed (min or weak limit) + * + * BSTREAM_AUTH_PROTECTED_ERR + * Device security prevented modification of non-volatile memory + * + * BSTREAM_AUTH_NOTENA + * Programming mode not enabled + * + * BSTREAM_AUTH_PNVMVERIFY + * pNVM verify operation failed + * + * BSTREAM_AUTH_SYSTEM + * System hardware error (PUF or DRBG) + * + * BSTREAM_AUTH_BADCOMPONENT + * An internal error was detected in a component payload + * + * BSTREAM_AUTH_HVPROGERR + * HV programming subsystem failure (pump failure) + * + * BSTREAM_AUTH_HVSTATE + * HV programming subsystem in unexpected state (internal error) + * + */ +#define BSTREAM_AUTH_CHAINING_MISMATCH_ERR 1 +#define BSTREAM_AUTH_UNEXPECTED_DATA_ERR 2 +#define BSTREAM_AUTH_INVALID_ENCRY_KEY_ERR 3 +#define BSTREAM_AUTH_INVALID_HEADER_ERR 4 +#define BSTREAM_AUTH_BACK_LEVEL_NOT_SATISFIED_ERR 5 +#define BSTREAM_AUTH_ILLEGAL_BITSTREAM_MODE_ERR 6 +#define BSTREAM_AUTH_DNS_BINDING_MISMATCH_ERR 7 +#define BSTREAM_AUTH_ILLEGAL_COMPONENT_SEQUENCE_ERR 8 +#define BSTREAM_AUTH_INSUFF_DEVICE_CAPAB_ERR 9 +#define BSTREAM_AUTH_INCORRECT_DEVICEID_ERR 10 +#define BSTREAM_AUTH_PROTOCOL_VERSION_ERR 11 +#define BSTREAM_AUTH_VERIFY_ERR 12 +#define BSTREAM_AUTH_INVALID_DEV_CERT_ERR 13 +#define BSTREAM_AUTH_INVALID_DIB_ERR 14 +#define BSTREAM_AUTH_SPI_NOT_MASTER_ERR 21 +#define BSTREAM_AUTH_AUTOIAP_NO_VALID_IMAGE_ERR 22 +#define BSTREAM_AUTH_INDEXIAP_NO_VALID_IMAGE_ERR 23 +#define BSTREAM_AUTH_NEWER_DESIGN_VERSION_ERR 24 +/* 25 Reserved */ +#define BSTREAM_AUTH_INVALID_IMAGE_ERR 26 +#define BSTREAM_AUTH_IMAGE_PROGRAM_FAILED_ERR 27 +#define BSTREAM_AUTH_ABORT_ERR 127 +#define BSTREAM_AUTH_NVMVERIFY_ERR 128 +#define BSTREAM_AUTH_PROTECTED_ERR 129 +#define BSTREAM_AUTH_NOTENA 130 +#define BSTREAM_AUTH_PNVMVERIFY 131 +#define BSTREAM_AUTH_SYSTEM 132 +#define BSTREAM_AUTH_BADCOMPONENT 133 +#define BSTREAM_AUTH_HVPROGERR 134 +#define BSTREAM_AUTH_HVSTATE 135 + +/***************************************************************************//** + * # Mailbox ECC Status + * Provides ECC status when the mailbox is read. The values are as follows: + * 00: No ECC errors detected, data is correct. + * 01: Exactly one bit error occurred and has been corrected. + * 10: Exactly two bits error occurred and no correction performed. + * 11: Reserved. + */ +#define SYS_MBOX_ECC_NO_ERROR_MASK 0x00u +#define SYS_MBOX_ONEBIT_ERROR_CORRECTED_MASK 0x40u +#define SYS_MBOX_TWOBIT_ERROR_MASK 0xC0u + +/***************************************************************************//** + * Service request command opcodes: +*/ +#define SERIAL_NUMBER_REQUEST_CMD 0x00u +#define USERCODE_REQUEST_CMD 0x01u +#define DESIGN_INFO_REQUEST_CMD 0x02u +#define DEVICE_CERTIFICATE_REQUEST_CMD 0x03u +#define READ_DIGEST_REQUEST_CMD 0x04u +#define QUERY_SECURITY_REQUEST_CMD 0x05u +#define READ_DEBUG_INFO_REQUEST_CMD 0x06u +#define READ_ENVM_PARAM_REQUEST_CMD 0x07u +#define SNVM_NON_AUTHEN_TEXT_REQUEST_CMD 0x10u +#define SNVM_AUTHEN_TEXT_REQUEST_CMD 0x11u +#define SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD 0x12u +#define SNVM_READ_REQUEST_CMD 0x18u +#define DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD 0x19u +#define PUF_EMULATION_SERVICE_REQUEST_CMD 0x20u +#define NONCE_SERVICE_REQUEST_CMD 0x21u +#define DIGITAL_SIGNATURE_DER_FORMAT_REQUEST_CMD 0x1Au + +#define BITSTREAM_AUTHENTICATE_CMD 0x23u +#define IAP_BITSTREAM_AUTHENTICATE_CMD 0x22u + +#define DIGEST_CHECK_CMD 0x47u + +#define IAP_PROGRAM_BY_SPIIDX_CMD 0x42u +#define IAP_VERIFY_BY_SPIIDX_CMD 0x44u +#define IAP_PROGRAM_BY_SPIADDR_CMD 0x43u +#define IAP_VERIFY_BY_SPIADDR_CMD 0x45u +#define IAP_AUTOUPDATE_CMD 0x46u + +/***************************************************************************//** + * Service request Mailbox return data length + */ +#define SERIAL_NUMBER_RESP_LEN 16u +#define USERCODE_RESP_LEN 4u +#define DESIGN_INFO_RESP_LEN 36u +#define DEVICE_CERTIFICATE_RESP_LEN 1024u +#define READ_DIGEST_RESP_LEN 416u +#define QUERY_SECURITY_RESP_LEN 9u +#define READ_DEBUG_INFO_RESP_LEN 76u +#define READ_ENVM_PARAM_RESP_LEN 256u +#define NONCE_SERVICE_RESP_LEN 32u + +#define PUF_EMULATION_SERVICE_CMD_LEN 20u +#define PUF_EMULATION_SERVICE_RESP_LEN 32u + +#define DIGITAL_SIGNATURE_HASH_LEN 48u +#define DIGITAL_SIGNATURE_RAW_FORMAT_RESP_SIZE 96u +#define DIGITAL_SIGNATURE_DER_FORMAT_RESP_SIZE 104u + +#define USER_SECRET_KEY_LEN 12u + +/* Same driver can be used on PolarFire SoC platform and the response length + * is different for PolarFire SoC. Constants defined below are used only when the + * PF System services driver is used with PolarFire SoC Platform. + */ +#define READ_DIGEST_MPFS_RESP_LEN 576u +#define QUERY_SECURITY_MPFS_RESP_LEN 33u + +/* SNVM Input data length from sNVM write. */ +#ifndef RT_DEVICE_FAMILY +/* SNVMADDR + RESERVED + PT + USK */ +#define NON_AUTHENTICATED_TEXT_DATA_LEN 256u + +/* SNVMADDR + RESERVED + PT */ +#define AUTHENTICATED_TEXT_DATA_LEN 252u +#else +/* SNVMADDR + RESERVED + PT + USK */ +#define NON_AUTHENTICATED_TEXT_DATA_LEN 224u + +/* SNVMADDR + RESERVED + PT */ +#define AUTHENTICATED_TEXT_DATA_LEN 220u +#endif + +/** + * # Digest Check Input Options + * + * DIGEST_CHECK_FABRIC + * Carry out digest check on Fabric + * + * DIGEST_CHECK_CC + * Carry out digest check on UFS Fabric Configuration (CC) segment + * + * DIGEST_CHECK_SNVM + * Carry out digest check on ROM digest in SNVM segment + * + * DIGEST_CHECK_UL + * Carry out digest check on UFS UL segment + * + * DIGEST_CHECK_UKDIGEST0 + * Carry out digest check on UKDIGEST0 in User Key segment + * + * DIGEST_CHECK_UKDIGEST1 + * Carry out digest check on UKDIGEST1 in User Key segment + * + * DIGEST_CHECK_UKDIGEST2 + * Carry out digest check on UKDIGEST2 in User Key segment (UPK1) + * + * DIGEST_CHECK_UKDIGEST3 + * Carry out digest check on UKDIGEST3 in User Key segment (UK1) + * + * DIGEST_CHECK_UKDIGEST4 + * Carry out digest check on UKDIGEST4 in User Key segment (DPK) + * + * DIGEST_CHECK_UKDIGEST5 + * Carry out digest check on UKDIGEST5 in User Key segment (UPK2) + * + * DIGEST_CHECK_UKDIGEST6 + * Carry out digest check on UKDIGEST6 in User Key segment (UK2) + * + * DIGEST_CHECK_UPERM + * Carry out digest check on UFS Permanent lock (UPERM) segment + * + * DIGEST_CHECK_SYS + * Carry out digest check on Factory and Factory Key Segments + * + */ +#define DIGEST_CHECK_FABRIC (0x01<<0x00u) /*Fabric digest*/ +#define DIGEST_CHECK_CC (0x01<<0x01u) /*UFS Fabric Configuration (CC) segment*/ +#define DIGEST_CHECK_SNVM (0x01<<0x02u) /*ROM digest in SNVM segment*/ +#define DIGEST_CHECK_UL (0x01<<0x03u) /*UFS UL segment*/ +#define DIGEST_CHECK_UKDIGEST0 (0x01<<0x04u) /*UKDIGEST0 in User Key segment*/ +#define DIGEST_CHECK_UKDIGEST1 (0x01<<0x05u) /*UKDIGEST1 in User Key segment*/ +#define DIGEST_CHECK_UKDIGEST2 (0x01<<0x06u) /*UKDIGEST2 in User Key segment (UPK1)*/ +#define DIGEST_CHECK_UKDIGEST3 (0x01<<0x07u) /*UKDIGEST3 in User Key segment (UK1)*/ +#define DIGEST_CHECK_UKDIGEST4 (0x01<<0x08u) /*UKDIGEST4 in User Key segment (DPK)*/ +#define DIGEST_CHECK_UKDIGEST5 (0x01<<0x09u) /*UKDIGEST5 in User Key segment (UPK2)*/ +#define DIGEST_CHECK_UKDIGEST6 (0x01<<0x0au) /*UKDIGEST6 in User Key segment (UK2)*/ +#define DIGEST_CHECK_UPERM (0x01<<0x0bu) /*UFS Permanent lock (UPERM) segment*/ +#define DIGEST_CHECK_SYS (0x01<<0x0cu) /*Factory and Factory Key Segments.*/ + +/***************************************************************************//** + * The function SYS_init() is used to initialize the internal data structures of + * this driver. Currently this function is empty. + * + * @param base_addr The base_addr parameter specifies the base address of the + * PF_System_services core. + * + * @return This function does not return a value. + */ +void +SYS_init +( + uint32_t base_addr +); + +/***************************************************************************//** + * The function SYS_get_serial_number() is used to execute "serial number" system + * service. + * + * @param p_serial_number The p_serial_number parameter is a pointer to a buffer + * in which the data returned by system controller + * is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t +SYS_get_serial_number +( + const uint8_t * p_serial_number, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_get_user_code() is used to execute "USERCODE" system + * service. + * @param p_user_code The p_user_code parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t +SYS_get_user_code +( + const uint8_t * p_user_code, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_get_design_info() is used to execute "Get Design Info" system + * service. + * + * @param p_design_info The p_design_info parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. Total size of debug information is 36 bytes. + * The data from the system controller includes the 256-bit + * user-defined design ID, 16-bit design version, and 16-bit + * design back level. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t +SYS_get_design_info +( + const uint8_t * p_design_info, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_get_device_certificate() is used to execute "Get Device + * Certificate" system service. + * + * @param p_device_certificate The p_device_certificate parameter is a pointer + * to a buffer in which the data returned by the + * system controller is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code means that + * the service was executed successfully. + * + */ +uint8_t +SYS_get_device_certificate +( + const uint8_t * p_device_certificate, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_read_digest() is used to execute "Read Digest" system service. + * + * @param p_digest The p_digest parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t SYS_read_digest +( + const uint8_t * p_digest, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_query_security() is used to execute "Query Security" system + * service. + * + * @param p_security_locks The p_security_locks parameter is a pointer to a buffer + * in which the data returned by system controller is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code means that + * the service was executed successfully. + */ +uint8_t SYS_query_security +( + uint8_t * p_security_locks, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_read_debug_info() is used to execute "Read Debug info" system + * service. + * + * @param p_debug_info The p_debug_info parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t SYS_read_debug_info +( + const uint8_t * p_debug_info, + uint16_t mb_offset +); + +#ifdef CORESYSSERVICES_PFSOC +/***************************************************************************//** + * The function SYS_read_envm_parameter() is used to retrieve all parameters needed + * for the eNVM operation and programming. + * + * NOTE: This service is available only on PolarFire SoC Platform. + * This service is not yet supported by PF_SYSTEM_SERVICES 3.0.100. + * + * @param p_envm_param The p_envm_param parameter is a pointer to a buffer + * in which the data returned by system controller is copied. + * This buffer stores all the eNVM parameters. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_read_envm_parameter service will return zero if the + * service executed successfully, otherwise, it will return + * one indicating error. + */ +uint8_t SYS_read_envm_parameter +( + uint8_t * p_envm_param, + uint16_t mb_offset +); +#endif +/***************************************************************************//** + * The function SYS_puf_emulation_service() is used to authenticate a device. + * + * The SYS_puf_emulation_service() function accept a challenge comprising a + * 8-bit optype and 128-bit challenge and return a 256-bit response unique to + * the given challenge and the device. + * + * @param p_challenge The p_challenge parameter specifies the 128-bit challenge + * to generate the 256-bits unique response. + * + * @param op_type The op_type parameter specifies the operational parameter + * to generate the 256-bits unique response. + * + * @param p_response The p_response parameter is a pointer to a buffer where + * the data returned which is the response by system controller + * is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_puf_emulation_service function will return zero + * if the service executed successfully, otherwise, it will + * return one indicating error. + */ +uint8_t SYS_puf_emulation_service +( + const uint8_t * p_challenge, + uint8_t op_type, + uint8_t* p_response, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_digital_signature_service() function is used to generate P-384 ECDSA + * signature based on SHA384 hash value. + * + * @param p_hash The p_hash parameter is a pointer to the buffer which + * contain the 48 bytes SHA384 Hash value (input value). + * + * @param format The format parameter specifies the output format of + * generated SIGNATURE field. The different types of output + * signature formats are as follow: + * - DIGITAL_SIGNATURE_RAW_FORMAT + * - DIGITAL_SIGNATURE_DER_FORMAT + * + * @param p_response The p_response parameter is a pointer to a buffer that + * contains the generated ECDSA signature. The field may be + * 96 bytes or 104 bytes depending upon the output format. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digital_signature_service function returns + * zero if the service executed successfully, otherwise, it + * returns non-zero values indicating error. + */ +uint8_t SYS_digital_signature_service +( + const uint8_t* p_hash, + uint8_t format, + uint8_t* p_response, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_secure_nvm_write() function writes data in the sNVM region. + * Data gets stored in the following format: + * - Non-authenticated plaintext + * - Authenticated plaintext + * - Authenticated ciphertext + * + * Note: If you are executing this function with Authenticated plaintext + * or Authenticated ciphertext on a device whose sNVM was never previously + * written to, then the service may fail. For it to work, you must first write + * Authenticated data to the sNVM using Libero along with USK client and + * custom security. This flow generates the SMK. See UG0753 PolarFire FPGA + * Security User Guide for further details. + + * @param format The format parameter specifies the format used to write + * data in sNVM region. The different type of text formats + * are as follow: + * - NON_AUTHENTICATED_PLAINTEXT_FORMAT + * - AUTHENTICATED_PLAINTEXT_FORMAT + * - AUTHENTICATED_CIPHERTEXT_FORMAT + * + * @param snvm_module The snvm_module parameter specifies the the sNVM module + * in which the data need to be written. + * + * @param p_data The p_data parameter is a pointer to a buffer which + * contains the data to be stored in sNVM region. The data + * length to be written is fixed depending on the format + * parameter. If NON_AUTHENTICATED_PLAINTEXT_FORMAT is + * selected, then you can write 252 bytes in the sNVM module. + * For other two formats the data length is 236 bytes. + * + * @param p_user_key The p_user_key parameter is a pointer to a buffer which + * contain the 96-bit key USK (user secret key). This user + * secret key will enhance the security when authentication + * is used. That is, when Authenticated plaintext and + * Authenticated ciphertext format is selected. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digital_signature_service function returns + * zero if the service executed successfully, otherwise, it + * returns non-zero values indicating error. + */ +uint8_t SYS_secure_nvm_write +( + uint8_t format, + uint8_t snvm_module, + const uint8_t* p_data, + const uint8_t* p_user_key, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_secure_nvm_read() function is used to read data present in sNVM region. + * User should provide USK key, if the data was programmed using authentication. + * If the data was written in the sNVM using the authenticated plaintext or the + * authenticated ciphertext service option then this service will return the + * valid data only when authentication is successful. For more details, see + * SYS_secure_nvm_write() function. If the data was written in + * the sNVM using the authenticated plaintext or the authenticated ciphertext + * service option then this service will return the valid data only when + * authentication is successful. For more details, see SYS_secure_nvm_write() + * function and its parameter description. + * + * @param snvm_module The snvm_module parameter specifies the sNVM module + * from which the data need to be read. + * + * @param p_user_key The p_user_key parameter is a pointer to a buffer which + * contain the 96-bit key USK (user secret key). User should + * provide same secret key which is previously used for + * authentication while writing data in sNVM region. + * + * @param p_admin The p_admin parameter is a pointer to the buffer where + * the output page admin data is stored. The page admin + * data is 4 bytes long. + * + * @param p_data The p_data parameter is a pointer to a buffer which + * contains the data read from sNVM region. User should + * provide the buffer large enough to store the read data. + * + * @param data_len The data_len parameter specifies the number of bytes to be + * read from sNVM. + * The application should know whether the data written in the + * chose sNVM module was previously stored using Authentication + * or not. + * The data_len should be 236 bytes, for authenticated data. + * For not authenticated data the data_len should be 252 bytes. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digital_signature_service function returns + * zero if the service executed successfully, otherwise, it + * returns non-zero values indicating error. + */ +uint8_t SYS_secure_nvm_read +( + uint8_t snvm_module, + const uint8_t* p_user_key, + uint8_t* p_admin, + uint8_t* p_data, + uint16_t data_len, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_nonce_service() is used to issue "Nonce Service" system + * service to the system controller. + * + * @param p_nonce The p_nonce parameter is a pointer to a buffer + * in which the data returned by system controller is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code means + * that the service was executed successfully and a non-zero + * value indicates error. See the document link + * provided in the theory of operation section to know more + * about the service and service response. + */ +uint8_t SYS_nonce_service +( + const uint8_t * p_nonce, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_bitstream_authenticate_service() function is used to authenticate + * the Bitstream which is located in SPI through a system service routine. Prior + * to using the IAP service, it may be required to first validate the new + * bitstream before committing the device to reprogramming, thus avoiding the + * need to invoke recovery procedures if the bitstream is invalid. + * + * This service is applicable to bitstreams stored in SPI Flash memory only. + * + * @param spi_flash_address + * The spi_flash_address parameter specifies the address within + * SPI Flash memory where the bit-stream is stored. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_bitstream_authenticate_service function will return + * zero if the service executed successfully and the non-zero + * response from system controller indicates error. See + * the document link provided in the theory of + * operation section to know more about the service and service + * response. + */ +uint8_t SYS_bitstream_authenticate_service +( + uint32_t spi_flash_address, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_IAP_image_authenticate_service() function is used to authenticate + * the IAP image which is located in SPI through a system service routine. The + * service checks the image descriptor and the referenced bitstream and optional + * initialization data. If the image is authenticated successfully, then the + * image is guaranteed to be valid when used by an IAP function. + * + * This service is applicable to bitstreams stored in SPI Flash memory only. + * + * @param spi_idx + * The spi_idx parameter specifies the index in the SPI directory to + * be used where the IAP bit-stream is stored. + * Note: To support recovery SPI_IDX=1 should be an empty slot and the recovery + * image should be located in SPI_IDX=0. Since SPI_IDX=1 should be an + * empty slot, it shouldn’t be passed into the system service. + * + * @return The SYS_IAP_image_authenticate_service function will return + * zero if the service executed successfully the non-zero + * response from system controller indicates error. Please + * refer to the document link provided in the theory of + * operation section to know more about the service and service + * response. + */ +uint8_t SYS_IAP_image_authenticate_service +( + uint8_t spi_idx +); + +/***************************************************************************//** + * The SYS_digest_check_service() function is used to Recalculates and compares + * digests of selected non-volatile memories. If the fabric digest is to be + * checked, then the user design must follow all prerequisite steps for the + * FlashFreeze service before invoking this service. + * This service is applicable to bitstreams stored in SPI Flash memory only. + * @param options + * The options parameter specifies the digest check options which + * indicate the area on which the digest check should be performed. + * Below is the list of options. You can OR these options to indicate + * to perform digest check on multiple segments. + * Note: The options parameter is of 2 bytes when used with PF + * device and 4 bytes when used with PolarFire SoC device. + * Options[i] | Description + * ---------------|---------------------------------- + * 0x01 | Fabric digest + * 0x02 | Fabric Configuration (CC) segment + * 0x04 | ROM digest in SNVM segment + * 0x08 | UL segment + * 0x10 | UKDIGEST0 in User Key segment + * 0x20 | UKDIGEST1 in User Key segment + * 0x40 | UKDIGEST2 in User Key segment (UPK1) + * 0x80 | UKDIGEST3 in User Key segment (UK1) + * 0x100 | UKDIGEST4 in User Key segment (DPK) + * 0x200 | UKDIGEST5 in User Key segment (UPK2) + * 0x400 | UKDIGEST6 in User Key segment (UK2) + * 0x800 | UFS Permanent lock (UPERM) segment + * 0x1000 | Factory and Factory Key Segments. + * 0x2000 | UKDIGEST7 in User Key segment (HWM) (PFSoC) + * 0x4000 | ENVMDIGEST (PFSoC only) + * 0x8000 | UKDIGEST8 for MSS Boot Info (PFSoC only) + * 0x10000 | SNVM_RW_ACCESS_MAP Digest (PFSoC only) + * 0x20000 | SBIC revocation digest (PFSoC only) + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digest_check_service function will return + * zero if the service executed successfully the non-zero + * response from system controller indicates error. Pleaes + * refer to the document link provided in the theory of + * operation section to know more about the service and service + * response. + */ +uint8_t SYS_digest_check_service +( + uint32_t options, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_iap_service() function is used to IAP service. The IAP service allows + * the user to reprogram the device without the need for an external master. The + * user design writes the bitstream to be programmed into a SPI Flash connected + * to the SPI port. When the service is invoked, the System Controller + * automatically reads the bitstream from the SPI flash and programs the device. + * The service allows the image to be executed in either VERIFY or PROGRAM modes. + * Another option for IAP is to perform the auto-update sequence. In this case + * the newest image of the first two images in the SPI directory is chosen to be + * programmed. + * + * @param iap_cmd + * The iap_cmd parameter specifies the specific IAP command which + * depends upon VERIFY or PROGRAM modes and the SPI address method. + * iap_cmd | Description + * -----------------------|------------ + * IAP_PROGRAM_BY_SPIIDX_CMD | IAP program. + * IAP_VERIFY_BY_SPIIDX_CMD | Fabric Configuration (CC) segment + * IAP_PROGRAM_BY_SPIADDR_CMD | ROM digest in SNVM segment + * IAP_VERIFY_BY_SPIADDR_CMD | UL segment + * IAP_AUTOUPDATE_CMD | UKDIGEST0 in User Key segment + * + * @param spiaddr + * The spiaddr parameter specifies either the index + * in the SPI directory or the SPI address in the SPI Flash memory. + * Below is the list of the possible meaning of spiaddr parameter + * in accordance with the iap_cmd parameter. + * iap_cmd | spiaddr + * ----------------------|----------------- + * IAP_PROGRAM_BY_SPIIDX_CMD | Index in the SPI directory. + * IAP_VERIFY_BY_SPIIDX_CMD | Index in the SPI directory. + * IAP_PROGRAM_BY_SPIADDR_CMD | SPI address in the SPI Flash memory + * IAP_VERIFY_BY_SPIADDR_CMD | SPI address in the SPI Flash memory + * IAP_AUTOUPDATE_CMD | spiaddr is ignored as No index/address required for this command. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * Note: For the IAP services with command IAP_PROGRAM_BY_SPIIDX_CMD and + * IAP_VERIFY_BY_SPIIDX_CMD To support recovery SPI_IDX=1 should be an + * empty slot and the recovery image should be located in SPI_IDX=0. + * Since SPI_IDX=1 should be an empty slot it shouldn’t be passed into + * the system service. + * + * @return The SYS_iap_service function will return zero if the service + * executed successfully and the non-zero response from system + * controller indicates error. Please refer to the document + * link provided in the theory of operation section to know + * more about the service and service response. + */ +uint8_t SYS_iap_service +( + uint8_t iap_cmd, + uint32_t spiaddr, + uint16_t mb_offset +); + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_SYSSERV_PF_H */ diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h new file mode 100644 index 0000000..8b14b7e --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h @@ -0,0 +1,149 @@ +/******************************************************************************* + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Register bit offsets and masks definitions for CoreSysServices_PF driver. + */ + +#ifndef __CORE_SYSSERV_PF_REGISTERS +#define __CORE_SYSSERV_PF_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * SYS_SERV_CMD (offset 0x04) register details + */ +#define SS_CMD_REG_OFFSET 0x04u + +#define SS_CMD_OFFSET 0x04 +#define SS_CMD_MASK 0x0000FFFFu +#define SS_CMD_SHIFT 0u + +/*------------------------------------------------------------------------------ + * SYS_SERV_STAT (offset 0x08) register details + */ +#define SS_STAT_REG_OFFSET 0x08u + +#define SS_STAT_OFFSET 0x08 +#define SS_STAT_MASK 0x0000FFFFu +#define SS_STAT_SHIFT 0u + +/*------------------------------------------------------------------------------ + * SYS_SERV_REQ (offset 0x0C) register details + */ +#define SS_REQ_REG_OFFSET 0x0Cu + + +#define SS_REQ_REQ_OFFSET 0x0Cu +#define SS_REQ_REQ_MASK 0x00000001UL +#define SS_REQ_REQ_SHIFT 0u + +#define SS_REQ_ABUSY_OFFSET 0x0Cu +#define SS_REQ_ABUSY_MASK 0x00000002UL +#define SS_REQ_ABUSY_SHIFT 1u + +#define SS_REQ_NABUSY_OFFSET 0x0Cu +#define SS_REQ_NABUSY_MASK 0x00000004UL +#define SS_REQ_NABUSY_SHIFT 2u + +#define SS_REQ_SSBUSY_OFFSET 0x0Cu +#define SS_REQ_SSBUSY_MASK 0x00000008UL +#define SS_REQ_SSBUSY_SHIFT 3u + +#define SS_REQ_AREQ_OFFSET 0x0Cu +#define SS_REQ_AREQ_MASK 0x00000010UL +#define SS_REQ_AREQ_SHIFT 4u + +#define SS_REQ_NAREQ_OFFSET 0x0Cu +#define SS_REQ_NAREQ_MASK 0x00000020UL +#define SS_REQ_NAREQ_SHIFT 5u +/*------------------------------------------------------------------------------ + * MBX_ECCSTATUS (offset 0x10) register details + */ +#define MBX_ECCSTATUS_REG_OFFSET 0x10u + +#define MBX_ECCSTATUS_OFFSET 0x10 +#define MBX_ECCSTATUS_MASK 0x03u +#define MBX_ECCSTATUS_SHIFT 0u + + +/*------------------------------------------------------------------------------ + * MBX_WCNT (offset 0x14) register details + */ +#define MBX_WCNT_REG_OFFSET 0x14u + +#define MBX_WCNT_OFFSET 0x14 +#define MBX_WCNT_MASK 0x000001FFu +#define MBX_WCNT_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_RWCNT (offset 0x18) register details + */ +#define MBX_RCNT_REG_OFFSET 0x18u + +#define MBX_RCNT_OFFSET 0x18 +#define MBX_RCNT_MASK 0x000001FFu +#define MBX_RCNT_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_WADRDESC (offset 0x1C) register details + */ +#define MBX_WADDR_REG_OFFSET 0x1Cu + +#define MBX_WADDR_OFFSET 0x1C +#define MBX_WADDR_MASK 0x000001FFu +#define MBX_WADDR_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_RADRDESC (offset 0x20) register details + */ +#define MBX_RADDR_REG_OFFSET 0x20u + +#define MBX_RADDR_OFFSET 0x20 +#define MBX_RADDR_MASK 0x000001FFu +#define MBX_RADDR_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_WDATA (offset 0x28) register details + */ +#define MBX_WDATA_REG_OFFSET 0x28u + +#define MBX_WDATA_OFFSET 0x28 +#define MBX_WDATA_MASK 0xFFFFFFFFu +#define MBX_WDATA_SHIFT 0u + + +/*------------------------------------------------------------------------------ + * MBX_RDATA (offset 0x2C) register details + */ +#define MBX_RDATA_REG_OFFSET 0x2Cu + +#define MBX_RDATA_OFFSET 0x2C +#define MBX_RDATA_MASK 0xFFFFFFFFu +#define MBX_RDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * SS_USER (offset 0x30) register details + */ +#define SS_USER_REG_OFFSET 0x30u + +#define SS_USER_BUSY_OFFSET 0x30 +#define SS_USER_BUSY_MASK 0x00000001u +#define SS_USER_BUSY_SHIFT 0u + +#define SS_USER_RDVLD_OFFSET 0x30 +#define SS_USER_RDVLD_MASK 0x00000002u +#define SS_USER_RDVLD_SHIFT 1u + +#define SS_USER_CMDERR_OFFSET 0x30 +#define SS_USER_CMDERR_MASK 0x00000004u +#define SS_USER_CMDERR_SHIFT 2u + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_SYSSERV_PF_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c new file mode 100755 index 0000000..0c0a866 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c @@ -0,0 +1,297 @@ +/******************************************************************************* + * (c) Copyright 2007-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file core_uart_apb.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreUARTapb driver implementation. See file "core_uart_apb.h" for + * description of the functions implemented in this file. + * + */ + +#include "coreuartapb_regs.h" +#include "core_uart_apb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define NULL_INSTANCE ( ( UART_instance_t* ) 0 ) +#define NULL_BUFFER ( ( uint8_t* ) 0 ) + +#define MAX_LINE_CONFIG ( ( uint8_t )( DATA_8_BITS | ODD_PARITY ) ) +#define MAX_BAUD_VALUE ( ( uint16_t )( 0x1FFF ) ) +#define STATUS_ERROR_MASK ( ( uint8_t )( STATUS_PARITYERR_MASK | \ + STATUS_OVERFLOW_MASK | \ + STATUS_FRAMERR_MASK ) ) +#define BAUDVALUE_LSB ( (uint16_t) (0x00FF) ) +#define BAUDVALUE_MSB ( (uint16_t) (0xFF00) ) +#define BAUDVALUE_SHIFT ( (uint8_t) (5) ) + +#define STATUS_ERROR_OFFSET STATUS_PARITYERR_SHIFT + +/***************************************************************************//** + * UART_init() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_init +( + UART_instance_t * this_uart, + addr_t base_addr, + uint16_t baud_value, + uint8_t line_config +) +{ + uint8_t rx_full; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( line_config <= MAX_LINE_CONFIG ) + HAL_ASSERT( baud_value <= MAX_BAUD_VALUE ) + + if( ( this_uart != NULL_INSTANCE ) && + ( line_config <= MAX_LINE_CONFIG ) && + ( baud_value <= MAX_BAUD_VALUE ) ) + { + /* + * Store lower 8-bits of baud value in CTRL1. + */ + HAL_set_8bit_reg( base_addr, CTRL1, (uint_fast8_t)(baud_value & + BAUDVALUE_LSB ) ); + + /* + * Extract higher 5-bits of baud value and store in higher 5-bits + * of CTRL2, along with line configuration in lower 3 three bits. + */ + HAL_set_8bit_reg( base_addr, CTRL2, (uint_fast8_t)line_config | + (uint_fast8_t)((baud_value & + BAUDVALUE_MSB) >> BAUDVALUE_SHIFT ) ); + + this_uart->base_address = base_addr; +#ifndef NDEBUG + { + uint8_t config; + uint8_t temp; + uint16_t baud_val; + baud_val = HAL_get_8bit_reg( this_uart->base_address, CTRL1 ); + config = HAL_get_8bit_reg( this_uart->base_address, CTRL2 ); + /* + * To resolve operator precedence between & and << + */ + temp = ( config & (uint8_t)(CTRL2_BAUDVALUE_MASK ) ); + baud_val |= (uint16_t)( (uint16_t)(temp) << BAUDVALUE_SHIFT ); + config &= (uint8_t)(~CTRL2_BAUDVALUE_MASK); + HAL_ASSERT( baud_val == baud_value ); + HAL_ASSERT( config == line_config ); + } +#endif + + /* + * Flush the receive FIFO of data that may have been received before the + * driver was initialized. + */ + rx_full = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_RXFULL_MASK; + while ( rx_full ) + { + HAL_get_8bit_reg( this_uart->base_address, RXDATA ); + rx_full = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_RXFULL_MASK; + } + + /* + * Clear status of the UART instance. + */ + this_uart->status = (uint8_t)0; + } +} + +/***************************************************************************//** + * UART_send() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_send +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +) +{ + size_t char_idx; + uint8_t tx_ready; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( tx_buffer != NULL_BUFFER ) + HAL_ASSERT( tx_size > 0 ) + + if( (this_uart != NULL_INSTANCE) && + (tx_buffer != NULL_BUFFER) && + (tx_size > (size_t)0) ) + { + for ( char_idx = (size_t)0; char_idx < tx_size; char_idx++ ) + { + /* Wait for UART to become ready to transmit. */ + do { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( !tx_ready ); + /* Send next character in the buffer. */ + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)tx_buffer[char_idx] ); + } + } +} + +/***************************************************************************//** + * UART_fill_tx_fifo() + * See "core_uart_apb.h" for details of how to use this function. + */ +size_t +UART_fill_tx_fifo +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +) +{ + uint8_t tx_ready; + size_t size_sent = 0u; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( tx_buffer != NULL_BUFFER ) + HAL_ASSERT( tx_size > 0 ) + + /* Fill the UART's Tx FIFO until the FIFO is full or the complete input + * buffer has been written. */ + if( (this_uart != NULL_INSTANCE) && + (tx_buffer != NULL_BUFFER) && + (tx_size > 0u) ) + { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + if ( tx_ready ) + { + do { + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)tx_buffer[size_sent] ); + size_sent++; + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( (tx_ready) && ( size_sent < tx_size ) ); + } + } + return size_sent; +} + +/***************************************************************************//** + * UART_get_rx() + * See "core_uart_apb.h" for details of how to use this function. + */ +size_t +UART_get_rx +( + UART_instance_t * this_uart, + uint8_t * rx_buffer, + size_t buff_size +) +{ + uint8_t new_status; + uint8_t rx_full; + size_t rx_idx = 0u; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( rx_buffer != NULL_BUFFER ) + HAL_ASSERT( buff_size > 0 ) + + if( (this_uart != NULL_INSTANCE) && + (rx_buffer != NULL_BUFFER) && + (buff_size > 0u) ) + { + rx_idx = 0u; + new_status = HAL_get_8bit_reg( this_uart->base_address, STATUS ); + this_uart->status |= new_status; + rx_full = new_status & STATUS_RXFULL_MASK; + while ( ( rx_full ) && ( rx_idx < buff_size ) ) + { + rx_buffer[rx_idx] = HAL_get_8bit_reg( this_uart->base_address, + RXDATA ); + rx_idx++; + new_status = HAL_get_8bit_reg( this_uart->base_address, STATUS ); + this_uart->status |= new_status; + rx_full = new_status & STATUS_RXFULL_MASK; + } + } + return rx_idx; +} + +/***************************************************************************//** + * UART_polled_tx_string() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_polled_tx_string +( + UART_instance_t * this_uart, + const uint8_t * p_sz_string +) +{ + uint32_t char_idx; + uint8_t tx_ready; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( p_sz_string != NULL_BUFFER ) + + if( ( this_uart != NULL_INSTANCE ) && ( p_sz_string != NULL_BUFFER ) ) + { + char_idx = 0U; + while( 0U != p_sz_string[char_idx] ) + { + /* Wait for UART to become ready to transmit. */ + do { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( !tx_ready ); + /* Send next character in the buffer. */ + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)p_sz_string[char_idx] ); + char_idx++; + } + } +} + +/***************************************************************************//** + * UART_get_rx_status() + * See "core_uart_apb.h" for details of how to use this function. + */ +uint8_t +UART_get_rx_status +( + UART_instance_t * this_uart +) +{ + uint8_t status = UART_APB_INVALID_PARAM; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + /* + * Extract UART error status and place in lower bits of "status". + * Bit 0 - Parity error status + * Bit 1 - Overflow error status + * Bit 2 - Frame error status + */ + if( this_uart != NULL_INSTANCE ) + { + status = ( ( this_uart->status & STATUS_ERROR_MASK ) >> + STATUS_ERROR_OFFSET ); + /* + * Clear the sticky status for this instance. + */ + this_uart->status = (uint8_t)0; + } + return status; +} + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h new file mode 100755 index 0000000..c016403 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h @@ -0,0 +1,451 @@ +/******************************************************************************* + * (c) Copyright 2007-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file core_uart_apb.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief This file contains the application programming interface for the + * CoreUARTapb bare metal driver. + * + */ +/*=========================================================================*//** + @mainpage CoreUARTapb Bare Metal Driver. + + @section intro_sec Introduction + CoreUARTapb is an implementation of the Universal Asynchronous + Receiver/Transmitter aimed at minimal FPGA tile usage within a Microchip FPGA. + The CoreUARTapb bare metal software driver is designed to be used in systems + with no operating system. + + The CoreUARTapb driver provides functions for basic polled transmitting and + receiving operations. It also provide functions that allow the use of the + CoreUARTapb in interrupt-driven mode but leaves the management of interrupts + to the calling application, as interrupt enabling and disabling are not + controlled through the CoreUARTapb registers. The CoreUARTapb driver is + provided as C source code. + + @section driver_configuration Driver Configuration + Your application software should configure the CoreUARTapb driver by calling + the UART_init() function for each CoreUARTapb instance in the hardware design. + The configuration parameters include the CoreUARTapb hardware instance base + address and other runtime parameters, such as baud rate, bit width, and + parity. No CoreUARTapb hardware configuration parameters are needed by the + driver, apart from the CoreUARTapb hardware instance base address. Hence, no + additional configuration files are required to use the driver. + + A CoreUARTapb hardware instance is generated with fixed baud rate, character + size, and parity configuration settings as part of the hardware flow. The + baud_value and line_config parameter values passed to the UART_init() function + have no effect if fixed values were selected for the baud rate, character + size, and parity in the hardware configuration of CoreUARTapb. When fixed + values are selected for these hardware configuration parameters, the driver is + unable to overwrite the fixed values in the CoreUARTapb control registers, + CTRL1 and CTRL2. + + @section theory_op Theory of Operation + The CoreUARTapb software driver is designed to allow the control of multiple + instances of CoreUARTapb. Each instance of CoreUARTapb in the hardware design + is associated with a single instance of the UART_instance_t structure in the + software. You need to allocate memory for one unique UART_instance_t structure + instance for each CoreUARTapb hardware instance. The contents of these data + structures are initialized while calling the UART_init() function. A pointer + to the structure is passed to the subsequent driver functions in order to + identify the CoreUARTapb hardware instance you wish to perform the requested + operation on. + + Note: Do not attempt to directly manipulate the content of UART_instance_t + structures. This structure is only intended to be modified by the driver + function. + + Once initialized, the driver transmits and receives data. Transmit is + performed using the UART_send() function. If this function blocks, then it + returns only when the data passed to it has been sent to the CoreUARTapb + hardware. Data received by the CoreUARTapb hardware is read by the user + application using the UART_get_rx() function. + + The UART_fill_tx_fifo() function is also provided as a part of the + interrupt-driven transmit. This function fills the CoreUARTapb hardware + transmit FIFO with the content of a data buffer passed as a parameter before + returning. The control of the interrupts must be implemented outside the + driver, as the CoreUARTapb hardware does not provide the ability to enable + or disable its interrupt sources. + + The UART_polled_tx_string() function is provided to transmit a NULL-terminated + string in polled mode. If this function blocks, then it returns only when the + data passed to it has been sent to the CoreUARTapb hardware. + + The UART_get_rx_status() function returns the error status of the CoreUARTapb + receiver. This is used by applications to take appropriate action in case of + receiver errors. +*//*=========================================================================*/ +#ifndef __CORE_UART_APB_H +#define __CORE_UART_APB_H 1 + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + Data Bits Length Defines + ======================== + These constants define the data length in a UART packet. + | Constant | Description | + |-------------|---------------------------------------| + | DATA_7_BITS | Data length is 7-bits | + | DATA_8_BITS | Data length is 8-bits | + */ +#define DATA_7_BITS 0x00u +#define DATA_8_BITS 0x01u + +/***************************************************************************//** + Parity Defines + ============== + These constants define parity check options. + | Constant | Description | + |-------------|---------------------------------------| + | NO_PARITY | No Parity bit | + | EVEN_PARITY | Even Parity bit | + | ODD_PARITY | ODD Parity bit | + */ +#define NO_PARITY 0x00u +#define EVEN_PARITY 0x02u +#define ODD_PARITY 0x06u + +/***************************************************************************//** + Error Status Definitions + ======================== + These constants define the different types of possible errors in UART + transmission of data. + | Constant | Description | + |-------------------------|---------------------------------------| + | UART_APB_PARITY_ERROR | Data parity error | + | UART_APB_OVERFLOW_ERROR | Data overflow error | + | UART_APB_FRAMING_ERROR | Data framing error | + | UART_APB_NO_ERROR | No error | + | UART_APB_INVALID_PARAM | Invalid parameter | + */ +#define UART_APB_PARITY_ERROR 0x01u +#define UART_APB_OVERFLOW_ERROR 0x02u +#define UART_APB_FRAMING_ERROR 0x04u +#define UART_APB_NO_ERROR 0x00u +#define UART_APB_INVALID_PARAM 0xFFu + +/***************************************************************************//** + * There should be one instance of this structure for each instance of + * CoreUARTapb in your system. This structure instance identifies various UARTs + * in a system and should be passed as first parameter to UART functions to + * identify which UART performs the requested operation. The 'status' element in + * the structure is used to provide sticky status information. + */ +typedef struct +{ + addr_t base_address; + uint8_t status; +} UART_instance_t; + +/***************************************************************************//** + * The UART_init() function initializes the UART with the configuration passed + * as parameters. The configuration parameters are the baud_value that generates + * the baud rate and the line configuration (bit length and parity). + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data regarding + * this instance of the CoreUARTapb. This pointer is used to + * identify the target CoreUARTapb hardware instance in + * subsequent calls to the CoreUARTapb functions. + * @param base_addr The base_address parameter is the base address in the + * processor's memory map for the registers of the + * CoreUARTapb instance being initialized. + * @param baud_value The baud_value parameter selects the baud rate for the + * UART. The baud value is calculated from the frequency of + * the system clock in hertz and the desired baud rate using + * the following equation: + * baud_value = (clock / (baud_rate * 16)) - 1. + * The baud_value parameter must be a value in the range 0 + * to 8191 (or 0x0000 to 0x1FFF). + * @param line_config This parameter is the line configuration, specifies the + * bit length and parity settings. This is the logical OR of: + * - DATA_7_BITS + * - DATA_8_BITS + * - NO_PARITY + * - EVEN_PARITY + * - ODD_PARITY + * For example, 8 bits even parity would be specified as + * (DATA_8_BITS | EVEN_PARITY). + * @return This function does not return a value. + * @example + * @code + * #define BAUD_VALUE_57600 25 + * + * #define COREUARTAPB0_BASE_ADDR 0xC3000000UL + * + * UART_instance_t g_uart; + * int main() + * { + * UART_init(&g_uart, COREUARTAPB0_BASE_ADDR, + BAUD_VALUE_57600, (DATA_8_BITS | EVEN_PARITY)); + * } + * @endcode + */ +void +UART_init +( + UART_instance_t * this_uart, + addr_t base_addr, + uint16_t baud_value, + uint8_t line_config +); + +/***************************************************************************//** + * The UART_send() function is used to transmit data. It transfers the content + * of the transmitter data buffer, passed as a function parameter, into the + * UART's hardware transmitter FIFO. It returns when the full content of the + * transmitter data buffer has been transferred to the UART's transmitter FIFO. + * + * Note: You should not assume that the data you are sending using this function + * has been received at the other end by the time this function returns. The + * actual transmission over the serial connection is still be taking place at + * the time of the function return. It is safe to release or reuse the memory + * used as the transmit buffer once this function returns. + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data + * regarding this instance of the CoreUARTapbUART. + * @param tx_buffer The tx_buffer parameter is a pointer to a buffer that + * contains the data to be transmitted. + * @param tx_size The tx_size parameter is the size in bytes of the + * transmitted data. + * + * @return This function does not return a value. + * + * @example + * @code + * uint8_t testmsg1[] = {"\n\r\n\r\n\rUART_send() test message 1"}; + * UART_send(&g_uart,(const uint8_t *)&testmsg1,sizeof(testmsg1)); + * @endcode + */ +void +UART_send +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +); + +/***************************************************************************//** + * The UART_fill_tx_fifo() function fills the UART's transmitter hardware FIFO + * with the data found in the transmitter buffer that is passed in as a + * function parameter. The function returns either when the FIFO is full or + * when the complete contents of the transmitter buffer have been copied into + * the FIFO. It returns the number of bytes copied into the UART's transmitter + * hardware FIFO. This function is intended to be used as part of + * interrupt-driven transmission. + * + * Note: You should not assume that the data you transmit using this function + * has been received at the other end by the time this function returns. The + * actual transmission over the serial connection is still be taking place at + * the time of the function return. + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data + * regarding this instance of the UART. + * @param tx_buffer The tx_buffer parameter is a pointer to a buffer that + * contains the data to be transmitted. + * @param tx_size The tx_size parameter is the size in bytes of the + * transmitted data. + * @return This function returns the number of bytes copied into + * the UART's transmitter hardware FIFO. + * + * @example + * @code + * void send_using_interrupt + * ( + * uint8_t * pbuff, + * size_t tx_size + * ) + * { + * size_t size_in_fifo; + * size_in_fifo = UART_fill_tx_fifo( &g_uart, pbuff, tx_size ); + * } + * @endcode + */ +size_t +UART_fill_tx_fifo +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +); + +/***************************************************************************//** + * The UART_get_rx() function reads the content of the UART's receiver hardware + * FIFO and stores it in the receiver buffer that is passed in as a function + * parameter. It copies either the full contents of the FIFO into the receiver + * buffer, or just enough data from the FIFO to fill the receiver buffer, + * depending on the size of the receiver buffer. The size of the receiver + * buffer is passed in as a function parameter. UART_get_rx() returns the number + * of bytes copied into the receiver buffer. If no data was received at the time + * the function is called, the function returns 0. + * + * Note: This function reads and accumulates the receiver status of the + * CoreUARTapb instance before reading each byte from the receiver's + * data register/FIFO. This allows the driver to maintain a sticky + * record of any receiver errors that occur as the UART receives each + * data byte; receiver errors would otherwise be lost after each read + * from the receiver's data register. A call to the UART_get_rx_status() + * function returns any receiver errors accumulated during the execution + * of the UART_get_rx() function. + * + * Note: When FIFO mode is disabled in the CoreUARTapb hardware configuration, + * the driver accumulates a sticky record of any parity errors, framing + * errors, or overflow errors. When FIFO mode is enabled, the driver + * accumulates a sticky record of overflow errors only; in this case, + * interrupts must be used to handle parity errors or framing errors. + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data + * regarding this instance of the UART. + * @param rx_buffer The rx_buffer parameter is a pointer to a buffer where + * the received data is copied. + * @param buff_size The buff_size parameter is the size of the receive + * buffer in bytes. + * @return This function returns the number of bytes copied into + * the receive buffer. + * + * @example + * @code + * #define MAX_RX_DATA_SIZE 256 + * + * uint8_t rx_data[MAX_RX_DATA_SIZE]; + * uint8_t rx_size = 0; + * + * rx_size = UART_get_rx( &g_uart, rx_data, sizeof(rx_data) ); + * @endcode + */ +size_t +UART_get_rx +( + UART_instance_t * this_uart, + uint8_t * rx_buffer, + size_t buff_size +); + +/***************************************************************************//** + * The UART_polled_tx_string() function is used to transmit a NULL ('\0') + * terminated string. Internally, it polls for the transmit ready status and + * transfers the text starting at the address pointed by p_sz_string into + * the UART's hardware transmitter FIFO. It is a blocking function and returns + * only when the complete string has been transferred to the UART's transmit + * FIFO. + * + * Note: You should not assume that the data you transmit using this function + * has been received at the other end by the time this function returns. The + * actual transmission over the serial connection is still be taking place at + * the time of the function return. + * + * @param this_uart The this_uart parameter is the pointer to a + * UART_instance_t structure, which holds all data + * regarding this instance of the UART. + * @param p_sz_string The p_sz_string parameter is a pointer to a buffer + * containing the NULL ('\0') terminated string to be + * transmitted. + * @return This function does not return a value. + * + * @example + * @code + * uint8_t testmsg1[] = {"\r\n\r\nUART_polled_tx_string() test message 1\0"}; + * UART_polled_tx_string(&g_uart,(const uint8_t *)&testmsg1); + * @endcode + */ +void +UART_polled_tx_string +( + UART_instance_t * this_uart, + const uint8_t * p_sz_string +); + +/***************************************************************************//** + * The UART_get_rx_status() function returns the receiver error status of the + * CoreUARTapb instance. It reads both the current error status of the receiver + * and the accumulated error status from preceding calls to the UART_get_rx() + * function and combines them using a bitwise OR. It returns the cumulative + * parity, framing, and overflow error status of the receiver, since the + * previous call to UART_get_rx_status() as an 8-bit encoded value. + * + * Note: The UART_get_rx() function reads and accumulates the receiver status + * of the CoreUARTapb instance before reading each byte from the receiver's data + * register/FIFO. The driver maintains a sticky record of the cumulative error + * status, which persists after the UART_get_rx() function returns. The + * UART_get_rx_status() function clears this accumulated record of receiver + * errors before returning. + * + * @param this_uart The this_uart parameter is a pointer to a + * UART_instance_t structure which holds all data regarding + * this instance of the UART. + * @return This function returns the UART receiver error status as + * an 8-bit encoded value. The return value is 0, if there + * are no receiver errors occurred. The driver provides a + * set of bit mask constants, which should be compared with + * and/or used to mask the returned value to determine the + * receiver error status. + * When the return value is compared to the following bit + * masks, a non-zero result indicates that the + * corresponding error occurred: + * UART_APB_PARITY_ERROR (bit mask = 0x01) + * UART_APB_OVERFLOW_ERROR (bit mask = 0x02) + * UART_APB_FRAMING_ERROR (bit mask = 0x04) + * When the return value is compared to the following bit + * mask, a non-zero result indicates that no error + * occurred: + * UART_APB_NO_ERROR (0x00) + * + * @example + * @code + * UART_instance_t g_uart; + * uint8_t rx_data[MAX_RX_DATA_SIZE]; + * uint8_t err_status; + * err_status = UART_get_err_status(&g_uart); + * + * if(UART_APB_NO_ERROR == err_status ) + * { + * rx_size = UART_get_rx( &g_uart, rx_data, MAX_RX_DATA_SIZE ); + * } + * @endcode + */ +uint8_t +UART_get_rx_status +( + UART_instance_t * this_uart +); + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_UART_APB_H */ diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h new file mode 100755 index 0000000..c123cc3 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h @@ -0,0 +1,133 @@ +/******************************************************************************* + * (c) Copyright 2007-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file coreuartapb_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreUARTapb register definitions + */ + +#ifndef __CORE_UART_APB_REGISTERS +#define __CORE_UART_APB_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * TxData register details + */ +#define TXDATA_REG_OFFSET 0x0u + +/* + * TxData bits. + */ +#define TXDATA_OFFSET 0x0u +#define TXDATA_MASK 0xFFu +#define TXDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * RxData register details + */ +#define RXDATA_REG_OFFSET 0x4u + +/* + * RxData bits. + */ +#define RXDATA_OFFSET 0x4u +#define RXDATA_MASK 0xFFu +#define RXDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * ControReg1 register details + */ +#define CTRL1_REG_OFFSET 0x8u + +/* + * Baud value (Lower 8-bits) + */ +#define CTRL1_BAUDVALUE_OFFSET 0x8u +#define CTRL1_BAUDVALUE_MASK 0xFFu +#define CTRL1_BAUDVALUE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * ControReg2 register details + */ +#define CTRL2_REG_OFFSET 0xCu + +/* + * Bit length + */ +#define CTRL2_BIT_LENGTH_OFFSET 0xCu +#define CTRL2_BIT_LENGTH_MASK 0x01u +#define CTRL2_BIT_LENGTH_SHIFT 0u + +/* + * Parity enable. + */ +#define CTRL2_PARITY_EN_OFFSET 0xCu +#define CTRL2_PARITY_EN_MASK 0x02u +#define CTRL2_PARITY_EN_SHIFT 1u + +/* + * Odd/even parity selection. + */ +#define CTRL2_ODD_EVEN_OFFSET 0xCu +#define CTRL2_ODD_EVEN_MASK 0x04u +#define CTRL2_ODD_EVEN_SHIFT 2u + +/* + * Baud value (Higher 5-bits) + */ +#define CTRL2_BAUDVALUE_OFFSET 0xCu +#define CTRL2_BAUDVALUE_MASK 0xF8u +#define CTRL2_BAUDVALUE_SHIFT 3u + +/*------------------------------------------------------------------------------ + * StatusReg register details + */ +#define StatusReg_REG_OFFSET 0x10u + +#define STATUS_REG_OFFSET 0x10u + +/* + * Transmit ready. + */ +#define STATUS_TXRDY_OFFSET 0x10u +#define STATUS_TXRDY_MASK 0x01u +#define STATUS_TXRDY_SHIFT 0u + +/* + * Receive full. + */ +#define STATUS_RXFULL_OFFSET 0x10u +#define STATUS_RXFULL_MASK 0x02u +#define STATUS_RXFULL_SHIFT 1u + +/* + * Parity error. + */ +#define STATUS_PARITYERR_OFFSET 0x10u +#define STATUS_PARITYERR_MASK 0x04u +#define STATUS_PARITYERR_SHIFT 2u + +/* + * Overflow. + */ +#define STATUS_OVERFLOW_OFFSET 0x10u +#define STATUS_OVERFLOW_MASK 0x08u +#define STATUS_OVERFLOW_SHIFT 3u + +/* + * Frame Error. + */ +#define STATUS_FRAMERR_OFFSET 0x10u +#define STATUS_FRAMERR_MASK 0x10u +#define STATUS_FRAMERR_SHIFT 4u + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_UART_APB_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.c b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.c new file mode 100644 index 0000000..a2f4911 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.c @@ -0,0 +1,765 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Mi-V I2C Soft IP bare-metal driver. This module is delivered as part of + * Extended Sub System(ESS) MIV_ESS. + * Please refer to miv_i2c.h file for more information. + */ + +#include "miv_i2c.h" + +#define MIV_I2C_ERROR 0xFFu + +/*------------------------------------------------------------------------------ + * MIV I2C transaction direction. + */ +#define MIV_I2C_WRITE_DIR 0u +#define MIV_I2C_READ_DIR 1u + +/* -- TRANSACTIONS TYPES -- */ +#define MIV_I2C_NO_TRANSACTION 0u +#define MIV_I2C_MASTER_WRITE_TRANSACTION 1u +#define MIV_I2C_MASTER_READ_TRANSACTION 2u +#define MIV_I2C_MASTER_SEQUENTIAL_READ_TRANSACTION 3u + +/*------------------------------------------------------------------------------ + * MIV I2C HW states + */ +#define MIV_I2C_IDLE 0x00u +#define MIV_I2C_TX_STA_CB 0x01u +#define MIV_I2C_TX_DATA 0x02u +#define MIV_I2C_RX_DATA 0x03u + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_disable_irq() disables the Mi-V I2C interrupt. + */ +void +MIV_I2C_disable_irq +( + void +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_enable_irq() enables the Mi-V I2C interrupt. + */ +void +MIV_I2C_enable_irq +( + void +); + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_init +( + miv_i2c_instance_t *this_i2c, + addr_t base_addr +) +{ + /* Assign the base address + * Clock Prescale value set + * MIV_I2C interrupt enabled + * I2C core enable + */ + psr_t processor_state; + + /* Disabling the interrupts */ + processor_state = HAL_disable_interrupts(); + + /* + * Initialize all items of the this_miv_i2c data structure to zero. This + * initializes all state variables to their init value. It relies on + * the fact that NO_TRANSACTION, MIV_I2C_SUCCESS and I2C_RELEASE_BUS all + * have an actual value of zero. + */ + memset(this_i2c, 0, sizeof(miv_i2c_instance_t)); + + this_i2c->base_addr = base_addr; + + HAL_restore_interrupts(processor_state); +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_config +( + miv_i2c_instance_t *this_i2c, + uint16_t clk_prescale +) +{ + /* Assign the base address + * Clock Prescale value set + * MIV_I2C interrupt enabled + * I2C core enable + */ + psr_t processor_state; + + /* Disabling the interrupts */ + processor_state = HAL_disable_interrupts(); + + /* Before writing to prescale reg, the core enable must be zero */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CTRL_CORE_EN, 0x00u); + + /* Set the prescale value */ + HAL_set_16bit_reg(this_i2c->base_addr, PRESCALE, clk_prescale); + + /* Enable the MIV I2C interrupts */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CTRL_IRQ_EN, 0x01u); + + /* Enable the MIV I2C core */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CTRL_CORE_EN, 0x01u); + + this_i2c->master_state = MIV_I2C_IDLE; + + HAL_restore_interrupts(processor_state); +} + +/* + * Please refer to miv_i2c.h for more info + */ +uint8_t +MIV_I2C_start +( + miv_i2c_instance_t *this_i2c +) +{ + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + /* Generate I2C start condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + HAL_restore_interrupts(processor_state); + + return 0u; +} + +/* + * Please refer to miv_i2c.h for more info + */ +uint8_t +MIV_I2C_stop +( + miv_i2c_instance_t *this_i2c +) +{ + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + /* Generate I2C stop condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + HAL_restore_interrupts(processor_state); + + return 0u; +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_write +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t bus_options, + uint8_t ack_polling_options +) +{ + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + /* I2C write flow + * + * Check I2C status for ongoing transaction + * Populate the structure with input data + * Generate start condition + * Set the write_direction and target address. + */ + + /* Update the transaction only when there is no ongoing I2C transaction */ + if (this_i2c->transaction == MIV_I2C_NO_TRANSACTION) + { + this_i2c->transaction = MIV_I2C_MASTER_WRITE_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MIV_I2C_MASTER_WRITE_TRANSACTION ; + + /* Populate the i2c instance structure */ + + /* Set the target addr */ + this_i2c->target_addr = i2c_target_addr; + this_i2c->dir = MIV_I2C_WRITE_DIR; + + /* Set up the tx buffer */ + this_i2c->master_tx_buffer = write_buffer; + this_i2c->master_tx_size = write_size; + this_i2c->master_tx_idx = 0u; + + /* Set the I2C status in progress and setup the options */ + this_i2c->bus_options = bus_options; + this_i2c->ack_polling_options = ack_polling_options; + this_i2c->master_status = MIV_I2C_IN_PROGRESS; + + + /* Generate I2C start condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* write target address and write bit */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, MIV_I2C_WRITE_DIR); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, i2c_target_addr); + + /* Set WR bit to transmit start condition and control byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + /* Set current master hw state -> transmitted start condition and + * control byte + */ + this_i2c->master_state = MIV_I2C_TX_STA_CB; + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( MIV_I2C_HOLD_BUS == this_i2c->bus_status ) + { + /* Must toggle IACK bit to clear the MIV_I2C IRQ*/ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00); + } + + MIV_I2C_enable_irq(); + + HAL_restore_interrupts(processor_state); + +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_read +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +) +{ + psr_t processor_state; + uint8_t status = MIV_I2C_SUCCESS; + + processor_state = HAL_disable_interrupts(); + + /* MIV I2C Read operation flow + * + * Check for ongoing transaction + * Populate the i2c instance structure + * Generate the start condition + * Set the READ_direction bit and target addr + */ + + uint8_t read_stat = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_TIP); + + /* Update the transaction only when there is no ongoing I2C transaction */ + if (this_i2c->transaction == MIV_I2C_NO_TRANSACTION) + { + this_i2c->transaction = MIV_I2C_MASTER_READ_TRANSACTION; + } + + this_i2c->pending_transaction = MIV_I2C_MASTER_READ_TRANSACTION; + + /* Populate the MIV I2C instance structure */ + + this_i2c->target_addr = i2c_target_addr; + this_i2c->dir = MIV_I2C_READ_DIR; + + /* Populate read buffer */ + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set the BUS and ACK polling options */ + this_i2c->bus_options = bus_options; + this_i2c->ack_polling_options = ack_polling_options; + + /* Generate the start condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* Set the DIR bit and target addr */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, MIV_I2C_READ_DIR); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, i2c_target_addr); + + /* Set the WR bit to transmit the start condition and command byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + /* Set the i2c master state and status transmitting STA and Command Byte */ + this_i2c->master_state = MIV_I2C_TX_STA_CB; + this_i2c->master_status = MIV_I2C_IN_PROGRESS; + + /* Toggle the IACK bit if required */ + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( MIV_I2C_HOLD_BUS == this_i2c->bus_status ) + { + /* Must toggle IACK bit to clear the MIV_I2C IRQ*/ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00); + } + /* Enable the I2C interrupt */ + MIV_I2C_enable_irq(); + + HAL_restore_interrupts(processor_state); +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_write_read +( + miv_i2c_instance_t *this_i2c, + uint8_t target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +) +{ + uint8_t status = MIV_I2C_SUCCESS; + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + uint8_t read_stat = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_TIP); + + /* I2C write read operation flow + * + * Used to read the data from set address offset + * + * Configure the i2c instance structure + * generate the start and configure the dir and target addr + * set wr bit to transmit the start and command byte + * + */ + + /* Update the transaction only when there is no ongoing I2C transaction */ + if (this_i2c->transaction == MIV_I2C_NO_TRANSACTION) + { + this_i2c->transaction = MIV_I2C_MASTER_READ_TRANSACTION; + } + + this_i2c->pending_transaction = MIV_I2C_MASTER_READ_TRANSACTION; + + /* Populate the I2C instance */ + + this_i2c->target_addr = target_addr; + + /* setup the i2c direction */ + this_i2c->dir = MIV_I2C_WRITE_DIR; + + /* set up transmit buffer */ + this_i2c->master_tx_buffer = write_buffer; + this_i2c->master_tx_size = write_size; + this_i2c->master_tx_idx = 0u; + + /* set up receive buffer */ + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set the bus and ack polling options */ + this_i2c->bus_options = bus_options; + this_i2c->ack_polling_options = ack_polling_options; + + /* Generate the start command */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* Set the DIR and target addr */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + /* Set the WR bit to transmit the start command and command byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + /* Set the i2c master state and status transmitting STA and Command Byte */ + this_i2c->master_state = MIV_I2C_TX_STA_CB; + this_i2c->master_status = MIV_I2C_IN_PROGRESS; + + /* + * Clear interrupt if required + */ + if ( MIV_I2C_HOLD_BUS == this_i2c->bus_status ) + { + /* Must toggle IACK bit to clear the MIV_I2C IRQ*/ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00u); + } + + /* Enable the I2C interrupt */ + MIV_I2C_enable_irq(); + + HAL_restore_interrupts(processor_state); +} + +/* MIV_I2C_isr() + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_isr +( + miv_i2c_instance_t *this_i2c +) +{ + uint8_t i2c_state; + uint8_t i2c_ack_status; + uint8_t i2c_al_status; + uint8_t hold_bus; + + /* Read the I2C master state */ + i2c_state = this_i2c->master_state; + + /* Read the ack and al status */ + i2c_ack_status = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_RXACK); + i2c_al_status = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_AL); + + switch (i2c_state) + { + /* I2C ISR State Machine + * + * Cases: + * - Transmit start condition and control byte + * - Received ACK and bus arbitration was not lost (Read or Write) + * - Received NACK + * - Bus arbitration lost + * + * - Transmit data + * - Received ACK and bus arbitration was not lost (Read or Write) + * - Received NACK + * - Bus arbitration lost + * + * - Receive data + * - Received ACK and bus arbitration was not lost (Read or Write) + * - Bus arbitration lost + */ + + case MIV_I2C_TX_STA_CB: + + /* Received ACK from target and I2C bus arbitration is not lost */ + if (i2c_ack_status == 0u && i2c_al_status == 0u) + { + /* If I2C master write operation */ + if (this_i2c->dir == MIV_I2C_WRITE_DIR) + { + /* write first byte of data and set the WR bit to transfer the data */ + HAL_set_8bit_reg(this_i2c->base_addr, TRANSMIT, + this_i2c->master_tx_buffer[this_i2c->master_tx_idx]); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + /* Increment the index */ + this_i2c->master_tx_idx++; + + /* Set the master state to TX data */ + this_i2c->master_state = MIV_I2C_TX_DATA; + } + /* Master read operation */ + else + { + if (this_i2c->master_rx_size == 1u) + { + /* Send the ACK if the rx size is 1, transmit NACK to slave + * after receiving 1 byte to indicate slave to stop sending + * the data + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_ACK, 0x01u); + } + + /* Send the RD command to slave */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_RD, 0x01u); + + /* Increment the index */ + this_i2c->master_rx_idx++; + + /* Change state to receive data */ + this_i2c->master_state = MIV_I2C_RX_DATA; + } + } + else if (i2c_ack_status == 1u) + { + if (this_i2c->ack_polling_options == MIV_I2C_ACK_POLLING_ENABLE) + { + /* Target responded with NACK and ACK polling option is enabled + * + * Re-send the start condition and control byte + * + * TO-DO: This might become infinite loop check for timeout + * options. + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + this_i2c->master_tx_idx = 0u; + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + else + { + /* Target responded with NACK and ACK polling is disabled + * Abort the transaction and move to IDLE state + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + + this_i2c->master_status = MIV_I2C_FAILED; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + + this_i2c->master_state = MIV_I2C_IDLE; + } + } + + else if (i2c_al_status == 1u) + { + /* Arbitration was lost on the BUS during the transmission of + * previous start condition and control byte. + * Re-send the STA and CB + */ + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + break; + + /* Transmit master data */ + case MIV_I2C_TX_DATA: + + /* ACK received and arbitration was not lost */ + if (i2c_ack_status == 0u && i2c_al_status == 0u) + { + uint8_t tx_buff[this_i2c->master_tx_size]; + if (this_i2c->master_tx_idx < this_i2c->master_tx_size) + { + HAL_set_8bit_reg(this_i2c->base_addr, TRANSMIT, + this_i2c->master_tx_buffer[this_i2c->master_tx_idx]); + + tx_buff[this_i2c->master_tx_idx] = this_i2c->master_tx_buffer[this_i2c->master_tx_idx]; + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + /* Increment the index */ + this_i2c->master_tx_idx++; + + /* Set the master state to TX data */ + this_i2c->master_state = MIV_I2C_TX_DATA; + } + + /* All the bytes are transmitted */ + else if (this_i2c->master_tx_idx == this_i2c->master_tx_size) + { + /* If this is a MASTER_READ_TRANSACTION, hold bus and start a + new transfer in read mode now that the read address has been + written to the slave */ + if(this_i2c->transaction == MIV_I2C_MASTER_READ_TRANSACTION) + + { + //Switch direction to READ + this_i2c->dir = MIV_I2C_READ_DIR; + + // Set the STA bit + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* Set the DIR bit and target addr */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, MIV_I2C_READ_DIR); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, this_i2c->target_addr); + + /* Set the WR bit to transmit the start condition and command byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + // Reset the buffer index + this_i2c->master_tx_idx = 0u; + this_i2c->master_rx_idx = 0u; + + /* Set the master state to RX data */ + this_i2c->master_state = MIV_I2C_RX_DATA; + } + + else + { + /* If releasing the bus, transmit the stop condition at the end + * of the transfer. + */ + hold_bus = this_i2c->bus_status & MIV_I2C_HOLD_BUS; + + if (hold_bus == 0) + { + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + } + else + { + MIV_I2C_disable_irq(); + } + this_i2c->master_status = MIV_I2C_SUCCESS; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + this_i2c->master_state = MIV_I2C_IDLE; + } + } + } + + else if (i2c_ack_status == 1u) + { + /* Received NACK from target device + * + * Release the bus and end the transfer + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + + this_i2c->master_status = MIV_I2C_FAILED; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + + this_i2c->master_state = MIV_I2C_IDLE; + } + + else if (i2c_al_status == 1u) + { + /* Arbitration was lost on the BUS during the transmission of + * previous start condition and control byte. + * Re-send the STA and CB + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, + this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + break; + + /* Receive target device data */ + case MIV_I2C_RX_DATA: + + if (i2c_al_status == 0u) + { + if (this_i2c->master_rx_idx < this_i2c->master_rx_size) + { + this_i2c->master_rx_buffer[this_i2c->master_rx_idx - 1u] = + HAL_get_8bit_reg(this_i2c->base_addr, RECEIVE); + + /* If next byte is last one + * Send NACK to target device to stop sending data + */ + if (this_i2c->master_rx_idx == (this_i2c->master_rx_size - 1u)) + { + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_ACK, 0x01u); + } + + else + { + /* Send ACK to receive next bytes */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_ACK, 0x00u); + } + + /* Set RD bit to receive next byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_RD, 0x01u); + + this_i2c->master_rx_idx++; + } + + /* Received all bytes */ + else //if (this_i2c->master_rx_idx == this_i2c->master_rx_size) + { + this_i2c->master_rx_buffer[this_i2c->master_rx_idx - 1] = + HAL_get_8bit_reg(this_i2c->base_addr, RECEIVE); + + hold_bus = this_i2c->bus_status & MIV_I2C_HOLD_BUS; + + if (hold_bus == 0) + { + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + } + else + { + MIV_I2C_disable_irq(); + } + this_i2c->master_status = MIV_I2C_SUCCESS; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + + this_i2c->master_state = MIV_I2C_IDLE; + } + } + + else if (i2c_al_status == 1u) + { + /* Arbitration was lost on the BUS during the transmission of + * previous start condition and control byte. + * Re-send the STA and CB + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, + this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + break; + } + + /* Toggle the IACK bit to clear interrupt */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00u); +} + +/* + * Please refer to miv_i2c.h for more info + */ +uint8_t +MIV_I2C_get_status +( + miv_i2c_instance_t *this_i2c +) +{ + uint8_t i2c_status; + + i2c_status = HAL_get_8bit_reg(this_i2c->base_addr, STATUS); + + return i2c_status; +} diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.h b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.h new file mode 100644 index 0000000..c5e704d --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.h @@ -0,0 +1,854 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * I2C module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(MIV_ESS). + */ + +/*=========================================================================*//** + @mainpage Mi-V I2C Bare Metal Driver + + ============================================================================== + Introduction + ============================================================================== + The Mi-V I2C driver provides a set of functions for controlling the Mi-V I2C + Soft-IP module. This module is delivered as a part of the Mi-V Extended + Sub System(MIV_ESS). The driver provides a minimal APB-driven I2C interface, + supporting initiator read and write access to peripheral I2C devices. + + The major features provided by the Mi-V I2C driver are: + - Support for configuring the I2C instance. + - I2C master operations. + - I2C ISR. + + This driver can be used as part of a bare metal system where no operating + system is available. The driver can be adapted for use as part of an + operating system, but the implementation of the adaptation layer between the + driver and the operating system's driver model is outside the scope of this + driver. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + The application software should initialize and configure the Mi-V I2C through + the call to the MIV_I2C_init() and MIV_I2C_config() function for Mi-V I2C + instance in the design. The configuration parameter include base address and + Prescaler value. + + ------------------------------ + Interrupt Control + ------------------------------ + The Mi-V I2C driver has to enable and disable the generation of interrupts by + Mi-V I2C at various times while operating. This enabling and disabling of the + interrupts must be done through the Mi-V RV32 HAL provided interrupt handlers. + For that reason, the method controlling the Mi-V I2C interrupts is system + specific and it is necessary to customize the MIV_I2C_enable_irq() and + MIV_I2C_disable_irq() functions as per requirement. + + The implementation of MIV_I2C_enable_irq() should permit the interrupts + generated by the Mi-V I2C to the processor through a call to respective miv-hal + interrupt handler. The implementation of MIV_I2C_disable_irq() should prevent + the interrupts generated by a Mi-V I2C from interrupting the processor. + Please refer to the miv_i2c_interrupt.c for more information about the + implementation. + + No MIV_I2C hardware configuration parameters are used by the driver, apart + from the MIV_I2C base address. Hence, no additional configuration files + are required to use the driver. + + ============================================================================== + Theory of Operation + ============================================================================== + The Mi-V I2C software driver is designed to allow the control of multiple + instances of Mi-V I2C. Each instance of Mi-V I2C in the hardware design is + associated with a single instance of the miv_i2c_instance_t structure in the + software. User must allocate memory for one unique miv_i2c_instance_t + structure for each instance of Mi-V I2C in the hardware. + A pointer to the structure is passed to the subsequent driver functions in + order to identify the MIV_I2C hardware instance and to perform requested + operation. + + Note: Do not attempt to directly manipulate the contents of the + miv_i2c_instance_t structure. These structures are only intended to be modified + by the driver functions. + + The Mi-V I2C driver functions are grouped into following categories: + - Initialization and configuration + - I2C master operation functions to handle write, read and write_read + operations. + - Interrupt control + + -------------------------------- + Initialization and configuration + -------------------------------- + The Mi-V I2C device is first initialized by the call to MIV_I2C_init(). This + function initializes the instance of Mi-V I2C with the base address. + MIV_I2C_init() function must be called before any other Mi-V I2C driver API. + + The configuration of the Mi-V I2C instance is done via call to the + MIV_I2C_config() function. This function will set the prescale value which is + used to set the frequency of the I2C clock(SCLK) generated by I2C module. + + --------------------------------- + Transaction types + --------------------------------- + The driver is designed to handle three types of transactions: + - Write transactions + - Read transactions + - Write-Read transaction + + ### Write Transaction + The write transaction begins with master sending a start condition, followed + by device address byte with the R/W bit set to logic '0', and then by the + word address bytes. The slave acknowledges the receipt of its address with + acknowledge bit. The master sends one byte at a time to the slave, which must + acknowledge the receipt of each byte for the next byte to be sent. The master + sends STOP condition to complete the transaction. The slave can abort the + transaction by replying with negative acknowledge. + + The application programmer can choose not to send the STOP bit at the end of + the transaction causing repetitive start conditions. + + ### Read Transaction + The master I2C device initiates a read transaction by sending a START bit + as soon as the bus becomes free. The start condition is followed by the + control byte which contains 7-bit slave address followed by R/W bit set to + logic '1'. The slave sends data one byte at a time to the master, which must + acknowledge receipt of each byte for the next byte to be sent. The master + sends a non-acknowledge bit following the last byte it wishes to read + followed by a STOP bit. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ### Write-Read Transaction + The write read transaction is a combination of a write transaction + immediately followed by a read transaction. There is no STOP condition sent + between the write and read phase of write-read transaction. A repeated START + condition is sent between the write and read phases. + + Whilst the write handler is being executed, the slave holds the clock line + low to stretch the clock until the response is ready. + + The write-read transaction is typically used to send an memory/register + address in the write transaction specifying the start address of the data to + be transferred during the read phase. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ------------------------------------- + Interrupt Control + ------------------------------------- + The Mi-V I2C driver is interrupt driven and it uses the MIV_I2C_irq() function + to drive the ISR state machine which is at the heart of the driver. The + application is responsible for providing the link between the interrupt + generating hardware and the Mi-V I2C interrupt handler and must ensure that + the MIV_I2C_isr() function is called with the correct miv_i2c_instance_t + structure pointer for the Mi-V I2C instance initiating the interrupt. + +*//*=========================================================================*/ +#ifndef MIV_I2C_H_ +#define MIV_I2C_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "miv_i2c_regs.h" +#include + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#else +#include "hal.h" +#endif + +/*-------------------------------------------------------------------------*//** + The miv_i2c_status_t type is used to report the status of I2C transactions. + */ +typedef enum miv_i2c_status +{ + MIV_I2C_SUCCESS = 0u, + MIV_I2C_IN_PROGRESS, + MIV_I2C_FAILED, + MIV_I2C_TIMED_OUT +}miv_i2c_status_t; + +/*-------------------------------------------------------------------------*//** + This structure is used to identify the MIV_I2C hardware instances in a system. + Your application software should declare one instance of this structure for + each instance of the MIV_I2C in your system. The function MIV_I2C_init() + Initializes this structure. A pointer to an initialised instance of the structure + should be passed as the first parameter to the MIV_I2C driver functions, to + identify which MIV_I2C hardware instance should perform the requested operation. + + The contents of this data structure should not be modified or used outside of + the MIV_I2C driver. Software using the MIV_I2C driver should only need to + create one single instance of this data structure for each MIV_I2C hardware + instance in the system, then pass a pointer to these data structures with each + call to the MIV_I2C driver in order to identify the MIV_I2C hardware instance + it wishes to use. +*/ + +typedef struct miv_i2c_instance +{ + addr_t base_addr; + + /* Transmit related info:*/ + uint_fast8_t target_addr; + + /* Current transaction type */ + uint8_t transaction; + + uint8_t bus_options; + + uint8_t ack_polling_options; + + /* Current State of the I2C master */ + uint8_t master_state; + + /* Master TX INFO: */ + const uint8_t * master_tx_buffer; + uint_fast16_t master_tx_size; + uint_fast16_t master_tx_idx; + uint_fast8_t dir; + + /* Master RX INFO: */ + uint8_t * master_rx_buffer; + uint_fast16_t master_rx_size; + uint_fast16_t master_rx_idx; + + /* Master Status */ + volatile miv_i2c_status_t master_status; + uint32_t master_timeout_ms; + + /* user specific data */ + void *p_user_data ; + + /* I2C bus status */ + uint8_t bus_status; + + /* Is transaction pending flag */ + uint8_t is_transaction_pending; + + /* I2C Pending transaction */ + uint8_t pending_transaction; + +}miv_i2c_instance_t; + + +/*-------------------------------------------------------------------------*//** + MIV_I2C_RELEASE_BUS + ===================== + The MIV_I2C_RELEASE_BUS constant is used to specify the bus_options parameter + for MIV_I2C_read(), MIV_I2C_write() and MIV_I2C_write_read() to indicate + that a STOP bit must be generated at the end of the I2C transaction to release + the bus. + */ +#define MIV_I2C_RELEASE_BUS 0x00u + + +/*-------------------------------------------------------------------------*//** + MIV_I2C_HOLD_BUS + ===================== + The MIV_I2C_HOLD_BUS constant is used to specify the bus_optionsparameter + for MIV_I2C_read(), MIV_I2C_write() and MIV_I2C_write_read() to indicate + that a STOP bit must not be generated at the end of the I2C transaction in + order to retain the bus ownership. This causes the next transaction to + begin with a repeated START bit and no STOP bit between the transactions. + */ +#define MIV_I2C_HOLD_BUS 0x01u + +/*-------------------------------------------------------------------------*//** + MIV_I2C_ACK_POLLING_DISABLE + ===================== + The MIV_I2C_ACK_POLLING_DISABLE constant is used to specify the + ack_polling_options parameter to functions MIV_I2C_write(), + MIV_I2C_write_read() and MIV_I2C_read(). Acknowledgment polling is used when + working with I2C memory devices such as EEPROM, which feature an internal + write cycle. + + With acknowledgment polling disabled, if the target slave device responds to the + control byte with a NACK, the MIV_I2C will abort the transfer. + */ +#define MIV_I2C_ACK_POLLING_DISABLE 0x00u + +/*-------------------------------------------------------------------------*//** + MIV_I2C_ACK_POLLING_ENABLE + ===================== + The MIV_I2C_ACK_POLLING_ENABLE constant is used to specify the + ack_polling_options parameter to functions MIV_I2C_write(), + MIV_I2C_write_read() and MIV_I2C_read(). acknowledgment polling is used when + working with I2C memory devices such as EEPROM, which feature an internal + write cycle. + + With acknowledgment polling enabled, if the slave device responds to the + control byte with a NACK, the MIV_I2C will repeatedly transmit another control + byte until the slave device accepts the connection with an ACK, or the timeout + specified in the MIV_I2C_wait_complete() function is reached. Acknowledgment + polling allows for the next read/write operation to be started as soon as the + EEPROM has completed its internal write cycle. + */ +#define MIV_I2C_ACK_POLLING_ENABLE 0x01u + +/*--------------------------------Public APIs---------------------------------*/ + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_init() function is used to initialize the Mi-V I2C module instance + with the base address. + + Note: This function should be called before calling any other Mi-V I2C + functions. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + @param base_addr + Base address of the Mi-V I2C module instance in the MIV_ESS + soft IP. + + @return + This function does not return any value. + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + } + @endcode + */ +void +MIV_I2C_init +( + miv_i2c_instance_t *this_i2c, + addr_t base_addr +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_config() function is used to configure the Mi-V I2C module. This + function will set the prescale value which is used to set the frequency of + the I2C clock(SCLK) generated by I2C module and also enables the I2C core and + interrupts. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param clk_prescale + The value used to set the frequency of Mi-V I2C serial clock + (SCLK) generated by the Mi-V I2C module instance. The + prescaler value required to set particular frequency of + Mi-V I2C can be calculated using following formula: + + prescaler = (System Clock Frequency) / (5 * (Desired I2C Clock Frequency)) - 1 + + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + } + @endcode + */ +void +MIV_I2C_config +( + miv_i2c_instance_t *this_i2c, + uint16_t clk_prescale +); + + +uint8_t +MIV_I2C_start +( + miv_i2c_instance_t *this_i2c +); + + +uint8_t +MIV_I2C_stop +( + miv_i2c_instance_t *this_i2c +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_write() is used to set up and start the Mi-V I2C master write + transaction. This function is used for all Mi-V master write operation. + + For more information about the operation, please refer to the 'theory of + operations' section at the start of this document. + + This function returns immediately after initiating the transaction. The content + of the write buffer passed as parameter should not be modified until the write + transaction completes. It also means that the memory allocated for the write + buffer should not be freed or should not go out of scope before the write + completes. + You can check for the write transaction completion by polling the master_status + from miv_i2c_instance_t structure as shown in the sample code. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param i2c_target_addr + This parameter specifies the serial address for the slave + device. + + @param write_buffer + This parameter is a pointer to the buffer holding data to be + written to target I2C device. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param write_size + Number of bytes held in the write_buffer to be written to the + I2C device. + @param bus_options: + The bus_options parameter is used to indicate if the I2C bus + should be released on completion of the write transaction. + Using the MIV_I2C_RELEASE_BUS constant for the bus_options + parameter causes a STOP bit to be generated at the end of the + write transaction causing the bus to be released for other I2C + devices to use. Using the MIV_I2C_HOLD_BUS constant as + bus_options parameter prevents a STOP bit from being generated + at the end of the write transaction, preventing other I2C + devices from initiating a bus transaction. + + @param ack_polling_options: + The ack_polling_options parameter is used to indicate how the + MIV_I2C will respond if the slave device transmits a NACK to + the I2C control byte. Using the MIV_I2C_ACK_POLLING_DISABLE + constant for the ack_polling_options parameter causes the + MIV_I2C to abort the transfer if the slave device responds to + the I2C control byte with a NACK. Using the + MIV_I2C_ACK_POLLING_ENABLE constant for the ack_polling_options + parameter causes the MIV_I2C to repeatedly transmit a control + byte to the slave device until the slave device responds with + an ACK. + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + + MIV_I2C_write (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_tx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + } + @endcode + */ +void +MIV_I2C_write +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t bus_options, + uint8_t ack_polling_options +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_read() is used to set up and start the Mi-V I2C master read + transaction. This function is used for all MIV_I2C master read operation. + + For more information about the operation, please refer to the 'theory of + operations' section at the start of this document. + + This function returns immediately after initiating the transaction. The content + of the read buffer passed as parameter should not be modified until the write + transaction completes. It also means that the memory allocated for the read + buffer should not be freed or should not go out of scope before the read + completes. + You can check for the write transaction completion by polling the master_status + from miv_i2c_instance_t structure as shown in the sample code. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param i2c_target_addr + This parameter specifies the serial address for the slave + device. + + @param read_buffer + This parameter is a pointer to the buffer where the data + received from the I2C slave device is stored. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param read_size + Number of bytes held in the write_buffer to be read from the + I2C device. + + @param bus_options: + The bus_options parameter is used to indicate if the I2C bus + should be released on completion of the write transaction. + Using the MIV_I2C_RELEASE_BUS constant for the bus_options + parameter causes a STOP bit to be generated at the end of the + write transaction causing the bus to be released for other I2C + devices to use. Using the MIV_I2C_HOLD_BUS constant as + bus_options parameter prevents a STOP bit from being generated + at the end of the write transaction, preventing other I2C + devices from initiating a bus transaction. + + @param ack_polling_options: + The ack_polling_options parameter is used to indicate how the + MIV_I2C will respond if the slave device transmits a NACK to + the I2C control byte. Using the MIV_I2C_ACK_POLLING_DISABLE + constant for the ack_polling_options parameter causes the + MIV_I2C to abort the transfer if the slave device responds to + the I2C control byte with a NACK. Using the + MIV_I2C_ACK_POLLING_ENABLE constant for the ack_polling_options + parameter causes the MIV_I2C to repeatedly transmit a control + byte to the slave device until the slave device responds with + an ACK. + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + + MIV_I2C_write (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_tx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + + // reset miv_i2c_status variable + miv_i2c_status = 0u; + + MIV_I2C_read (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_rx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + } + @endcode + */ +void +MIV_I2C_read +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_write_read() is used to set up and start the Mi-V I2C master + write_read transaction. This function is used for all MIV_I2C master write_read + operation. + + This function is used in cases where data is being requested from a specific + address offset inside the target I2C slave device. + In this type of I2C operation, the I2C master starts by initiating a write + operation. During this write operation, the specific address offset is written + to the I2C slave. Once the address offset has been written to the I2C slave, + the I2C master transmits a repeated start, and initiates a read operation to + read data from the set address. + + For more information about the operation, please refer to the 'theory of + operations' section at the start of this document. + + This function returns immediately after initiating the transaction. The content + of the write and read buffer passed as parameter should not be modified until + the write transaction completes. It also means that the memory allocated for + the write and read buffer should not be freed or should not go out of scope + before the operation completes. + You can check for the write_read transaction completion by polling the + master_status from miv_i2c_instance_t structure. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param i2c_target_addr + This parameter specifies the serial address for the slave + device. + + @param write_buffer + This parameter is a pointer to the buffer holding data to be + written to target I2C device. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param write_size + Number of bytes held in the write_buffer to be written to the + I2C device. + + @param read_buffer + This parameter is a pointer to the buffer where the data + received from the I2C slave device is stored. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param read_size + Number of bytes held in the write_buffer to be read from the + I2C device. + + @param bus_options: + The bus_options parameter is used to indicate if the I2C bus + should be released on completion of the write transaction. + Using the MIV_I2C_RELEASE_BUS constant for the bus_options + parameter causes a STOP bit to be generated at the end of the + write transaction causing the bus to be released for other I2C + devices to use. Using the MIV_I2C_HOLD_BUS constant as + bus_options parameter prevents a STOP bit from being generated + at the end of the write transaction, preventing other I2C + devices from initiating a bus transaction. + + @param ack_polling_options: + The ack_polling_options parameter is used to indicate how the + MIV_I2C will respond if the slave device transmits a NACK to + the I2C control byte. Using the MIV_I2C_ACK_POLLING_DISABLE + constant for the ack_polling_options parameter causes the + MIV_I2C to abort the transfer if the slave device responds to + the I2C control byte with a NACK. Using the + MIV_I2C_ACK_POLLING_ENABLE constant for the ack_polling_options + parameter causes the MIV_I2C to repeatedly transmit a control + byte to the slave device until the slave device responds with + an ACK or the timeout specified in the MIV_I2C_wait_complete() + function is reached. + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + + MIV_I2C_write (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_tx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + + // reset miv_i2c_status variable + miv_i2c_status = 0u; + + uint8_t addr_offset[2] = {0x00, 0x00}; + MIV_I2C_write_read(&miv_i2c, + DUALEE_SLAVEADDRESS_1, + addr_offset, + sizeof(addr_offset), + i2c_rx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + } + @endcode + */ +void +MIV_I2C_write_read +( + miv_i2c_instance_t *this_i2c, + uint8_t target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_isr() function contains the MIV_I2C's interrupt service routine. + This ISR is at the heart of the MIV_I2C driver, and is used to control the + interrupt-driven, byte-by-byte I2C read and write operations. + + The ISR operates as a Finite State Machine (FSM), which uses the previously + completed I2C operation and its result to determine which I2C operation will + be performed next. + + The ISR operation is divided into following categories: + - MIV_I2C_IDLE + - MIV_I2C_TX_STA_CB + - MIV_I2C_TX_DATA + - MIV_I2C_RX_DATA + + ##### MIV_I2C_IDLE + The MIV_I2C_IDLE is entered on reset, or when an I2C master operation has been + completed or aborted. + Upon entering, the FSM will remain in this state until a write, read, or + write-read operation is requested + + ##### MIV_I2C_STA_CB + The MIV_I2C_TX_STA_CB operation is performed when the start condition and + control byte(i2c target address(7-bit) and direction of transaction(1-bit)) is + transmitted by the Mi-V I2C master device to the slave. + If the target I2C slave device responded to the previous START Condition + + Control Byte with an ACK, the MIV_I2C will start the requested I2C + read/write operation. + If the target slave I2C slave device responds with NACK, the MIV_I2C will + remain in this state or return to the idle state based on ack_polling + configuration. + + ##### MIV_I2C_TX_DATA + The MIV_I2C_TX_DATA state is entered after the target slave device accepts a + write request with an ACK. + This state is used to handle the byte-by-byte MIV_I2C write operations. + The FSM will remain in this state until either all data bytes have been + written to the target slave device, or an error occurs during the write + operation. + + ##### MIV_I2C_RX_DATA + The MIV_I2C_RX_DATA state is entered after the target slave device accepts a + read request with an ACK. + This state is used to handle the byte-by-byte MIV_I2C read operations. + The FSM will remain in this state until either all data bytes have been + received from the target slave device, or an error occurs. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + */ +void +MIV_I2C_isr +( + miv_i2c_instance_t *this_i2c +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_get_status() returns the 8-bit Mi-V I2C status register value. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + @return + This function returns 8-bit Mi-V I2C status register value. + */ +uint8_t +MIV_I2C_get_status +( + miv_i2c_instance_t *this_i2c +); + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_I2C_H_ */ diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_interrupt.c b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_interrupt.c new file mode 100644 index 0000000..871eafe --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_interrupt.c @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains functions used for MIV_I2C driver interrupt control. + * User should enable and disable the interrupts according to their design. + * Please refer to miv_i2c.h file for more information. + */ + +#include "miv_rv32_hal/miv_rv32_hal.h" + +void MIV_I2C_disable_irq(void) +{ +/* Disable I2C interrupt */ + MRV_disable_local_irq(MRV32_MSYS_EIE2_IRQn); +} + +void MIV_I2C_enable_irq(void) +{ +/* Enable I2C interrupt */ + MRV_enable_local_irq(MRV32_MSYS_EIE2_IRQn); +} + + diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_regs.h b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_regs.h new file mode 100644 index 0000000..9a4bfbf --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_regs.h @@ -0,0 +1,158 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP I2C module driver. This module is delivered as a part of Mi-V extended + * Sub-System(MIV_ESS). + */ + +#ifndef MIV_I2C_APB_REGISTERS +#define MIV_I2C_APB_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * Prescale register details + */ +#define PRESCALE_REG_OFFSET 0x00u + +/* Prescale register bits */ +#define PRESCALE_OFFSET 0x00u +#define PRESCALE_MASK 0xFFFFu +#define PRESCALE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Control register details + */ +#define CONTROL_REG_OFFSET 0x04u + +/* Control register bits */ +#define CONTROL_OFFSET 0x04u +#define CONTROL_MASK 0xC0u +#define CONTROL_SHIFT 0u + +/* Control register Core Enable Bit */ +#define CTRL_CORE_EN_OFFSET 0x04u +#define CTRL_CORE_EN_MASK 0x80u +#define CTRL_CORE_EN_SHIFT 7u + +/* Control register IRQ Enable bit */ +#define CTRL_IRQ_EN_OFFSET 0x04u +#define CTRL_IRQ_EN_MASK 0x40u +#define CTRL_IRQ_EN_SHIFT 6u + +/*------------------------------------------------------------------------------ + * Transmit register details + */ +#define TRANSMIT_REG_OFFSET 0x08u + +/* Transmit register bits */ +#define TRANSMIT_OFFSET 0x08u +#define TRANSMIT_MASK 0xFFu +#define TRANSMIT_SHIFT 0u + +/* Transmit register DIR bit */ +#define TX_DIR_OFFSET 0x08u +#define TX_DIR_MASK 0x01u +#define TX_DIR_SHIFT 0u + +/* Transmit register TARGET_ADDR bit */ +#define TX_TARGET_ADDR_OFFSET 0x08u +#define TX_TARGET_ADDR_MASK 0xFEu +#define TX_TARGET_ADDR_SHIFT 1u + +/*------------------------------------------------------------------------------ + * Receive register details + */ +#define RECEIVE_REG_OFFSET 0x0Cu + +/* Receive register bits */ +#define RECEIVE_OFFSET 0x0Cu +#define RECEIVE_MASK 0xFFu +#define RECEIVE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Command register details + */ +#define COMMAND_REG_OFFSET 0x10u + +/* Command register bits */ +#define COMMAND_OFFSET 0x10u +#define COMMAND_MASK 0xF9u +#define COMMAND_SHIFT 0u + +/* Command register IACK bit */ +#define CMD_IACK_OFFSET 0x10u +#define CMD_IACK_MASK 0x01u +#define CMD_IACK_SHIFT 0u + +/* Command register ACK bit */ +#define CMD_ACK_OFFSET 0x10u +#define CMD_ACK_MASK 0x08u +#define CMD_ACK_SHIFT 3u + +/* Command register WR bit */ +#define CMD_WR_OFFSET 0x10u +#define CMD_WR_MASK 0x10u +#define CMD_WR_SHIFT 4u + +/* Command register RD bit */ +#define CMD_RD_OFFSET 0x10u +#define CMD_RD_MASK 0x20u +#define CMD_RD_SHIFT 5u + +/* Command register STO bit */ +#define CMD_STO_OFFSET 0x10u +#define CMD_STO_MASK 0x40u +#define CMD_STO_SHIFT 6u + +/* Command register STA bit */ +#define CMD_STA_OFFSET 0x10u +#define CMD_STA_MASK 0x80u +#define CMD_STA_SHIFT 7u + +/*------------------------------------------------------------------------------ + * Status register details + */ +#define STATUS_REG_OFFSET 0x14u + +/* Command register bits */ +#define STATUS_OFFSET 0x14u +#define STATUS_MASK 0xFFu +#define STATUS_SHIFT 0u + +/* Status register Interrupt Flag(IF) bit */ +#define STAT_IF_OFFSET 0x14u +#define STAT_IF_MASK 0x01u +#define STAT_IF_SHIFT 0u + +/* Status register Transfer in Progress(TIP) bit */ +#define STAT_TIP_OFFSET 0x14u +#define STAT_TIP_MASK 0x02u +#define STAT_TIP_SHIFT 1u + +/* Status register Arbitration Lost(AL) bit */ +#define STAT_AL_OFFSET 0x14u +#define STAT_AL_MASK 0x20u +#define STAT_AL_SHIFT 5u + +/* Status register Busy(BUSY) bit */ +#define STAT_BUSY_OFFSET 0x14u +#define STAT_BUSY_MASK 0x40u +#define STAT_BUSY_SHIFT 6u + +/* Status register Ack received(RXACK) bit */ +#define STAT_RXACK_OFFSET 0x14u +#define STAT_RXACK_MASK 0x80u +#define STAT_RXACK_SHIFT 7u + + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_I2C_APB_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.c b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.c new file mode 100644 index 0000000..903f029 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.c @@ -0,0 +1,283 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * MI-V Soft IP fabric bare-metal driver for Mi-V PLIC module. This module is + * delivered as a part of Mi-V Extended Sub System(MIV_ESS). + * Please refer to miv_plic.h file for more information. + */ + +#include "miv_plic.h" + +/***************************************************************************//** + * Mi-V PLIC interrupt handler function declaration. + * These functions are called by the external interrupt handler of the MIV_RV32 + * core base on the PLIC source causing the interrupt. + */ +uint8_t Invalid_IRQHandler(void); +uint8_t MIV_PLIC_EXT0_IRQHandler(void); +uint8_t MIV_PLIC_EXT1_IRQHandler(void); +uint8_t MIV_PLIC_EXT2_IRQHandler(void); +uint8_t MIV_PLIC_EXT3_IRQHandler(void); +uint8_t MIV_PLIC_EXT4_IRQHandler(void); +uint8_t MIV_PLIC_EXT5_IRQHandler(void); +uint8_t MIV_PLIC_EXT6_IRQHandler(void); +uint8_t MIV_PLIC_EXT7_IRQHandler(void); +uint8_t MIV_PLIC_EXT8_IRQHandler(void); +uint8_t MIV_PLIC_EXT9_IRQHandler(void); +uint8_t MIV_PLIC_EXT10_IRQHandler(void); +uint8_t MIV_PLIC_EXT11_IRQHandler(void); +uint8_t MIV_PLIC_EXT12_IRQHandler(void); +uint8_t MIV_PLIC_EXT13_IRQHandler(void); +uint8_t MIV_PLIC_EXT14_IRQHandler(void); +uint8_t MIV_PLIC_EXT15_IRQHandler(void); +uint8_t MIV_PLIC_EXT16_IRQHandler(void); +uint8_t MIV_PLIC_EXT17_IRQHandler(void); +uint8_t MIV_PLIC_EXT18_IRQHandler(void); +uint8_t MIV_PLIC_EXT19_IRQHandler(void); +uint8_t MIV_PLIC_EXT20_IRQHandler(void); +uint8_t MIV_PLIC_EXT21_IRQHandler(void); +uint8_t MIV_PLIC_EXT22_IRQHandler(void); +uint8_t MIV_PLIC_EXT23_IRQHandler(void); +uint8_t MIV_PLIC_EXT24_IRQHandler(void); +uint8_t MIV_PLIC_EXT25_IRQHandler(void); +uint8_t MIV_PLIC_EXT26_IRQHandler(void); +uint8_t MIV_PLIC_EXT27_IRQHandler(void); +uint8_t MIV_PLIC_EXT28_IRQHandler(void); +uint8_t MIV_PLIC_EXT29_IRQHandler(void); +uint8_t MIV_PLIC_EXT30_IRQHandler(void); + +/***************************************************************************//** + * MIV_PLIC interrupt handler for external interrupts. + * The array of the function pointers pointing to the weak handler of the Mi-V + * PLIC interrupt handlers. + * These functions are called by the external interrupt handler of the MIV_RV32 + * core base on the PLIC source causing the interrupt. + */ +uint8_t (* const ext_irq_handler_table[32]) (void) = +{ + Invalid_IRQHandler, + MIV_PLIC_EXT0_IRQHandler, + MIV_PLIC_EXT1_IRQHandler, + MIV_PLIC_EXT2_IRQHandler, + MIV_PLIC_EXT3_IRQHandler, + MIV_PLIC_EXT4_IRQHandler, + MIV_PLIC_EXT5_IRQHandler, + MIV_PLIC_EXT6_IRQHandler, + MIV_PLIC_EXT7_IRQHandler, + MIV_PLIC_EXT8_IRQHandler, + MIV_PLIC_EXT9_IRQHandler, + MIV_PLIC_EXT10_IRQHandler, + MIV_PLIC_EXT11_IRQHandler, + MIV_PLIC_EXT12_IRQHandler, + MIV_PLIC_EXT13_IRQHandler, + MIV_PLIC_EXT14_IRQHandler, + MIV_PLIC_EXT15_IRQHandler, + MIV_PLIC_EXT16_IRQHandler, + MIV_PLIC_EXT17_IRQHandler, + MIV_PLIC_EXT18_IRQHandler, + MIV_PLIC_EXT19_IRQHandler, + MIV_PLIC_EXT20_IRQHandler, + MIV_PLIC_EXT21_IRQHandler, + MIV_PLIC_EXT22_IRQHandler, + MIV_PLIC_EXT23_IRQHandler, + MIV_PLIC_EXT24_IRQHandler, + MIV_PLIC_EXT25_IRQHandler, + MIV_PLIC_EXT26_IRQHandler, + MIV_PLIC_EXT27_IRQHandler, + MIV_PLIC_EXT28_IRQHandler, + MIV_PLIC_EXT29_IRQHandler, + MIV_PLIC_EXT30_IRQHandler +}; + +/* Mi-V PLIC interrupt weak handlers */ +__attribute__((weak)) uint8_t Invalid_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT0_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT1_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT2_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT3_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT4_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT5_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT6_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT7_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT8_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT9_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT10_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT11_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT12_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT13_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT14_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT15_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT16_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT17_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT18_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT19_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT20_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT21_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT22_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT23_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT24_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT25_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT26_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT27_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT28_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT29_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT30_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +/*-------------------------------------------------------------------------*//** + * Please refer to miv_plic.h for more information about this function. +*/ +void +MIV_PLIC_isr +( + miv_plic_instance_t *this_plic +) +{ + unsigned long hart_id = read_csr(mhartid); + + /* claim the interrupt from PLIC controller */ + + uint32_t int_num = HAL_get_32bit_reg(this_plic->base_addr + + (0x1000 * hart_id), INT_CLAIM_COMPLETE); + + uint8_t disable = EXT_IRQ_KEEP_ENABLED; + disable = ext_irq_handler_table[int_num](); + + /* Indicate the PLIC controller that the interrupt is processed and claim is + * complete. */ + HAL_set_32bit_reg(this_plic->base_addr + + (0x1000 * hart_id), INT_CLAIM_COMPLETE, int_num); + + if (EXT_IRQ_DISABLE == disable) + { + MIV_PLIC_disable_irq(this_plic, (miv_plic_irq_num_t)int_num); + } +} diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.h b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.h new file mode 100644 index 0000000..f5d64cd --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.h @@ -0,0 +1,425 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * PLIC module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(ESS). + */ + /*=========================================================================*//** + @mainpage Mi-V PLIC Bare Metal Driver + + ============================================================================== + Introduction + ============================================================================== + The Mi-V driver provides a set of functions for controlling the Mi-V PLIC + (platform level interrupt controller) soft-IP module. This module is delivered + as a part of the MIV_ESS. The PLIC multiplexes external interrupt signals into + a single interrupt signal that is connected to an external interrupt of the + processor. + + The major features provided by the driver are: + - Support for configuring the PLIC instances. + - Enabling and Disabling interrupts + - Interrupt Handling + + This driver can be used as part of a bare metal system where no operating + system is available. The driver can be adapted for use as part of an + operating system, but the implementation of the adaptation layer between the + driver and the operating system's driver model is outside the scope of this + driver. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + The application software should initialize the Mi-V PLIC through the call to + the MIV_PLIC_init() function for Mi-V PLIC instance in the design. + + No Mi-V PLIC hardware configuration parameters are used by the driver, apart + from the Mi-V PLIC base address. Hence, no additional configuration files + are required to use the driver. + + ============================================================================== + Theory of Operation + ============================================================================== + The operation of Mi-V PLIC driver is divided into following steps: + - Initialization + - Enabling and Disabling interrupts + - Interrupt control + + -------------------------------------------- + Initialization + -------------------------------------------- + The Mi-V PLIC module is first initialized by the call to MIV_PLIC_init(). This + function takes a pointer to the Mi-V PLIC instance data structure and the base + address of the Mi-V PLIC instance is defined by the hardware design. The + instance data structure is used to store the base address of the Mi-V PLIC + module and a pointer to the Mi-V PLIC register data structure. The Mi-V PLIC + register data structure maps the address of the Mi-V PLIC registers. + + --------------------------------------------- + Enabling and Disabling interrupts + --------------------------------------------- + The MIV_PLIC_enable_irq() function enables the specific interrupt provided by + user. A call to this function will allow the enabling of each of the global + interrupts corresponding to the bit in the interrupt enable register of Mi-V + PLIC. + The MIV_PLIC_disable_irq() function disables the specific interrupt provided + by the user. This function can be used to disable the interrupts from outside + of the external interrupt handler. + + ---------------------------------------- + Interrupt Control + ---------------------------------------- + When an interrupt occurs on an enabled interrupt, the PLIC gateway captures + the interrupt and asserts the corresponding interrupt pending bit. Once + the enable bit and pending bit are asserted, then the PLIC_IRQ signal asserts + until the interrupt is claimed by the driver interrupt handler MIV_PLIC_irq() + function. + When multiple interrupts assert then the lowest interrupt number will be + serviced first, for example, if interrupt 1 and 6 assert at the same time, + interrupt 1 will be serviced first, followed by interrupt 6. + +*/ + +#ifndef MIV_PLIC_H_ +#define MIV_PLIC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "miv_plic_regs.h" + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#include "miv_rv32_hal/miv_rv32_hal.h" +#else +#include "hal.h" +#include "miv_rv32_hal.h" +#endif + +/*-------------------------------------------------------------------------*//** + This enumeration is used to select a specific Mi-V PLIC interrupt. It is + used as a parameter to enable or disable the interrupt. +*/ +typedef enum miv_plic_irq_num +{ + NoInterrupt_IRQn = 0, + MIV_PLIC_EXT0_IRQn = 1, + MIV_PLIC_EXT1_IRQn = 2, + MIV_PLIC_EXT2_IRQn = 3, + MIV_PLIC_EXT3_IRQn = 4, + MIV_PLIC_EXT4_IRQn = 5, + MIV_PLIC_EXT5_IRQn = 6, + MIV_PLIC_EXT6_IRQn = 7, + MIV_PLIC_EXT7_IRQn = 8, + MIV_PLIC_EXT8_IRQn = 9, + MIV_PLIC_EXT9_IRQn = 10, + MIV_PLIC_EXT10_IRQn = 11, + MIV_PLIC_EXT11_IRQn = 12, + MIV_PLIC_EXT12_IRQn = 13, + MIV_PLIC_EXT13_IRQn = 14, + MIV_PLIC_EXT14_IRQn = 15, + MIV_PLIC_EXT15_IRQn = 16, + MIV_PLIC_EXT16_IRQn = 17, + MIV_PLIC_EXT17_IRQn = 18, + MIV_PLIC_EXT18_IRQn = 19, + MIV_PLIC_EXT19_IRQn = 20, + MIV_PLIC_EXT20_IRQn = 21, + MIV_PLIC_EXT21_IRQn = 22, + MIV_PLIC_EXT22_IRQn = 23, + MIV_PLIC_EXT23_IRQn = 24, + MIV_PLIC_EXT24_IRQn = 25, + MIV_PLIC_EXT25_IRQn = 26, + MIV_PLIC_EXT26_IRQn = 27, + MIV_PLIC_EXT27_IRQn = 28, + MIV_PLIC_EXT28_IRQn = 29, + MIV_PLIC_EXT29_IRQn = 30, + MIV_PLIC_EXT30_IRQn = 31 +} miv_plic_irq_num_t; + +/*--------------------------------------------------------------------------*//* + * This structure maps the priority threshold and claim complete register in + * the memory. + */ +typedef struct +{ + volatile uint32_t PRIORITY_THRESHOLD; + volatile uint32_t CLAIM_COMPLETE; + volatile uint32_t reserved[1022]; +} IRQ_Target_Type; + +/*--------------------------------------------------------------------------*//* + * This structure maps the Interrupt enable sources from 0 - 1023 for one + * context. + */ +typedef struct +{ + volatile uint32_t ENABLES[32]; +} Target_Enables_Type; + +/*-------------------------------------------------------------------------*//** + This structure holds the base address of the Mi-V PLIC module. This structure + is used by all the functions to access the Mi-V PLIC registers. +*/ +typedef struct miv_plic_instance +{ + addr_t base_addr; +} miv_plic_instance_t; + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_isr is the top level interrupt handler function for the Mi-V PLIC + * driver. You must call the MIV_PLIC_isr() from the system level interrupt + * handler(External_IRQHandler). + * This function must be called from the external interrupt handler function + * provided by the processor hardware abstraction layer. In case of MIV_RV32 + * soft processor, it must be called from External_IRQHandler() function + * provided by MIV_RV32 HAL. + * + * The MIV_PLIC_isr() function claims the interrupt number + * that triggered the interrupt and then invokes the appropriate PLIC interrupt + * handler. + * After handling the PLIC interrupt, this function will complete the interrupt + * by clearing the claim complete bit for the particular interrupt source. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * + * @return + * This function does not return any value. + * + * Example: + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * uint8_t MIV_PLIC_EXT0_IRQHandler(void) + * { + * *** ISR operation *** + * + * return(EXT_IRQ_KEEP_ENABLED); + * } + * + * void External_IRQHandler(void) + * { + * uint32_t reg_val = read_csr(mip); + * MIV_PLIC_isr(&g_plic); + * } + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * } + * @endcode + */ +void MIV_PLIC_isr(miv_plic_instance_t *this_plic); + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_init() function initializes the Mi-V PLIC instance with base + * address. This function resets the PLIC controller by disabling all the PLIC + * interrupts. + * + * Note: This function must be called before calling any other Mi-V PLIC driver + * function. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * + * @param base_addr + * Base address of the Mi-V PLIC instance in the MIV_ESS soft-IP. + * + * @param ext_intr_sources + * Number of interrupts initialized in the design. + * + * @return + * This function does not return any value. + * + * Example + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * } + * @endcode + */ +static inline void +MIV_PLIC_init +( + miv_plic_instance_t *this_plic, + addr_t base_addr, + uint8_t ext_intr_sources +) +{ + uint32_t inc; + unsigned long hart_id = read_csr(mhartid); + + this_plic->base_addr = base_addr; + + /* Disable all interrupts for the current hart. + * The PLIC_EXT_INTR_SOURCES should be defined in the hw_platform.h. This + * macro holds the number of PLIC interrupts enabled in the design. + */ + for(inc = 0; inc < ((ext_intr_sources + 32u) / 32u); ++inc) + { + HAL_set_32bit_reg( + (this_plic->base_addr + inc + (hart_id * 128)), INT_ENABLE , 0x0u); + } +} + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_enable_irq() function enables the PLIC interrupt provided with + * IRQn parameter. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * @param IRQn + * Number of PLIC interrupt to enable. + * + * @return + * This function does not return any value. + * + * Example + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * } + * @endcode + */ +static inline void +MIV_PLIC_enable_irq +( + miv_plic_instance_t *this_plic, + miv_plic_irq_num_t IRQn +) +{ + unsigned long hart_id = read_csr(mhartid); + + uint32_t current = HAL_get_32bit_reg( + (this_plic->base_addr + (IRQn/32) + (hart_id * 128)) , INT_ENABLE); + + current |= (uint32_t)1 << (IRQn % 32); + + HAL_set_32bit_reg( + (this_plic->base_addr + (IRQn/32) + (hart_id * 128)), INT_ENABLE, current); + +} + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_disable_irq() function disables the PLIC interrupt provided with + * IRQn parameter. + * + * NOTE: + * This function can be used to disable the PLIC interrupt from outside the + * external interrupt handler functions. + * If you wish to disable the PLIC interrupt from the external interrupt handler, + * you should use the return value of EXT_IRQ_DISABLE. This will disable the + * selected PLIC interrupt from the Mi-V PLIC driver interrupt handler. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * @param IRQn + * Number of PLIC interrupt to disable. + * + * @return + * This function does not return any value. + * + * Example + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * } + * @endcode + */ +static inline void +MIV_PLIC_disable_irq +( + miv_plic_instance_t *this_plic, + miv_plic_irq_num_t IRQn +) +{ + unsigned long hart_id = read_csr(mhartid); + + uint32_t current = HAL_get_32bit_reg((this_plic->base_addr + (IRQn/32) + (hart_id * 128)) , INT_ENABLE); + + current &= ~((uint32_t)1 << (IRQn % 32)); + + HAL_set_32bit_reg((this_plic->base_addr + (IRQn/32) + (hart_id * 128)), INT_ENABLE, current); + +} + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_PLIC_H_ */ diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic_regs.h b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic_regs.h new file mode 100644 index 0000000..76cbc0b --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic_regs.h @@ -0,0 +1,31 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP PLIC module driver. This module is delivered as a part of Mi-V extended + * Sub-System(MIV_ESS). + */ + +#ifndef MIV_PLIC_REGISTERS +#define MIV_PLIC_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Interrupt pending register offset */ +#define INT_PENDING_REG_OFFSET 0x1000u + +/* Interrupt enable register */ +#define INT_ENABLE_REG_OFFSET 0x2000u + +/* Interrupt claim complete register */ +#define INT_CLAIM_COMPLETE_REG_OFFSET 0x200004u + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_PLIC_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_timer/miv_timer.h b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_timer/miv_timer.h new file mode 100644 index 0000000..5f00889 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_timer/miv_timer.h @@ -0,0 +1,329 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Mi-V Timer Soft IP bare-metal driver. This module is delivered as part of + * the Mi-V Extended Sub System(ESS) MIV_ESS. + */ + +/*=========================================================================*//** + @mainpage Mi-V Timer Bare Metal Driver. + The Mi-V Timer bare metal software driver supports the timer module which + serves as a system timer for the Mi-V Extended Sub System(ESS). + + @section intro_sec Introduction + The MI-V Timer driver supports set of functions for controlling the Mi-V + Timer module. + The Mi-V Timer can generate a timer interrupt signal for the system based on + special system clock intervals specified by the parameters that can be passed + in by the user. + + The major features provided by Mi-V Timer driver are: + - Support for Mi-V Timer instance for each Mi-V Timer peripheral. + - Read current time + - Write to the machine time compare register + + @section hw_dependencies Hardware Flow dependency + The application should configure the Mi-V Timer driver through calls to + MIV_TIMER_init() functions for each MIV_TIMER instance in the hardware + design. The configuration parameter include the MIV_TIMER hardware instance, + base address and number of ticks to generate timer interrupt. + + MIV_RV32 core offers flexibility in terms of generating the MTIME and MTIMECMP + registers internal to the core or using external time reference. + When MIV_ESS is interfaced with MIV_RV32 core, the timer module in the MIV_ESS + can be configured as follows: + - Internal MTIME External MTIME IRQ + Generate the MTIME internally(MIV_RV32) and have a timer interrupt input + to the core as external pin(from MIV_ESS). + + - External MTIME Internal MTIME IRQ + Generate the time value externally(from MIV_ESS), in this case a 64-bit + port will open in the MIV_RV32 core as input and MIV_ESS will output the + 64-bit TIME_COUNT value. The generation of mtimecmp and interrupt is + done internally(MIV_RV32). + + - External MTIME External MTIME IRQ + Generate both the time and timer interrupt externally. + In this case 64-bit port will be available on the Mi-V RV32 core as input + and a 1 pin port will be available for timer interrupt. + + The design must be configured accordingly to use these combinations in the + firmware. + + No MIV_TIMER hardware configuration parameters are used by the driver, apart + from MIV_TIMER base address. Hence, no additional configuration files are + required to use the driver. + + @section theory_op Theory of Operation + + The MIV_TIMER module is a simple systick timer which can generate a timer + interrupt signal for the system at specific intervals specified by the + parameters that can be passed by the user. + These interrupt signal are then fed to the MIV_RV32 core via timer interrupt. + + The operation of MIV_TIMER is divided into following steps: + - Initialization + - Configuration + - Read/Write TIME + + ## Initialization + The MIV_TIMER is first initialized by a call to MIV_TIMER_init(). This + function initializes the instance of Mi-V TIMER with the base address. + The MIV_TIMER_init() function must be called before any other Mi-V Timer driver + function. + + ## Configuration + The Mi-V TIMER configuration includes writing the mtimecmp register with the + initial time value at which timer interrupt should be generated. + When the mtime register value becomes greater than or equal to mtimecmp value, + a timer interrupt signal(TIMER_IRQ) is generated. + + ## Read/Write TIME + The time value can be read by reading the mtime register via call to the + MIV_TIMER_read_mtime(). This function reads the MTIME register which contains + the 64-bit value of the timer count. The count increments by 1 every time the + prescale ticks. This function returns 64-bit MTIME_COUNT value which is the + current value of timer count. + + The time value read in the MIV_TIMER_read_mtime() function can be written to + the mtimecmp register by calling MIV_TIMER_write_mtimecmp() to generate + periodic interrupts. + The writing of the mtimecmp register should be done in the systick_handler() + function. + */ + +#ifndef MIV_TIMER_H_ +#define MIV_TIMER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#endif +/*-------------------------------------------------------------------------*//** +MIV_TIMER_SUCCESS +===================== + +The MIV_TIMER_SUCCESS constant indicates successful configuration of +Mi-V Timer module. +*/ +#define MIV_TIMER_SUCCESS 0u + +/*-------------------------------------------------------------------------*//** +MIV_TIMER_ERROR +===================== + +The MIV_TIMER_ERROR constant indicates that there is an error with +configuring the Mi-V Timer module. +*/ +#define MIV_TIMER_ERROR 1u + +/*-------------------------------------------------------------------------*//* +MIV_TIMER_MASK_32BIT +===================== + +32-bit mask constant used in calculation of 64-bit register value. +*/ +#define MIV_TIMER_MASK_32BIT 0xFFFFFFFFu + +/*-------------------------------------------------------------------------*//* +Mi-V Timer register offsets +===================== +The MTIMECMP is the 64-bit timer compare register, it pre-sets the threshold +which needs to be reached by the timer count register. +This 64-bit register is accessed with 2 32-bit address offset, lower 32-bits +and higher 32-bits. + - MIV_TIMER_MTIMECMP_L_REG_OFFSET + - MIV_TIMER_MTIMECMP_H_REG_OFFSET + +The MTIME is the 64-bit register that contains the 64-bit timer count. The +count increments by 1 every time the prescaler ticks. +This 64-bit register is accessed with 2 32-bit address offset, lower 32-bits +and higher 32-bits. + - MIV_TIMER_MTIME_L_REG_OFFSET + - MIV_TIMER_MTIME_H_REG_OFFSET + +The PRESCALE register is used to determine the amount of clock cycles the +selected clock needs to go through, for MTIME register to increment count. + - MIV_TIMER_PRESCALAR_REG_OFFSET +*/ + +/// @cond private +#define MIV_TIMER_MTIMECMP_L_REG_OFFSET 0x4000u +#define MIV_TIMER_MTIMECMP_H_REG_OFFSET 0x4004u + +#define MIV_TIMER_MTIME_L_REG_OFFSET 0xBFF8u +#define MIV_TIMER_MTIME_H_REG_OFFSET 0xBFFCu + +#define MIV_TIMER_PRESCALAR_REG_OFFSET 0x5000u +/// @endcond + +/*-------------------------------------------------------------------------*//** + This structure holds the base address of the Mi-V Timer module and instance + of the Mi-V Timer register structure. +*/ +typedef struct miv_timer_instance +{ + addr_t base_addr; +} miv_timer_instance_t; + +/** The MIV_TIMER_init() is used to initialize the Mi-V Timer module. This + function will assign the base addresses of the Mi-V Timer module. + User should call this function before calling any of the Mi-V Timer driver + APIs. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @param base_address + Base address of the Mi-V Timer module. + + @return + This function does not return any value. + */ +static inline void +MIV_TIMER_init +( + miv_timer_instance_t* this_timer, + addr_t base_addr +) +{ + this_timer->base_addr = base_addr; +} + +/** MIV_TIMER_read_current_time() is used to read the mtimecmp register values. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @return + This function returns 64-bit mtimecmp register value. + */ +static inline uint64_t +MIV_TIMER_read_current_time +( + miv_timer_instance_t* this_timer +) +{ + volatile uint64_t read_data = 0u; + volatile uint32_t mtime_hi = 0u; + volatile uint32_t mtime_lo = 0u; + + /* when mtime lower word is 0xFFFFFFFF, there will be rollover and + * returned value could be wrong. */ + do { + mtime_hi = HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIME_H); + mtime_lo = HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIME_L); + + } while(mtime_hi != HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIME_H)); + + read_data = mtime_hi; + + return(((read_data) << 32u) | mtime_lo); +} + +/** MIV_TIMER_write_compare_time() is used to write to the MTIMECMP register in + the event of interrupt. User must use this function in the interrupt handler + to de-assert the MIV_TIMER interrupt. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @param write_value + Value to write into the mtimecmp register. + + @return + This function does not return any value. + */ +static inline void +MIV_TIMER_write_compare_time +( + miv_timer_instance_t* this_timer, + uint64_t compare_reg_value +) +{ + HAL_set_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIMECMP_H, MIV_TIMER_MASK_32BIT); + + HAL_set_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIMECMP_L, + (compare_reg_value & MIV_TIMER_MASK_32BIT)); + + HAL_set_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIMECMP_H, + ((compare_reg_value >> 32u) & MIV_TIMER_MASK_32BIT)); +} + +/** The MIV_TIMER_config() is used to configure the MIV_ESS Timer module. The + prescale value serves to divide the count of clock cycles for the timer and + provides control over what point in time, the timer interrupt gets + asserted. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @param ticks + Number of ticks after which interrupt will be generated. + + @return + This function returns Mi-V Timer configuration status. + */ +static inline uint32_t +MIV_TIMER_config +( + miv_timer_instance_t* this_timer, + uint64_t ticks +) +{ + uint32_t ret_val = MIV_TIMER_ERROR; + uint64_t mtime_val = 0u; + uint32_t prescalar = 0u; + uint64_t miv_timer_increment = 0U; + + prescalar = HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_PRESCALAR); + + miv_timer_increment = (uint64_t)(ticks) / prescalar; + + if (miv_timer_increment > 0U) + { + mtime_val = MIV_TIMER_read_current_time(this_timer); + + MIV_TIMER_write_compare_time(this_timer ,(mtime_val + miv_timer_increment)); + + ret_val = MIV_TIMER_SUCCESS; + } + + return ret_val; +} + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_TIMER_H */ diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c new file mode 100644 index 0000000..cbd9652 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c @@ -0,0 +1,109 @@ +/******************************************************************************* + * (c) Copyright 2022-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Mi-V uDMA Soft IP bare-metal driver. This module is delivered as part of + * Mi-V Extended Sub System(MIV_ESS) + */ + +#include "miv_udma_regs.h" +#include "miv_udma.h" + +/***************************************************************************//** + * MIV_uDMA_init() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_init +( + miv_udma_instance_t* this_udma, + addr_t base_addr +) +{ + /* Assign the Mi-V uDMA base address to the uDMA instance structure */ + this_udma->base_address = base_addr; +} + +/***************************************************************************//** + * MIV_uDMA_config() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_config +( + miv_udma_instance_t* this_udma, + addr_t src_addr, + addr_t dest_addr, + uint32_t transfer_size, + uint32_t irq_config +) +{ + /* Source memory start address */ + HAL_set_32bit_reg(this_udma->base_address, SRC_START_ADDR, src_addr); + + /* Destination memory start address */ + HAL_set_32bit_reg(this_udma->base_address, DEST_START_ADDR, dest_addr); + + /* Data transfer size */ + HAL_set_32bit_reg(this_udma->base_address, BLK_SIZE, transfer_size); + + /* Configure the uDMA IRQ */ + HAL_set_32bit_reg(this_udma->base_address, IRQ_CFG, irq_config); +} + +/***************************************************************************//** + * MIV_uDMA_start() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_start +( + miv_udma_instance_t* this_udma +) +{ + /* Start the uDMA transfer */ + HAL_set_32bit_reg(this_udma->base_address, CONTROL_SR, CTRL_START_TX_MASK); +} + +/***************************************************************************//** + * MIV_uDMA_reset() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_reset +( + miv_udma_instance_t* this_udma +) +{ + /* Toggle the uDMA_reset bit to reset the uDMA. + * Resetting the uDMA will clear all the configuration made by + * MIV_uDMA_config(). + * + * This function should be called from the interrupt handler to clear the + * IRQ. + */ + HAL_set_32bit_reg_field(this_udma->base_address, CTRL_RESET_TX, 0x1u); + HAL_set_32bit_reg_field(this_udma->base_address, CTRL_RESET_TX, 0x0u); +} + +/***************************************************************************//** + * MIV_uDMA_read_status() + * See "miv_udma.h" for details of how to use this function. + */ +uint32_t +MIV_uDMA_read_status +( + miv_udma_instance_t* this_udma +) +{ + uint32_t status = 0u; + + /* Read the status of the uDMA transfer. + * The transfer status register can be Error or Busy depending on the + * current uDMA transfer. + */ + status = HAL_get_32bit_reg(this_udma->base_address, TX_STATUS); + + return status; +} diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h new file mode 100644 index 0000000..efa8731 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h @@ -0,0 +1,290 @@ +/******************************************************************************* + * Copyright 2022-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * uDMA module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(MIV_ESS). + */ + +/*=========================================================================*//** + @mainpage Mi-V uDMA Bare Metal Driver. + The Mi-V uDMA bare metal software driver. + + @section intro_sec Introduction + The Mi-V uDMA driver provides a set of functions to control the Mi-V uDMA + module in the Mi-V Extended Subsystem (MIV_ESS) soft-IP. The Mi-V uDMA module + allows peripherals with AHB interfaces to transfer data independently of the + MIV_RV32 RISC-V processor. + + Following are the major features provided by the Mi-V uDMA driver: + - Initialization and configuration + - Start and reset the transaction + + This driver can be used as part of a bare metal system where no operating + system is available. The driver can be adapted for use as part of an + operating system, but the implementation of the adaptation layer between the + driver and the operating system's driver model is outside the scope of this + driver. + + @section hw_dependencies Hardware Flow Dependency + The application software should initialize and configure the Mi-V uDMA through + calling the MIV_uDMA_init() and MIV_uDMA_config() functions for each Mi-V + uDMA instance in the design. + + The uDMA can operate in two possible transfer configurations: + + - AHBL Read -> AHBL Write: + In this configuration, the uDMA reads data from the source memory over an + AHBL (mirrored main/initiator) read interface and writes data to the + destination memory over an AHBL (mirrored main/initiator) write interface. + + - AHBL Read -> TAS Write: + In this configuration, the uDMA reads data from the source memory over an + AHBL (mirrored main/initiator) read interface and writes data to the + destination memory over the TAS (mirrored main/initiator) write interface. + + Note: The AHBL Read -> TAS Write configuration is out of scope for this + driver. + + @section theory_op Theory of Operation + The uDMA module in the Mi-V Extended Sub System (MIV_ESS) is a single-channel + uDMA module that allows peripherals to perform read-write operations between + source and destination memory. The Mi-V uDMA driver is used in + interrupt-driven mode and uses the Mi-V uDMA IRQ signal to drive the + interrupt service routine (ISR), which signifies a transfer has completed. + The status is checked in the ISR to ensure the transfer is completed + successfully. + The reset operation in the ISR resets the Mi-V uDMA controller. Once the Mi-V + uDMA transfer is complete, Mi-V uDMA retires. To initiate another + transaction, Mi-V uDMA needs to be configured again. + + The operation of the Mi-V uDMA driver is divided into the following + categories: + - Initialization + - Configuration + - Start and reset the transfer + + Initialization and configuration: + Mi-V uDMA is first initialized by calling MIV_uDMA_init() function. This + function initializes the instance of Mi-V uDMA with the base address. The + MIV_uDMA_init() function must be called before calling any other Mi-V uDMA + driver functions. + + The Mi-V uDMA is configured by calling MIV_uDMA_config() function. This + function configures the source_addr and dest_addr registers of the Mi-V + uDMA with source and destination addresses for Mi-V uDMA transfers. + This function also configures the transfer size and interrupt preference for + successful transfers using Mi-V uDMA. + + Start and reset the transfer: + Once the Mi-V uDMA is configured, initiate the transfers by calling the + MIV_uDMA_start() function. Once the Mi-V uDMA transfer is started, it cannot + be aborted, and the status of the transfer should be read from the ISR by + calling the MIV_uDMA_read_status() function. + + Reset the Mi-V uDMA to the default state by calling the MIV_uDMA_reset() + function. After performing the reset operation, reconfigure the Mi-V uDMA to + perform transfers as MIV_uDMA_reset() resets the Mi-V uDMA controller. + */ + +#ifndef MIV_uDMA_H_ +#define MIV_uDMA_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#include "hal/cpu_types.h" + +#else +#include "hal.h" +#include "cpu_types.h" +#endif + +/*-------------------------------------------------------------------------*//** + MIV_uDMA_CTRL_IRQ_CONFIG + ===================== + + The MIV_uDMA_CTRL_IRQ_CONFIG macro is used to assert the uDMA IRQ when an error + occurs during a uDMA transfer or on the completion of a uDMA transfer. + */ +#define MIV_uDMA_CTRL_IRQ_CONFIG 1u + +/*-------------------------------------------------------------------------*//** + MIV_uDMA_STATUS_BUSY + ===================== + + The MIV_uDMA_STATUS_BUSY macro is used to indicate that the uDMA transfer is + in progress. + */ +#define MIV_uDMA_STATUS_BUSY 1u + +/*-------------------------------------------------------------------------*//** + MIV_uDMA_STATUS_ERROR + ===================== + + The MIV_uDMA_STATUS_ERROR macro is used to indicate that the last uDMA + transfer has caused an error. + */ +#define MIV_uDMA_STATUS_ERROR 2u + +/***************************************************************************//** + * This structure holds the base of the Mi-V uDMA module, which is used in the + * other functions of the driver to access the uDMA registers. + */ +typedef struct miv_udma_instance +{ + addr_t base_address; +} miv_udma_instance_t; + +/***************************************************************************//** + * The MIV_uDMA_init() function assigns the base address of the Mi-V uDMA module + * to the uDMA instance structure. + * This address is used in a later part of the driver to access the uDMA + * registers. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure. + * + * @param base_addr + * Base address of the Mi-V uDMA module. + * + * @return + * This function does not return a value. + */ +void +MIV_uDMA_init +( + miv_udma_instance_t* this_udma, + addr_t base_addr +); + +/***************************************************************************//** + * The MIV_uDMA_config() function is used to configure the Mi-V uDMA controller. + * This function will set the source address, destination address, block size, + * and IRQ configuration register. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @param base_addr + * Base address of the Mi-V uDMA. + * + * @param src_addr + * Source address of memory from where the uDMA reads the data. + * + * @param dest_addr + * Destination address where the data is written from src_addr. + * + * @param transfer_size + * Number of 32-bit words to transfer. + * + * @param irq_config + * uDMA IRQ configuration + * - When set, the IRQ is asserted when an error occurs during a uDMA + * transfer or on the completion of the uDMA transfer. + * - When clear, the IRQ is only asserted when an error occurs during a + * uDMA transfer. + * + * @return + * This function does not return any value. + */ +void +MIV_uDMA_config +( + miv_udma_instance_t* this_udma, + addr_t src_addr, + addr_t dest_addr, + uint32_t transfer_size, + uint32_t irq_config +); + +/***************************************************************************//** + * The MIV_uDMA_start() function is used to start the uDMA transfer. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @return + * This function does not return any value. + */ +void +MIV_uDMA_start +( + miv_udma_instance_t* this_udma +); + +/***************************************************************************//** + * The MIV_uDMA_reset() function is used to clear the uDMA interrupt and reset + * the uDMA transfer. + * + * This function should be called from the interrupt handler to reset the values + * set during MIV_uDMA_config(). + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @return + * This function does not return any value. + */ +void +MIV_uDMA_reset +( + miv_udma_instance_t* this_udma +); + +/***************************************************************************//** + * The MIV_uDMA_read_status() function is used to read the status of the uDMA + * transfer. When interrupt is enabled, this function can be called from the + * interrupt handler to know the reason for a uDMA interrupt. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @return + * The return value indicates an error due to the busy status of the uDMA + * channel. + * + * |Bit Number| Name | Description | + * |----------|---------|------------------------------------------------------| + * | 0 | Busy | When set indicates that uDMA transfer is in progress| + * | 1 | Error | When set indicates that last uDMA transfer caused an| + * | | | error. | + */ +uint32_t +MIV_uDMA_read_status +( + miv_udma_instance_t* this_pdma +); + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_uDMA_H_ */ diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h new file mode 100644 index 0000000..14d0759 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h @@ -0,0 +1,94 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP uDMA module driver. This module is delivered as a part of Mi-V + * extended Sub-System(ESS) MIV_ESS. + */ + +#ifndef MIV_UDMA_APB_REGISTERS +#define MIV_UDMA_APB_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/**************************************************************************//** + * Control start/Reset register details + */ + +#define CONTROL_SR_REG_OFFSET 0x0u + +/* Control start/Reset register bits */ +#define CONTROL_SR_OFFSET 0x00u +#define CONTROL_SR_MASK 0x03u +#define CONTROL_SR_SHIFT 0u + +/* uDMA Control Start Transfer */ + +#define CTRL_START_TX_OFFSET 0x00u +#define CTRL_START_TX_MASK 0x01u +#define CTRL_START_TX_SHIFT 0u + +/* uDMA Control Reset Transfer */ +#define CTRL_RESET_TX_OFFSET 0x00u +#define CTRL_RESET_TX_MASK 0x02u +#define CTRL_RESET_TX_SHIFT 1u + +/**************************************************************************//** + * IRQ Configuration register details + */ +#define IRQ_CFG_REG_OFFSET 0x4u + +/* Control start/Reset register bits */ +#define IRQ_CFG_OFFSET 0x04u +#define IRQ_CFG_MASK 0x01u +#define IRQ_CFG_SHIFT 0u + +/***************************************************************************//** + * Transfer Status register details + */ +#define TX_STATUS_REG_OFFSET 0x08u + +/* Transfer status register bits */ +#define TX_STATUS_OFFSET 0x08u +#define TX_STATUS_MASK 0x03u +#define TX_STATUS_SHIFT 0u + +/***************************************************************************//** + * Source Memory Start Address Register + */ +#define SRC_START_ADDR_REG_OFFSET 0x0cu + +/* Source Memory Start Address Register bits */ +#define SRC_START_ADDR_OFFSET 0x0cu +#define SRC_START_ADDR_MASK 0xFFFFFFFFu +#define SRC_START_ADDR_SHIFT 0u + +/***************************************************************************//** + * Destination Memory Start Address register details + */ +#define DEST_START_ADDR_REG_OFFSET 0x10u + +/* Destination Memory Start Address register bits */ +#define DEST_START_ADDR_OFFSET 0x10u +#define DEST_START_ADDR_MASK 0xFFFFFFFFu +#define DEST_START_ADDR_SHIFT 0x0u + +/***************************************************************************//** + * Block Size register details + */ +#define BLK_SIZE_REG_OFFSET 0x14u + +/* Destination Memory Start Address register bits */ +#define BLK_SIZE_OFFSET 0x14u +#define BLK_SIZE_MASK 0xFFFFFFFFu +#define BLK_SIZE_SHIFT 0x0u + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_UDMA_APB_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c new file mode 100644 index 0000000..525928a --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Mi-V Watchdog Soft IP bare-metal driver. This module is delivered as part of + * Extended Sub System(ESS) MIV_ESS. + * Please refer to miv_watchdog.h file for more information. + */ + +#include "miv_watchdog.h" + +addr_t g_this_wdog; + +/***************************************************************************//* + * Please refer to miv_watchdog.h for more info about this function + */ +void +MIV_WDOG_init +( + addr_t base_addr +) +{ + /* Register the Mi-V Watchdog base address to the driver */ + g_this_wdog = base_addr; +} + +/***************************************************************************//* + * Please refer to miv_watchdog.h for more info about this function + */ +uint8_t MIV_WDOG_configure +( + const miv_wdog_config_t *config +) +{ + uint8_t error = 0u; + + /* check load value and trigger max value */ + if (config->timeout_val <= MIV_WDOG_TRIGGER_MAX) + { + HAL_set_32bit_reg(g_this_wdog, WDOGTRIG,(config->timeout_val)); + } + else + { + error = 1u; + } + + if (config->time_val <= MIV_WDOG_TIMER_MAX) + { + HAL_set_32bit_reg(g_this_wdog, WDOGMSVP,(config->mvrp_val)); + } + else + { + error = 1u; + } + + HAL_set_32bit_reg_field(g_this_wdog, WDOGCNTL_NEXT_ENFORBIDDEN, + config->forbidden_en); + + /* Reload watchdog with new load if it is not in forbidden window */ + if (!(WDOGSTAT_FORBIDDEN_MASK & (HAL_get_32bit_reg(g_this_wdog, WDOGSTAT)))) + { + HAL_set_32bit_reg(g_this_wdog, WDOGRFSH, MIV_WDOG_REFRESH_KEY); + } + else + { + error = 1u; + } + + return (error); +} + +/***************************************************************************//* + * Please refer to miv_watchdog.h for more info about this function + */ +void MIV_WDOG_get_config +( + miv_wdog_config_t *config +) +{ + if (0 != g_this_wdog) + { + + config->time_val = HAL_get_32bit_reg(g_this_wdog, WDOGTIME); + + config->timeout_val = HAL_get_32bit_reg(g_this_wdog, WDOGTRIG); + + config->mvrp_val = HAL_get_32bit_reg(g_this_wdog, WDOGMSVP); + + config->forbidden_en = HAL_get_32bit_reg_field(g_this_wdog, + WDOGCNTL_NEXT_ENFORBIDDEN); + } +} + diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h new file mode 100644 index 0000000..8877e55 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h @@ -0,0 +1,553 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * Watchdog module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(MIV_ESS). + */ +/*=========================================================================*//** + @mainpage MiV Watchdog Bare Metal Driver + + ============================================================================== + Introduction + ============================================================================== + The Mi-V Watchdog module in the MIV_ESS is used to generate a reset for the + system automatically if the software doesn't periodically update or refresh + the timer countdown register. This software driver provides set of functions + for controlling Mi-V Watchdog module as a part of bare metal system where no + operating system is available. The driver can be adapted for use as a part of + an operating system, but the implementation of the adaptation layer between + the driver and the operating system's driver model is outside the scope of the + driver. + + Mi-V Watchdog provides following features: + - Initializing the Mi-V Watchdog + - Reading current value and status of watchdog timer + - Refreshing the watchdog timer value + - Enabling, disabling and clearing timeout and Maximum Value up to which + Refresh is Permitted (MVRP) interrupts. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + The application software should initialize and configure the Mi-V Watchdog + module the the call to the MIV_WDOG_init() and MIV_WDOG_configure() functions. + + No MIV_WDOG hardware configuration parameter are used by the driver, apart + from the MIV_WDOG base address. Hence, no additional configuration files are + required to use the driver. + + ============================================================================== + Theory of Operation + ============================================================================== + The Mi-V Watchdog driver functions are grouped into the following categories: + - Initialization and configuration + - Reading the current value and status of the watchdog timer + - Refreshing the watchdog timer value + - Support for enabling, disabling and clearing time-out and MVRP interrupts. + + -------------------------------- + Initialization and Configuration + -------------------------------- + The MIV_WDOG_init() function stores the base of MIV_WDT module in the MIV_ESS. + This base address is used by rest of the functions to access the Mi-V Watchdog + registers. Please make call this function before calling any other function + from this driver. + Note: The Mi-V Watchdog driver supports only one instance of MIV_WDT in the + hardware. + The Mi-V Watchdog driver provides the MIV_WDOG_configure() function to + configure the MIV_WDOG module with desired configuration values. It also + provides the MIV_WDOG_get_config() to read back the current configuration of + the MIV_WDOG. You can use this function to retrieve the current configurations + and then overwrite them with the application specific values, such as initial + watchdog timer value, Maximum Value (up to which) Refresh (is) Permitted, + watchdog time-out value, enable/disable forbidden region, enable/disable + MVRP interrupt and interrupt type. + + -------------------------------------------- + Reading the Watchdog Timer Value and Status + -------------------------------------------- + Mi-V Watchdog is a down counter. A refresh forbidden window can be created by + configuring the watchdog Maximum Value up to which Refresh is Permitted (MVRP). + When the current value of the watchdog timer is greater than the MVRP value, + refreshing the watchdog is forbidden. Attempting to refresh the watchdog timer + in the forbidden window will assert a timeout interrupt. The + MIV_WDOG_forbidden_status() function can be used to know whether the watchdog + timer is in forbidden window or has crossed it. By default, the forbidden + window is disabled. It can be enabled by providing an appropriate value as + parameter to the MIV_WDOG_configure() function. When the forbidden window is + disabled, any attempt to refresh the watchdog timer is ignored and the counter + keeps on down counting. + + The current value of the watchdog timer can be read using the + MIV_WDOG_current_value() function. This function can be called at any time. + + -------------------------------------------- + Refreshing the Watchdog Timer Value + -------------------------------------------- + The watchdog timer value is refreshed using the MIV_WDOG_reload() function. + The value reloaded into the watchdog timer down-counter is specified at the + configuration time with an appropriate value as parameter to the + MIV_WDOG_get_config() function. + + -------------------------------------------- + Interrupt Control + -------------------------------------------- + The Mi-V Watchdog generates two interrupts, The MVRP interrupt and + the timeout interrupt. + The MVRP interrupt is generated when the watchdog down-counter crosses the + Maximum Value up to which Refresh is Permitted (MVRP). Following functions to + control MVRP interrupt: + - MIV_WDOG_enable_mvrp_irq + - MIV_WDOG_disable_mvrp_irq + - MIV_WDOG_clear_mvrp_irq + + The timeout interrupt is generated when the watchdog down-counter crosses the + watchdog timeout value. The timeout value is a non-zero value and it can be + set to a maximum of MIV_WDOG_TRIGGER_MAX. The non-maskable interrupt is + generated when the watchdog crosses this timeout value, the down counter + keeps on down counting and a reset signal is generated when reaches zero. + Following functions to control timeout interrupt: + - MIV_WDOG_enable_timeout_irq + - MIV_WDOG_disable_timeout_irq + - MIV_WDOG_clear_timeout_irq + +*//*=========================================================================*/ + +#ifndef MIV_WATCHDOG_H_ +#define MIV_WATCHDOG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "miv_watchdog_regs.h" + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#else +#include "hal.h" +#endif + +/****************************************************************************//* + * The following constants can be used to configure the Mi-V Watchdog where a + * zero or non-zero value such as enable or disable is to be provided as a input + * parameter as shown below: + */ +#define MIV_WDOG_ENABLE 1u +#define MIV_WDOG_DISABLE 0u + +/***************************************************************************//** + The miv_wdog_config_t type for the watchdog Configuration structure. This + type is used as a parameter for the MIV_WDOG_configure() and the + MIV_WDOG_get_config() functions. + + Following are the values as part of this structure +| Parameter | Description | +|------------------|-----------------------------------------------------------| +| time_val | The value from which the watchdog timer counts down | +| mvrp_val | The Watchdog MVRP value | +| timeout_val | The watchdog timeout value | +| forbidden_en | Enable/disable the forbidden window | +| | When set, if a refresh occurs in the forbidden window, | +| | the watchdog timeout interrupt will be generated. | + +Time calculation example: + + time_val = 0xFFFFF0u + mvrp_val = 0x989680u + timeout_val = 0x3e8u + + A prescaler = 256 is used. + Considering clock = 50Mhz + + The MVRP interrupt will happen after + (0xFFFFF0 - 0x989680) * ( 1/(50MHz/256)) + mvrp interrupt will happen after 34 sec. after system reset + + (0xFFFFF0 - 0x3e8) * ( 1/(50MHz/256)) + timeout interrupt will happen after 85 sec. after system reset + */ +typedef struct miv_wdog_config +{ + uint32_t time_val; + uint32_t mvrp_val; + uint32_t timeout_val; + uint32_t forbidden_en; + uint32_t intr_type; +}miv_wdog_config_t; + +extern addr_t g_this_wdog; + +/***************************************************************************//* + Internal constants and types +*******************************************************************************/ + +/// @cond private +#define MIV_WDOG_TRIGGER_MAX 4095u +#define MIV_WDOG_TIMER_MAX 16777200u +/// @endcond + +/*-------------------------------------------------------------------------*//* +MIV_WDOG_REFRESH_KEY +===================== + +The MIV_WDOG_REFRESH_KEY macro holds the magic value which will cause a +reload of the watchdog's down counter when written to the watchdog's +WDOGREFRESH register. +*/ +#define MIV_WDOG_REFRESH_KEY (uint32_t)0xDEADC0DEU + +/*-------------------------------------------------------------------------*//* +MIV_WDOG_FORCE_RESET_KEY +===================== +The MIV_WDOG_FORCE_RESET_KEY macro holds the magic value which will force a +reset if the watchdog is already timeout. Writing any other value or writing +TRIGGER register at other times will trigger the watchdog NMI sequence +(i.e raise a timeout interrupt) + */ +#define MIV_WDOG_FORCE_RESET_KEY (uint32_t)0xDEADU + +/***************************************************************************//** + * The MIV_WDOG_init() is used to register the Mi-V Watchdog module base + * address to the driver. + * + * Note: User should call this function before calling any other Mi-V watchdog + * driver function. + * + * @param base_addr + * The base address of the Mi-V watchdog module. This address is used by + * rest of the watchdog driver functions to access the registers. + * + * @return + * This function does not return any value. + */ +void +MIV_WDOG_init +( + addr_t base_addr +); + +/***************************************************************************//** + * The MIV_WDOG_get_config() function returns the current configurations of the + * Mi-V Watchdog. The Mi-V Watchdog is pre-initialized by the flash + * bits at the design time. When used for the first time before calling the + * MIV_WDOG_configure() function, this function will return the default + * configurations as configured at the design time. + * + * @param config + * The config parameter is used to store the current configuration of the Mi-V + * Watchdog. + * + * Please see the description of miv_wdog_config_t for details. + * + * @return + * This function does not return any value. + * + * Example: + */ +void +MIV_WDOG_get_config +( + miv_wdog_config_t* config +); + +/***************************************************************************//** + * The MIV_WDOG_configure() function configures the watchdog module. The + * Watchdog module is pre-initialized by the flash bits at the design time to the + * default values. You can reconfigure the Watchdog module using + * MIV_WDOG_configure() function. + * + * Note that the MIV_WDOG_configure() function can be used only once, as it + * writes into the TIME register. After a write into the TIME register, the TIME, + * TRIGGER and MSVP register values are frozen and can't be altered again unless + * a system reset happens. + * + * Note also that the Mi-V Watchdog is not enabled at reset, calling this function + * will start the watchdog, it cannot then be disabled and must be refreshed + * periodically. + * + * @param config + * The config parameter is the input parameter in which the configurations to + * be applied to the watchdog module are provided by the application. + * Please see the description of miv_wdog_config_t for details. + * + * @return + * This function returns a zero value when executed successfully. A non-zero + * value is returned when the configuration values are out of bound. + * + * Example: + */ +uint8_t +MIV_WDOG_configure +( + const miv_wdog_config_t * config +); + +/***************************************************************************//** + * The MIV_WDOG_reload() function causes the watchdog to reload its down-counter + * timer with the load value configured through interrupt handler. This function + * must be called regularly to avoid a system reset or a watchdog interrupt. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_reload +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg(g_this_wdog, WDOGRFSH, MIV_WDOG_REFRESH_KEY); + } +} + +/***************************************************************************//** + * The MIV_WDOG_current_value() function returns the current value of the + * watchdog's down-counter. + * + * @param + * Void + * + * @return + * This function returns the current value of the watchdog’s down-counter as + * a 32-bit unsigned integer. + */ +static inline uint32_t +MIV_WDOG_current_value +( + void +) +{ + return (HAL_get_32bit_reg(g_this_wdog, WDOGRFSH)); +} + +/***************************************************************************//** + * The MIV_WDOG_forbidden_status() function returns the refresh status of the + * Mi-V Watchdog. + * + * @param + * Void + * + * @return + * This function returns the refresh status of the watchdog. A value of 1 + * indicates that watchdog's down-counter is within the forbidden window and + * that a reload should not be done. A value of 0 indicates that the watchdog's + * down counter is within the permitted window and that a reload is allowed. + */ +static inline uint32_t +MIV_WDOG_forbidden_status +( + void +) +{ + return (HAL_get_32bit_reg_field(g_this_wdog, WDOGSTAT_FORBIDDEN)); +} + +/***************************************************************************//** + * The MIV_WDOG_enable_mvrp_irq() function enables the MVRP interrupt. + * This interrupt is asserted when the timer countdown register leaves the + * maximum value up to which refresh is permitted (MVRP) window. + * + * @param + * Void + * + * @return + * This function does not return a value. + * + * Example: + */ +static inline void +MIV_WDOG_enable_mvrp_irq +( + void +) +{ + + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGCNTL_NEXT_INTENT_MSVP, 0x01u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_disable_mvrp_irq() function disables the generation of the + * MVRP interrupt. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_disable_mvrp_irq +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGCNTL_NEXT_INTENT_MSVP, 0x0u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_clear_timeout_irq() function clears the watchdog’s timeout + * interrupt which is connected to the MIV-RV32 interrupt. Calling + * MIV_WDOG_clear_timeout_irq() results in clearing the MIV-RV32 interrupt. + * Note: You must call the MIV_WDOG_clear_timeout_irq() function as part of your + * implementation of the interrupt handler in order to prevent the same + * interrupt event re-triggering a call to the timeout ISR. + * + * @param + * Void + * + * @return + * This function does not return any value. + * + */ +static inline void +MIV_WDOG_clear_timeout_irq +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_WDOG_TRIPPED, 0x01u); + /* + * Perform a second write to ensure that the first write completed before + * returning from this function. This is to account for posted writes across + * the AHB matrix. The second write ensures that the first write has + * completed and that the interrupt line has been de-asserted by the time + * the function returns. Omitting the second write may result in a delay + * in the de-assertion of the interrupt line going to the RISC-V and a + * retriggering of the interrupt. + */ + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_WDOG_TRIPPED, 0x01u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_clear_mvrp_irq() function clears the mvrp interrupt. + * + * Note: You must call the MIV_WDOG_clear_mvrp_irq() function as part of your + * implementation of the interrupt service routine (ISR) in order to + * prevent the same interrupt event re-triggering a call to the mvrp ISR. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_clear_mvrp_irq +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_MSVP_TRIPPED, 0x01u); + /* + * Perform a second write to ensure that the first write completed before + * returning from this function. This is to account for posted writes across + * the AHB matrix. The second write ensures that the first write has + * completed and that the interrupt line has been de-asserted by the time + * the function returns. Omitting the second write may result in a delay + * in the de-assertion of the interrupt line going to the RISC-V and a + * re-triggering of the interrupt. + */ + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_MSVP_TRIPPED, 0x01u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_timeout_occured() function reports the occurrence of a timeout + * event. + * + * @param + * Void + * + * @return + * A zero value indicates no watchdog timeout event occurred. A value of 1 + * indicates that a timeout event occurred. + */ +static inline uint32_t +MIV_WDOG_timeout_occured +( + void +) +{ + return (HAL_get_32bit_reg_field(g_this_wdog, WDOGSTAT_TRIGGERED)); +} + +/***************************************************************************//** + * The MIV_WDOG_force_reset() function is used to force an immediate reset + * if the watchdog has already triggered. Writing any value in this condition + * will result in watchdog timeout. + * The time out interrupt WDOG_IRQ will be set to high and watchdog timer + * countdown register updated with watchdog trigger timeout register value. + * If the Watchdog has timed out, a special 16-bit value needs to be written + * to the register to force a reset on CPU_RESETN, 0xDEAD + * Then the Watchdog countdown is reset/updated with the top Watchdog Runtime + * register value. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_force_reset +( + void +) +{ + if (WDOGSTAT_TRIGGERED_MASK == + HAL_get_32bit_reg_field(g_this_wdog, WDOGSTAT_TRIGGERED)) + + { + HAL_set_32bit_reg(g_this_wdog, WDOGFORCE, MIV_WDOG_FORCE_RESET_KEY); + } + + else + { + HAL_set_32bit_reg(g_this_wdog, WDOGFORCE, 0x0u); + } +} + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_WATCHDOG_H_ */ diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h new file mode 100644 index 0000000..2fca983 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h @@ -0,0 +1,122 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP watchdog module driver. This module is delivered as a part of Mi-V + * extended Sub-System(ESS) MIV_ESS. + */ + +#ifndef MIV_WDOG_REGISTERS +#define MIV_WDOG_REGISTERS 1u + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * Refresh register details + */ +#define WDOGRFSH_REG_OFFSET 0x00u + +/* Refresh register bits */ +#define WDOGRFSH_OFFSET 0x00u +#define WDOGRFSH_MASK 0xFFFFFFFFu +#define WDOGRFSH_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Control register details + */ +#define WDOGCNTL_REG_OFFSET 0x04u + +/* Control register next intent msvp bit */ +#define WDOGCNTL_NEXT_INTENT_MSVP_OFFSET 0x04u +#define WDOGCNTL_NEXT_INTENT_MSVP_MASK 0x01u +#define WDOGCNTL_NEXT_INTENT_MSVP_SHIFT 0u + +/* Control register next intent wdog bit */ +#define WDOGCNTL_NEXT_INTENT_WDOG_OFFSET 0x04u +#define WDOGCNTL_NEXT_INTENT_WDOG_MASK 0x02u +#define WDOGCNTL_NEXT_INTENT_WDOG_SHIFT 1u + +/* Control register next enforbidden bit */ +#define WDOGCNTL_NEXT_ENFORBIDDEN_OFFSET 0x04u +#define WDOGCNTL_NEXT_ENFORBIDDEN_MASK 0x10u +#define WDOGCNTL_NEXT_ENFORBIDDEN_SHIFT 4u + +/*------------------------------------------------------------------------------ + * Watchdog status register + */ +#define WDOGSTAT_REG_OFFSET 0x08u + +/* msvp_tripped bit */ +#define WDOGSTAT_MSVP_TRIPPED_OFFSET 0x08u +#define WDOGSTAT_MSVP_TRIPPED_MASK 0x01u +#define WDOGSTAT_MSVP_TRIPPED_SHIFT 0u + +/* WDOG Tripped bit */ +#define WDOGSTAT_WDOG_TRIPPED_OFFSET 0x08u +#define WDOGSTAT_WDOG_TRIPPED_MASK 0x02u +#define WDOGSTAT_WDOG_TRIPPED_SHIFT 1u + +/* Forbidden bit */ +#define WDOGSTAT_FORBIDDEN_OFFSET 0x08u +#define WDOGSTAT_FORBIDDEN_MASK 0x04u +#define WDOGSTAT_FORBIDDEN_SHIFT 2u + +/* Triggered bit */ +#define WDOGSTAT_TRIGGERED_OFFSET 0x08u +#define WDOGSTAT_TRIGGERED_MASK 0x08u +#define WDOGSTAT_TRIGGERED_SHIFT 3u + +/* wdoglocked bit */ +#define WDOGSTAT_WDOGLOCKED_OFFSET 0x08u +#define WDOGSTAT_WDOGLOCKED_MASK 0x10u +#define WDOGSTAT_WDOGLOCKED_SHIFT 4u + +/*------------------------------------------------------------------------------ + * Watchdog runtime register + */ +#define WDOGTIME_REG_OFFSET 0x0Cu + +/* wdogmsvp bit */ +#define WDOGTIME_WDOGVALUE_OFFSET 0x0Cu +#define WDOGTIME_WDOGVALUE_MASK 0xFFFFFFu +#define WDOGTIME_WDOGVALUE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Watchdog MVRP register + */ +#define WDOGMSVP_REG_OFFSET 0x10u + +/* wdogmsvp bit */ +#define WDOGMSVP_OFFSET 0x10u +#define WDOGMSVP_MASK 0xFFFFFFu +#define WDOGMSVP_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Watchdog Trigger Timeout register + */ +#define WDOGTRIG_REG_OFFSET 0x14u + +/* wdogmsvp bit */ +#define WDOGTRIG_WDOGRST_OFFSET 0x14u +#define WDOGTRIG_WDOGRST_MASK 0xFFFFFFu +#define WDOGTRIG_WDOGRST_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Watchdog Force Reset register details + */ +#define WDOGFORCE_REG_OFFSET 0x18u + +/* Refresh register bits */ +#define WDOGFORCE_OFFSET 0x18u +#define WDOGFORCE_MASK 0xFFFFFFFFu +#define WDOGFORCE_SHIFT 0u + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_WATCHDOG_REGS_H_ */ diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/hal/cpu_types.h b/applications/user-crypto/miv-rv32-dsa-services/src/platform/hal/cpu_types.h new file mode 100755 index 0000000..ef8ab20 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/hal/cpu_types.h @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file cpu_types.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Type definitions which can be commonly used by the fabric-ip drivers. + * + */ +#ifndef __CPU_TYPES_H +#define __CPU_TYPES_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned int size_t; + +/*------------------------------------------------------------------------------ + * addr_t: address type. + * Used to specify the address of peripherals present in the processor's memory + * map. + */ +typedef unsigned int addr_t; + +/*------------------------------------------------------------------------------ + * psr_t: processor state register. + * Used by HAL_disable_interrupts() and HAL_restore_interrupts() to store the + * processor's state between disabling and restoring interrupts. + */ +typedef unsigned int psr_t; + +#ifdef __cplusplus +} +#endif + +#endif /* CPU_TYPES_H */ + diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/hal/hal.h b/applications/user-crypto/miv-rv32-dsa-services/src/platform/hal/hal.h new file mode 100755 index 0000000..7eec17a --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/hal/hal.h @@ -0,0 +1,235 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file hal.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware abstraction layer functions for peripheral register accesses. + * + */ +#ifndef __HAL_H +#define __HAL_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include "cpu_types.h" +#include "hw_reg_access.h" +#include "hal_assert.h" +/***************************************************************************//** + * Enable all interrupts at the processor level. + */ +void HAL_enable_interrupts( void ); + +/***************************************************************************//** + * Disable all interrupts at the processor core level. + * Return the interrupts enable state before disabling occurred so that it can + * later be restored. + */ +psr_t HAL_disable_interrupts( void ); + +/***************************************************************************//** + * Restore the interrupts enable state at the processor core level. + * This function is normally passed the value returned from a previous call to + * HAL_disable_interrupts(). + */ +void HAL_restore_interrupts( psr_t saved_psr ); + +/***************************************************************************//** + */ +#define FIELD_OFFSET(FIELD_NAME) (FIELD_NAME##_OFFSET) +#define FIELD_SHIFT(FIELD_NAME) (FIELD_NAME##_SHIFT) +#define FIELD_MASK(FIELD_NAME) (FIELD_NAME##_MASK) + +/***************************************************************************//** + * The macro HAL_set_32bit_reg() allows writing a 32 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint32_t containing the value to write. + */ +#define HAL_set_32bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_32bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_32bit_reg() is used to read the value of a 32 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint32_t value. + */ +#define HAL_get_32bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_32bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)) )) + +/***************************************************************************//** + * The macro HAL_set_32bit_reg_field() is used to write a field within a + * 32 bits wide register. The field written can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * VALUE: A variable of type uint32_t containing the field value to write. + */ +#define HAL_set_32bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_32bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_32bit_reg_field() is used to read a register field from + * within a 32 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint32_t value. + */ +#define HAL_get_32bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_32bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +/***************************************************************************//** + * The macro HAL_set_16bit_reg() allows writing a 16 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint_fast16_t containing the value to write. + */ +#define HAL_set_16bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_16bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_16bit_reg() is used to read the value of a 16 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint16_t value. + */ +#define HAL_get_16bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_16bit_reg( (BASE_ADDR) + (REG_NAME##_REG_OFFSET) )) + +/***************************************************************************//** + * The macro HAL_set_16bit_reg_field() is used to write a field within a + * 16 bits wide register. The field written can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * VALUE: A variable of type uint16_t containing the field value to write. + */ +#define HAL_set_16bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_16bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_16bit_reg_field() is used to read a register field from + * within a 8 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint16_t value. + */ +#define HAL_get_16bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_16bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +/***************************************************************************//** + * The macro HAL_set_8bit_reg() allows writing a 8 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint_fast8_t containing the value to write. + */ +#define HAL_set_8bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_8bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_8bit_reg() is used to read the value of a 8 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint8_t value. + */ +#define HAL_get_8bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_8bit_reg( (BASE_ADDR) + (REG_NAME##_REG_OFFSET) )) + +/***************************************************************************//** + */ +#define HAL_set_8bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_8bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_8bit_reg_field() is used to read a register field from + * within a 8 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint8_t value. + */ +#define HAL_get_8bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_8bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +#ifdef __cplusplus +} +#endif + +#endif /*HAL_H*/ + diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/hal/hal_assert.h b/applications/user-crypto/miv-rv32-dsa-services/src/platform/hal/hal_assert.h new file mode 100755 index 0000000..1e18b54 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/hal/hal_assert.h @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hal_assert.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief HAL assert functions + */ +#ifndef __HAL_ASSERT_HEADER +#define __HAL_ASSERT_HEADER 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Disable assertions if we do not recognize the compiler. */ +#if defined ( __GNUC__ ) +#if defined(NDEBUG) +/***************************************************************************//** + * HAL_ASSERT() is defined out when the NDEBUG symbol is used. + ******************************************************************************/ +#define HAL_ASSERT(CHECK) + +#else + +/***************************************************************************//** + * Default behavior for HAL_ASSERT() macro: + *------------------------------------------------------------------------------ + The behavior is toolchain specific and project setting specific. + ******************************************************************************/ +#define HAL_ASSERT(CHECK)\ + do { \ + if (!(CHECK)) \ + { \ + __asm__ volatile ("ebreak"); \ + }\ + } while(0); + +#endif /* NDEBUG */ +#endif /*__GNUC__*/ + +#ifdef __cplusplus +} +#endif +#endif /* __HAL_ASSERT_HEADER */ + diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/hal/hal_irq.c b/applications/user-crypto/miv-rv32-dsa-services/src/platform/hal/hal_irq.c new file mode 100755 index 0000000..95a0775 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/hal/hal_irq.c @@ -0,0 +1,45 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hal_irq.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Legacy interrupt control functions for the Microchip driver library + * hardware abstraction layer. + * + */ +#include "hal.h" +#include "miv_rv32_hal/miv_rv32_hal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * + */ +void HAL_enable_interrupts(void) { + MRV_enable_interrupts(); +} + +/*------------------------------------------------------------------------------ + * + */ +psr_t HAL_disable_interrupts(void) { + psr_t psr; + psr = read_csr(mstatus); + MRV_disable_interrupts(); + return(psr); +} + +/*------------------------------------------------------------------------------ + * + */ +void HAL_restore_interrupts(psr_t saved_psr) { + write_csr(mstatus, saved_psr); +} + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/hal/hw_macros.h b/applications/user-crypto/miv-rv32-dsa-services/src/platform/hal/hw_macros.h new file mode 100755 index 0000000..189609c --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/hal/hw_macros.h @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hw_macros.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware registers access macros. + * + * THE MACROS DEFINED IN THIS FILE ARE DEPRECATED. DO NOT USE FOR NEW + * DEVELOPMENT. + * + * These macros are used to access peripheral registers. They allow access to + * 8, 16 and 32 bit wide registers. All accesses to peripheral registers should + * be done through these macros in order to ease porting across different + * processors/bus architectures. + * + * Some of these macros also allow access to a specific register field. + * + */ +#ifndef __HW_REGISTER_MACROS_H +#define __HW_REGISTER_MACROS_H 1 +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * 32 bits registers access: + */ +#define HW_get_uint32_reg(BASE_ADDR, REG_OFFSET) (*((uint32_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint32_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint32_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint32_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint32_t) \ + ( \ + (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint32_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint32_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 32 bits memory access: + */ +#define HW_get_uint32(BASE_ADDR) (*((uint32_t volatile *)(BASE_ADDR))) + +#define HW_set_uint32(BASE_ADDR, VALUE) (*((uint32_t volatile *)(BASE_ADDR)) = (VALUE)) + +/*------------------------------------------------------------------------------ + * 16 bits registers access: + */ +#define HW_get_uint16_reg(BASE_ADDR, REG_OFFSET) (*((uint16_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint16_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint16_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint16_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint16_t) \ + ( \ + (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint16_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint16_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 8 bits registers access: + */ +#define HW_get_uint8_reg(BASE_ADDR, REG_OFFSET) (*((uint8_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint8_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint8_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint8_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint8_t) \ + ( \ + (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint8_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint8_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 8 bits memory access: + */ +#define HW_get_uint8(BASE_ADDR) (*((uint8_t volatile *)(BASE_ADDR))) + +#define HW_set_uint8(BASE_ADDR, VALUE) (*((uint8_t volatile *)(BASE_ADDR)) = (VALUE)) + +#ifdef __cplusplus +extern "C" { +#endif + +#endif /* __HW_REGISTER_MACROS_H */ + diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/hal/hw_reg_access.S b/applications/user-crypto/miv-rv32-dsa-services/src/platform/hal/hw_reg_access.S new file mode 100755 index 0000000..dd29223 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/hal/hw_reg_access.S @@ -0,0 +1,215 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hw_reg_access.S + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware registers access functions. + * The implementation of these function is platform and toolchain specific. + * The functions declared here are implemented using assembler as part of the + * processor/toolchain specific HAL. This implementation is for the combination + * of the 32 bit RISC-V processors and GNU tool chain. + * + */ + +.section .text + .globl HW_set_32bit_reg + .globl HW_get_32bit_reg + .globl HW_set_32bit_reg_field + .globl HW_get_32bit_reg_field + .globl HW_set_16bit_reg + .globl HW_get_16bit_reg + .globl HW_set_16bit_reg_field + .globl HW_get_16bit_reg_field + .globl HW_set_8bit_reg + .globl HW_get_8bit_reg + .globl HW_set_8bit_reg_field + .globl HW_get_8bit_reg_field + + +/***************************************************************************//** + * HW_set_32bit_reg is used to write the content of a 32 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint32_t value + */ +HW_set_32bit_reg: + sw a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_32bit_reg is used to read the content of a 32 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + + * @return 32 bits value read from the peripheral register. + */ +HW_get_32bit_reg: + lw a0, 0(a0) + ret + +/***************************************************************************//** + * HW_set_32bit_reg_field is used to set the content of a field in a 32 bits + * wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint32_t mask + * a3: uint32_t value + */ +HW_set_32bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lw t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sw t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_32bit_reg_field is used to read the content of a field out of a + * 32 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint32_t mask + * + * @return 32 bits value containing the register field value specified + * as parameter. + */ +HW_get_32bit_reg_field: + lw a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +/***************************************************************************//** + * HW_set_16bit_reg is used to write the content of a 16 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint_fast16_t value + */ +HW_set_16bit_reg: + sh a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_16bit_reg is used to read the content of a 16 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + + * @return 16 bits value read from the peripheral register. + */ +HW_get_16bit_reg: + lh a0, (a0) + ret + +/***************************************************************************//** + * HW_set_16bit_reg_field is used to set the content of a field in a 16 bits + * wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast16_t mask + * a3: uint_fast16_t value + * @param value Value to be written in the specified field. + */ +HW_set_16bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lh t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sh t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_16bit_reg_field is used to read the content of a field from a + * 16 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast16_t mask + * + * @return 16 bits value containing the register field value specified + * as parameter. + */ +HW_get_16bit_reg_field: + lh a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +/***************************************************************************//** + * HW_set_8bit_reg is used to write the content of a 8 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint_fast8_t value + */ +HW_set_8bit_reg: + sb a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_8bit_reg is used to read the content of a 8 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + + * @return 8 bits value read from the peripheral register. + */ +HW_get_8bit_reg: + lb a0, 0(a0) + ret + +/***************************************************************************//** + * HW_set_8bit_reg_field is used to set the content of a field in a 8 bits + * wide peripheral register. + * + * a0: addr_t reg_addr, + * a1: int_fast8_t shift + * a2: uint_fast8_t mask + * a3: uint_fast8_t value + */ +HW_set_8bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lb t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sb t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_8bit_reg_field is used to read the content of a field from a + * 8 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast8_t mask + * + * @return 8 bits value containing the register field value specified + * as parameter. + */ +HW_get_8bit_reg_field: + lb a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +.end diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/hal/hw_reg_access.h b/applications/user-crypto/miv-rv32-dsa-services/src/platform/hal/hw_reg_access.h new file mode 100755 index 0000000..1a24309 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/hal/hw_reg_access.h @@ -0,0 +1,239 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hw_reg_access.S + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware registers access functions. + * The implementation of these function is platform and tool-chain specific. + * The functions declared here are implemented using assembler as part of the + * processor/tool-chain specific HAL. This implementation is for the combination + * of the 32 bit RISC-V processors and GNU tool chain. + * + */ +#ifndef __HW_REG_ACCESS +#define __HW_REG_ACCESS +#ifdef __cplusplus +extern "C" { +#endif + +#include "cpu_types.h" +/***************************************************************************//** + * HW_set_32bit_reg is used to write the content of a 32 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_32bit_reg +( + addr_t reg_addr, + uint32_t value +); + +/***************************************************************************//** + * HW_get_32bit_reg is used to read the content of a 32 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 32 bits value read from the peripheral register. + */ +uint32_t +HW_get_32bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_32bit_reg_field is used to set the content of a field in a 32 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void +HW_set_32bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint32_t mask, + uint32_t value +); + +/***************************************************************************//** + * HW_get_32bit_reg_field is used to read the content of a field out of a + * 32 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 32 bits value containing the register field value specified + * as parameter. + */ +uint32_t +HW_get_32bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint32_t mask +); + +/***************************************************************************//** + * HW_set_16bit_reg is used to write the content of a 16 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_16bit_reg +( + addr_t reg_addr, + uint_fast16_t value +); + +/***************************************************************************//** + * HW_get_16bit_reg is used to read the content of a 16 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 16 bits value read from the peripheral register. + */ +uint16_t +HW_get_16bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_16bit_reg_field is used to set the content of a field in a 16 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void HW_set_16bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast16_t mask, + uint_fast16_t value +); + +/***************************************************************************//** + * HW_get_16bit_reg_field is used to read the content of a field from a + * 16 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 16 bits value containing the register field value specified + * as parameter. + */ +uint16_t HW_get_16bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast16_t mask +); + +/***************************************************************************//** + * HW_set_8bit_reg is used to write the content of a 8 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_8bit_reg +( + addr_t reg_addr, + uint_fast8_t value +); + +/***************************************************************************//** + * HW_get_8bit_reg is used to read the content of a 8 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 8 bits value read from the peripheral register. + */ +uint8_t +HW_get_8bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_8bit_reg_field is used to set the content of a field in a 8 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void HW_set_8bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast8_t mask, + uint_fast8_t value +); + +/***************************************************************************//** + * HW_get_8bit_reg_field is used to read the content of a field from a + * 8 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 8 bits value containing the register field value specified + * as parameter. + */ +uint8_t HW_get_8bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast8_t mask +); + +#ifdef __cplusplus +} +#endif + +#endif /* __HW_REG_ACCESS */ + diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld b/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld new file mode 100644 index 0000000..474eb43 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld @@ -0,0 +1,154 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-execute-in-place.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * image executing from a one address space whereas the data, sdata and stack + * sections are placed in another address space. This could be used in cases such + * as: + * 1) When using MIV_RV32, the reset vector points to the LSRAM at address + * 0x80000000 and the data, sdata, bss and stack sections are placed in the + * TCM region. + * + * 2) Executing from a Non Volatile memory. The actual memory will depend on + * the FPGA platform. For exameple, it could be the eNVM on SmartFusion2, + * Igloo2 or on-board non-volatile memory which supports code execution. + * + * NOTE: Modify the memory section addresses and the sizes according to your + * Libero design. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + + +MEMORY +{ + rom (rx) : ORIGIN = 0x80000000, LENGTH = 16k + ram (rwx) : ORIGIN = 0x80004000, LENGTH = 16k +} + +STACK_SIZE = 1k; /* needs to be calculated for your application */ +HEAP_SIZE = 1k; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > rom + + .text : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.text.entry))) + . = ALIGN(0x10); + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } >rom + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } >ram AT>rom + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } >ram AT>rom + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram +} + diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv-rv32-ram.ld b/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv-rv32-ram.ld new file mode 100755 index 0000000..53076a0 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv-rv32-ram.ld @@ -0,0 +1,150 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-ram.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * debug image executing in SRAM. + * + * This linker script assumes that a RAM is connected at on Mi-V soft processor + * memory space pointed by the reset vector address. + * + * NOTE : Modify the memory section address and the size according to your + * Libero design. + * For example: + * 1) If you want to download and step debug at a different RAM memory address in + * your design (For example TCM base address) than the one provided in this file. + * 2) The MIV_RV32, when used with MIV_ESS IP, provides ways to copy the executable + * HEX file from external Non-Volatile memory into the TCM at reset. In this + * case your executable must be linked to the TCM address. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +MEMORY +{ + ram (rwx) : ORIGIN = 0x80000000, LENGTH = 32k +} + +STACK_SIZE = 2k; /* needs to be calculated for your application */ +HEAP_SIZE = 1k; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > ram + + .text : ALIGN(0x10) + { + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } > ram + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } > ram + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } > ram + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram +} + diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv_rv32_assert.h b/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv_rv32_assert.h new file mode 100644 index 0000000..b3912ed --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv_rv32_assert.h @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * MIV_RV32 HAL Embedded Software + * + */ +#ifndef MIV_RV32_ASSERT_HEADER +#define MIV_RV32_ASSERT_HEADER + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + * ASSERT() implementation. + ******************************************************************************/ +/* Disable assertions if we do not recognize the compiler. */ +#if defined ( __GNUC__ ) +#if defined(NDEBUG) +#define ASSERT(CHECK) +#else +#define ASSERT(CHECK)\ + do { \ + if (!(CHECK)) \ + { \ + __asm__ volatile ("ebreak"); \ + }\ + } while(0); + +#endif /* NDEBUG check */ +#endif /* compiler check */ + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_RV32_ASSERT_HEADER */ + diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv_rv32_entry.S b/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv_rv32_entry.S new file mode 100755 index 0000000..0ea3172 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv_rv32_entry.S @@ -0,0 +1,590 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_entry.S + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor vectors, trap handling and startup code. + * + */ +#ifndef ENTRY_S +#define ENTRY_S + +#define A_EXTENSION_MASK 0x00000001u +#define MTVEC_MODE_BIT_MASK 0x00000003u +#define MTVEC_VECTORED_MODE_VAL 0x00000001u + +#define MTIMEH_ADDR 0x200BFFCu + + +#if __riscv_xlen == 64 +# define LREG ld +# define SREG sd +# define REGBYTES 8 +#else +# define LREG lw +# define SREG sw +# define REGBYTES 4 +#endif + +#if defined(MIV_FP_CONTEXT_SAVE) && defined(__riscv_flen) +#define SP_SHIFT_OFFSET 64 +#else +#define SP_SHIFT_OFFSET 32 +#endif + +.macro STORE_CONTEXT + addi sp, sp, -SP_SHIFT_OFFSET*REGBYTES + SREG x1, 0 * REGBYTES(sp) + SREG x1, 0 * REGBYTES(sp) + SREG x2, 1 * REGBYTES(sp) + SREG x3, 2 * REGBYTES(sp) + SREG x4, 3 * REGBYTES(sp) + SREG x5, 4 * REGBYTES(sp) + SREG x6, 5 * REGBYTES(sp) + SREG x7, 6 * REGBYTES(sp) + SREG x8, 7 * REGBYTES(sp) + SREG x9, 8 * REGBYTES(sp) + SREG x10, 9 * REGBYTES(sp) + SREG x11, 10 * REGBYTES(sp) + SREG x12, 11 * REGBYTES(sp) + SREG x13, 12 * REGBYTES(sp) + SREG x14, 13 * REGBYTES(sp) + SREG x15, 14 * REGBYTES(sp) + SREG x16, 15 * REGBYTES(sp) + SREG x17, 16 * REGBYTES(sp) + SREG x18, 17 * REGBYTES(sp) + SREG x19, 18 * REGBYTES(sp) + SREG x20, 19 * REGBYTES(sp) + SREG x21, 20 * REGBYTES(sp) + SREG x22, 21 * REGBYTES(sp) + SREG x23, 22 * REGBYTES(sp) + SREG x24, 23 * REGBYTES(sp) + SREG x25, 24 * REGBYTES(sp) + SREG x26, 25 * REGBYTES(sp) + SREG x27, 26 * REGBYTES(sp) + SREG x28, 27 * REGBYTES(sp) + SREG x29, 28 * REGBYTES(sp) + SREG x30, 29 * REGBYTES(sp) + SREG x31, 30 * REGBYTES(sp) + + #ifdef __riscv_flen + #ifdef MIV_FP_CONTEXT_SAVE + fsw f0, 31*REGBYTES(sp) + fsw f1, 32*REGBYTES(sp) + fsw f2, 33*REGBYTES(sp) + fsw f3, 34*REGBYTES(sp) + fsw f4, 35*REGBYTES(sp) + fsw f5, 36*REGBYTES(sp) + fsw f6, 37*REGBYTES(sp) + fsw f7, 38*REGBYTES(sp) + fsw f8, 39*REGBYTES(sp) + fsw f9, 40*REGBYTES(sp) + fsw f10, 41*REGBYTES(sp) + fsw f11, 42*REGBYTES(sp) + fsw f12, 43*REGBYTES(sp) + fsw f13, 44*REGBYTES(sp) + fsw f14, 45*REGBYTES(sp) + fsw f15, 46*REGBYTES(sp) + fsw f16, 47*REGBYTES(sp) + fsw f17, 48*REGBYTES(sp) + fsw f18, 49*REGBYTES(sp) + fsw f19, 50*REGBYTES(sp) + fsw f20, 51*REGBYTES(sp) + fsw f21, 52*REGBYTES(sp) + fsw f22, 53*REGBYTES(sp) + fsw f23, 54*REGBYTES(sp) + fsw f24, 55*REGBYTES(sp) + fsw f25, 56*REGBYTES(sp) + fsw f26, 57*REGBYTES(sp) + fsw f27, 58*REGBYTES(sp) + fsw f28, 59*REGBYTES(sp) + fsw f29, 60*REGBYTES(sp) + fsw f30, 61*REGBYTES(sp) + fsw f31, 62*REGBYTES(sp) + #endif /* __riscv_flen */ + #endif /* MIV_FP_CONTEXT_SAVE */ +.endm + + .section .entry, "ax" + .globl _start + +_start: + j handle_reset + +/* Some of the Mi-V soft IP cores support compressed 'C' extension. If the Mi-V + core in your design doesn't support 'C' extension and you enable 'C' extension + in firmware project compiler options, then it would result in a trap. For this + case, we are avoiding compressed instruction here so you can put a breakpoint + at the jump and you can at least look at mcause, mepc and get some hints + about the crash. */ +trap_entry: +.option push +.option norvc +j generic_trap_handler +.option pop + .word 0 + .word 0 + +sw_trap_entry: + j vector_sw_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + +tmr_trap_entry: + j vector_tmr_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + +ext_trap_entry: + j vector_ext_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + .word 0 + +#ifndef MIV_LEGACY_RV32 +MGEUI_trap_entry: + j vector_MGEUI_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MGECI_trap_entry: + j vector_MGECI_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + .word 0 + +#ifndef MIV_RV32_V3_0 +MSYS_MIE22_trap_entry: +#ifndef MIV_RV32_V3_0 + j vector_SUBSYSR_IRQHandler +#endif /*MIV_RV32_V3_0*/ +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE23_trap_entry: + j vector_SUBSYS_IRQHandler +#ifdef __riscv_compressed + .2byte 0 +#endif +#endif /*MIV_RV32_V3_0*/ + +MSYS_MIE24_trap_entry: + j vector_MSYS_EI0_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE25_trap_entry: + j vector_MSYS_EI1_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE26_trap_entry: + j vector_MSYS_EI2_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE27_trap_entry: + j vector_MSYS_EI3_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE28_trap_entry: + j vector_MSYS_EI4_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE29_trap_entry: + j vector_MSYS_EI5_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE30_trap_entry: +#ifndef MIV_RV32_V3_0 + j vector_MSYS_EI6_trap_handler +#else + j vector_SUBSYS_IRQHandler +#endif +#ifdef __riscv_compressed + .2byte 0 +#endif + +#ifndef MIV_RV32_V3_0 +MSYS_MIE31_trap_entry: + j vector_MSYS_EI7_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif +#endif /* MIV_RV32_V3_0 */ +#endif /* MIV_LEGACY_RV32 */ + +.align 4 +generic_trap_handler: + STORE_CONTEXT + csrr a0, mcause + csrr a1, mepc + jal handle_trap + j generic_restore + +vector_sw_trap_handler: + STORE_CONTEXT + jal handle_m_soft_interrupt + j generic_restore + +vector_tmr_trap_handler: + STORE_CONTEXT + jal handle_m_timer_interrupt + j generic_restore + +vector_ext_trap_handler: + STORE_CONTEXT +#ifdef MIV_LEGACY_RV32 + jal handle_m_ext_interrupt +#else + jal External_IRQHandler +#endif /* MIV_LEGACY_RV32 */ + j generic_restore + +#ifndef MIV_LEGACY_RV32 +vector_MGEUI_trap_handler: + STORE_CONTEXT + jal MGEUI_IRQHandler + j generic_restore + +vector_MGECI_trap_handler: + STORE_CONTEXT + jal MGECI_IRQHandler + j generic_restore + +vector_MSYS_EI0_trap_handler: + STORE_CONTEXT + jal MSYS_EI0_IRQHandler + j generic_restore + +vector_MSYS_EI1_trap_handler: + STORE_CONTEXT + jal MSYS_EI1_IRQHandler + j generic_restore + +vector_MSYS_EI2_trap_handler: + STORE_CONTEXT + jal MSYS_EI2_IRQHandler + j generic_restore + +vector_MSYS_EI3_trap_handler: + STORE_CONTEXT + jal MSYS_EI3_IRQHandler + j generic_restore + +vector_MSYS_EI4_trap_handler: + STORE_CONTEXT + jal MSYS_EI4_IRQHandler + j generic_restore + +vector_MSYS_EI5_trap_handler: + STORE_CONTEXT + jal MSYS_EI5_IRQHandler + j generic_restore + +vector_SUBSYS_IRQHandler: + STORE_CONTEXT + jal SUBSYS_IRQHandler + j generic_restore + +#ifndef MIV_RV32_V3_0 +vector_MSYS_EI6_trap_handler: + STORE_CONTEXT + jal MSYS_EI6_IRQHandler + j generic_restore + +vector_MSYS_EI7_trap_handler: + STORE_CONTEXT + jal MSYS_EI7_IRQHandler + j generic_restore + + +vector_SUBSYSR_IRQHandler: + STORE_CONTEXT + jal SUBSYSR_IRQHandler + j generic_restore + +#endif /*MIV_RV32_V3_0*/ +#endif /* MIV_LEGACY_RV32 */ + +generic_restore: + LREG x1, 0 * REGBYTES(sp) + LREG x2, 1 * REGBYTES(sp) + LREG x3, 2 * REGBYTES(sp) + LREG x4, 3 * REGBYTES(sp) + LREG x5, 4 * REGBYTES(sp) + LREG x6, 5 * REGBYTES(sp) + LREG x7, 6 * REGBYTES(sp) + LREG x8, 7 * REGBYTES(sp) + LREG x9, 8 * REGBYTES(sp) + LREG x10, 9 * REGBYTES(sp) + LREG x11, 10 * REGBYTES(sp) + LREG x12, 11 * REGBYTES(sp) + LREG x13, 12 * REGBYTES(sp) + LREG x14, 13 * REGBYTES(sp) + LREG x15, 14 * REGBYTES(sp) + LREG x16, 15 * REGBYTES(sp) + LREG x17, 16 * REGBYTES(sp) + LREG x18, 17 * REGBYTES(sp) + LREG x19, 18 * REGBYTES(sp) + LREG x20, 19 * REGBYTES(sp) + LREG x21, 20 * REGBYTES(sp) + LREG x22, 21 * REGBYTES(sp) + LREG x23, 22 * REGBYTES(sp) + LREG x24, 23 * REGBYTES(sp) + LREG x25, 24 * REGBYTES(sp) + LREG x26, 25 * REGBYTES(sp) + LREG x27, 26 * REGBYTES(sp) + LREG x28, 27 * REGBYTES(sp) + LREG x29, 28 * REGBYTES(sp) + LREG x30, 29 * REGBYTES(sp) + LREG x31, 30 * REGBYTES(sp) + + #ifdef __riscv_flen + #ifdef MIV_FP_CONTEXT_SAVE + flw f0, 0 * REGBYTES(sp) + flw f1, 1 * REGBYTES(sp) + flw f2, 2 * REGBYTES(sp) + flw f3, 3 * REGBYTES(sp) + flw f4, 4 * REGBYTES(sp) + flw f5, 5 * REGBYTES(sp) + flw f6, 6 * REGBYTES(sp) + flw f7, 7 * REGBYTES(sp) + flw f8, 8 * REGBYTES(sp) + flw f9, 9 * REGBYTES(sp) + flw f10, 10 * REGBYTES(sp) + flw f11, 11 * REGBYTES(sp) + flw f12, 12 * REGBYTES(sp) + flw f13, 13 * REGBYTES(sp) + flw f14, 14 * REGBYTES(sp) + flw f15, 15 * REGBYTES(sp) + flw f16, 16 * REGBYTES(sp) + flw f17, 17 * REGBYTES(sp) + flw f18, 18 * REGBYTES(sp) + flw f19, 19 * REGBYTES(sp) + flw f20, 20 * REGBYTES(sp) + flw f21, 21 * REGBYTES(sp) + flw f22, 22 * REGBYTES(sp) + flw f23, 23 * REGBYTES(sp) + flw f24, 24 * REGBYTES(sp) + flw f25, 25 * REGBYTES(sp) + flw f26, 26 * REGBYTES(sp) + flw f27, 27 * REGBYTES(sp) + flw f28, 28 * REGBYTES(sp) + flw f29, 29 * REGBYTES(sp) + flw f30, 30 * REGBYTES(sp) + flw f31, 31 * REGBYTES(sp) + #endif /* __riscv_flen */ + #endif /* MIV_FP_CONTEXT_SAVE */ + + addi sp, sp, SP_SHIFT_OFFSET*REGBYTES + mret + + .section .text, "ax" +handle_reset: +/* Ensure instructions are not relaxed, since gp is not yet set */ +.option push +.option norelax + +#ifndef MIV_RV32_V3_0 + csrwi mstatus, 0 + csrwi mie, 0 + la ra, _start + +/* Clearnig this to be on safer side as RTL doesnt seem to clear it on reset. */ +#ifndef MIV_LEGACY_RV32 + li t0, MTIMEH_ADDR + sw x0, 0(t0) +#endif + + csrr t0, misa + andi t0, t0, A_EXTENSION_MASK + bnez t0, ima_cores_setup /* Jump to IMA core handling */ + + +/* For MIV_RV32 cores the mtvec exception base address is fixed at Reset vector + address + 0x4. Check the mode bits. */ +/* In the MIV_RV32 v3.1, the MTVEC exception base address is WARL, and can be + configured by the user at runtime */ + + csrr t0, mtvec + andi t0, t0, MTVEC_MODE_BIT_MASK + li t1, MTVEC_VECTORED_MODE_VAL + bne t0, t1, ima_cores_setup /* Jump to IMA core handling */ + + /* When mode = 1 => this is vectored mode on MIV_RV32 core. + Verify that the trap_handler address matches the configuration in MTVEC */ + csrr t0, mtvec + andi t0, t0, 0xFFFFFFFC + la t1, trap_entry + bne t0, t1, vector_address_not_matching + j generic_reset_handling + +#else /* MIV_RV32_V3_0 */ + +/* Clearnig this to be on safer side as RTL doesnt seem to clear it on reset. */ +#ifndef MIV_LEGACY_RV32 + li t0, MTIMEH_ADDR + sw x0, 0(t0) +#endif + +/* In the MIV_RV32 v3.1, the MTVEC exception base address is WARL, and can be + configured by the user at runtime */ + csrr t0, mtvec + andi t0, t0, MTVEC_MODE_BIT_MASK + li t1, MTVEC_VECTORED_MODE_VAL + bne t0, t1, ima_cores_setup /* Jump to IMA core handling */ + +/* When mode = 1 => this is vectored mode on MIV_RV32 core. + Verify that the trap_handler address matches the configuration in MTVEC */ + csrr t0, mtvec + andi t0, t0, 0xFFFFFFFC + la t1, trap_entry + bne t0, t1, vector_address_not_matching + j generic_reset_handling +#endif /*MIV_RV32_V3_0*/ + +ima_cores_setup: + la t0, trap_entry + +#ifdef MIV_LEGACY_RV32_VECTORED_INTERRUPTS + addi t0, t0, 0x01 /* Set the mode bit for IMA cores. + For both MIV_RV32 v3.1 and v3.0 cores this is done by configurator. */ +#endif + csrw mtvec, t0 + +generic_reset_handling: +/* Copy sdata section first so that the gp is set and linker relaxation can be + used */ + la a4, __sdata_load + la a5, __sdata_start + la a6, __sdata_end + beq a4, a5, 1f /* Exit if source and dest are same */ + beq a5, a6, 1f /* Exit if section start and end addresses are same */ + call block_copy + +1: + /* initialize global pointer */ + la gp, __global_pointer$ + +.option pop + +/* Floating point support configuration */ +#ifdef __riscv_flen + csrr t0, mstatus + lui t1, 0xffffa + addi t1, t1, -1 + and t0, t0, t1 + lui t1, 0x4 + or t1, t0, t1 + csrw mstatus, t1 + + lui t0, 0x0 + fscsr t0 +#endif + call initializations + /* Initialize stack pointer */ + la sp, __stack_top + + /* Jump into C code */ + j _init + +/* Error: trap_entry is not at the expected address of reset_vector+mtvec offset + as configured in the MIV_RV32 core vectored mode */ +vector_address_not_matching: + ebreak + +initializations: +/* Initialize the .bss section */ + mv t0, ra /* Store ra for future use */ + la a5, __bss_start + la a6, __bss_end + beq a5, a6, 1f /* Section start and end address are the same */ + call zeroize_block + +1: +/* Initialize the .sbss section */ + la a5, __sbss_start + la a6, __sbss_end + beq a5, a6, 1f /* Section start and end address are the same */ + call zeroize_block + +/* Clear heap */ + la a5, __heap_start + la a6, __heap_end + beq a5, a6, 1f /* Section start and end address are the same */ + call zeroize_block + +1: +/* Copy data section */ + la a4, __data_load + la a5, __data_start + la a6, __data_end + beq a4, a5, 1f /* Exit early if source and dest are same */ + beq a5, a6, 1f /* Section start and end addresses are the same */ + call block_copy + +1: + mv ra, t0 /* Retrieve ra */ + ret + +zeroize_block: + bltu a6, a5, block_copy_error /* Error. End address is less than start */ + or a7, a6, a5 /* Check if start or end is unalined */ + andi a7, a7, 0x03u + bgtz a7, block_copy_error /* Unaligned addresses error*/ +zeroize_loop: + sw x0, 0(a5) + add a5, a5, __SIZEOF_POINTER__ + blt a5, a6, zeroize_loop + ret + +block_copy: + bltu a6, a5, block_copy_error /* Error. End address is less than start */ + or a7, a6, a5 /* Check if start or end is unalined */ + andi a7, a7, 0x03u + bgtz a7, block_copy_error /* Unaligned addresses error*/ +block_copy_loop: + lw a7, 0(a4) + sw a7, 0(a5) + addi a5, a5, 0x04 + addi a4, a4, 0x04 + blt a5, a6, block_copy_loop + j block_copy_exit + +block_copy_error: + j block_copy_error + +block_copy_exit: + ret + +#endif /*ENTRY_S*/ diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv_rv32_hal.c b/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv_rv32_hal.c new file mode 100755 index 0000000..a112821 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv_rv32_hal.c @@ -0,0 +1,410 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_hal.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Implementation of Hardware Abstraction Layer for Mi-V soft processors + * + */ +#include +#include "miv_rv32_hal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SUCCESS 0U +#define ERROR 1U +#define MASK_32BIT 0xFFFFFFFFu + +/*------------------------------------------------------------------------------ + * Write in a sequence recommended by privileged spec to avoid spurious + * interrupts + + # New comparand is in a1:a0. + li t0, -1 + sw t0, mtimecmp # No smaller than old value. + sw a1, mtimecmp+4 # No smaller than new value. + sw a0, mtimecmp # New value. + */ +#ifndef MIV_RV32_EXT_TIMECMP +#define WRITE_MTIMECMP(value) MTIMECMPH = MASK_32BIT; \ + MTIMECMP = value & MASK_32BIT;\ + MTIMECMPH = (value >> 32u) & MASK_32BIT; +#else +#define WRITE_MTIMECMP(value) +#endif + +#ifndef MIV_RV32_EXT_TIMER +#define WRITE_MTIME(value) MTIME = value & MASK_32BIT;\ + MTIMEH = (value >> 32u) & MASK_32BIT; +#else +#define WRITE_MTIME(value) +#endif + +extern void Software_IRQHandler(void); + +#ifdef MIV_LEGACY_RV32 +#define MTIME_PRESCALER 100UL +/*------------------------------------------------------------------------------ + * + */ +uint8_t Invalid_IRQHandler(void); +uint8_t External_1_IRQHandler(void); +uint8_t External_2_IRQHandler(void); +uint8_t External_3_IRQHandler(void); +uint8_t External_4_IRQHandler(void); +uint8_t External_5_IRQHandler(void); +uint8_t External_6_IRQHandler(void); +uint8_t External_7_IRQHandler(void); +uint8_t External_8_IRQHandler(void); +uint8_t External_9_IRQHandler(void); +uint8_t External_10_IRQHandler(void); +uint8_t External_11_IRQHandler(void); +uint8_t External_12_IRQHandler(void); +uint8_t External_13_IRQHandler(void); +uint8_t External_14_IRQHandler(void); +uint8_t External_15_IRQHandler(void); +uint8_t External_16_IRQHandler(void); +uint8_t External_17_IRQHandler(void); +uint8_t External_18_IRQHandler(void); +uint8_t External_19_IRQHandler(void); +uint8_t External_20_IRQHandler(void); +uint8_t External_21_IRQHandler(void); +uint8_t External_22_IRQHandler(void); +uint8_t External_23_IRQHandler(void); +uint8_t External_24_IRQHandler(void); +uint8_t External_25_IRQHandler(void); +uint8_t External_26_IRQHandler(void); +uint8_t External_27_IRQHandler(void); +uint8_t External_28_IRQHandler(void); +uint8_t External_29_IRQHandler(void); +uint8_t External_30_IRQHandler(void); +uint8_t External_31_IRQHandler(void); + + +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for external interrupts. + */ +uint8_t (* const mrv_ext_irq_handler_table[32])(void) = +{ + + Invalid_IRQHandler, + External_1_IRQHandler, + External_2_IRQHandler, + External_3_IRQHandler, + External_4_IRQHandler, + External_5_IRQHandler, + External_6_IRQHandler, + External_7_IRQHandler, + External_8_IRQHandler, + External_9_IRQHandler, + External_10_IRQHandler, + External_11_IRQHandler, + External_12_IRQHandler, + External_13_IRQHandler, + External_14_IRQHandler, + External_15_IRQHandler, + External_16_IRQHandler, + External_17_IRQHandler, + External_18_IRQHandler, + External_19_IRQHandler, + External_20_IRQHandler, + External_21_IRQHandler, + External_22_IRQHandler, + External_23_IRQHandler, + External_24_IRQHandler, + External_25_IRQHandler, + External_26_IRQHandler, + External_27_IRQHandler, + External_28_IRQHandler, + External_29_IRQHandler, + External_30_IRQHandler, + External_31_IRQHandler +}; + +#else +/*------------------------------------------------------------------------------ + * Interrupt handlers as mapped into the MIE register of the MIV_RV32 + */ +extern void Reserved_IRQHandler(void); +extern void External_IRQHandler(void); +extern void MGEUI_IRQHandler(void); +extern void MGECI_IRQHandler(void); +extern void MSYS_EI0_IRQHandler(void); +extern void MSYS_EI1_IRQHandler(void); +extern void MSYS_EI2_IRQHandler(void); +extern void MSYS_EI3_IRQHandler(void); +extern void MSYS_EI4_IRQHandler(void); +extern void MSYS_EI5_IRQHandler(void); +extern void SUBSYS_IRQHandler(void); + +#ifndef MIV_RV32_V3_0 /*For MIV_RV32 v3.1*/ +extern void MSYS_EI6_IRQHandler(void); +extern void MSYS_EI7_IRQHandler(void); +extern void SUBSYSR_IRQHandler(void); // @suppress("Unused function declaration") +#endif /*MIV_RV32_V3_0*/ + +#endif /* MIV_LEGACY_RV32 */ + +/*------------------------------------------------------------------------------ + * Increment value for the mtimecmp register in order to achieve a system tick + * interrupt as specified through the MRV_systick_config() function. + */ +static uint64_t g_systick_increment = 0U; +static uint64_t g_systick_cmp_value = 0U; + +/*------------------------------------------------------------------------------ + * Configure the machine timer to generate an interrupt. + */ +uint32_t MRV_systick_config(uint64_t ticks) +{ + uint32_t ret_val = ERROR; + uint64_t remainder = ticks; + g_systick_increment = 0U; + g_systick_cmp_value = 0U; + + while (remainder >= MTIME_PRESCALER) + { + remainder -= MTIME_PRESCALER; + g_systick_increment++; + } + + g_systick_cmp_value = g_systick_increment + MRV_read_mtime(); + + if (g_systick_increment > 0U) + { + WRITE_MTIMECMP(g_systick_cmp_value); + set_csr(mie, MIP_MTIP); + MRV_enable_interrupts(); + ret_val = SUCCESS; + } + + return ret_val; +} + +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for machine timer interrupts. + */ +void handle_m_timer_interrupt(void) +{ + clear_csr(mie, MIP_MTIP); + + uint64_t mtime_at_irq = MRV_read_mtime(); + +#ifndef NDEBUG + static volatile uint32_t d_tick = 0u; +#endif + + while(g_systick_cmp_value < (mtime_at_irq + MTIME_DELTA)) { + g_systick_cmp_value = g_systick_cmp_value + g_systick_increment; + +#ifndef NDEBUG + d_tick += 1; +#endif + } +/***************************************************************************//** + /* + * Note: If d_tick > 1 it means, that a system timer interrupt has been + * missed. + * Please ensure that interrupt handlers are as short as possible to prevent + * them stopping other interrupts from being handled. For example, if a + * system timer interrupt occurs during a software interrupt, the system + * timer interrupt will not be handled until the software interrupt handling + * is complete. If the software interrupt handling time is more than one + * systick interval, it will result in d_tick > 1. + * If you are running the program using the debugger and halt the CPU at a + * breakpoint, MTIME will continue to increment and interrupts will be + * missed; resulting in d_tick > 1. + */ + + WRITE_MTIMECMP(g_systick_cmp_value); + + SysTick_Handler(); + + set_csr(mie, MIP_MTIP); +} + +void handle_m_soft_interrupt(void) +{ + Software_IRQHandler(); + MRV_clear_soft_irq(); +} +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for software interrupts. + */ +#ifdef MIV_LEGACY_RV32 +void handle_m_ext_interrupt(void) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; + uint8_t disable = EXT_IRQ_KEEP_ENABLED; + + if (0u !=int_num) + { + disable = mrv_ext_irq_handler_table[int_num](); + + PLIC->TARGET[hart_id].CLAIM_COMPLETE = int_num; + + if(EXT_IRQ_DISABLE == disable) + { + MRV_PLIC_disable_irq((IRQn_Type)int_num); + } + } +} +#else + +/*------------------------------------------------------------------------------ + * MSYS local interrupts table + */ +void (* const local_irq_handler_table[16])(void) = +{ +#ifndef MIV_RV32_V3_0 + MGEUI_IRQHandler, + MGECI_IRQHandler, + SUBSYS_IRQHandler, + SUBSYSR_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + MSYS_EI0_IRQHandler, + MSYS_EI1_IRQHandler, + MSYS_EI2_IRQHandler, + MSYS_EI3_IRQHandler, + MSYS_EI4_IRQHandler, + MSYS_EI5_IRQHandler, + MSYS_EI6_IRQHandler, + MSYS_EI7_IRQHandler +#else + MGEUI_IRQHandler, + MGECI_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + MSYS_EI0_IRQHandler, + MSYS_EI1_IRQHandler, + MSYS_EI2_IRQHandler, + MSYS_EI3_IRQHandler, + MSYS_EI4_IRQHandler, + MSYS_EI5_IRQHandler, + SUBSYS_IRQHandler, + Reserved_IRQHandler, +#endif +}; + +/*------------------------------------------------------------------------------ + * Jump to interrupt table containing local interrupts + */ +void handle_local_ei_interrupts(uint8_t irq_no) +{ + uint64_t mhart_id = read_csr(mhartid); + ASSERT(irq_no <= MIV_LOCAL_IRQ_MAX) + ASSERT(irq_no >= MIV_LOCAL_IRQ_MIN) + + uint8_t ei_no = (uint8_t)(irq_no - MIV_LOCAL_IRQ_MIN); + (*local_irq_handler_table[ei_no])(); +} +#endif /* MIV_LEGACY_RV32 */ + + +/*------------------------------------------------------------------------------ + * Trap handler. This function is invoked in the non-vectored mode. + */ +void handle_trap(uintptr_t mcause, uintptr_t mepc) +{ + uint64_t is_interrupt = mcause & MCAUSE_INT; + + if (is_interrupt) + { +#ifndef MIV_LEGACY_RV32 + if (((mcause & MCAUSE_CAUSE) >= MIV_LOCAL_IRQ_MIN) && ((mcause & MCAUSE_CAUSE) <= MIV_LOCAL_IRQ_MAX)) + { + handle_local_ei_interrupts((uint8_t)(mcause & MCAUSE_CAUSE)); + } + else if ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT) +#else + if ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT) +#endif + { +#ifndef MIV_LEGACY_RV32 + External_IRQHandler(); +#else + handle_m_ext_interrupt(); +#endif + } + else if ((mcause & MCAUSE_CAUSE) == IRQ_M_SOFT) + { + handle_m_soft_interrupt(); + } + else if ((mcause & MCAUSE_CAUSE) == IRQ_M_TIMER) + { + handle_m_timer_interrupt(); + } + } + else + { +#ifndef NDEBUG + /* + Arguments supplied to this function are mcause, mepc (exception PC) and + stack pointer. + Based on privileged-isa specification mcause values and meanings are: + + 0 Instruction address misaligned (mtval/mtval is the address) + 1 Instruction access fault (mtval/mtval is the address) + 2 Illegal instruction (mtval/mtval contains the + offending instruction opcode) + 3 Breakpoint + 4 Load address misaligned (mtval/mtval is the address) + 5 Load address fault (mtval/mtval is the address) + 6 Store/AMO address fault (mtval/mtval is the address) + 7 Store/AMO access fault (mtval/mtval is the address) + 8 Environment call from U-mode + 9 Environment call from S-mode + A Environment call from M-mode + B Instruction page fault + C Load page fault (mtval/mtval is the address) + E Store page fault (mtval/mtval is the address) + + # Please note: mtval is the newer name for register mbadaddr + # If you get a compile failure here, use the older name. + # At this point, both are supported in latest compiler, older compiler + # versions only support mbadaddr. + # See: https://github.com/riscv/riscv-gcc/issues/133 + */ + + /* interrupt pending */ + uintptr_t mip = read_csr(mip); + + /* additional info and meaning depends on mcause */ + uintptr_t mtval = read_csr(mtval); + + /* trap vector */ + uintptr_t mtvec = read_csr(mtvec); + + /* temporary, sometimes might hold temporary value of a0 */ + uintptr_t mscratch = read_csr(mscratch); + + /* status contains many smaller fields: */ + uintptr_t mstatus = read_csr(mstatus); + + /* PC value when the exception was taken*/ + uintptr_t mmepc = read_csr(mepc); + + /* breakpoint */ + __asm__("ebreak"); +#else + _exit(1 + mcause); +#endif /* NDEBUG */ + } +} + +#ifdef __cplusplus +} +#endif + diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv_rv32_hal.h b/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv_rv32_hal.h new file mode 100755 index 0000000..9ce9ef6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv_rv32_hal.h @@ -0,0 +1,773 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_hal.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware Abstraction Layer functions for Mi-V soft processors + * + */ + +/*=========================================================================*//** + @mainpage MIV_RV32 Hardware Abstraction Layer + + ============================================================================== + Introduction + ============================================================================== + This document describes the Hardware Abstraction Layer (HAL) for the MIV_RV32 + Soft IP Core. This release of the HAL corresponds to the Soft IP core MIV_RV32 + v3.1 release. It also supports earlier versions of the MIV_RV32 as well as the + legacy RV32 IP cores. + The preprocessor macros provided with the MIV_RV32 HAL are used to customize + it to target the Soft Processor IP version being used in your project. + + The term "MIV_RV32" represents following two cores: + - MIV_RV32 v3.0 and later (the latest and greatest Mi-V soft processor) + - MIV_RV32IMC v2.1 (MIV_RV32 v3.0 is a drop in replacement for this core) + It is highly recommended to migrate your design to MIV_RV32 v3.1 + + The term, Legacy RV32 IP cores, represents following IP cores: + - MIV_RV32IMA_L1_AHB + - MIV_RV32IMA_L1_AXI + - MIV_RV32IMAF_L1_AHB + + These legacy RV32 IP cores are deprecated. It is highly recommended to migrate + your designs to MIV_RV32 v3.1 (and subsequent IP releases) for the latest + enhancements, bug fixes, and support. + + -------------------------------- + MIV_RV32 V3.1 + -------------------------------- + This is the latest release of the MIV_RV32 Soft IP core. For more details, + refer to the MIV_RV32 User [Guide](https://www.microchip.com/en-us/products/fpgas-and-plds/ip-core-tools/miv-rv32) + + The MIV_RV32 Core as well as this document use the terms defined below: + + -------------------------------- + - SUBSYS - Processor Subsystem for RISC-V + - OPSRV - Offload Processor Subsystem for RISC-V + - GPR - General Purpose Registers + - MGECIE - Machine GPR ECC Correctable Interrupt Enable + - MGEUIE - Machine GPR ECC Uncorrectable Interrupt Enable + - MTIE - Machine Timer Interrupt Enable + - MEIE - Machine External Interrupt Enable + - MSIE - Machine Software Interrupt Enable + - ISR - Interrupt Service Routine + + ============================================================================== + Customizing MIV_RV32 HAL + ============================================================================== + To use the HAL with older releases of MIV_RV32, preprocessor macros have been + provided. Using these macros, any of the IP version is targeted. + The HAL is used to target any of the mentioned platforms by adding the + following macros in the way : + Project Properties > C/C++ Build > Settings > Preprocessor in Assembler and + Compiler settings. + The table below shows the macros corresponding to the MIV Core being used in + your libero project. By default, the HAL targets v3.1 of the IP core and no + macros need to be set for this configutation. + + | Libero MI-V Soft IP Version | SoftConsole Macro | + |-----------------------------|-------------------| + | MIV_RV32 v3.1 | no macro required | + | MIV_RV32 v3.0 | MIV_CORE_V3_0 | + | Legacy RV32 Cores | MIV_LEGACY_RV32 | + + -------------------------------- + Interrupt Handling + -------------------------------- + The MIE Register is defined as a enum in the HAL, and the table below is used + as a reference when the vectored interrupts are enabled in the GUI core + configurator. + + The MIE register is a RISC-V Control and Status Register (CSR), which stands + for the Machine Interrupt Enable. This is used to enable the machine mode + interrupts in the MIV_RV32 hart. Refer to the RISC-V Priv spec for more details. + + The following table shows the trap entry addresses when an interrupt occurs and + the vectored interrupts are enabled in the GUI configurator. + + | MIE Register Bit | Interrupt Enable | Vector Address | + |-------------------|------------------|----------------| + | 31 | MSYS_IE7 | mtvec.BASE + 0x7C | + | 30 | MSYS_IE6 | mtvec.BASE + 0x78 | + | 29 | MSYS_IE5 | mtvec.BASE + 0x74 | + | 28 | MSYS_IE4 | mtvec.BASE + 0x70 | + | 27 | MSYS_IE3 | mtvec.BASE + 0x6C | + | 26 | MSYS_IE2 | mtvec.BASE + 0x68 | + | 25 | MSYS_IE1 | mtvec.BASE + 0x64 | + | 24 | MSYS_IE0 | mtvec.BASE + 0x60 | + | 23 | SUBSYS_EI | mtvec.BASE + 0x5C | + | 22 | SUBSYSR | mtvec.BASE + 0x58 | + | 17 | MGECIE | mtvec.BASE + 0x44 | + | 16 | MGEUIE | mtvec.BASE + 0x40 | + | 11 | MEIE | mtvec.BASE + 0x2C | + | 7 | MTIE | mtvec.BASE + 0x1C | + | 3 | MSIE | mtvec.BASE + 0x0C | + + + For changes in MIE register map, see the [MIE Register Map for MIV_RV32 v3.0] + (#mie-register-map-for-miv_rv32-v3.0) section. + + SUBSYSR is currently not being used by the core and is Reserved for future use. + + The mtvec.BASE field corresponds to the bits [31:2], where mtvec stands for + Machine Trap Vector, and all traps set the PC to the the value stored in the + mtvec.BASE field when in Non-Vectored mode. In this case, a generic trap + handler is as an interrupt service routine. + + When Vectored interrupts are enabled, use this formula to calculate the trap + address: (mtvec.BASE + 4*cause), where cause comes from the mcause CSR. The + mcause register is written with a code indicating the event that caused the trap. + For more details, see the RISC-V priv specification. + + The MIV_RV32 Soft IP core does not contain a Platfrom Level Interrup Controller + (PLIC). It is advised to use the PLIC contained within the MIV_ESS sub-system. + Connect the PLIC interrupt output of the MIV_ESS to the EXT_IRQ pin on the + MIV_RV32. + + The following table is the MIE register map for the MIV_RV32 Core V3.0. It only + highlights the differences between the V3.0 and V3.1 of the core. + + -------------------------------- + MIE Register Map for MIV_RV32 V3.0 + -------------------------------- + + | MIE Register Bit | Target Interrupt | Vector Address | + |-------------------|------------------|----------------| + | 31 | Not in use | top table | + | 30 | SUBSYS_EI | addr + 0x78 | + | 23 | Not in use | Not in use | + | 22 | Not in use | Not in use | + + Other interrupt bit postions like the MGEUIE and MSYS_IE5 to MSYS_IE0 remain + unchanged. + + -------------------------------- + Floating Point Interrupt Support + -------------------------------- + When an interrupt is taken and Floating Point instructions are used in the + ISR, the floating point register context must be saved to resume the application + correctly. To use this feature, enable the provided macro in the + Softconsole build settings. + This feature is turned off by default as it adds overhead which is not required + when the ISR does not used FP insturctions and saving the general purpose + register context is sufficient. + + | Macro Name | Definition | + |--------------------------|-------------------------------------------------| + | MIV_FP_CONTEXT_SAVE | Define to save the FP register file | + + + -------------------------------- + SUBSYS - SubSystem for RISC-V + -------------------------------- + SUBSYS stands for SubSystem for RISC-V. This was previously (MIV_RV32 v3.0) + known as OPSRV, which stands for "Offload Processor Subsystem + for RISC-V". See the earlier versions of the handbook for more details. + In the latest release of the MIV_RV32 IP core v3.1, OPSRV has been renamed to + SUBSYS. The MIV_RV32 HAL now uses SUBSYS instead of OPSRV. + + *//*=========================================================================*/ +#ifndef RISCV_HAL_H +#define RISCV_HAL_H + +#include "miv_rv32_regs.h" +#include "miv_rv32_plic.h" +#include "miv_rv32_assert.h" +#include "miv_rv32_subsys.h" + +#ifndef LEGACY_DIR_STRUCTURE +#include "fpga_design_config/fpga_design_config.h" +#else +#include "hw_platform.h" +#endif /*LEGACY_DIR_STRUCTURE*/ + +#ifdef __cplusplus +extern "C" { +#endif +/*-------------------------------------------------------------------------*//** + SUBSYS Backwards Compatibility + ======================================= + For application code using the older macro names and API functions, these macros + act as a compatibility layer and applications which use OPSRV API features work + due to these macro definitions. However, it is adviced to update your + application code to use the SUBSYS macros and API functions. + + | Macro Name | Now Called | + |-------------------------|--------------------------| + | OPSRV_TCM_ECC_CE_IRQ | SUBSYS_TCM_ECC_CE_IRQ | + | OPSRV_TCM_ECC_UCE_IRQ | SUBSYS_TCM_ECC_UCE_IRQ | + | OPSRV_AXI_WR_RESP_IRQ | SUBSYS_AXI_WR_RESP_IRQ | + | MRV32_MSYS_OPSRV_IRQn | MRV32_SUBSYS_IRQn | + | MRV32_opsrv_enable_irq | MRV32_subsys_enable_irq | + | MRV32_opsrv_disable_irq | MRV32_subsys_disable_irq | + | MRV32_opsrv_clear_irq | MRV32_subsys_clear_irq | + | OPSRV_IRQHandler | SUBSYS_IRQHandler | + */ + +/*-------------------------------------------------------------------------*//** + MTIME Timer Interrupt Constants + ======================================= + These values contain the register addresses for the registers used by the + machine timer interrupt + + MTIME_PRESCALER is not defined on the MIV_RV32IMC v2.0 and v2.1. By using this + definition the system crashes. For those core, use the following definition: + + #define MTIME_PRESCALER 100u + + MTIME and MTIMECMP + -------------------------------- + MIV_RV32 core offers flexibility in terms of generating MTIME and MTIMECMP + registers internal to the core or using external time reference. There four + possible combinations: + + - Internal MTIME and Internal MTIME IRQ enabled Generate the MTIME and MTIMECMP + registers internally. (The only combination available on legacy RV32 cores) + + - Internal MTIME enabled and Internal MTIME IRQ disabled Generate the MTIME + internally and have a timer interrupt input to the core as external pin. In + this case, 1 pin port will be available on MIV_RV32 for timer interrupt. + + - When the internal MTIME is disabled, and the Internal MTIME IRQ is enabled, the + system generates the time value externally and generates the mtimecmp and + interrupt internally (for example, a multiprocessor system with a shared time + between all cores). In this case, a 64-bit port is available on the MIV_RV32 + core as input. + + - Internal MTIME and Internal MTIME IRQ disabled Generate both the time and + timer interrupts externally. In this case a 64 bit port will be available on + the MIV_RV32 core as input, and a 1 pin port will be available for timer + interrupt. + + To handle all these combinations in the firmware, the following constants must + be defined in accordance with the configuration that you have made on your + MIV_RV32 core design. + + MIV_RV32_EXT_TIMER + -------------------------------- + When defined, it means that the MTIME register is not available internal to + the core. In this case, a 64 bit port will be available on the MIV_RV32 core as + input. When this macro is not defined, it means that the MTIME register is + available internally to the core. + + MIV_RV32_EXT_TIMECMP + -------------------------------- + When defined, it means the MTIMECMP register is not available internally to + the core and the Timer interrupt input to the core comes as an external pin. + When this macro is not defined it means the that MTIMECMP register exists + internal to the core and that the timer interrupt is generated internally. + +NOTE: All these macros must not be defined if you are using a MIV_RV32 core. + */ + +#define OPSRV_TCM_ECC_CE_IRQ SUBSYS_TCM_ECC_CE_IRQ +#define OPSRV_TCM_ECC_UCE_IRQ SUBSYS_TCM_ECC_UCE_IRQ +#define OPSRV_AXI_WR_RESP_IRQ SUBSYS_AXI_WR_RESP_IRQ +#define MRV32_MSYS_OPSRV_IRQn MRV32_SUBSYS_IRQn +#define MRV32_opsrv_enable_irq MRV32_subsys_enable_irq +#define MRV32_opsrv_disable_irq MRV32_subsys_disable_irq +#define MRV32_opsrv_clear_irq MRV32_subsys_clear_irq +#define OPSRV_IRQHandler SUBSYS_IRQHandler + +/*-------------------------------------------------------------------------*//** + External IRQ + ======================================= + Return value from External IRQ handler. This is used to disable the + External Interrupt. + + | Macro Name | Value | Description| + |-------------------|--------|----------------| + | EXT_IRQ_KEEP_ENABLED | 0 | Keep external interrupts enabled | + | EXT_IRQ_DISABLE | 1 | Disable external interrupts | + */ +#define EXT_IRQ_KEEP_ENABLED 0U +#define EXT_IRQ_DISABLE 1U + +#define MTIME_DELTA 5 +#ifdef MIV_LEGACY_RV32 +#define MSIP (*(uint32_t*)0x44000000UL) +#define MTIMECMP (*(uint32_t*)0x44004000UL) +#define MTIMECMPH (*(uint32_t*)0x44004004UL) +#define MTIME (*(uint32_t*)0x4400BFF8UL) +#define MTIMEH (*(uint32_t*)0x4400BFFCUL) + +/* To maintain backward compatibility with FreeRTOS config code */ +#define PRCI_BASE 0x44000000UL +#else /* MIV_LEGACY_RV32 */ + +/* To maintain backward compatibility with FreeRTOS config code */ +#define PRCI_BASE 0x02000000UL + +#ifndef MIV_RV32_EXT_TIMECMP +#define MTIMECMP (*(volatile uint32_t*)0x02004000UL) +#define MTIMECMPH (*(volatile uint32_t*)0x02004004UL) +#else +#define MTIMECMP (0u) +#define MTIMECMPH (0u) +#endif + +#define MTIME_PRESCALER (*(volatile uint32_t*)0x02005000UL) + +#ifndef MIV_RV32_EXT_TIMER +#define MTIME (*(volatile uint32_t*)0x0200BFF8UL) +#define MTIMEH (*(volatile uint32_t*)0x0200BFFCUL) + +/***************************************************************************//** + MIMPID Register + The MIMPID register is a RISC-V Control and Status Register In the v3.0 of + MIV_RV32, the value of `MIMPID = 0x000540AD`. In the v3.1 of MIV_RV32, the + value if `MIMPID = 0xE5010301` corresponding to (E)mbedded (5)ystem(01) core + version (03).(01) this terminology will be followed in the subsequent releases + of the core read the csr value and store it in a varible which may be used to + check the MIV_RV32 core version during runtime. + + Future releases of the core will increment the 03 and 01 as major and minor + releases respectively and the register can be read at runtime to find the + Soft IP core version. + + | Core Version | Register | Value | Notes | + |----------------|------------|---------|---------| + | MIV_RV32 V3.1 | mimpid | 0xE5010301 | implimentation ID | + | MIV_RV32 V3.0 | mimpid | 0x000540AD | implimentation ID | + */ +#define MIMPID read_csr(mimpid) + +/*Used as a mask to read and write to mte mtvec.BASE address*/ +#define MTVEC_BASE_ADDR_MASK 0xFFFFFFFC + +#else +#define MTIME (0u) +#define MTIMEH (0u) +#endif /*MIV_RV32_EXT_TIMER*/ + +/*-------------------------------------------------------------------------*//** + RISC-V Specification Interrupts + ======================================= + These definitions are provided for easy identification of the interrupt + in the MIE/MIP registers. + Apart from the standard software, timer, and external interrupts, the names + of the additional interrupts correspond to the names as used in the MIV_RV32 + handbook. Please refer the MIV_RV32 handbook for more details. + + All the interrups, provided by the MIV_RV32 core, follow the interrupt priority + order and register description as mentioned in the RISC-V spec. + + | Macro Name | Value | Description| + |-------------------|--------|----------------| + | MRV32_SOFT_IRQn | MIE_3_IRQn | Software interrupt enable | + | MRV32_TIMER_IRQn | MIE_7_IRQn | Timer interrupt enable | + | MRV32_EXT_IRQn | MIE_11_IRQn | External interrupt enable | + + */ +#define MRV32_SOFT_IRQn MIE_3_IRQn +#define MRV32_TIMER_IRQn MIE_7_IRQn +#define MRV32_EXT_IRQn MIE_11_IRQn + +/***************************************************************************//** + Interrupt numbers: + This enum represents the interrupt enable bits in the MIE register. + */ +enum +{ + MIE_0_IRQn = (0x01u), + MIE_1_IRQn = (0x01u<<1u), + MIE_2_IRQn = (0x01u<<2u), + MIE_3_IRQn = (0x01u<<3u), /*MSIE 0xC*/ + MIE_4_IRQn = (0x01u<<4u), + MIE_5_IRQn = (0x01u<<5u), + MIE_6_IRQn = (0x01u<<6u), + MIE_7_IRQn = (0x01u<<7u), /*MTIE 0x1C*/ + MIE_8_IRQn = (0x01u<<8u), + MIE_9_IRQn = (0x01u<<9u), + MIE_10_IRQn = (0x01u<<10u), + MIE_11_IRQn = (0x01u<<11u), /*MEIE 0x2C*/ + MIE_12_IRQn = (0x01u<<12u), + MIE_13_IRQn = (0x01u<<13u), + MIE_14_IRQn = (0x01u<<14u), + MIE_15_IRQn = (0x01u<<15u), + MIE_16_IRQn = (0x01u<<16u), /*MGEUIE ECC Uncorrectable 0x40*/ + MIE_17_IRQn = (0x01u<<17u), /*MGECIE ECC Correctable 0x44*/ + MIE_18_IRQn = (0x01u<<18u), + MIE_19_IRQn = (0x01u<<19u), + MIE_20_IRQn = (0x01u<<20u), + MIE_21_IRQn = (0x01u<<21u), + MIE_22_IRQn = (0x01u<<22u), /*SUBSYSR 0x58 (R)eserved*/ + MIE_23_IRQn = (0x01u<<23u), /*SUBSYS_IE 0x5C for MIV_RV32 v3.1*/ + MIE_24_IRQn = (0x01u<<24u), /*MSYS_IE0 0x60*/ + MIE_25_IRQn = (0x01u<<25u), /*MSYS_IE1 0x64*/ + MIE_26_IRQn = (0x01u<<26u), /*MSYS_IE2 0x68*/ + MIE_27_IRQn = (0x01u<<27u), /*MSYS_IE3 0x6C*/ + MIE_28_IRQn = (0x01u<<28u), /*MSYS_IE4 0x70*/ + MIE_29_IRQn = (0x01u<<29u), /*MSYS_IE5 0x74*/ + MIE_30_IRQn = (0x01u<<30u), /*MSYS_IE6 0x78, read comment below*/ + MIE_31_IRQn = (0x01u<<31u) /*MSYS_IE7 0x7C*/ +} MRV_LOCAL_IRQn_Type; + +#define MRV32_MGEUIE_IRQn MIE_16_IRQn +#define MRV32_MGECIE_IRQn MIE_17_IRQn +#define MRV32_MSYS_EIE0_IRQn MIE_24_IRQn +#define MRV32_MSYS_EIE1_IRQn MIE_25_IRQn +#define MRV32_MSYS_EIE2_IRQn MIE_26_IRQn +#define MRV32_MSYS_EIE3_IRQn MIE_27_IRQn +#define MRV32_MSYS_EIE4_IRQn MIE_28_IRQn +#define MRV32_MSYS_EIE5_IRQn MIE_29_IRQn +#ifndef MIV_RV32_V3_0 /*For MIV_RV32 v3.1*/ +#define MRV32_SUBSYSR_IRQn MIE_22_IRQn +#define MRV32_SUBSYS_IRQn MIE_23_IRQn +#define MRV32_MSYS_EIE6_IRQn MIE_30_IRQn +#define MRV32_MSYS_EIE7_IRQn MIE_31_IRQn +#else +#define MRV32_SUBSYS_IRQn MIE_30_IRQn +#endif /*MIV_RV32_V3_0*/ + +/*--------------------------------Public APIs---------------------------------*/ + +/***************************************************************************//** + The MRV32_clear_gpr_ecc_errors() function clears single bit ECC errors on the + GPRs. The ECC block does not write back corrected data to memory. Hence, when + ECC is enabled for the GPRs and if that data has a single bit error then the + data coming out of the ECC block is corrected and will not have the error, but + the data source will still have the error. Therefore, if data has a single bit + error, then the corrected data must be written back to prevent the single bit + error from becoming a double bit error. Clear the pending interrupt bit after + this using MRV32_mgeci_clear_irq() function to complete the ECC error handling. + + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline void MRV32_clear_gpr_ecc_errors(void) +{ + uint32_t temp; + + __asm__ __volatile__ ( + "sw x31, %0" + :"=m" (temp)); + + __asm__ volatile ( + "mv x31, x1;" + "mv x1, x31;" + + "mv x31, x2;" + "mv x2, x31;" + + "mv x31, x3;" + "mv x3, x31;" + + "mv x31, x4;" + "mv x4, x31;" + + "mv x31, x5;" + "mv x5, x31;" + + "mv x31, x6;" + "mv x6, x31;" + + "mv x31, x7;" + "mv x7, x31;" + + "mv x31, x8;" + "mv x8, x31;" + + "mv x31, x9;" + "mv x9, x31;" + + "mv x31, x10;" + "mv x10, x31;" + + "mv x31, x11;" + "mv x11, x31;" + + "mv x31, x12;" + "mv x12, x31;" + + "mv x31, x13;" + "mv x13, x31;" + + "mv x31, x14;" + "mv x14, x31;" + + "mv x31, x15;" + "mv x15, x31;" + + "mv x31, x16;" + "mv x16, x31;" + + "mv x31, x17;" + "mv x17, x31;" + + "mv x31, x18;" + "mv x18, x31;" + + "mv x31, x19;" + "mv x19, x31;" + + "mv x31, x20;" + "mv x20, x31;" + + "mv x31, x21;" + "mv x21, x31;" + + "mv x31, x22;" + "mv x22, x31;" + + "mv x31, x23;" + "mv x23, x31;" + + "mv x31, x24;" + "mv x24, x31;" + + "mv x31, x25;" + "mv x25, x31;" + + "mv x31, x26;" + "mv x26, x31;" + + "mv x31, x27;" + "mv x27, x31;" + + "mv x31, x28;" + "mv x28, x31;" + + "mv x31, x29;" + "mv x29, x31;" + + "mv x31, x30;" + "mv x30, x31;"); + + __asm__ __volatile__ ( + "lw x31, %0;" + : + :"m" (temp)); +} + + +/***************************************************************************//** + The MRV32_mgeui_clear_irq() function clears the GPR ECC Uncorrectable + Interrupt. MGEUI interrupt is available only when ECC is enabled in the MIV_RV32 + IP configurator. + + @return + This function does not return any value. + */ +static inline void MRV32_mgeui_clear_irq(void) +{ + clear_csr(mip, MRV32_MGEUIE_IRQn); +} + +/***************************************************************************//** + The MRV32_mgeci_clear_irq() function clears the GPR ECC Correctable Interrupt + MGECI interrupt is available only when ECC is enabled in the MIV_RV32 IP + configurator. + + @return + This function does not return any value. + */ +static inline void MRV32_mgeci_clear_irq(void) +{ + clear_csr(mip, MRV32_MGECIE_IRQn); +} + +/***************************************************************************//** + The MRV_enable_local_irq() function enables the local interrupts. It takes a + mask value as input. For each set bit in the mask value, the corresponding + interrupt bit in the MIE register is enabled. + + MRV_enable_local_irq( MRV32_SOFT_IRQn | MRV32_TIMER_IRQn | MRV32_EXT_IRQn | + MRV32_MSYS_EIE0_IRQn | + MRV32_MSYS_SUBSYS_IRQn); + */ +static inline void MRV_enable_local_irq(uint32_t mask) +{ + set_csr(mie, mask); +} + +/***************************************************************************//** + The MRV_disable_local_irq() function disables the local interrupts. It takes a + mask value as input. For each set bit in the mask value, the corresponding + interrupt bit in the MIE register is disabled. + + MRV_disable_local_irq( MRV32_SOFT_IRQn | MRV32_TIMER_IRQn | MRV32_EXT_IRQn | + MRV32_MSYS_EIE0_IRQn | + MRV32_MSYS_SUBSYS_IRQn); + */ +static inline void MRV_disable_local_irq(uint32_t mask) +{ + clear_csr(mie, mask); +} +#endif /* MIV_LEGACY_RV32 */ + +/***************************************************************************//** + The MRV_enable_interrupts() function enables all interrupts by setting the + machine mode interrupt enable bit in MSTATUS register. + + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline void MRV_enable_interrupts(void) +{ + set_csr(mstatus, MSTATUS_MIE); +} + +/***************************************************************************//** + The MRV_disable_interrupts() function disables all interrupts by clearing the + machine mode interrupt enable bit in MSTATUS register. + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline void MRV_disable_interrupts(void) +{ + clear_csr(mstatus, MSTATUS_MPIE); + clear_csr(mstatus, MSTATUS_MIE); +} + +/***************************************************************************//** + The MRV_read_mtvec_base() function reads the mtvec base value, which is the + addr used when an interrupt/trap occurs. In the mtvec register, [31:2] is the + BASE address. NOTE: The BASE address must be aligned on a 4B boundary. + + @param + The function does not take any parameters. + + @return + The function returns the value of the BASE field [31:2] as an unsigned 32-bit + value. + */ + +#ifndef MIV_LEGACY_RV32 +#ifndef MIV_RV32_v3_0 +static inline uint32_t MRV_read_mtvec_base (void) +{ + uint32_t mtvec_addr_base = read_csr(mtvec); + return mtvec_addr_base & MTVEC_BASE_ADDR_MASK; +} + +/***************************************************************************//** + The MRV_set_mtvec_base() function takes the mtvec_base address as a unsigned int + and writes the value into the BASE field [31:2] in the mtvec CSR, MODE[1:0] + is Read-only. BASE is 4B aligned, so the lowest 2 bits of mtvec_base are + ignored. + + @param mtvec_base + Any legal value is passed into the function, and it is used as the trap_entry + for interrupts. The PC jumps to this address provided when an interrupt occurs. + In case of vectored interrupts, the address value mentioned in the vector + table under the MIE Register Map is updated to the value passed to this + function parameter. + + @return + This function does not return any value. + */ +static inline void MRV_set_mtvec_base (uint32_t mtvec_base) +{ + mtvec_base = mtvec_base & MTVEC_BASE_ADDR_MASK; + write_csr(mtvec, mtvec_base); +} +#endif /*MIV_RV32_v3_0*/ +#endif /*MIV_LEGACY_RV32*/ + +/***************************************************************************//** + The MRV_read_mtime() function returns the current MTIME register value. + */ +static inline uint64_t MRV_read_mtime(void) +{ + volatile uint32_t hi = 0u; + volatile uint32_t lo = 0u; + + /* when mtime lower word is 0xFFFFFFFF, there will be rollover and + * returned value could be wrong. */ + do { + hi = MTIMEH; + lo = MTIME; + } while(hi != MTIMEH); + + return((((uint64_t)MTIMEH) << 32u) | lo); +} + +/***************************************************************************//** + The MRV_raise_soft_irq() function raises a synchronous software interrupt + by writing into the MSIP register. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV_raise_soft_irq(void) +{ + set_csr(mie, MIP_MSIP); /* Enable software interrupt bit */ + +#ifdef MIV_LEGACY_RV32 + /* You need to make sure that the global interrupt is enabled */ + MSIP = 0x01; /* raise soft interrupt */ +#else + /* Raise soft IRQ on MIV_RV32 processor */ + SUBSYS->soft_reg |= SUBSYS_SOFT_IRQ; +#endif +} + +/***************************************************************************//** + The MRV_clear_soft_irq() function clears a synchronous software interrupt + by clearing the MSIP register. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV_clear_soft_irq(void) +{ +#ifdef MIV_LEGACY_RV32 + MSIP = 0x00u; /* clear soft interrupt */ +#else + /* Clear soft IRQ on MIV_RV32 processor */ + SUBSYS->soft_reg &= ~SUBSYS_SOFT_IRQ; +#endif +} + +/***************************************************************************//** + System tick handler. This handler function gets called when the Machine + timer interrupt asserts. An implementation of this function must be provided + by the application to implement the application specific machine timer + interrupt handling. If application does not provide such implementation, the + weakly linked handler stub function implemented in riscv_hal_stubs.c gets + linked. + */ +void SysTick_Handler(void); + +/***************************************************************************//** + System timer tick configuration. + Configures the machine timer to generate a system tick interrupt at regular + intervals. Takes the number of system clock ticks between interrupts. + + Though this function can take any valid ticks value as parameter, we expect + that, for all practical purposes, a small tick value (to generate periodic + interrupts every few miliseconds) is passed. If you need to generate periodic + events in the range of seconds or more, you may use the SysTick_Handler() to + further count the number of interrupts and hence the larger time intervals. + + @param ticks + This is the number of ticks or clock cycles which are counted down from the + interrupt to be triggered. + + @return + Returns 0 if successful. + Returns 1 if the interrupt interval is not achieved. + */ +uint32_t MRV_systick_config(uint64_t ticks); + +#ifdef __cplusplus +} +#endif +#endif /* RISCV_HAL_H */ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv_rv32_hal_version.h b/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv_rv32_hal_version.h new file mode 100644 index 0000000..4922bf2 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv_rv32_hal_version.h @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_hal_version.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware Abstraction Layer functions for Mi-V soft processors + * + */ + +#ifndef MIV_RV32_HAL_VERSION_H +#define MIV_RV32_HAL_VERSION_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MIV_RV32_HAL_VERSION_MAJOR 4 +#define MIV_RV32_HAL_VERSION_MINOR 2 +#define MIV_RV32_HAL_VERSION_PATCH 100 + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv_rv32_init.c b/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv_rv32_init.c new file mode 100755 index 0000000..85f8aca --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv_rv32_init.c @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_init.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor memory section initializations and start-up code. + * + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern void main(void); + +void _init(void) +{ + /* This function is a placeholder for the case where some more hardware + * specific initializations are required before jumping into the application + * code. You can implement it here. */ + + /* Jump to the application code after all initializations are completed */ + main(); +} + +/* Function called after main() finishes */ +void +_fini(void) +{ +} + +#ifdef __cplusplus +} +#endif + diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv_rv32_plic.h b/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv_rv32_plic.h new file mode 100755 index 0000000..3fd4103 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv_rv32_plic.h @@ -0,0 +1,214 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_plic.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V legacy RV32 soft processor PLIC access data structures and + * functions. + * Legacy RV32 soft processors are DEPRICATED. + * Migrate to MIV_RV32 v3.0 or later. + * + */ +#ifndef RISCV_PLIC_H +#define RISCV_PLIC_H + +#include +#include "miv_rv32_regs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================== + * Interrupt numbers: + */ +#ifdef MIV_LEGACY_RV32 +typedef enum +{ + MRV_NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + External_3_IRQn = 3, + External_4_IRQn = 4, + External_5_IRQn = 5, + External_6_IRQn = 6, + External_7_IRQn = 7, + External_8_IRQn = 8, + External_9_IRQn = 9, + External_10_IRQn = 10, + External_11_IRQn = 11, + External_12_IRQn = 12, + External_13_IRQn = 13, + External_14_IRQn = 14, + External_15_IRQn = 15, + External_16_IRQn = 16, + External_17_IRQn = 17, + External_18_IRQn = 18, + External_19_IRQn = 19, + External_20_IRQn = 20, + External_21_IRQn = 21, + External_22_IRQn = 22, + External_23_IRQn = 23, + External_24_IRQn = 24, + External_25_IRQn = 25, + External_26_IRQn = 26, + External_27_IRQn = 27, + External_28_IRQn = 28, + External_29_IRQn = 29, + External_30_IRQn = 30, + External_31_IRQn = 31 +} IRQn_Type; + +#define EXT_INTR_SOURCES 31 + +/*============================================================================== + * PLIC: Platform Level Interrupt Controller + */ +#define PLIC_BASE_ADDR 0x40000000UL + +typedef struct +{ + volatile uint32_t PRIORITY_THRESHOLD; + volatile uint32_t CLAIM_COMPLETE; + volatile uint32_t reserved[1022]; +} MRV_IRQ_Target_Type; + +typedef struct +{ + volatile uint32_t ENABLES[32]; +} MRV_Target_Enables_Type; + +typedef struct +{ + /*-------------------- Source Priority --------------------*/ + volatile uint32_t SOURCE_PRIORITY[1024]; + + /*-------------------- Pending array --------------------*/ + volatile const uint32_t PENDING_ARRAY[32]; + volatile uint32_t RESERVED1[992]; + + /*-------------------- Target enables --------------------*/ + volatile MRV_Target_Enables_Type TARGET_ENABLES[15808]; + + volatile uint32_t RESERVED2[16384]; + + /*--- Target Priority threshold and claim/complete---------*/ + MRV_IRQ_Target_Type TARGET[15872]; + +} PLIC_Type; + +#define PLIC ((PLIC_Type *)PLIC_BASE_ADDR) + +/*============================================================================== + * The function MRV_PLIC_init() initializes the PLIC controller and enables + * the global external interrupt bit. + */ +static inline void MRV_PLIC_init(void) +{ + uint32_t inc; + unsigned long hart_id = read_csr(mhartid); + + /* Disable all interrupts for the current hart. */ + for(inc = 0; inc < ((EXT_INTR_SOURCES + 32u) / 32u); ++inc) + { + PLIC->TARGET_ENABLES[hart_id].ENABLES[inc] = 0; + } + + /* Set priorities to zero. */ + for(inc = 0; inc < EXT_INTR_SOURCES; ++inc) + { + PLIC->SOURCE_PRIORITY[inc] = 0; + } + + /* Set the threshold to zero. */ + PLIC->TARGET[hart_id].PRIORITY_THRESHOLD = 0; + + /* Enable machine external interrupts. */ + set_csr(mie, MIP_MEIP); +} + +/*============================================================================== + * The function MRV_PLIC_enable_irq() enables the external interrupt for the + * interrupt number indicated by the parameter IRQn. + */ +static inline void MRV_PLIC_enable_irq(IRQn_Type IRQn) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t current = PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32]; + current |= (uint32_t)1 << (IRQn % 32); + PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32] = current; +} + +/*============================================================================== + * The function MRV_PLIC_disable_irq() disables the external interrupt for + * the interrupt number indicated by the parameter IRQn. + + * NOTE: + * This function can be used to disable the external interrupt from outside + * external interrupt handler function. + * This function MUST NOT be used from within the External Interrupt handler. + * If you wish to disable the external interrupt while the interrupt handler + * for that external interrupt is executing then you must use the return value + * EXT_IRQ_DISABLE to return from the extern interrupt handler. + */ +static inline void MRV_PLIC_disable_irq(IRQn_Type IRQn) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t current = PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32]; + + current &= ~((uint32_t)1 << (IRQn % 32)); + + PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32] = current; +} + +/*============================================================================== + * The function MRV_PLIC_set_priority() sets the priority for the external + * interrupt for the interrupt number indicated by the parameter IRQn. + */ +static inline void MRV_PLIC_set_priority(IRQn_Type IRQn, uint32_t priority) +{ + PLIC->SOURCE_PRIORITY[IRQn] = priority; +} + +/*============================================================================== + * The function MRV_PLIC_get_priority() returns the priority for the external + * interrupt for the interrupt number indicated by the parameter IRQn. + */ +static inline uint32_t MRV_PLIC_get_priority(IRQn_Type IRQn) +{ + return PLIC->SOURCE_PRIORITY[IRQn]; +} + +/***************************************************************************//** + * MRV_PLIC_clear_pending_irq(void) + * This is only called by the startup hart and only once + * Clears any pending interrupts as PLIC can be in unknown state on startup + */ +static inline void MRV_PLIC_clear_pending_irq(void) +{ + unsigned long hart_id = read_csr(mhartid); + volatile uint32_t int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; + volatile int32_t wait_possible_int; + + while (MRV_NoInterrupt_IRQn != int_num) + { + PLIC->TARGET[hart_id].CLAIM_COMPLETE = int_num; + wait_possible_int = 0xFU; + while (wait_possible_int) + { + wait_possible_int--; + } + + int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; + } +} + +#endif /* MIV_LEGACY_RV32 */ + +#ifdef __cplusplus +} +#endif + +#endif /* RISCV_PLIC_H */ diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv_rv32_regs.h b/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv_rv32_regs.h new file mode 100755 index 0000000..07d58e7 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv_rv32_regs.h @@ -0,0 +1,520 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor register bit mask and shift constants encodings. + * + */ +#ifndef MIV_RV32_REGS_H +#define MIV_RV32_REGS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MSTATUS_UIE 0x00000001UL +#define MSTATUS_SIE 0x00000002UL +#define MSTATUS_HIE 0x00000004UL +#define MSTATUS_MIE 0x00000008UL +#define MSTATUS_UPIE 0x00000010UL +#define MSTATUS_SPIE 0x00000020UL +#define MSTATUS_HPIE 0x00000040UL +#define MSTATUS_MPIE 0x00000080UL +#define MSTATUS_SPP 0x00000100UL +#define MSTATUS_HPP 0x00000600UL +#define MSTATUS_MPP 0x00001800UL +#define MSTATUS_FS 0x00006000UL +#define MSTATUS_XS 0x00018000UL +#define MSTATUS_MPRV 0x00020000UL +#define MSTATUS_SUM 0x00040000UL +#define MSTATUS_MXR 0x00080000UL +#define MSTATUS_TVM 0x00100000UL +#define MSTATUS_TW 0x00200000UL +#define MSTATUS_TSR 0x00400000UL +#define MSTATUS_RES 0x7F800000UL +#define MSTATUS32_SD 0x80000000UL +#define MSTATUS64_SD 0x8000000000000000UL + +#define MCAUSE32_CAUSE 0x7FFFFFFFUL +#define MCAUSE64_CAUSE 0x7FFFFFFFFFFFFFFFUL +#define MCAUSE32_INT 0x80000000UL +#define MCAUSE64_INT 0x8000000000000000UL + +#define MIP_SSIP (1u << IRQ_S_SOFT) +#define MIP_HSIP (1u << IRQ_H_SOFT) +#define MIP_MSIP (1u << IRQ_M_SOFT) +#define MIP_STIP (1u << IRQ_S_TIMER) +#define MIP_HTIP (1u << IRQ_H_TIMER) +#define MIP_MTIP (1u << IRQ_M_TIMER) +#define MIP_SEIP (1u << IRQ_S_EXT) +#define MIP_HEIP (1u << IRQ_H_EXT) +#define MIP_MEIP (1u << IRQ_M_EXT) + +#define PRV_M 3U + +#define VM_MBARE 0U +#define VM_MBB 1U +#define VM_MBBID 2U +#define VM_SV32 8U +#define VM_SV39 9U +#define VM_SV48 10U + +#define IRQ_S_SOFT 1U +#define IRQ_H_SOFT 2U +#define IRQ_M_SOFT 3U +#define IRQ_S_TIMER 5U +#define IRQ_H_TIMER 6U +#define IRQ_M_TIMER 7U +#define IRQ_S_EXT 9U +#define IRQ_H_EXT 10U +#define IRQ_M_EXT 11U + +#define DEFAULT_RSTVEC 0x00001000 +#define DEFAULT_NMIVEC 0x00001004 +#define DEFAULT_MTVEC 0x00001010 +#define CONFIG_STRING_ADDR 0x0000100C +#define EXT_IO_BASE 0x40000000 +#define DRAM_BASE 0x80000000 + +#ifdef __riscv + +#if __riscv_xlen == 64 +# define MSTATUS_SD MSTATUS64_SD +# define SSTATUS_SD SSTATUS64_SD +# define MCAUSE_INT MCAUSE64_INT +# define MCAUSE_CAUSE MCAUSE64_CAUSE +# define RISCV_PGLEVEL_BITS 9 +#else +# define MSTATUS_SD MSTATUS32_SD +# define SSTATUS_SD SSTATUS32_SD +# define RISCV_PGLEVEL_BITS 10 +# define MCAUSE_INT MCAUSE32_INT +# define MCAUSE_CAUSE MCAUSE32_CAUSE +#endif + +#define RISCV_PGSHIFT 12U +#define RISCV_PGSIZE (1U << RISCV_PGSHIFT) + +#ifndef __ASSEMBLER__ + +#ifdef __GNUC__ + +#define read_csr(reg) ({ unsigned long __tmp; \ + __asm__ volatile ("csrr %0, " #reg : "=r"(__tmp)); \ + __tmp; }) + +#define write_csr(reg, val) ({ \ + __asm__ volatile ("csrw " #reg ", %0" :: "rK"(val)); }) + +#define swap_csr(reg, val) ({ unsigned long __tmp; \ + __asm__ volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "rK"(val)); \ + __tmp; }) + +#define set_csr(reg, bit) ({ unsigned long __tmp; \ + __asm__ volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ + __tmp; }) + +#define clear_csr(reg, bit) ({ unsigned long __tmp; \ + __asm__ volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ + __tmp; }) + +#ifdef __riscv_atomic + +#define MASK(nr) (1UL << nr) +#define MASK_NOT(nr) (~(1UL << nr)) + +/** + * atomic_read - read atomic variable + * @v: pointer of type int + * + * Atomically reads the value of @v. + */ +static inline int atomic_read(const int *v) +{ + return *((volatile int *)(v)); +} + +/** + * atomic_set - set atomic variable + * @v: pointer of type int + * @i: required value + * + * Atomically sets the value of @v to @i. + */ +static inline void atomic_set(int *v, int i) +{ + *v = i; +} + +/** + * atomic_add - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v. + */ +static inline void atomic_add(int i, int *v) +{ + __asm__ __volatile__ ( + "amoadd.w zero, %1, %0" + : "+A" (*v) + : "r" (i)); +} + +static inline int atomic_fetch_add(unsigned int mask, int *v) +{ + int out; + + __asm__ __volatile__ ( + "amoadd.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_sub - subtract integer from atomic variable + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v. + */ +static inline void atomic_sub(int i, int *v) +{ + atomic_add(-i, v); +} + +static inline int atomic_fetch_sub(unsigned int mask, int *v) +{ + int out; + + __asm__ __volatile__ ( + "amosub.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_add_return - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v and returns the result + */ +static inline int atomic_add_return(int i, int *v) +{ + register int c; + __asm__ __volatile__ ( + "amoadd.w %0, %2, %1" + : "=r" (c), "+A" (*v) + : "r" (i)); + return (c + i); +} + +/** + * atomic_sub_return - subtract integer from atomic variable + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v and returns the result + */ +static inline int atomic_sub_return(int i, int *v) +{ + return atomic_add_return(-i, v); +} + +/** + * atomic_inc - increment atomic variable + * @v: pointer of type int + * + * Atomically increments @v by 1. + */ +static inline void atomic_inc(int *v) +{ + atomic_add(1, v); +} + +/** + * atomic_dec - decrement atomic variable + * @v: pointer of type int + * + * Atomically decrements @v by 1. + */ +static inline void atomic_dec(int *v) +{ + atomic_add(-1, v); +} + +static inline int atomic_inc_return(int *v) +{ + return atomic_add_return(1, v); +} + +static inline int atomic_dec_return(int *v) +{ + return atomic_sub_return(1, v); +} + +/** + * atomic_sub_and_test - subtract value from variable and test result + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v and returns + * true if the result is zero, or false for all + * other cases. + */ +static inline int atomic_sub_and_test(int i, int *v) +{ + return (atomic_sub_return(i, v) == 0); +} + +/** + * atomic_inc_and_test - increment and test + * @v: pointer of type int + * + * Atomically increments @v by 1 + * and returns true if the result is zero, or false for all + * other cases. + */ +static inline int atomic_inc_and_test(int *v) +{ + return (atomic_inc_return(v) == 0); +} + +/** + * atomic_dec_and_test - decrement and test + * @v: pointer of type int + * + * Atomically decrements @v by 1 and + * returns true if the result is 0, or false for all other + * cases. + */ +static inline int atomic_dec_and_test(int *v) +{ + return (atomic_dec_return(v) == 0); +} + +/** + * atomic_add_negative - add and test if negative + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v and returns true + * if the result is negative, or false when + * result is greater than or equal to zero. + */ +static inline int atomic_add_negative(int i, int *v) +{ + return (atomic_add_return(i, v) < 0); +} + +static inline int atomic_xchg(int *v, int n) +{ + register int c; + __asm__ __volatile__ ( + "amoswap.w %0, %2, %1" + : "=r" (c), "+A" (*v) + : "r" (n)); + return c; +} + +/** + * atomic_and - Atomically clear bits in atomic variable + * @mask: Mask of the bits to be retained + * @v: pointer of type int + * + * Atomically retains the bits set in @mask from @v + */ +static inline void atomic_and(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoand.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_and(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoand.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_or - Atomically set bits in atomic variable + * @mask: Mask of the bits to be set + * @v: pointer of type int + * + * Atomically sets the bits set in @mask in @v + */ +static inline void atomic_or(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoor.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_or(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoor.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_xor - Atomically flips bits in atomic variable + * @mask: Mask of the bits to be flipped + * @v: pointer of type int + * + * Atomically flips the bits set in @mask in @v + */ +static inline void atomic_xor(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoxor.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_xor(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoxor.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * test_and_set_bit - Set a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_set_bit(int nr, volatile unsigned long *addr) +{ + unsigned long __res, __mask; + __mask = MASK(nr); + __asm__ __volatile__ ( \ + "amoor.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to clear + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_clear_bit(int nr, volatile unsigned long *addr) +{ + unsigned long __res, __mask; + __mask = MASK_NOT(nr); + __asm__ __volatile__ ( \ + "amoand.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * test_and_change_bit - Change a bit and return its old value + * @nr: Bit to change + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_change_bit(int nr, volatile unsigned long *addr) +{ + + unsigned long __res, __mask; + __mask = MASK(nr); + __asm__ __volatile__ ( \ + "amoxor.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * set_bit - Atomically set a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * This function is atomic and may not be reordered. + */ + +static inline void set_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOOR.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK(nr))); +} + +/** + * clear_bit - Clears a bit in memory + * @nr: Bit to clear + * @addr: Address to start counting from + * + * clear_bit() is atomic and may not be reordered. + */ +static inline void clear_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOAND.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK_NOT(nr))); +} + +/** + * change_bit - Toggle a bit in memory + * @nr: Bit to change + * @addr: Address to start counting from + * + * change_bit() is atomic and may not be reordered. + */ +static inline void change_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOXOR.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK(nr))); +} + +#endif /* __riscv_atomic */ + +#endif /* __GNUC__ */ + +#endif /* __ASSEMBLER__ */ + +#endif /* __riscv */ + +#ifdef __cplusplus +} +#endif + +#endif /* RISCV_REGS_H */ diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv_rv32_stubs.c b/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv_rv32_stubs.c new file mode 100755 index 0000000..e26ecfc --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv_rv32_stubs.c @@ -0,0 +1,243 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_stubs.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Stubs for the Mi-V soft processor Interrupt handler. + * + * The functions below will only be linked with the application code if the user + * does not provide an implementation for these functions. These functions are + * defined with weak linking so that they can be overridden by a function with + * same prototype in the user's application code. + * + */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +__attribute__((weak)) void Software_IRQHandler(void) +{ + _exit(10); +} + +__attribute__((weak)) void SysTick_Handler(void) +{ + /* Default handler */ +} + +#ifdef MIV_LEGACY_RV32 +__attribute__((weak)) uint8_t Invalid_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_1_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_2_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_3_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_4_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_5_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_6_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_7_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_8_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_9_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_10_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_11_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_12_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_13_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_14_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_15_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_16_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_17_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_18_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_19_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_20_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_21_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_22_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_23_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_24_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_25_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_26_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_27_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_28_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_29_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_30_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_31_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +#else +__attribute__((weak)) void External_IRQHandler(void) +{ +} +__attribute__((weak)) void MGECI_IRQHandler(void) +{ +} +__attribute__((weak)) void MGEUI_IRQHandler(void) +{ +} +__attribute__((weak)) void SUBSYS_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI0_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI1_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI2_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI3_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI4_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI5_IRQHandler(void) +{ +} +__attribute__((weak)) void Reserved_IRQHandler(void) +{ + _exit(10); +} +#ifndef MIV_RV32_V3_0 /* For MIV_RV32 v3.0 */ +__attribute__((weak)) void MSYS_EI6_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI7_IRQHandler(void) +{ +} +__attribute__((weak)) void SUBSYSR_IRQHandler(void) +{ +} +#endif /* MIV_RV32_V3_0 */ +#endif /* MIV_LEGACY_RV32 */ + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv_rv32_subsys.h b/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv_rv32_subsys.h new file mode 100644 index 0000000..509f13b --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv_rv32_subsys.h @@ -0,0 +1,293 @@ +/******************************************************************************* + * Copyright 2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_subsys.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor SUBSYS regsiter description and API fuctions. + * + */ +#ifndef MIV_RV32_SUBSYS_H +#define MIV_RV32_SUBSYS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef MIV_LEGACY_RV32 +#define MGEUI 16U +#define MGECI 17U +#define MSYS_EI0 24U +#define MSYS_EI1 25U +#define MSYS_EI2 26U +#define MSYS_EI3 27U +#define MSYS_EI4 28U +#define MSYS_EI5 29U + +#define MGEUI_MEIP (1u << MGEUI) +#define MGECI_MEIP (1u << MGECI) +#define MSYS_EI0IP (1u << MSYS_EI0) +#define MSYS_EI1IP (1u << MSYS_EI1) +#define MSYS_EI2IP (1u << MSYS_EI2) +#define MSYS_EI3IP (1u << MSYS_EI3) +#define MSYS_EI4IP (1u << MSYS_EI4) +#define MSYS_EI5IP (1u << MSYS_EI5) + +#define MIV_LOCAL_IRQ_MIN 16 +#ifndef MIV_RV32_V3_0 /*For MIV_RV32 v3.1*/ +#define SUBSYSR 22U +#define SUBSYS_EI 23U +#define MSYS_EI6 30U +#define MSYS_EI7 31U +#define MIV_SUBSYSR (1u << SUBSYSR) +#define MIV_SUBSYS (1u << SUBSYS_EI) +#define MSYS_EI6IP (1u << MSYS_EI6) +#define MSYS_EI7IP (1u << MSYS_EI7) +#define MIV_LOCAL_IRQ_MAX 31 + +#else /* MIV_RV32_V3_0 */ +#define MIV_LOCAL_IRQ_MAX 29 +#define SUBSYS_EI 30U +#define MIP_SUBSYS_REG (1u << SUBSYS_EI) + +#endif /* MIV_RV32_V3_0 */ +#endif /* MIV_LEGACY_RV32 */ + +#ifdef MIV_LEGACY_RV32 +#define MIV_LOCAL_IRQ_MAX 0U +#define MIV_LOCAL_IRQ_MIN 0U +#endif /* MIV_LEGACY_RV32 */ + +#ifdef __cplusplus +} +#endif + +/*-------------------------------------------------------------------------*//** + SUBSYS Register Configuration + ======================================= + For the SUBSYS registers configutation, the following definitions are used in + the SUBSUS API functions. For example, to raise soft interrupts, enable parity + checks, soft reset, and so on. + + | Configuration | Value | Description | + |--------------------------|-------|------------------------------------------------| + | SUBSYS_SOFT_REG_GRP_DED | 0x04 | Mask for the Core GPR DED Reset Register | + | SUBSYS_CFG_PARITY_CHECK | 0x01 | Use to set or clear the parity check on the TCM | + | SUBSYS_SOFT_RESET | 0x01 | Use the SUBSYS soft reset the MIV_RV32 IP core | + | SUBSYS_SOFT_IRQ | 0x02 | Use to raise a software interrupt through SUBSYS| + */ +/*Mask for the Core GPR DED Reset Register*/ +#define SUBSYS_SOFT_REG_GRP_DED 0x04U + +/*Use to set or clear the parity check on the TCM*/ +#define SUBSYS_CFG_PARITY_CHECK 0x01U + +/*Use the SUBSYS soft reset the MIV_RV32 IP core*/ +#define SUBSYS_SOFT_RESET 0x01U + +/*Use to raise a software interrupt through SUBSYS*/ +#define SUBSYS_SOFT_IRQ 0x02U + +/*-------------------------------------------------------------------------*//** + SUBSYS Interrupt Request Masks + ======================================= + The following values correspond to the bit value of the SUBSYS interrupt + enable and interrupt pending register. + + | Interrupt Mask | Value | Description | + |----------------------------|---------|-------------------------------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | TCM ECC controllable error irq enable | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | TCM ECC uncontrollable error irq enable | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | AXI write response error irq enable | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | Icache ECC Correctable error irq | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | Icache ECC Uncorrectable error irq | + | SUBSYS_BASE_ADDR | 0x6000u | Base address of the SUBSYS | + */ +/* TCM ECC correctable error irq enable mask value */ +#define SUBSYS_TCM_ECC_CE_IRQ 0x01u + +/* TCMECC uncorrectable error irq enable */ +#define SUBSYS_TCM_ECC_UCE_IRQ 0x02u + +/* AXI write response error irq enable */ +#define SUBSYS_AXI_WR_RESP_IRQ 0x10u + +/*Icache ECC Correctable error irq*/ +#define SUBSYS_ICACHE_ECC_CE_IRQ 0x40u + +/*Icache ECC Uncorrectable error irq*/ +#define SUBSYS_ICACHE_ECC_UCE_IRQ 0x80u + +/*Base address of the SUBSYS*/ +#define SUBSYS_BASE_ADDR 0x00006000UL + +/***************************************************************************//** + Subsys contains interrupt enable, interrupt pending and Subsys registers + which can be used to enable SUBSYS specific features such as ECC for vaious + memories. For more available features refer to the MIV_RV32 User Guide +*/ +typedef struct +{ + volatile uint32_t cfg; /*Parity is not supported by MIV_RV32 v3.1 and MIV_RV32 v3.0.100*/ + volatile uint32_t reserved0[3]; + volatile uint32_t irq_en; /*offset 0x10*/ + volatile uint32_t irq_pend; + volatile uint32_t reserved1[2]; + volatile uint32_t soft_reg; /*offset 0x20*/ +} SUBSYS_Type; + +#define SUBSYS ((SUBSYS_Type *)SUBSYS_BASE_ADDR) + +/***************************************************************************//** + The MRV32_subsys_enable_irq() function initializes the SUBSYS interrupts. It + takes the logical OR of the following defined IRQ masks as a parameter. + + @param irq_mask + | irq_mask | Value | + |------------------------|------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | + Use logical OR values of one or more interrupts to enable them in the SUBSYS + @return + This function does not return any value. + */ +static inline void MRV32_subsys_enable_irq(uint32_t irq_mask) +{ + SUBSYS->irq_en |= irq_mask; +} + +/***************************************************************************//** + The MRV32_subsys_disable_irq() function disables the SUBSYS interrupts. It + takes the logical OR of the following defined IRQ masks as a parameter. + + @param irq_mask + | irq_mask | Value | + |------------------------|------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | + Use logical OR values of one or more interrupts to disable them in the SUBSYS + @return + This function does not return any value. + */ +static inline void MRV32_subsys_disable_irq(uint32_t irq_mask) +{ + SUBSYS->irq_en &= ~irq_mask; +} + +/***************************************************************************//** + The MRV32_subsys_clear_irq() function clears the SUBSYS interrupts, which was + triggered. It takes the logical OR of the following defined IRQ masks as a + parameter. + @param irq_mask + | irq_mask | Value | + |------------------------|------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | + Use logical OR values of one or more interrupts to disable them in the SUBSYS + @return + This function does not return any value. + */ +static inline void MRV32_subsys_clear_irq(uint32_t irq_mask) +{ + SUBSYS->irq_pend |= irq_mask; +} + +/***************************************************************************//** + The MRV32_subsys_irq_cause() function returns the irq_pend register value which + is present in the SUBSYS. This is be used to check which irq_mask value + caused the SUBSYS interrupt to occur. + @param + This function does not take any parameters + + @return + This function returns the irq_pend regsiter value. +*/ +static inline uint32_t MRV32_subsys_irq_cause() +{ + return SUBSYS->irq_pend; +} + +/***************************************************************************//** + The MRV32_is_gpr_ded() function returns the core_gpr_ded_reset_reg bit value. + When ECC is enabled, the core_gpr_ded_reset_reg is set when the core was + reset due to GPR DED error. + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline uint32_t MRV32_is_gpr_ded(void) +{ + return((SUBSYS->soft_reg & SUBSYS_SOFT_REG_GRP_DED) >> 0x02u); +} + +/***************************************************************************//** + The MRV32_clear_gpr_ded() function must be used to clear the + core_gpr_ded_reset_reg bit. When ECC is enabled, the core_gpr_ded_reset_reg is + set when the core was previously reset due to GPR DED error. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV32_clear_gpr_ded(void) +{ + SUBSYS->soft_reg &= ~SUBSYS_SOFT_REG_GRP_DED; +} + +/***************************************************************************//** + The MRV32_enable_parity_check() function is used to enable parity check on + the TCM and it's interface transactions. This feature is not available on + MIV_RV32 v3.1 and MIV_RV32 v3.0.100 + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV32_enable_parity_check(void) +{ + SUBSYS->cfg |= SUBSYS_CFG_PARITY_CHECK; +} + +/***************************************************************************//** + The MRV32_disable_parity_check() function is used to disable parity check on + the TCM and it's interface transactions. + @param + This function does not take any parameters + + @return + This function does not return any value. + + */ +static inline void MRV32_disable_parity_check(void) +{ + SUBSYS->cfg &= ~SUBSYS_CFG_PARITY_CHECK; +} + +/***************************************************************************//** + The MRV32_cpu_soft_reset() function is used to cause a soft cpu reset on + the MIV_RV32 soft processor core. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV32_cpu_soft_reset(void) +{ + SUBSYS->soft_reg |= SUBSYS_SOFT_RESET; +} +#endif /* MIV_RV32_SUBSYS_H */ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv_rv32_syscall.c b/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv_rv32_syscall.c new file mode 100755 index 0000000..bd2f881 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/miv_rv32_syscall.c @@ -0,0 +1,364 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_syscall.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Stubs for system calls. + * + */ +#include +#include +#include +#include +#include "miv_rv32_hal.h" + +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +#include + +#ifndef LEGACY_DIR_STRUCTURE +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" +#else +#include "core_uart_apb.h" +#endif + +#endif /*MSCC_STDIO_THRU_CORE_UART_APB*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + +/*------------------------------------------------------------------------------ + * CoreUARTapb instance data for the CoreUARTapb instance used for standard + * output. + */ +static UART_instance_t g_stdio_uart; + +/*============================================================================== + * Flag used to indicate if the UART driver needs to be initialized. + */ +static int g_stdio_uart_init_done = 0; + +/* + * Disable semihosting apis + */ +#pragma import(__use_no_semihosting_swi) + +/*============================================================================== + * sendchar() + */ +int sendchar(int ch) +{ + /*-------------------------------------------------------------------------- + * Initialize the UART driver if it is the first time this function is + * called. + */ + if ( !g_stdio_uart_init_done ) + { + /****************************************************************************** + * Baud value: + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + UART_init( &g_stdio_uart, + MSCC_STDIO_UART_BASE_ADDR, + ((SYS_CLK_FREQ/(16 * MSCC_STDIO_BAUD_VALUE))-1), + (DATA_8_BITS | NO_PARITY)); + + g_stdio_uart_init_done = 1; + } + + /*-------------------------------------------------------------------------- + * Output text to the UART. + */ + UART_send( &g_stdio_uart, (uint8_t *)&ch, 1 ); + + return (ch); +} + +/*============================================================================== + * getachar() + */ +int getachar(void) +{ + uint8_t rx_size; + uint8_t rx_byte; + + if ( !g_stdio_uart_init_done ) + { + /****************************************************************************** + * Baud value: + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + UART_init( &g_stdio_uart, + MSCC_STDIO_UART_BASE_ADDR, + ((SYS_CLK_FREQ/(16 * MSCC_STDIO_BAUD_VALUE))-1), + (DATA_8_BITS | NO_PARITY)); + + g_stdio_uart_init_done = 1; + } + + do + { + rx_size = UART_get_rx(&g_stdio_uart, &rx_byte, 1); + } while(0u == rx_size); + + return rx_byte; +} + +#endif /*MSCC_STDIO_THRU_CORE_UART_APB*/ + +#undef errno +static int errno; + +static char *__env[1] = { 0 }; +char **environ = __env; + +void write_hex(int fd, uint32_t hex) +{ + char towrite; + + write( fd , "0x", 2U ); + + for (uint32_t ii = 8U ; ii > 0U; ii--) + { + uint32_t jj = ii-1U; + uint8_t digit = ((hex & (0xFU << (jj*4U))) >> (jj*4U)); + towrite = digit < 0xAU ? (0x48U + digit) : (0x65U + (digit - 0xAU)); + write( fd, &towrite, 1U); + } +} + + +#ifdef GDB_TESTING +void __attribute__((optimize("O0"))) _exit(int code) +#else +void _exit(int code) +#endif +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + const char * message = "\nProgam has exited with code:"; + + write(STDERR_FILENO, message, strlen(message)); + write_hex(STDERR_FILENO, code); +#endif + + while (1){}; +} + +void *_sbrk(ptrdiff_t incr) +{ + extern char _end; + extern char _heap_end; + extern char __heap_start; + extern char __heap_end; + static char *curbrk = &_end; + void * ret = NULL; + + /* + * Did we allocated memory for the heap in the linker script? + * You need to set HEAP_SIZE to a non-zero value in your linker script if + * the following assertion fires. + */ + ASSERT(&__heap_end > &__heap_start); + + if (((curbrk + incr) < &_end) || ((curbrk + incr) > &_heap_end)) + { + errno = ENOMEM; + ret = ((char *) - 1); + } + else + { + curbrk += incr; + ret = curbrk - incr; + } + + /* + * Did we run out of heap? + * You need to increase the heap size in the linker script if the following + * assertion fires. + * */ + ASSERT(curbrk <= &__heap_end); + + return(ret); +} + +int _isatty(int fd) +{ + int ret = 0; + + if (fd <= 2) /* one of stdin, stdout, stderr */ + { + ret = 1; + } + else + { + errno = EBADF; + ret = 0; + } + + return(ret); +} + +static int stub(int err) +{ + errno = err; + return -1; +} + +int _open(const char* name, int flags, int mode) +{ + return stub(ENOENT); +} + +int _openat(int dirfd, const char* name, int flags, int mode) +{ + return stub(ENOENT); +} + +int _close(int fd) +{ + return stub(EBADF); +} + +int _execve(const char* name, char* const argv[], char* const env[]) +{ + return stub(ENOMEM); +} + +int _fork(void) +{ + return stub(EAGAIN); +} + +int _fstat(int fd, struct stat *st) +{ + int ret = 0; + + if (isatty(fd)) + { + st->st_mode = S_IFCHR; + ret = 0; + } + else + { + ret = stub(EBADF); + } + + return ret; +} + +int _getpid(void) +{ + return 1; +} + +int _kill(int pid, int sig) +{ + return stub(EINVAL); +} + +int _link(const char *old_name, const char *new_name) +{ + return stub(EMLINK); +} + +off_t _lseek(int fd, off_t ptr, int dir) +{ + off_t ret = 0; + if (_isatty(fd)) + { + ret = 0; + } + else + { + ret = stub(EBADF); + } + + return ret; +} + +ssize_t _read(int fd, void* ptr, size_t len) +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + + char* ptr1 = (char*)ptr; + + if (_isatty(fd)) + { + int count; + + for (count = 0; count < len; count++) + { + ptr1[count] = getachar(); + sendchar(ptr1[count]); + + /* Return partial buffer if we get EOL */ + if (('\r' == ptr1[count])||('\n' == ptr1[count])) + { + ptr1[count] = '\n'; + return count; + } + } + + return count; /* Filled the buffer */ + } +#endif + + return stub(EBADF); +} + +int _stat(const char* file, struct stat* st) +{ + return stub(EACCES); +} + +clock_t _times(struct tms* buf) +{ + return stub(EACCES); +} + +int _unlink(const char* name) +{ + return stub(ENOENT); +} + +int _wait(int* status) +{ + return stub(ECHILD); +} + +ssize_t _write(int fd, const void* ptr, size_t len) +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + int count_out; + char* ptr1 = (char*)ptr; + + /*-------------------------------------------------------------------------- + * Output text to the UART. + */ + count_out = 0; + while(len--) + { + sendchar(ptr1[count_out]); + count_out++; + } + + errno = 0; + return count_out; + +#else /* MSCC_STDIO_THRU_CORE_UART_APB */ + + return stub(EBADF); + +#endif /* MSCC_STDIO_THRU_CORE_UART_APB */ + +} + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/sample_fpga_design_config.h b/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/sample_fpga_design_config.h new file mode 100644 index 0000000..a380d96 --- /dev/null +++ b/applications/user-crypto/miv-rv32-dsa-services/src/platform/miv_rv32_hal/sample_fpga_design_config.h @@ -0,0 +1,167 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file sample_fpga_design_config.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Sample design configuration settings + * + */ + /*========================================================================*//** + @mainpage + Example file detailing how the fpga_design_config.h should be constructed + for the SoftConsole project targeted for Mi-V processors. + + @section intro_sec Introduction + The SoftConsole project targeted for Mi-V processors now have an improved + folder structure. Detailed description of the folder structure is available + at https://github.com/Mi-V-Soft-RISC-V/miv-rv32-documentation. + + The fpga_design_config.h must be stored as shown below + /boards//fpga_design_config.h + + Currently this file must be hand crafted when using the Mi-V Soft Processor. + In future, all the design and soft IP configurations will be automatically + generated from the Libero design description data. + + You can use this sample file as an example. + Rename this file from sample_fpga_design_config.h to fpga_design_config.h + and then customize it per your hardware design. + + @section Project configuration Instructions + 1. Change SYS_CLK_FREQ define to frequency of Mi-V Soft processor clock + 2 Add all the soft IP core BASE addresses + 3. Add the peripheral Core Interrupts to Mi-V Soft processor IRQ number + mappings + 4. Define MSCC_STDIO_UART_BASE_ADDR if you want a CoreUARTapb mapped to + STDIO + + **NOTE** + In the legacy folder structures, the file hw_config.h as was used at the + root of the project folder. This file is now depricated. + +*//*=========================================================================*/ + +#ifndef FPGA_DESIGN_CONFIG_H_ +#define FPGA_DESIGN_CONFIG_H_ + +/***************************************************************************//** + * Soft-processor clock definition + * This is the only clock brought over from the Mi-V Libero design. + */ +#ifndef SYS_CLK_FREQ +#define SYS_CLK_FREQ 50000000UL +#endif + +/***************************************************************************//** + * Peripheral base addresses. + * Format of define is: + * __BASE_ADDR + * The field is optional if there is only one instance of the core + * in the design + * MIV_ESS is an extended peripheral subsystem IP core with peripherals + * connections as defined below. + * The system can be further extended by attaching APB peripherals to the + * empty APB slots. + */ +#define MIV_ESS_PLIC_BASE_ADDR 0x70000000UL +#define COREUARTAPB0_BASE_ADDR 0x71000000UL +#define MIV_MTIMER_BASE_ADDR 0x72000000UL +#define MIV_ESS_APBSLOT3_BASE_ADDR 0x73000000UL +#define MIV_ESS_APBSLOT4_BASE_ADDR 0x74000000UL +#define COREGPIO_OUT_BASE_ADDR 0x75000000UL +#define CORESPI_BASE_ADDR 0x76000000UL +#define MIV_ESS_uDMA_BASE_ADDR 0x78000000UL +#define MIV_ESS_WDOG_BASE_ADDR 0x79000000UL +#define MIV_ESS_I2C_BASE_ADDR 0x7A000000UL +#define MIV_ESS_APBSLOTB_BASE_ADDR 0x7B000000UL +#define MIV_ESS_APBSLOTC_BASE_ADDR 0x7C000000UL +#define MIV_ESS_APBSLOTD_BASE_ADDR 0x7D000000UL +#define MIV_ESS_APBSLOTE_BASE_ADDR 0x7E000000UL +#define MIV_ESS_APBSLOTF_BASE_ADDR 0x7F000000UL + +/***************************************************************************//** + * Peripheral Interrupts are mapped to the corresponding Mi-V Soft processor + * interrupt in the Libero design. + * + * On the legacy RV32 cores, there can be up to 31 external interrupts (IRQ[30:0] + * pins). The legacy RV32 Soft processor external interrupts are defined in the + miv_rv32_plic.h + * + * These are of the form + * typedef enum +{ + NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + . + . + . + External_31_IRQn = 31 +} IRQn_Type; + + On the legacy RV32 processors, the PLIC identifies the interrupt and passes it + on to the processor core. The interrupt 0 is not used. The pin IRQ[0] should + map to External_1_IRQn likewise IRQ[30] should map to External_31_IRQn + +e.g + +#define TIMER0_IRQn External_30_IRQn +#define TIMER1_IRQn External_31_IRQn + + The MIV_RV32 soft processor has up to six optional system interrupts, MSYS_EI[n] + in addition to one EXT_IRQ. + The MIV_RV32 does not have an inbuilt PLIC and all the interrupts are directly + delivered to the processor core, hence unlike legacy RV32 cores, no interrupt + number mapping is necessary on MIV_RV32 core. + */ + +/**************************************************************************** + * Baud value to achieve a 115200 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ +#define BAUD_VALUE_115200 ((SYS_CLK_FREQ / (16 * 115200)) - 1) + +/****************************************************************************** + * Baud value to achieve a 57600 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + #define BAUD_VALUE_57600 ((SYS_CLK_FREQ / (16 * 57600)) - 1) + +/***************************************************************************//** + * Define MSCC_STDIO_THRU_CORE_UART_APB in the project settings if you want the + * standard IOs to be redirected to a terminal via UART. + */ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +/* + * A base address mapping for the STDIO printf/scanf mapping to CortUARTapb + * must be provided if it is being used + * + * e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR + */ +#define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB0_BASE_ADDR + +#ifndef MSCC_STDIO_UART_BASE_ADDR +#error MSCC_STDIO_UART_BASE_ADDR not defined- e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR +#endif + +#ifndef MSCC_STDIO_BAUD_VALUE +/* + * The MSCC_STDIO_BAUD_VALUE define should be set in your project's settings to + * specify the baud value used by the standard output CoreUARTapb instance for + * generating the UART's baud rate if you want a different baud rate from the + * default of 115200 baud + */ +#define MSCC_STDIO_BAUD_VALUE 115200 +#endif /*MSCC_STDIO_BAUD_VALUE*/ + +#endif /* end of MSCC_STDIO_THRU_CORE_UART_APB */ +/******************************************************************************* + * End of user edit section + */ +#endif /* FPGA_DESIGN_CONFIG_H_ */ diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/.cproject b/applications/user-crypto/miv-rv32-ecdsa-services/.cproject new file mode 100755 index 0000000..20076af --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/.cproject @@ -0,0 +1,333 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/.gitignore b/applications/user-crypto/miv-rv32-ecdsa-services/.gitignore new file mode 100755 index 0000000..f1b6b72 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/.gitignore @@ -0,0 +1,3 @@ +/.settings/ +/*miv-rv32-imc-debug*/ +/*miv-rv32-imc-release*/ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/.project b/applications/user-crypto/miv-rv32-ecdsa-services/.project new file mode 100755 index 0000000..c537dbe --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/.project @@ -0,0 +1,26 @@ + + + miv-rv32-ecdsa-services + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/README.md b/applications/user-crypto/miv-rv32-ecdsa-services/README.md new file mode 100755 index 0000000..8c66f19 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/README.md @@ -0,0 +1,176 @@ +PolarFire User Crypto ECDSA Services example +================================================================================ +This Example Project demonstrates the usage of the User Crypto hardware block for +the signature generation and verification using ECDSA service functions. It uses +**NIST-P384** elliptic curve for signature generation and verification. + + - CALECDSASignHash() is used to generate digital signature. + - CALECDSAVerifyHash() is used to verify the digital signature. + +User can Experiment with different standard elliptic curves supported by user- +crypto core by changing curve domain parameters. + +Here's the list of supported NIST-P curves +- *P192*,*P224*,*P256*,*P384*,*P512* + +**NOTE** -: Athena core uses an Elliptic curve of the following format. + +> Y = X^3 - 3X + b + +The coefficient of X is fixed to a = -3 thus one should only choose a set of +domain parameters which is based on the above mentioned elliptic curve. + +There are two different build configurations provided with this project which +configure this SoftConsole project for RISC-V IMC instruction extension. +The following configurations are provided with the example: + + - miv-rv32-imc-debug + - miv-rv32-imc-release + +Mi-V Soft Processor +-------------------------------------------------------------------------------- +This example uses Mi-V SoftProcessor MiV_RV32.The design is built for debugging +MiV_RV32 through the PolarFire FPGA programming JTAG port using a FlashPro5. +To achieve this the CoreJTAGDebug IP is used to connect to the JTAG port of the +MiV_RV32. + +All the platform/design specific definitions such as peripheral base addresses, +system clock frequency etc. are included in fpga_design_config.h. The +fpga_design_config.h is located at the root folder of this project. + +The Mi-V Soft Processor MiV_RV32 firmware projects needs the miv_rv32_hal and +the hal firmware(RISC-V HAL). + +The RISC-V HAL is available at GitHub [Mi-V-Soft-RISC-V](https://mi-v-ecosystem.github.io/redirects/platform). + +How to use this example +-------------------------------------------------------------------------------- +This example project is targeted at a MIV_RV32 design running on a PolarFire-Eval-Kit +connected via a USB-UART serial cable to a host PC running a terminal emulator +such as TeraTerm or Putty configured as follows: + + - 115200 baud + - 8 data bits + - 1 stop bit + - no parity + - no flow control. + +Run the example project using a debugger. The example project will display +instructions over the serial port. To execute the particular service, user has +to select the options as shown over the serial port. + +This program displays the return data from User Crypto processor for digital +signature generation and verification services. + +fpga_design_config (formerly known as hw_config.h) +-------------------------------------------------------------------------------- +The SoftConsole project targeted for Mi-V processors now use an improved +directory structure. The fpga_design_config.h must be stored as shown below + +` + /boards//fpga_design_config/fpga_design_config.h +` + +Currently, this file must be hand crafted when using the Mi-V Soft Processor. +In future, all the design and soft IP configurations will be automatically +generated from the Libero design description data. + +You can use the sample file provided with MIV_RV32 HAL as an example. Rename it +from sample_fpga_design_config.h to fpga_design_config.h and then customize it +per your hardware design such as SYS_CLK_FREQ, peripheral BASE addresses, +interrupt numbers, definition of MSCC_STDIO_UART_BASE_ADDR if you want a +CoreUARTapb mapped to STDIO, etc. + +### Generate digital signature + +Select '1' to generate a digital signature for ECDSA public-key cryptographic +service. The signature generation function take following parameters as an input. +1. *msg* -: message string +2. *Gx,Gy* -: which is a generator point for NIST-P384 curve. +3. *K* -: A random per message parameter. +4. *modulus n* -: The order of cyclic group G +5. *private_key* -: private key to encrypt the message. + +This project uses **SHA384** algorithm to generate a unique Hash value from the +given message string. The **CALECDSASignHash()** function performs signature +generation and after the successful generation program displays a success +message along with generated signature set {R,S} on the UART terminal. + +*NOTE* -: **b** parameter of P384 elliptic is fixed as far as this example is concerned. + +### Verify digital signature: + +Select '2' to verify the digital signature set {R,S} generated by ECDSA public +key cryptographic services. The program takes a public key to verify the message +signature along with other domain parameters. The **CALECDSAVerifyHash()** +function performs ECDSA signature verification and after successful completion +it returns the result of verification process. An appropriate message will be +displayed on the UART terminal based on the returned result. + +*NOTE* -: The ECDSA signature Generation operation should be executed before +executing ECDSA signature verification operation. + +### Configurations + +The CAL library needs a config_user.h containing the configuration data. +This application provides following settings as per CAL requirement + 1. A variable which provides the base address of the User Crypto hardware block + is defined in main.c + + `uint32_t g_user_crypto_base_addr = 0x62000000UL;` + + 2. A symbol INC_STDINT_H is defined in project preprocessor setting. + For more detail, please refer to caltypes.h file present in CAL folder. + +### Test script + +A test script is provided with this example which automatically enters the NIST +vectors and associated data to verify the functionality. You can use +ecdsa_services.ttl Tera Term Macro script present in project directory for +testing ECDSA Signature Services example project. + +**NOTE:** +1. Tera Term Macros don’t work with Windows 10 build 14393.0. You should update + to Windows 10 build 14393.0.105 or [later.](https://osdn.net/ticket/browse.php?group_id=1412&tid=36526) +2. Before running Tera Term Macro script, set language as English + (Setup->General->Language). Also setup transmit delay in (Setup->Serial port) + to 5msec/char and 5msec/line. +3. By default, Tera Term log will be stored in Tera Term installation Directory. + +## Target hardware + +This project was tested on PolarFire-Eval-Kit with CFG4 configuration of the +MIV_RV32 design available [here](https://github.com/Mi-V-Soft-RISC-V/PolarFire-Eval-Kit/tree/main/Libero_Projects) + +All the design specific definitions such as peripheral base addresses, system +clock frequency etc. are included in fpga_design_config.h. + +The firmware projects needs the HAL and the MIV_RV32 HAL firmware components. + +This example project can be used with another design using a different hardware +configurations. This can be achieved by overwriting the content of this example +project's "fpga_design_config.h" file with the correct data per your Libero design. + +### Booting the system + +Currently the example project is configured to use FlashPro debugger to execute +from LSRAM in both Debug and Release mode. + +In the release mode build configuration, following setting is used +`--change-section-lma *-0x80000000` under +Tool Settings > Cross RISCV GNU Create Flash Image > General > Other flags. + +This will allow you to attach the release mode executable as the memory +initialization client in Libero when you want to execute it from non-volatile memory. + +## Silicon revision dependencies + +This example is tested on PolarFire MPF300TS device. + +### CAL library src + +To obtain the CAL source code and a SoftConsole project to generate the CAL +library archive file (*.a) refer [SoftConsole Documentation](https://mi-v-ecosystem.github.io/SoftConsole-Documentation/SoftConsole-v2021.3/using_softconsole/other.html#crypto-application-library). +The CAL source code is bound by license agreement and it will be available as +part of the SoftConsole installation if the CAL specific license was agreed +while installing it. \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/ecdsa_services.ttl b/applications/user-crypto/miv-rv32-ecdsa-services/ecdsa_services.ttl new file mode 100755 index 0000000..80a6dc6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/ecdsa_services.ttl @@ -0,0 +1,170 @@ +; Tera Term Setting: +; 1. Before running Tera Term Macro script, you should set language as English +; and transmit delay in Serial port setup to 5msec/char and 5msec/line. +; 2. By default, Tera Term log will be stored in Tera Term installation Directory. + +changedir '.' +logopen "ECDSA_service.log" 0 0 0 1 + +settitle 'PolarFire SoC MSS User Crypto ECDSA service' + +setsync 1 + +;Clear screen +clearscreen 0 + +; Set baud rate to 115200 +setbaud 115200 + +; local echo off +setecho 00 + +; ---------------------------------------------------------------------------------------------------------------------------------------------------------- +; Test Case 1 +; INPUT +; Xg = aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760aB7 +; Yg = 3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5F +; Msg=54686973206973206f6e6c7920612074657374206d6573736167652e204974206973203438206279746573206c6f6e67 +; Hash H = b9210c9d7e20897ab86597266a9d5077e8db1b06f7220ed6ee75bd8b45db37891f8ba5550304004159f4453dc5b3f5a1 +; K = dc6b44036989a196e39d1cdac000812f4bdd8b2db41bb33af51372585ebd1db63f0ce8275aa1fd45e2d2a735f8749359 +; D = c838b85253ef8dc7394fa5808a5183981c7deef5a69ba8f4f2117ffea39cfcd90e95f6cbc854abacab701d50c1f3cf24 + +; OUTPUT +; r = a0c27ec8 93092dea 1e1bd2cc fed3cf94 5c8134ed 0c9f8131 1a0f4a05 942db8db +; ed8dd59f 267471d5 462aa14f e72de856 +; s = 20ab3f45 b74f10b6 e11f96a2 c8eb694d 206b9dda 86d3c7e3 31c26b22 c987b753 +; 77265776 67adadf1 68ebbe80 3794a402 +;---------------------------------------------------------------------------------------------------------------------------------------------------------- +; Signature Generation +;----------------------------------------------------------------------------------------------------------------------------------------------------------------- + +; select signature generation +pause 1 +send '1' +pause 2 + +;Msg +pause 1 +send '54686973206973206f6e6c7920612074657374206d6573736167652e204974206973203438206279746573206c6f6e67' +pause 2 + +;Gx +pause 1 +send 'aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760aB7' +pause 2 + +;Gy +pause 1 +send '3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5F' +pause 2 + +;K +pause 1 +send 'dc6b44036989a196e39d1cdac000812f4bdd8b2db41bb33af51372585ebd1db63f0ce8275aa1fd45e2d2a735f8749359' +pause 2 + +;Modulus N +pause 1 +send 'ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973' + +; select option to enter private key +send '2' +pause 5 + +;D +pause 1 +send 'c838b85253ef8dc7394fa5808a5183981c7deef5a69ba8f4f2117ffea39cfcd90e95f6cbc854abacab701d50c1f3cf24' +pause 2 + +; send dummy +send '1' +pause 2 + +;------------------------------------------------------------------------------------------- +; signature verification +;------------------------------------------------------------------------------------------- + +; select signature verification +send '2' +pause 2 + +; select automatic public key generation +send '1' +pause 5 + +; ---------------------------------------------------------------------------------------------------------------------------------------------------------- +; Test Case 2 +; INPUT +; Xg = aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760aB7 +; Yg = 3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5F +; Msg= 4578616D706C65206F66204543445341207769746820502D333834 +; Hash H = 5AEA187D1C4F6E1B35057D20126D836C6ADBBC7049EE0299C9529F5E0B3F8B5A7411149D6C30D6CB2B8AF70E0A781E89 +; K = 2E44EF1F8C0BEA8394E3DDA81EC6A7842A459B534701749E2ED95F054F0137680878E0749FC43F85EDCAE06CC2F43FEF +; D = F92C02ED629E4B48C0584B1C6CE3A3E3B4FAAE4AFC6ACB0455E73DFC392E6A0AE393A8565E6B9714D1224B57D83F8A08 + +; OUTPUT +; r = 30EA514FC0D38D8208756F068113C7CADA9F66A3B40EA3B313D040D9B57DD41A332795D02CC7D507FCEF9FAF01A27088 +; s = CC808E504BE414F46C9027BCBF78ADF067A43922D6FCAA66C4476875FBB7B94EFD1F7D5DBE620BFB821C46D549683AD8 +;---------------------------------------------------------------------------------------------------------------------------------------------------------- +; Signature Generation +;----------------------------------------------------------------------------------------------------------------------------------------------------------------- +pause 1 +send '5' +pause 2 + +; select signature generation +pause 1 +send '1' +pause 2 + +;Msg +pause 1 +send '4578616D706C65206F66204543445341207769746820502D333834' +send 13 +pause 2 + +;Gx +pause 1 +send 'aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760aB7' +pause 2 + +;Gy +pause 1 +send '3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5F' +pause 2 + +;K +pause 1 +send '2E44EF1F8C0BEA8394E3DDA81EC6A7842A459B534701749E2ED95F054F0137680878E0749FC43F85EDCAE06CC2F43FEF' +pause 2 + +;Modulus N +pause 1 +send 'ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973' + +; select option to enter private key +send '2' +pause 5 + +;D +pause 1 +send 'F92C02ED629E4B48C0584B1C6CE3A3E3B4FAAE4AFC6ACB0455E73DFC392E6A0AE393A8565E6B9714D1224B57D83F8A08' +pause 2 + +; send dummy +send '1' +pause 2 + +;------------------------------------------------------------------------------------------- +; signature verification +;------------------------------------------------------------------------------------------- + +; select signature verification +send '2' +pause 2 + +; select automatic public key generation +send '1' +pause 3 + +logclose \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/miv-rv32-ecdsa-services hw Debug.launch b/applications/user-crypto/miv-rv32-ecdsa-services/miv-rv32-ecdsa-services hw Debug.launch new file mode 100755 index 0000000..18f709f --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/miv-rv32-ecdsa-services hw Debug.launch @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/miv-rv32-ecdsa-services hw attach.launch b/applications/user-crypto/miv-rv32-ecdsa-services/miv-rv32-ecdsa-services hw attach.launch new file mode 100644 index 0000000..423811a --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/miv-rv32-ecdsa-services hw attach.launch @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/application/helper.c b/applications/user-crypto/miv-rv32-ecdsa-services/src/application/helper.c new file mode 100755 index 0000000..3be82f2 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/application/helper.c @@ -0,0 +1,303 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file helper.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Helper function for PolarFire User Crypto- Cryptography service example. + * + */ +#include +#include +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" +#include "helper.h" + +static const uint8_t g_separator[] = +"\r\n\ +------------------------------------------------------------------------------"; +static const uint8_t hex_chars[16] = { '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + +/*============================================================================== + Function to clear local variable and array. + */ +static void clear_variable(uint8_t *p_var, uint16_t size) +{ + uint16_t inc; + + for(inc = 0; inc < size; inc++) + { + *p_var = 0x00; + p_var++; + } +} + +/*============================================================================== + Function to get the input data from user. + */ +uint16_t get_input_data +( + uint8_t* location, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +) +{ + uint16_t count = 0u; + + /* Clear the memory location. */ + clear_variable(location, size); + + /* Read data from UART terminal. */ + count = get_data_from_uart(location, size, msg, msg_size); + + return count; +} + +/*============================================================================== + Function to get the key from user. + */ +void get_key +( + uint8_t key_type, + uint8_t* location, + uint8_t size, + const uint8_t* msg, + uint8_t msg_size +) +{ + uint8_t status = 0u; + const uint8_t invalid_ms[] = "\r\n Invalid key type. "; + + if(status == VALID) + { + /* Read the 16 bytes of input data from UART terminal. */ + get_input_data(location, size, msg, msg_size); + } + else + { + UART_send(&g_uart, invalid_ms, sizeof( invalid_ms)); + } +} + +/*============================================================================== + Convert ASCII value to hex value. + */ +uint8_t convert_ascii_to_hex(uint8_t* dest, const uint8_t* src) +{ + uint8_t error_flag = 0u; + + if((*src >= '0') && (*src <= '9')) + { + *dest = (*src - '0'); + } + else if((*src >= 'a') && (*src <= 'f')) + { + *dest = (*src - 'a') + 10u; + } + else if((*src >= 'A') && (*src <= 'F')) + { + *dest = (*src - 'A') + 10u; + } + else if(*src != 0x00u) + { + UART_send(&g_uart, (const uint8_t *)"\r\n Invalid data.", sizeof("\r\n Invalid data.")); + error_flag = 1u; + } + return error_flag; +} + +/*============================================================================== + Validate the input hex value . + */ +uint8_t validate_input(uint8_t ascii_input) +{ + uint8_t valid_key = 0u; + + if(((ascii_input >= 'A') && (ascii_input <= 'F')) || \ + ((ascii_input >= 'a') && (ascii_input <= 'f')) || \ + ((ascii_input >= '0') && (ascii_input <= '9'))) + { + valid_key = 1u; + } + else + { + valid_key = 0u; + } + return valid_key; +} + +/*============================================================================== + Display content of buffer passed as parameter as hex values. + */ +void display_output +( + uint8_t* in_buffer, + uint32_t byte_length, + uint8_t reverse_buffer +) +{ + + uint32_t inc; + + + uint8_t byte = 0; + + UART_send(&g_uart, (const uint8_t*)" ", sizeof(" ")); + + + if(reverse_buffer == 0) + { + for(inc = 0; inc < byte_length; ++inc) + { + + + if((inc > 1u) &&(0u == (inc % 16u))) + { + UART_send(&g_uart, (const uint8_t*)"\r\n ", sizeof("\r\n ")); + } + + byte = in_buffer[inc]; + UART_send(&g_uart, &hex_chars[((byte & 0xF0) >> 4) ], 1); + UART_send(&g_uart, &hex_chars[(byte & 0x0F)], 1); + } + } + /* if reverse_byte is true */ + else + { + for(inc = byte_length ; inc > 0; inc -= 1) + { + if((inc < byte_length) &&(0u == (inc % 16u))) + { + UART_send(&g_uart, (const uint8_t*)"\r\n ", sizeof("\r\n ")); + } + + byte = in_buffer[inc - 1]; + UART_send(&g_uart, &hex_chars[((byte & 0xF0) >> 4) ], 1); + UART_send(&g_uart, &hex_chars[(byte & 0x0F)], 1); + } + } +} + +/*============================================================================== + Function to read data from UART terminal and stored it. + */ +uint16_t get_data_from_uart +( + uint8_t* src_ptr, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +) +{ + uint8_t complete = 0u; + uint8_t rx_buff[1]; + uint8_t rx_size = 0u; + uint16_t count = 0u; + uint16_t ret_size = 0u; + uint8_t first = 0u; + uint16_t src_ind = 0u; + uint8_t prev = 0; + uint8_t curr = 0; + uint8_t temp = 0; + uint8_t next_byte = 0; + uint16_t read_data_size = 0; + + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, msg, msg_size); + + if(size != 1) + { + read_data_size = size * 2; + } + else + { + read_data_size = size; + } + + /* Read the key size sent by user and store it. */ + count = 0u; + while(!complete) + { + rx_size = UART_get_rx(&g_uart, rx_buff, sizeof(rx_buff)); + if(rx_size > 0u) + { + /* Is it to terminate from the loop */ + if(ENTER == rx_buff[0]) + { + complete = 1u; + } + /* Is entered key valid */ + else if(validate_input(rx_buff[0]) != 1u) + { + UART_send(&g_uart, rx_buff, sizeof(rx_buff)); + UART_send(&g_uart, (const uint8_t *)"\r\n Invalid input.", + sizeof("\r\n Invalid input.")); + UART_send(&g_uart, msg, msg_size); + complete = 0u; + count = 0u; + first = 0u; + } + else + { + if(next_byte == 0) + { + convert_ascii_to_hex(&src_ptr[src_ind], &rx_buff[0]); + prev = src_ptr[src_ind]; + next_byte = 1; + } + else + { + convert_ascii_to_hex(&curr, &rx_buff[0]); + temp = ((prev << 4) & 0xF0); + src_ptr[src_ind] = (temp | curr); + next_byte = 0; + src_ind++; + } + + + /* Switching to next line after every 8 bytes */ + if(((count % 32u) == 0x00u) && (count > 0x00u) && (complete != 0x01u)) + { + UART_send(&g_uart, (const uint8_t *)"\n\r", sizeof("\n\r")); + first = 0u; + } + + if(first == 0u) + { + UART_send(&g_uart, (const uint8_t *)" ", sizeof(" ")); + first++; + } + UART_send(&g_uart, rx_buff, sizeof(rx_buff)); + count++; + if(read_data_size == count) + { + complete = 1u; + } + } + } + } + + if((count % 2) == 0) + { + ret_size = count / 2; + } + else + { + if(size != 1) + { + temp = src_ptr[src_ind]; + src_ptr[src_ind] = ((temp << 4) & 0xF0); + + ret_size = (count / 2) + 1; + } + else + { + ret_size = 1; + } + } + + return ret_size; +} + diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/application/helper.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/application/helper.h new file mode 100755 index 0000000..0a2effe --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/application/helper.h @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file helper.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Helper function public API. + * + */ +#ifndef __HELPER_H_ +#define __HELPER_H_ 1 + +/****************************************************************************** + * Maximum buffer size. + *****************************************************************************/ +#define MAX_RX_DATA_SIZE 256 +#define MASTER_TX_BUFFER 10 +#define DATA_LENGTH_32_BYTES 32 + +/*============================================================================== + Macro + */ +#define VALID 0U +#define INVALID 1U +#define ENTER 13u + +/****************************************************************************** + * CoreUARTapb instance data. + *****************************************************************************/ +extern UART_instance_t g_uart; + +uint16_t get_input_data +( + uint8_t* location, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +); +void get_key +( + uint8_t key_type, + uint8_t* location, + uint8_t size, + const uint8_t* msg, + uint8_t msg_size +); +uint16_t get_data_from_uart +( + uint8_t* src_ptr, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +); +void display_output +( + uint8_t* in_buffer, + uint32_t byte_length, + uint8_t reverse_buffer +); +#endif /* __HELPER_H_ */ diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/application/main.c b/applications/user-crypto/miv-rv32-ecdsa-services/src/application/main.c new file mode 100755 index 0000000..e7bca98 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/application/main.c @@ -0,0 +1,639 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file main.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Application demonstrating the ECDSA cryptography service. Please see + * the Readme.md for more details. + * + */ +#include +#include +#include "cal/calpolicy.h" +#include "cal/pk.h" +#include "cal/pkx.h" +#include "cal/pkxlib.h" +#include "cal/calini.h" +#include "cal/utils.h" +#include "cal/hash.h" +#include "cal/drbgf5200.h" +#include "cal/drbg.h" +#include "cal/nrbg.h" +#include "cal/sym.h" +#include "cal/shaf5200.h" +#include "cal/calenum.h" +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" +#include "fpga_design_config/fpga_design_config.h" +#include "miv_rv32_hal/miv_rv32_hal.h" +#include "helper.h" + + +#define KEY_SIZE 32 +#define DATA_LENGTH_32_BYTES 32 +#define REVERSE_FALSE 0 +#define REVERSE_TRUE 1 + +/*flag to verify that ECDSA Signature has been generated before verification */ +#define SIG_GEN_TRUE 1 +#define SIG_GEN_FALSE 0 +#define PARAM_WORD_SIZE 12 + +/****************************************************************************** + * User Crypto base address. This will be used in config_user.h in CAL. + *****************************************************************************/ +uint32_t g_user_crypto_base_addr = 0x62000000UL; + +/****************************************************************************** + * CoreUARTapb instance data. + *****************************************************************************/ +UART_instance_t g_uart; + +/*============================================================================== + Messages displayed over the UART. + */ + +const uint8_t g_greeting_msg[] = +"\r\n\r\n\ +******************************************************************************\r\n\ +*************** PolarFire User Crypto ECDSA Service Example Project **********\r\n\ +******************************************************************************\r\n\ + This example project demonstrates the use of the ECDSA service to calculate\r\n\ + an ECDSA signature on a provided message and also verifies the generated message \r\n\ +signature\r\n"; +const uint8_t g_select_operation_msg[] = +"\r\n\ +------------------------------------------------------------------------------\r\n\ + Select the Cryptographic operation to perform:\r\n\ + Press Key '1' to perform ECDSA signature generation \r\n\ + Press Key '2' to perform ECDSA signature verification \r\n\ +------------------------------------------------------------------------------\r\n"; +const uint8_t ecdsa_generation_msg[] = +"\r\n\ +******************************************************************************\r\n\ + ECDSA Signature Generation\r\n\ +******************************************************************************\r\n" ; +const uint8_t ecdsa_verification_msg[] = +"\r\n\ +******************************************************************************\r\n\ + ECDSA Signature verification\r\n\ +******************************************************************************\r\n"; +const uint8_t select_private_key_msg[] = +"\r\n\ +------------------------------------------------------------------------------\r\n\ + Select one of the following options:\r\n\ + Press Key '1' to generate private key through CALECKeyPairGen() function \r\n\ + Press Key '2' to get private key from the terateram macro. \r\n\ +------------------------------------------------------------------------------\r\n"; + +const uint8_t select_public_key_msg[] = +"\r\n\ +------------------------------------------------------------------------------\r\n\ + Select one of the following options:\r\n\ + Press Key '1' to generate public key through entered private_key \r\n\ + Press Key '2' to get public key from the terateram macro. \r\n\ +------------------------------------------------------------------------------\r\n"; + +static const uint8_t g_separator[] = +"\r\n\ +------------------------------------------------------------------------------"; +static const uint8_t msg[] = + "\r\n Enter message (max size : 12 words): \r\n"; +static const uint8_t read_mod_n[] = + "\r\n Enter modulus value n for P-384 elliptic curve: \r\n"; +static const uint8_t read_private_key[] = + "\r\n Enter private key d (max size : 12 words):\r\n"; +static const uint8_t read_public_key_qx[] = + "\r\n Enter public key qx (max size : 12 words):\r\n"; +static const uint8_t read_public_key_qy[] = + "\r\n Enter public key qy (max size : 12 words):\r\n"; +static const uint8_t msg_gen_success[] = "\r\n\ +------------------------------------------------------------------------------\r\n\ + \r EC-DSA signature generation successful \r\n"; +static const uint8_t msg_gen_fail[] = "\r\n\ +------------------------------------------------------------------------------\r\n\ + \r\n EC-DSA signature generation fail \r\n"; +static const uint8_t msg_ver_success[] = "\r\n\ +------------------------------------------------------------------------------\r\n\ + \r EC-DSA signature verification successful \r\n"; +static const uint8_t msg_ver_fail[] = "\r\n\ +------------------------------------------------------------------------------\r\n\ + \r\n EC-DSA signature verification fail \r\n"; +static const uint8_t read_Gx[] = + "\r\n Enter Curve generator point Gx for P-384 elliptic curve:\r\n"; +static const uint8_t read_Gy[] = + "\r\n Enter Curve generator point Gy for P-384 elliptic curve:\r\n"; + +static const uint8_t read_k[] = + "\r\n Enter the random value k (exactly 12 words):\r\n"; +/*============================================================================== + Global Variables. + */ +uint32_t __attribute__ ((section (".crypto_data"))) msg_g[PARAM_WORD_SIZE] = { + 0x54686973,0x20697320,0x6f6e6c79,0x20612074, + 0x65737420,0x6d657373,0x6167652e,0x20497420, + 0x69732034,0x38206279,0x74657320,0x6c6f6e67 +}; +uint16_t msg_len = 0 ; +uint8_t sig_gen_flag ; +/* for simplicity the value of k is fixed */ + +uint32_t __attribute__ ((section (".crypto_data"))) k_g[PARAM_WORD_SIZE] = { + 0xdc6b4403,0x6989a196,0xe39d1cda,0xc000812f, + 0x4bdd8b2d,0xb41bb33a,0xf5137258,0x5ebd1db6, + 0x3f0ce827,0x5aa1fd45,0xe2d2a735,0xf8749359 +}; +uint32_t __attribute__ ((section (".crypto_data"))) private_key_d[PARAM_WORD_SIZE] = { +0x00}; +uint32_t __attribute__ ((section (".crypto_data"))) public_key_qx[PARAM_WORD_SIZE] = { 0x00 }; +uint32_t __attribute__ ((section (".crypto_data"))) public_key_qy[PARAM_WORD_SIZE] = { 0x00 }; +/* signature paramters */ + +uint32_t __attribute__ ((section (".crypto_data"))) r_g[PARAM_WORD_SIZE] = {0x00}; +uint32_t __attribute__ ((section (".crypto_data"))) s_g[PARAM_WORD_SIZE] = {0x00}; + +uint32_t __attribute__ ((section (".crypto_data"))) P384_Gx[PARAM_WORD_SIZE] = { + 0x72760aB7,0x3a545e38,0xbf55296c,0x5502f25d, + 0x82542a38,0x59f741e0,0x8ba79b98,0x6e1d3b62, + 0xf320ad74,0x8eb1c71e,0xbe8b0537,0xaa87ca22 +}; +uint32_t __attribute__ ((section (".crypto_data"))) P384_Gy[PARAM_WORD_SIZE] = { + 0x90ea0e5F,0x7a431d7c,0x1d7e819d,0x0a60b1ce, + 0xb5f0b8c0,0xe9da3113,0x289a147c,0xf8f41dbd, + 0x9292dc29,0x5d9e98bf,0x96262c6f,0x3617de4a +}; +uint32_t __attribute__ ((section (".crypto_data"))) P384_n[PARAM_WORD_SIZE] = { + + 0xccc52973, 0xecec196a, 0x48b0a77a, 0x581a0db2, + 0xf4372ddf, 0xc7634d81, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff +}; +uint32_t __attribute__ ((section (".crypto_data"))) P384_npc[PARAM_WORD_SIZE+1] = { + 0x333ad68d, 0x1313e695, 0xb74f5885, 0xa7e5f24d, + 0x0bc8d220, 0x389cb27e, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000001 +}; +uint32_t __attribute__ ((section (".crypto_data"))) P384_n1[PARAM_WORD_SIZE] = { + + 0xccc52973, 0xecec196a, 0x48b0a77a, 0x581a0db2, + 0xf4372ddf, 0xc7634d81, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffE +}; +uint32_t __attribute__ ((section (".crypto_data"))) P384_npc1[PARAM_WORD_SIZE+1] = { + 0x333ad68d, 0x1313e695, 0xb74f5885, 0xa7e5f24d, + 0x0bc8d220, 0x389cb27e, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000001 +}; +uint32_t __attribute__ ((section (".crypto_data"))) P384_b[PARAM_WORD_SIZE] = { + 0xd3ec2aef, 0x2a85c8ed, 0x8a2ed19d, 0xc656398d, + 0x5013875a, 0x0314088f, 0xfe814112, 0x181d9c6e, + 0xe3f82d19, 0x988e056b, 0xe23ee7e4, 0xb3312fa7 +}; + +/*============================================================================== + Local functions. + */ +static void ecdsa_sign(void); +static void display_greeting(void); +static void ecdsa_verify(void); + +/*============================================================================== + Performs signature generation for ECDSA public-key cryptography. + */ +void ecdsa_sign(void) +{ + SATR result; + uint16_t mod_len = 0; + uint8_t opt = 0; + + /* Read message value. */ + msg_len = get_input_data((uint8_t*)&msg_g[0], sizeof(msg_g), msg, + sizeof(msg)); + + /* Read Generator Gx. */ + get_input_data((uint8_t*)&P384_Gx[0], sizeof(P384_Gx), read_Gx, + sizeof(read_Gx)); + + /* adjust endianness */ + CALWordReverse(P384_Gx, sizeof(P384_Gx)/4); + CALByteReverseWord(P384_Gx, sizeof(P384_Gx)/4); + + /* Read Generator Gy */ + get_input_data((uint8_t*)&P384_Gy[0], sizeof(P384_Gy), read_Gy, + sizeof(read_Gy)); + + /* adjust endianness */ + CALWordReverse(P384_Gy, sizeof(P384_Gy)/4); + CALByteReverseWord(P384_Gy, sizeof(P384_Gy)/4); + + /* Read Random parameter K */ + get_input_data((uint8_t*)&k_g[0], sizeof(k_g), read_k, + sizeof(read_k)); + + /* adjust endianness */ + CALWordReverse(k_g, sizeof(k_g)/4); + CALByteReverseWord(k_g, sizeof(k_g)/4); + + /* Read modulus value n (length of cyclic group) */ + get_input_data((uint8_t*)&P384_n[0], sizeof(P384_n), read_mod_n, + sizeof(read_mod_n)); + + /* adjust endianness */ + CALWordReverse(P384_n, sizeof(P384_n)/4); + CALByteReverseWord(P384_n, sizeof(P384_n)/4); + + /*precompute of mod n */ + result = CALPreCompute(P384_n,P384_npc,PARAM_WORD_SIZE); + if(SATR_SUCCESS == result) + { + /* transfer the result to P384_npc */ + CALPKTrfRes(SAT_TRUE); + } + else + { + UART_polled_tx_string(&g_uart, (uint8_t*)"\r\n N Mod value is not correct "); + } + /* P384 curve b parameter is fixed for this example */ + + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_polled_tx_string(&g_uart,(uint8_t*)"\r\n Fixed B parameter for P384 curve: \r\n" ); + display_output((uint8_t*)&P384_b[0],sizeof(P384_b),REVERSE_TRUE); + + /* option to get the value of private key */ + get_input_data((uint8_t*)&opt, sizeof(opt),select_private_key_msg, + sizeof(select_private_key_msg)); + if (opt == 1) + { + + /* copy the contents of P384_n to P384_n1 because we need mod -1 */ + memcpy(P384_n1,P384_n,sizeof(P384_n)); + + /* search for first non zero word and subtract 1 from it */ + for(int wc = 0 ; wc < PARAM_WORD_SIZE; wc++) + { + if(P384_n1[wc] != 0) + { + P384_n1[0] -= 1; + break; + } + else + { + continue ; + } + } + + /* precompute of mod(N-1) */ + result = CALPreCompute(P384_n1,P384_npc1,PARAM_WORD_SIZE); + if(SATR_SUCCESS == result) + { + /* transfer the result to P384_npc */ + CALPKTrfRes(SAT_TRUE); + } + else + { + UART_polled_tx_string(&g_uart, (uint8_t*)"\r\n N-1 Mod value is not correct "); + } + + /* generate private and public key pair */ + result = CALECKeyPairGen(&k_g[0],P384_Gx,P384_Gy,P384_MOD,SAT_NULL, + P384_n1,P384_npc1,P384_b,private_key_d,public_key_qx,public_key_qy,12); + + result = CALPKTrfRes(SAT_TRUE); + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_polled_tx_string(&g_uart,(uint8_t*)"\r\n Generated private key : \r\n" ); + display_output((uint8_t*)&private_key_d[0],sizeof(private_key_d),REVERSE_TRUE); + } + else + { + get_input_data((uint8_t*)&private_key_d[0], sizeof(private_key_d), read_private_key, + sizeof(read_private_key)); + + /* adjust endianness */ + CALWordReverse(private_key_d, sizeof(private_key_d)/4); + CALByteReverseWord(private_key_d, sizeof(private_key_d)/4); + } + + /* Calculates ECDSA signature */ + result = CALECDSASignHash(&msg_g[0], SATHASHTYPE_SHA384, msg_len, P384_Gx, + P384_Gy, (const uint32_t*)&k_g, + (const uint32_t*)&private_key_d, P384_b, + P384_MOD, SAT_NULL, P384_n, P384_npc, 12, r_g, + s_g, SAT_TRUE, X52CCR_DEFAULT); + if(SATR_SUCCESS == result) + { + result = CALPKTrfRes(SAT_TRUE); + switch(result) + { + case SATR_SUCCESS: + + /* Display the generated signature in hex format. */ + UART_send(&g_uart, msg_gen_success, sizeof(msg_gen_success)); + UART_polled_tx_string(&g_uart,(uint8_t*)"\r\n R value:\r\n\r\n"); + display_output((uint8_t*)&r_g[0],sizeof(r_g),REVERSE_TRUE); + UART_polled_tx_string(&g_uart,(uint8_t*)"\r\n S value:\r\n\r\n"); + display_output((uint8_t*)&s_g[0],sizeof(s_g),REVERSE_TRUE); + break; + case SATR_VALPARMX: + + UART_polled_tx_string(&g_uart, (uint8_t*)"\r\n\n X parameter not in range \r\n"); + UART_send(&g_uart, msg_gen_fail, sizeof(msg_gen_fail)); + break ; + case SATR_VALPARMY: + UART_polled_tx_string(&g_uart, (uint8_t*)"\r\n\n Y parameter not in range \r\n"); + UART_send(&g_uart, msg_gen_fail, sizeof(msg_gen_fail)); + break; + + case SATR_VALPARMB: + UART_polled_tx_string(&g_uart, (uint8_t*)"\r\n\n B parameter greater than modulus \r\n"); + UART_send(&g_uart, msg_gen_fail, sizeof(msg_gen_fail)); + break ; + + case SATR_VALIDATEFAIL : + UART_polled_tx_string(&g_uart, (uint8_t*)"\r\n\n Generator point is not on the curve \r\n"); + UART_send(&g_uart, msg_gen_fail, sizeof(msg_gen_fail)); + break ; + + case SATR_SIGNPARMD: + UART_polled_tx_string(&g_uart, (uint8_t*)"\r\n\n private_key parameter is not in range [1,N-1] \r\n"); + UART_send(&g_uart, msg_gen_fail, sizeof(msg_gen_fail)); + break ; + + case SATR_SIGNPARMK : + UART_polled_tx_string(&g_uart, (uint8_t*)"\r\n\n random parameter K is not in range [1,N-1] \r\n"); + UART_send(&g_uart, msg_gen_fail, sizeof(msg_gen_fail)); + break ; + + case SATR_SIGNFAIL : + UART_send(&g_uart, msg_gen_fail, sizeof(msg_gen_fail)); + break ; + } + + } + else + { + /* ECDSA signature generation fail */ + UART_send(&g_uart, msg_gen_fail, sizeof(msg_gen_fail)); + } +} + +/*============================================================================== + Performs signature verification for ECDSA public-key cryptography. + */ +void ecdsa_verify(void) +{ + SATR result; + uint8_t opt = 0; + + /* option to get public key */ + get_input_data((uint8_t*)&opt, sizeof(opt),select_public_key_msg, + sizeof(select_public_key_msg)); + if (opt == 1) + { + /* generate private and public key pair */ + result = CALECMult(private_key_d,P384_Gx, P384_Gy, P384_b, P384_MOD, SAT_NULL, + 12, 0,public_key_qx, public_key_qy); + + if(SATR_SUCCESS == result) + { + CALPKTrfRes(SAT_TRUE); + + /* display the generated public key */ + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_polled_tx_string(&g_uart,(uint8_t*)"\r\n Public key generation successful \r\n" ); + UART_send(&g_uart, (const uint8_t *)"\r\n public_key_qx value : \r\n\r\n", + sizeof("\r\n public_key_qx value : \r\n")); + display_output((uint8_t*)&public_key_qx[0], sizeof(public_key_qx),REVERSE_TRUE); + UART_send(&g_uart, (const uint8_t *)"\r\n public_key_qy value: \r\n\r\n", + sizeof("\r\n public_key_qy value: \r\n")); + display_output((uint8_t*)&public_key_qy[0], sizeof(public_key_qy),REVERSE_TRUE); + } + } + else + { + /* get public key x point */ + get_input_data((uint8_t*)&public_key_qx[0], sizeof(public_key_qx), read_public_key_qx, + sizeof(read_public_key_qx)); + + /* adjust endianness */ + CALWordReverse(public_key_qx, sizeof(public_key_qx)); + CALByteReverseWord(public_key_qx, sizeof(public_key_qx)); + + /* get public key y point */ + get_input_data((uint8_t*)&public_key_qy[0], sizeof(public_key_qy), read_public_key_qy, + sizeof(read_public_key_qy)); + + /* adjust endianness */ + CALWordReverse(public_key_qy, sizeof(public_key_qy)); + CALByteReverseWord(public_key_qy, sizeof(public_key_qy)); + } + + // validate that public key is on the curve + result = CALECPtValidate(public_key_qx, public_key_qy, P384_b, P384_MOD, SAT_NULL,12); + + if(SATR_SUCCESS == result) + { + result = CALPKTrfRes(SAT_TRUE); + switch(result) + { + case SATR_SUCCESS: + + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_polled_tx_string(&g_uart, (uint8_t*)"\r\n\n Validation successful public key point is on the curve \r\n"); + break; + case SATR_VALPARMX: + + UART_polled_tx_string(&g_uart, (uint8_t*)"\r\n\n X parameter not in range \r\n"); + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_polled_tx_string(&g_uart, (uint8_t*)"\r\n\n validation Fail \r\n"); + break ; + case SATR_VALPARMY: + UART_polled_tx_string(&g_uart, (uint8_t*)"\r\n\n Y parameter not in range \r\n"); + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_polled_tx_string(&g_uart, (uint8_t*)"\r\n\n validation Fail \r\n"); + break; + case SATR_VALPARMB: + UART_polled_tx_string(&g_uart, (uint8_t*)"\r\n\n B parameter greater than modulus \r\n"); + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_polled_tx_string(&g_uart, (uint8_t*)"\r\n\n validation Fail \r\n"); + break ; + case SATR_VALIDATEFAIL : + UART_polled_tx_string(&g_uart, (uint8_t*)"\r\n\n public key point is not on the curve \r\n"); + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_polled_tx_string(&g_uart, (uint8_t*)"\r\n\n validation Fail \r\n"); + break ; + } + + } + else + { + /* public key validation fail */ + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_polled_tx_string(&g_uart, (uint8_t*)"\r\n\n validation Fail \r\n"); + } + + result = CALECDSAVerifyHash(&msg_g[0], SATHASHTYPE_SHA384, msg_len, P384_Gx, + P384_Gy, public_key_qx,public_key_qy, + r_g,s_g, P384_b, + P384_MOD, SAT_NULL, P384_n, P384_npc, 12, 0, SAT_TRUE, X52CCR_DEFAULT); + + /* Display the generated signature in hex format. */ + if(SATR_SUCCESS == result) + { + result = CALPKTrfRes(SAT_TRUE); + switch(result) + { + case SATR_SUCCESS: + + /* Display the generated signature in hex format. */ + UART_send(&g_uart, msg_ver_success, sizeof(msg_ver_success)); + break; + case SATR_VALPARMX: + + UART_polled_tx_string(&g_uart, (uint8_t*)"\r\n\n X parameter not in range \r\n"); + UART_send(&g_uart, msg_ver_fail, sizeof(msg_ver_fail)); + break ; + case SATR_VALPARMY: + UART_polled_tx_string(&g_uart, (uint8_t*)"\r\n\n Y parameter not in range \r\n"); + UART_send(&g_uart, msg_ver_fail, sizeof(msg_ver_fail)); + break; + + case SATR_VALPARMB: + UART_polled_tx_string(&g_uart, (uint8_t*)"\r\n\n B parameter greater than modulus \r\n"); + UART_send(&g_uart, msg_ver_fail, sizeof(msg_ver_fail)); + break ; + + case SATR_VERPARMR: + UART_polled_tx_string(&g_uart, (uint8_t*)"\r\n\n R parameter Not in [1,N-1]\r\n"); + UART_send(&g_uart, msg_ver_fail, sizeof(msg_ver_fail)); + break ; + + case SATR_VERPARMS: + UART_polled_tx_string(&g_uart, (uint8_t*)"\r\n\n S parameter Not in [1,N-1]\r\n"); + UART_send(&g_uart, msg_ver_fail, sizeof(msg_ver_fail)); + break ; + + case SATR_VALIDATEFAIL : + UART_polled_tx_string(&g_uart, (uint8_t*)"\r\n\n Generator point is not on the curve \r\n"); + UART_send(&g_uart, msg_ver_fail, sizeof(msg_ver_fail)); + break ; + + case SATR_PAF: + UART_polled_tx_string(&g_uart, (uint8_t*)"\r\n\n point at infinity Generated \r\n"); + UART_send(&g_uart, msg_ver_fail, sizeof(msg_ver_fail)); + break ; + + case SATR_VERIFYFAIL : + UART_send(&g_uart, msg_ver_fail, sizeof(msg_ver_fail)); + break ; + + case SATR_SIGNFAIL : + UART_send(&g_uart, msg_ver_fail, sizeof(msg_ver_fail)); + break ; + } + + } + else + { + /* ECDSA signature generation fail */ + UART_send(&g_uart, msg_ver_fail, sizeof(msg_ver_fail)); + } +} + +/*============================================================================== + Display greeting message when application is started. + */ +static void display_greeting(void) +{ + UART_send(&g_uart, g_greeting_msg,sizeof(g_greeting_msg)); +} + +/*============================================================================== + Display the choice of cryptographic operation to perform. + */ +static void display_operation_choices(void) +{ + UART_send(&g_uart, g_select_operation_msg, sizeof(g_select_operation_msg)); +} + +/*============================================================================== + Display the Option to continue. + */ +static void display_option(void) +{ + uint8_t rx_size; + uint8_t rx_buff[1]; + + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, (const uint8_t*)"\r\n Press any key to continue.\r\n", + sizeof("\r\n Press any key to continue.\r\n")); + do + { + rx_size = UART_get_rx(&g_uart, rx_buff, sizeof(rx_buff)); + } while(0u == rx_size); +} + +/*============================================================================== + * Perform ECDSA signature and verification sequentially + */ +/* Main function */ +void main(void) +{ + uint8_t rx_buff[1]; + uint8_t rx_size = 0; + uint8_t sig_gen_success = SIG_GEN_FALSE ; + + UART_init(&g_uart, COREUARTAPB0_BASE_ADDR, BAUD_VALUE_115200, + (DATA_8_BITS | NO_PARITY)); + + /* Initializes the Athena Processor */ + CALIni(); + + /* Display greeting message. */ + display_greeting(); + + /* Select cryptographic operation to perform */ + display_operation_choices(); + + for(;;) + { + /* Read inputs from UART terminal. */ + rx_size = UART_get_rx(&g_uart, rx_buff, sizeof(rx_buff)); + if(rx_size > 0) + { + switch(rx_buff[0]) + { + case '1': + /* Performs signature generation for ECDSA */ + UART_send(&g_uart, ecdsa_generation_msg, sizeof(ecdsa_generation_msg)); + ecdsa_sign(); + sig_gen_success = SIG_GEN_TRUE ; + display_option(); + display_operation_choices(); + break; + + case '2': + /* Performs signature verification for ECDSA */ + UART_send(&g_uart, ecdsa_verification_msg, sizeof(ecdsa_verification_msg)); + if(sig_gen_success == SIG_GEN_TRUE) + { + ecdsa_verify(); + } + else + { + UART_polled_tx_string(&g_uart,(uint8_t*)"\r\n Please perform ECDSA signature Generation at least once before ECDSA verification \r\n "); + } + display_option(); + display_operation_choices(); + break; + + default: + break; + } + } + } + + return; +} diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h new file mode 100644 index 0000000..3fd1438 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h @@ -0,0 +1,156 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file fpga_design_config.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Sample design configuration settings. + * + */ + /*========================================================================*//** + @mainpage + Example file detailing how the fpga_design_config.h should be constructed + for the SoftConsole project targeted for Mi-V processors. + + @section intro_sec Introduction + The SoftConsole project targeted for Mi-V processors now have an improved + folder structure. Detailed description of the folder structure is available + at https://github.com/Mi-V-Soft-RISC-V/miv-rv32-documentation. + + The fpga_design_config.h must be stored as shown below + /boards//fpga_design_config.h + + Currently this file must be hand crafted when using the Mi-V Soft Processor. + In future, all the design and soft IP configurations will be automatically + generated from the Libero design description data. + + You can use this sample file as an example. + Rename this file from sample_fpga_design_config.h to fpga_design_config.h + and then customize it per your hardware design. + + @section Project configuration Instructions + 1. Change SYS_CLK_FREQ define to frequency of Mi-V Soft processor clock + 2 Add all the soft IP core BASE addresses + 3. Add the peripheral Core Interrupts to Mi-V Soft processor IRQ number + mappings + 4. Define MSCC_STDIO_UART_BASE_ADDR if you want a CoreUARTapb mapped to + STDIO + + **NOTE** + In the legacy folder structures, the file hw_config.h as was used at the + root of the project folder. This file is now depricated. + +*//*=========================================================================*/ + +#ifndef FPGA_DESIGN_CONFIG_H_ +#define FPGA_DESIGN_CONFIG_H_ + +/***************************************************************************//** + * Soft-processor clock definition + * This is the only clock brought over from the Mi-V Libero design. + */ +#ifndef SYS_CLK_FREQ +#define SYS_CLK_FREQ 83000000UL +#endif + +/***************************************************************************//** + * Peripheral base addresses. + * Format of define is: + * __BASE_ADDR + * The field is optional if there is only one instance of the core + * in the design + * MIV_ESS is an extended peripheral subsystem IP core with peripherals + * connections as defined below. + * The system can be further extended by attaching APB peripherals to the + * empty APB slots. + */ +#define COREUARTAPB0_BASE_ADDR 0x70000000UL +#define COREGPIO_OUT_BASE_ADDR 0x70001000UL +#define CORESPI_BASE_ADDR 0x70002000UL +#define CORESYS_SERV_BASE_ADDR 0x70003000UL + +/***************************************************************************//** + * Peripheral Interrupts are mapped to the corresponding Mi-V Soft processor + * interrupt in the Libero design. + * + * On the legacy RV32 cores, there can be up to 31 external interrupts (IRQ[30:0] + * pins). The legacy RV32 Soft processor external interrupts are defined in the + miv_rv32_plic.h + * + * These are of the form + * typedef enum +{ + NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + . + . + . + External_31_IRQn = 31 +} IRQn_Type; + + On the legacy RV32 processors, the PLIC identifies the interrupt and passes it + on to the processor core. The interrupt 0 is not used. The pin IRQ[0] should + map to External_1_IRQn likewise IRQ[30] should map to External_31_IRQn + +e.g + +#define TIMER0_IRQn External_30_IRQn +#define TIMER1_IRQn External_31_IRQn + + The MIV_RV32 soft processor has up to six optional system interrupts, MSYS_EI[n] + in addition to one EXT_IRQ. + The MIV_RV32 does not have an inbuilt PLIC and all the interrupts are directly + delivered to the processor core, hence unlike legacy RV32 cores, no interrupt + number mapping is necessary on MIV_RV32 core. + */ + +/**************************************************************************** + * Baud value to achieve a 115200 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ +#define BAUD_VALUE_115200 ((SYS_CLK_FREQ / (16 * 115200)) - 1) + +/****************************************************************************** + * Baud value to achieve a 57600 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + #define BAUD_VALUE_57600 ((SYS_CLK_FREQ / (16 * 57600)) - 1) + +/***************************************************************************//** + * Define MSCC_STDIO_THRU_CORE_UART_APB in the project settings if you want the + * standard IOs to be redirected to a terminal via UART. + */ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +/* + * A base address mapping for the STDIO printf/scanf mapping to CortUARTapb + * must be provided if it is being used + * + * e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR + */ +#define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB0_BASE_ADDR + +#ifndef MSCC_STDIO_UART_BASE_ADDR +#error MSCC_STDIO_UART_BASE_ADDR not defined- e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR +#endif + +#ifndef MSCC_STDIO_BAUD_VALUE +/* + * The MSCC_STDIO_BAUD_VALUE define should be set in your project's settings to + * specify the baud value used by the standard output CoreUARTapb instance for + * generating the UART's baud rate if you want a different baud rate from the + * default of 115200 baud + */ +#define MSCC_STDIO_BAUD_VALUE 115200 +#endif /*MSCC_STDIO_BAUD_VALUE*/ + +#endif /* end of MSCC_STDIO_THRU_CORE_UART_APB */ +/******************************************************************************* + * End of user edit section + */ +#endif /* FPGA_DESIGN_CONFIG_H_ */ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld b/applications/user-crypto/miv-rv32-ecdsa-services/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld new file mode 100755 index 0000000..8541db6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld @@ -0,0 +1,160 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-ram.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * debug image executing in SRAM. + * + * This linker script assumes that a RAM is connected at on Mi-V soft processor + * memory space pointed by the reset vector address. + * + * NOTE : Modify the memory section address and the size according to your + * Libero design. + * For example: + * 1) If you want to download and step debug at a different RAM memory address in + * your design (For example TCM base address) than the one provided in this file. + * 2) The MIV_RV32, when used with MIV_ESS IP, provides ways to copy the executable + * HEX file from external Non-Volatile memory into the TCM at reset. In this + * case your executable must be linked to the TCM address. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +MEMORY +{ + ram (rwx) : ORIGIN = 0x80000000, LENGTH = 64k + crypto_ram (rw) : ORIGIN = 0x61000000, LENGTH = 32k +} + +RAM_START_ADDRESS = 0x80000000; /* Must be the same value MEMORY region ram ORIGIN above. */ +RAM_SIZE = 64k; /* Must be the same value MEMORY region ram LENGTH above. */ +STACK_SIZE = 2k; /* needs to be calculated for your application */ +HEAP_SIZE = 0k; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > ram + + .text : ALIGN(0x10) + { + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } > ram + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } > ram + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } > ram + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram + + . = 0x61000000; + .crypto_data : ALIGN(0x10) + { + . = ALIGN(0x10); + *(.crypto_data) + } > crypto_ram +} + diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/aesf5200.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/aesf5200.h new file mode 100755 index 0000000..889dddd --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/aesf5200.h @@ -0,0 +1,104 @@ +/* ------------------------------------------------------------------- + $Rev: 1293 $ $Date: 2017-07-27 14:09:14 -0400 (Thu, 27 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for F5200 AES function hardware implementation for + CAL. + ------------------------------------------------------------------- */ + +#ifndef AESF5200_H +#define AESF5200_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef AESF5200_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATR aesf5200aes (SATSYMTYPE eSymType, SATSYMMODE eMode, + void *pIV, SATBOOL bLoadIV, const void *pSrc, void *pDest, SATUINT32_t uiLen, + SATBOOL bDecrypt); + +extern SATR aesf5200aesk (SATSYMTYPE eSymType, const SATUINT32_t *puiKey); + +extern SATR aesf5200gcm (SATSYMTYPE eSymType, SATSYMMODE eMode, void *pIV, + const void *pSrc, void *pDest, SATUINT32_t uiEncLen, + const void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, SATUINT32_t uiMACLen, + SATBOOL bDecrypt); + +extern SATR aesf5200gcmdma(SATSYMTYPE eSymType, SATSYMMODE eMode, void *pIV, + const void *pSrc, void *pDest, SATUINT32_t uiEncLen, const void *pAuth, + SATUINT32_t uiAuthLen, void *pMAC, SATUINT32_t uiMACLen, SATBOOL bDecrypt, + SATUINT32_t uiDMAChConfig); + +extern SATR aesf5200kw(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR aesf5200kwp(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR aesf5200kr(SATSYMTYPE eSymType, SATSYMMODE eMode, + const SATUINT32_t *puiKey, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKrf, SATBOOL bDecrypt); + +extern SATR aesf5200dma(SATSYMTYPE eSymType, SATSYMMODE eMode, void *pIV, + SATBOOL bLoadIV, const void *pExtSrc, void *pExtDest, SATUINT32_t uiLen, + SATUINT32_t uiDMAChConfig, SATBOOL bDecrypt); + +extern SATR aesf5200krdma(SATSYMTYPE eSymType, SATSYMMODE eMode, + const SATUINT32_t *puiKey, void *pIV, SATBOOL bLoadIV, const void *pExtSrc, + void *pExtDest, SATUINT32_t uiLen, SATUINT32_t uiKrf, + SATUINT32_t uiDMAChConfig, SATBOOL bDecrypt); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/calcontext.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/calcontext.h new file mode 100755 index 0000000..fc408c2 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/calcontext.h @@ -0,0 +1,88 @@ +/* ------------------------------------------------------------------- + $Rev: 1298 $ $Date: 2017-08-04 13:04:19 -0400 (Fri, 04 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL context management functions. + ------------------------------------------------------------------- */ + +#ifndef CALCONTEXT_H +#define CALCONTEXT_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* Function resource handle. */ +/* ----- ------ ------- ---- */ +#define SATRES_DEFAULT (SATRESHANDLE)0U +#define SATRES_CALSW (SATRESHANDLE)1U + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ +typedef struct{ + SATUINT32_t uiBase; + SATRESCONTEXTPTR pContext; + }SATRESHANDLESTRUCT; + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALCONTEXT_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATRESCONTEXTPTR CALContextCurrent(const SATRESHANDLE hResource); + +extern SATR CALContextLoad(const SATRESHANDLE hResource, + const SATRESCONTEXTPTR pContext); + +extern SATR CALContextRemove(const SATRESHANDLE hResource); + +extern SATR CALContextUnload(const SATRESHANDLE hResource); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern void init_reshandles(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/calenum.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/calenum.h new file mode 100755 index 0000000..6281f3f --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/calenum.h @@ -0,0 +1,289 @@ +/* ------------------------------------------------------------------- + $Rev: 1566 $ $Date: 2018-09-14 11:04:30 -0400 (Fri, 14 Sep 2018) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + This file defines common types in the CAL. + + Most CAL types and constants are defined with the "SAT" prefix to + reduce the chance of name space collisions with other users. + ------------------------------------------------------------------- */ + +#ifndef CALENUM_H +#define CALENUM_H + +/* -------- */ +/* Includes */ +/* -------- */ + +/* CAL base types. */ +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ +/* NULL definitions. */ +#define SAT_NULL 0 + +/* Boolean definitions. */ +#define SAT_TRUE ((SATBOOL)1) +#define SAT_FALSE ((SATBOOL)0) + + +/* Major cipher key/SSP type. */ +/* ----- ------ ------- ----- */ +#define SATSSPTYPE_NULL (SATSSPTYPE)0 +#define SATSSPTYPE_SYMKEY (SATSSPTYPE)1 +#define SATSSPTYPE_ASYMKEY (SATSSPTYPE)2 +/* Special marker for end of list. */ +#define SATSSPTYPE_LAST (SATSSPTYPE)3 + + +/* Asymmetric Ciphers */ +/* ---------- ------- */ +#define SATASYMTYPE_NULL (SATASYMTYPE)0U +#define SATASYMTYPE_DSA_SIGN (SATASYMTYPE)1U +#define SATASYMTYPE_DSA_VERIFY (SATASYMTYPE)2U +#define SATASYMTYPE_RSA_ENCRYPT (SATASYMTYPE)3U +#define SATASYMTYPE_RSA_DECRYPT (SATASYMTYPE)4U +#define SATASYMTYPE_DH (SATASYMTYPE)5U +#define SATASYMTYPE_ECDSA_SIGN (SATASYMTYPE)6U +#define SATASYMTYPE_ECDSA_VERIFY (SATASYMTYPE)7U +#define SATASYMTYPE_ECDH (SATASYMTYPE)8U +#define SATASYMTYPE_RSA_SIGN (SATASYMTYPE)9U +#define SATASYMTYPE_RSA_VERIFY (SATASYMTYPE)10U +/* Special marker for end of list. */ +#define SATASYMTYPE_LAST (SATASYMTYPE)11U + + +/* Encoding Types */ +/* -------- ----- */ +#define SATRSAENCTYPE_NULL (SATRSAENCTYPE)0U +#define SATRSAENCTYPE_PKCS (SATRSAENCTYPE)1U +#define SATRSAENCTYPE_ANSI (SATRSAENCTYPE)2U +#define SATRSAENCTYPE_PSS (SATRSAENCTYPE)3U +/* Special marker for end of list. */ +#define SATRSAENCTYPE_LAST (SATRSAENCTYPE)4U + + +/* Symmetric Ciphers */ +/* --------- ------- */ + +/* Cipher Type. */ +#define SATSYMTYPE_NULL (SATSYMTYPE)0U +#define SATSYMTYPE_AES128 (SATSYMTYPE)1U +#define SATSYMTYPE_AES192 (SATSYMTYPE)2U +#define SATSYMTYPE_AES256 (SATSYMTYPE)3U +#define SATSYMTYPE_AESKS128 (SATSYMTYPE)4U +#define SATSYMTYPE_AESKS192 (SATSYMTYPE)5U +#define SATSYMTYPE_AESKS256 (SATSYMTYPE)6U +/* Special marker for end of list. */ +#define SATSYMTYPE_LAST (SATSYMTYPE)7U + +/* Names for common cipher key lengths, in bits. */ +#define SATSYMKEYSIZE_AES128 (SATSYMKEYSIZE)128U +#define SATSYMKEYSIZE_AES192 (SATSYMKEYSIZE)192U +#define SATSYMKEYSIZE_AES256 (SATSYMKEYSIZE)256U +#define SATSYMKEYSIZE_AESKS128 (SATSYMKEYSIZE)256U +#define SATSYMKEYSIZE_AESKS192 (SATSYMKEYSIZE)384U +#define SATSYMKEYSIZE_AESKS256 (SATSYMKEYSIZE)512U + +/* Cipher Mode. */ +#define SATSYMMODE_NULL (SATSYMMODE)0U +#define SATSYMMODE_ECB (SATSYMMODE)1U +#define SATSYMMODE_CBC (SATSYMMODE)2U +#define SATSYMMODE_CFB (SATSYMMODE)3U +#define SATSYMMODE_OFB (SATSYMMODE)4U +#define SATSYMMODE_CTR (SATSYMMODE)5U +#define SATSYMMODE_GCM (SATSYMMODE)6U +#define SATSYMMODE_GHASH (SATSYMMODE)8U +/* Special marker for end of list. */ +#define SATSYMMODE_LAST (SATSYMMODE)9U + + +/* Hashes */ +/* ------ */ +#define SATHASHTYPE_NULL (SATHASHTYPE)0U +#define SATHASHTYPE_SHA1 (SATHASHTYPE)1U +#define SATHASHTYPE_SHA224 (SATHASHTYPE)2U +#define SATHASHTYPE_SHA256 (SATHASHTYPE)3U +#define SATHASHTYPE_SHA384 (SATHASHTYPE)4U +#define SATHASHTYPE_SHA512 (SATHASHTYPE)5U +#define SATHASHTYPE_SHA512_224 (SATHASHTYPE)6U +#define SATHASHTYPE_SHA512_256 (SATHASHTYPE)7U +/* Special marker for end of list. */ +#define SATHASHTYPE_LAST (SATHASHTYPE)8U + +/* Hash sizes defined in bits */ +#define SATHASHSIZE_NULL (SATHASHSIZE)0U +#define SATHASHSIZE_SHA1 (SATHASHSIZE)160U +#define SATHASHSIZE_SHA224 (SATHASHSIZE)224U +#define SATHASHSIZE_SHA256 (SATHASHSIZE)256U +#define SATHASHSIZE_SHA384 (SATHASHSIZE)384U +#define SATHASHSIZE_SHA512 (SATHASHSIZE)512U +#define SATHASHSIZE_SHA512_224 (SATHASHSIZE)224U +#define SATHASHSIZE_SHA512_256 (SATHASHSIZE)256U + +#define SATHASHSIZE_HASH160 (SATHASHSIZE)160U +#define SATHASHSIZE_HASH192 (SATHASHSIZE)192U +#define SATHASHSIZE_HASH224 (SATHASHSIZE)224U +#define SATHASHSIZE_HASH256 (SATHASHSIZE)256U +#define SATHASHSIZE_HASH320 (SATHASHSIZE)320U +#define SATHASHSIZE_HASH384 (SATHASHSIZE)384U +#define SATHASHSIZE_HASH512 (SATHASHSIZE)512U +#define SATHASHSIZE_HASH521 (SATHASHSIZE)521U + + +/* Message Authentication Codes */ +/* ------- -------------- ----- */ + +/* Message Authentication Types */ +#define SATMACTYPE_NULL (SATMACTYPE)0U +#define SATMACTYPE_SHA1 (SATMACTYPE)1U +#define SATMACTYPE_SHA224 (SATMACTYPE)2U +#define SATMACTYPE_SHA256 (SATMACTYPE)3U +#define SATMACTYPE_SHA384 (SATMACTYPE)4U +#define SATMACTYPE_SHA512 (SATMACTYPE)5U +#define SATMACTYPE_SHA512_224 (SATMACTYPE)6U +#define SATMACTYPE_SHA512_256 (SATMACTYPE)7U +#define SATMACTYPE_AESCMAC128 (SATMACTYPE)10U +#define SATMACTYPE_AESCMAC192 (SATMACTYPE)11U +#define SATMACTYPE_AESCMAC256 (SATMACTYPE)12U +#define SATMACTYPE_AESGMAC (SATMACTYPE)13U +/* Special marker for end of list. */ +#define SATMACTYPE_LAST (SATMACTYPE)14U + + +/* Message Authentication Flags */ +#define SATMACFLAG_OP (SATMACTYPEFLAG)0U +#define SATMACFLAG_FIRSTPASS (SATMACTYPEFLAG)1U +#define SATMACFLAG_FINALPASS (SATMACTYPEFLAG)2U +#define SATMACFLAG_IKEYFINAL (SATMACTYPEFLAG)4U +#define SATMACFLAG_OKEYFINAL (SATMACTYPEFLAG)8U + + +/* Non-deterministic Random Bit Generator */ +/* ------- -------------- ----- */ + +/* NRBG register write enables */ +#define SATNRBGCONFIG_NONE 0x0 +#define SATNRBGCONFIG_RNG_CSR 0x1 +#define SATNRBGCONFIG_RNG_CNTLIM 0x2 +#define SATNRBGCONFIG_RNG_VOTIMER 0X4 +#define SATNRBGCONFIG_RNG_FMSK 0X8 + +/* RNG_CSR access defines */ +#define SATNRBGCONFIG_CSR_RODIS 0x0 +#define SATNRBGCONFIG_CSR_ROEN 0x1 +#define SATNRBGCONFIG_CSR_ROFATAL 0x2 +#define SATNRBGCONFIG_CSR_ROFATALCLR 0X4 + +/* RNG_FMSK mask values */ +#define SATNRBGCONFIG_FMSK_ROOSCF 0xFF +#define SATNRBGCONFIG_FMSK_MONOBITF 0x10000 +#define SATNRBGCONFIG_FMSK_POKERF 0x20000 +#define SATNRBGCONFIG_FMSK_RUNSF 0x40000 +#define SATNRBGCONFIG_FMSK_LRUNSF 0x80000 +#define SATNRBGCONFIG_FMSK_F1401 0xF0000 +#define SATNRBGCONFIG_FMSK_REPCNTF 0x100000 +#define SATNRBGCONFIG_FMSK_APROPF 0x200000 +#define SATNRBGCONFIG_FMSK_SP800 0x300000 + +/* RNG_ROHEALTH mask values */ +#define SATNRBGCONFIG_HLTH_ROOSCF 0x3FC0 +#define SATNRBGCONFIG_HLTH_APROPF 0x20 +#define SATNRBGCONFIG_HLTH_REPCNTF 0x10 +#define SATNRBGCONFIG_HLTH_LRUNSF 0x8 +#define SATNRBGCONFIG_HLTH_RUNSF 0x4 +#define SATNRBGCONFIG_HLTH_POKERF 0x2 +#define SATNRBGCONFIG_HLTH_MONOBITF 0x1 + + +/* Return Codes */ +/* ------ ----- */ +#define SATR_SUCCESS (SATR)0U +#define SATR_FAIL (SATR)1U +#define SATR_BADPARAM (SATR)2U +#define SATR_VERIFYFAIL (SATR)3U +#define SATR_KEYSFULL (SATR)4U +#define SATR_BUSY (SATR)5U +#define SATR_ROFATAL (SATR)6U +#define SATR_PARITYFLUSH (SATR)7U +#define SATR_SIGNFAIL (SATR)8U +#define SATR_VALIDATEFAIL (SATR)9U +#define SATR_PAF (SATR)10U +#define SATR_VALPARMX (SATR)11U +#define SATR_VALPARMY (SATR)12U +#define SATR_VALPARMB (SATR)13U +#define SATR_DCMPPARMX (SATR)14U +#define SATR_DCMPPARMB (SATR)15U +#define SATR_DCMPPARMP (SATR)16U +#define SATR_SIGNPARMD (SATR)17U +#define SATR_SIGNPARMK (SATR)18U +#define SATR_VERPARMR (SATR)19U +#define SATR_VERPARMS (SATR)20U +#define SATR_MSBICV1 (SATR)21U +#define SATR_MSBICV2 (SATR)22U +#define SATR_PADLEN (SATR)23U +#define SATR_LSB0PAD (SATR)24U +#define SATR_BADLEN (SATR)25U +#define SATR_BADHASHTYPE (SATR)26U +#define SATR_BADTYPE (SATR)27U +#define SATR_BADMODE (SATR)28U +#define SATR_BADCONTEXT (SATR)29U +#define SATR_BADHASHLEN (SATR)30U +#define SATR_BADMACTYPE (SATR)31U +#define SATR_BADMACLEN (SATR)32U +#define SATR_BADHANDLE (SATR)33U +#define SATR_FNP (SATR)34U +#define SATR_HFAULT (SATR)35U +#define SATR_NOPEND (SATR)36U +#define SATR_BADRSAENC (SATR)37U +#define SATR_BADMOD (SATR)38U +/* Special marker for end of list. */ +#define SATR_LAST (SATR)39U + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* See caltypes.h for type definitions associated with defines above. */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALENUM_C +#ifdef __cplusplus +extern "C" { +#endif + +/* NOTE: this header file does not have an associated C file. */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/calini.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/calini.h new file mode 100755 index 0000000..62461d1 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/calini.h @@ -0,0 +1,69 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL initialization + ------------------------------------------------------------------- */ + +#ifndef CALINI_H +#define CALINI_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALINI_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALIni(void); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/calpolicy.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/calpolicy.h new file mode 100755 index 0000000..2a43445 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/calpolicy.h @@ -0,0 +1,183 @@ +/* ------------------------------------------------------------------- + $Rev: 1293 $ $Date: 2017-07-27 14:09:14 -0400 (Thu, 27 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file defining CAL policy for endianess, HW/SW, etc. + ------------------------------------------------------------------- */ + +#ifndef CALPOLICY_H +#define CALPOLICY_H + +/* -------- */ +/* Includes */ +/* -------- */ + +/* The following include provides a custom configuration header file when + CALCONFIGH is defined +*/ +#ifdef CALCONFIGH +# include CALCONFIGH +#else +# error "CALCONFIGH not defined. CAL requires a custom configuration header \ +defined by CALCONFIGH. Review CAL README." +#endif + +/* ------- */ +/* Defines */ +/* ------- */ + +/* Context switching */ +#ifndef MAXRESHANDLES +# define MAXRESHANDLES 1 +#endif + +/* Little Endian (default) / Big Endian */ +#ifndef SAT_LITTLE_ENDIAN +# define SAT_LITTLE_ENDIAN 1 +#endif + +/* PK SW Point Validate Checking */ +#ifndef PKSWCHKVALPT +# define PKSWCHKVALPT 1 +#endif + +/* DMA */ +#ifndef USE_X52EXEC_DMA +# define USE_X52EXEC_DMA 0 +#endif + +/* SHA */ +#define MAXHASHLEN 512 +#define MAXHMACKEYLEN 512 + +/* RNG */ +#define NRBGSIMNUMRO 16 +#define ENTROPYMEMBLOCKS 7 +#define BUFMEMBLOCKS 3 +#ifndef RNXBLKLEN +#define RNXBLKLEN 32 +#endif +#ifndef RNXBLKOUTLEN +#define RNXBLKOUTLEN 4 +#endif + +#ifndef USENRBGSW +# define USENRBGSW 0 +#endif + +/* PK */ +#ifndef PKX0_BASE +# define PKX0_BASE 0xE0000000u +#endif + +#if USEPKSW +# ifndef MAXMODSIZE +# define MAXMODSIZE 8192 +# endif +# ifndef PKSWBUFSIZE +# define PKSWBUFSIZE 15*(MAXMODSIZE/32) +# endif +#else +# define USEPKSW 0 +#endif + +/* Set default values for X52 configuration defines. */ +#ifndef X52_CFG_OPT +# define X52_CFG_OPT 0 +#endif +#ifndef X52_LIR_LEN +# define X52_LIR_LEN 0x800 +#endif +#ifndef X52_BER_LEN +# define X52_BER_LEN 0x400 +#endif +#ifndef X52_MMR_LEN +# define X52_MMR_LEN 0x400 +#endif +#ifndef X52_TSR_LEN +# define X52_TSR_LEN 0x400 +#endif +#ifndef X52_FPR_LEN +# define X52_FPR_LEN 0x400 +#endif +#if X52_LIR_ROM_LEN>0 && X52_LIR_LEN>X52_LIR_ROM_LEN +# define PKX_OFFSET 2048 +#else +# define PKX_OFFSET 0 +#endif + +/* X52 Configuration Options */ +#define AESPKX (X52_CFG_OPT&0x00000001u) +#define AESPKXGCM (X52_CFG_OPT&0x00000008u) +#define AESPKXFASTKEY (X52_CFG_OPT&0x01000000u) +#define SHAPKXOPT1 (X52_CFG_OPT&0x00000020u) +#define SHAPKXOPT224 (X52_CFG_OPT&0x00000040u) +#define SHAPKXOPT256 (X52_CFG_OPT&0x00000080u) +#define SHAPKXOPT384 (X52_CFG_OPT&0x00000100u) +#define SHAPKXOPT512 (X52_CFG_OPT&0x00000200u) +#define SHAPKXOPT5124 (X52_CFG_OPT&0x00400000u) +#define SHAPKXOPT5126 (X52_CFG_OPT&0x00800000u) + +/* Define the maximum number of return values that may be handled using + CAL*TrfRes() function(s). +*/ +#define CAL_MAXTRFS 4 + +/* Volatile pointer operations */ +/* These access macros are designed so that they may be redefined by a + user compiling CAL. +*/ +#ifndef CALREAD32 +# define CALREAD32(ptr) ( *(ptr) ) +#endif +#ifndef CALWRITE32 +# define CALWRITE32(ptr, val) ( *(ptr)=val ) +#endif +#ifndef CALPOLL32 +# define CALPOLL32(ptr, val, mask) while ((*(ptr) & (mask)) != (val)); +#endif + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +#ifndef CALPOLICY_C +#ifdef __cplusplus +extern "C" { +#endif + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +/* NOTE: this header file does not have an associated C file. */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/caltypes.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/caltypes.h new file mode 100755 index 0000000..3b2fe0b --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/caltypes.h @@ -0,0 +1,328 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + This file defines common types in the CAL. + + Since support for the C99 stdint.h integer types is not universal, + these are defined herein and may require customization from compiler + to compiler, or use of the stdint.h header, if present (recommended). + + C99 supports 64-bit types; however, support in older compilers is + spotty. For those that do not support it, the macro NO64BITINT may be + defined by the user to prevent defintion of 64-bit types. This is + generally safe with CAL-PK and CAL-SYM; however, this is incompatible + with CAL-SW. + + Most CAL types and constants are defined with the "SAT" prefix to + reduce the chance of name space collisions with other users. + ------------------------------------------------------------------- */ + +#ifndef CALTYPES_H +#define CALTYPES_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* Base Types */ +/* ---- ----- */ + +/* The user may compile using stdint.h instead of the definitions below + by defining the macro INC_STDINT_H. */ +#ifdef INC_STDINT_H +#include +#endif + +/* Integer type abstraction layer. */ +#ifndef INC_STDINT_H + +typedef unsigned char uint8_t; +typedef signed char int8_t; + +typedef unsigned short uint16_t; +typedef signed short int16_t; + +typedef unsigned int uint32_t; +typedef int int32_t; + +/* stdint.h is a C99 feature, and C99 supports 64-bit ints, so this is + immune to the macro used to disable 64-bit int support. +*/ +typedef unsigned long long uint64_t; +typedef long long int64_t; + +typedef long uintptr_t; + +#endif + +/* Boolean type. */ +typedef uint8_t SATBOOL; + +/* Unsigned integer type */ +typedef uint8_t SATUINT8_t; +typedef uint16_t SATUINT16_t; +typedef uint32_t SATUINT32_t; +#ifdef INC_STDINT_H +typedef uint64_t SATUINT64_t; +#else +#ifndef NO64BITINT +typedef uint64_t SATUINT64_t; +#endif +#endif + +/* Integer type */ +typedef int8_t SATINT8_t; +typedef int16_t SATINT16_t; +typedef int32_t SATINT32_t; +#ifdef INC_STDINT_H +typedef int64_t SATINT64_t; +#else +#ifndef NO64BITINT +typedef int64_t SATINT64_t; +#endif +#endif + +typedef uintptr_t SATUINTPTR_t; + +/* Major cipher key/SSP type. */ +/* ----- ------ ------- ----- */ +typedef uint8_t SATSSPTYPE; +typedef SATSSPTYPE * SATSSPTYPEPTR; + + +/* Asymmetric Ciphers */ +/* ---------- ------- */ + +/* Cipher type. */ +typedef uint8_t SATASYMTYPE; +typedef SATASYMTYPE * SATASYMTYPEPTR; + +/* Cipher size type. */ +typedef uint16_t SATASYMSIZE; +typedef SATASYMSIZE * SATASYMSIZEPTR; + +/* Cipher encoding */ +typedef uint8_t SATRSAENCTYPE; +typedef SATRSAENCTYPE * SATRSAENCTYPEPTR; + +/* DSA public/private key. */ +typedef struct { + uint16_t ui16PLen; /* Length of modulus p. */ + uint16_t ui16QLen; /* Length of prime divisor q. */ + uint32_t *pui32P; /* Prime modulus p. */ + uint32_t *pui32Q; /* Prime divisor q. */ + uint32_t *pui32G; /* Generator g, length==p. */ + uint32_t *pui32X; /* Private key x, length==p. */ + uint32_t *pui32Y; /* Private key y, length==q. */ +} SATASYMDSADOMAIN; +typedef SATASYMDSADOMAIN * SATASYMDSADOMAINPTR; + + +/* Symmetric Ciphers */ +/* --------- ------- */ + +/* Cipher type. */ +typedef uint8_t SATSYMTYPE; +typedef SATSYMTYPE * SATSYMTYPEPTR; + +/* Cipher key size type (in bits). */ +typedef uint16_t SATSYMKEYSIZE; +typedef SATSYMKEYSIZE * SATSYMKEYSIZEPTR; + +/* Cipher mode type. */ +typedef uint8_t SATSYMMODE; +typedef SATSYMMODE * SATSYMMODEPTR; + +/* Cipher key object. */ +/* Other fields are only valid when sstCipher!=SATSYMTYPE_NULL. */ +typedef struct { + SATSYMTYPE sstCipher; + SATSYMKEYSIZE ssksKeyLen; + uint32_t *pui32Key; +} SATSYMKEY; +typedef SATSYMKEY * SATSYMKEYPTR; + + +/* Hashes */ +/* ------ */ + +/* Hash type. */ +typedef uint8_t SATHASHTYPE; +typedef SATHASHTYPE * SATHASHTYPEPTR; + +/* Hash size type (in bits). */ +typedef uint16_t SATHASHSIZE; +typedef SATHASHSIZE * SATHASHSIZEPTR; + + +/* Context switching. */ +/* ----- ------ ------- ----- */ + +typedef uint32_t SATRESHANDLE; +typedef SATRESHANDLE * SATRESHANDLEPTR; + +typedef struct { + SATHASHTYPE sshashtype; + uint32_t uiRunLen; + uint32_t uiHash[MAXHASHLEN/32]; /* holds intermed hash */ +} SHACTX; + +typedef struct { + SATHASHTYPE sshashtype; + uint32_t uiRunLen; + uint32_t uiKeyLen; + uint32_t uiHash[MAXHASHLEN/32]; /* holds intermed hash */ + uint32_t uiKey[MAXHMACKEYLEN/32]; /* holds intermed key */ +} SHAHMACCTX; + +typedef struct { + uint8_t uiContextType; + union{ + SHACTX ctxSHA; + SHAHMACCTX ctxMAC; + }CTXUNION; +} SATRESCONTEXT; +typedef SATRESCONTEXT * SATRESCONTEXTPTR; + + +/* Message Authentication Codes */ +/* ------- -------------- ----- */ + +/* MAC type. */ +typedef uint8_t SATMACTYPE; +typedef SATMACTYPE * SATMACTYPEPTR; +typedef uint8_t SATMACTYPEFLAG; + + +/* Random Number Generator */ +/* ------ ------ --------- */ +typedef union { + uint32_t u32[4]; + uint8_t u8[16]; +} uint128_t; + +typedef struct { + uint128_t ui128V; + uint128_t ui128K[2]; + uint32_t uiReseedCnt; + uint32_t uiReseedLim; + uint32_t uiEntropyFactor; + SATSYMKEYSIZE eStrength; + SATBOOL bTesting; + +} DRBGCTX; + +typedef DRBGCTX * DRBGCTXPTR; + + +/* Function Return Code */ +/* -------- ------ ---- */ +typedef uint16_t SATR ; +typedef SATR * SATRPTR ; + + +/* Transfer Results */ +/* -------- ------- */ +typedef struct { + SATUINT32_t uiLen; + volatile SATUINT32_t* vpuiSrc; + void* pDest; +} SATDATATRF; + +typedef struct { + SATUINT32_t uiResType; + SATUINT32_t uiNumDataTrf; + SATDATATRF dtrfArray[CAL_MAXTRFS]; +} SATRESULT; + + +/* EC Ultra Structs */ +/* -- ----- ------- */ +typedef uint32_t SATECTYPE; + +typedef struct { + SATUINT32_t uiLen; + SATUINT32_t* puiX; + SATUINT32_t* puiY; +} SATECPOINT; + +typedef struct { + SATUINT32_t uiLen; + SATUINT32_t* puiMod; + SATUINT32_t* puiMontPrecompute; + SATUINT32_t* puiRSqd; +} SATECMONTMOD; + +typedef struct { + SATUINT32_t uiCurveSize; + SATECTYPE eCurveType; + SATECPOINT* pBasePoint; + SATECMONTMOD* pModP; + SATECMONTMOD* pModN; + SATUINT32_t* puiA; + SATUINT32_t* puiB; +} SATECCURVE; + +typedef struct { + SATUINT32_t uiLen; + SATUINT32_t* puiSigR; + SATUINT32_t* puiSigS; + SATUINT32_t* puiSigX; + SATUINT32_t* puiSigY; +} SATECDSASIG; + +typedef struct { + SATHASHSIZE sHashLen; + SATUINT32_t* puiHash; +} SATHASH; + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALTYPES_C +#ifdef __cplusplus +extern "C" { +#endif + +/* NOTE: this header file does not have an associated C file. */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/config_user.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/config_user.h new file mode 100755 index 0000000..3728565 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/config_user.h @@ -0,0 +1,44 @@ +/* ------------------------------------------------------------------- + $Rev: 727 $ $Date: 2017-10-20 16:50:53 -0400 (Fri, 20 Oct 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + + User configuration file to include/exclude CAL components. + ------------------------------------------------------------------- */ + +#ifndef CALCONFIG_F5200_H +#define CALCONFIG_F5200_H + +#include "x52cfg_user.h" +#include + +extern uint32_t g_user_crypto_base_addr; + +#define SAT_LITTLE_ENDIAN 1 +#define PKX0_BASE (g_user_crypto_base_addr) +#define USEPKX 1 +#define USEAESPKX 1 +#define USESHAPKX 1 +#define USEDRBGPKX 1 +#define USENRBGPKX 1 +#define USECALCTX 1 + +#endif diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/drbg.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/drbg.h new file mode 100755 index 0000000..dba16f7 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/drbg.h @@ -0,0 +1,91 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for DRBG functions for CAL + ------------------------------------------------------------------- */ + +#ifndef DRBG_H +#define DRBG_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ +#define CALDRBGENTROPYFACTOR 2 + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef DRBG_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALDRBGInstantiate(const SATUINT32_t *puiNonce, + SATUINT32_t uiNonceLen, const SATUINT32_t *puiPzStr, + SATUINT32_t uiPzStrLen, SATSYMKEYSIZE eStrength, + SATUINT32_t uiEntropyFactor, SATUINT32_t uiReseedLim, SATBOOL bTesting); + +extern SATR CALDRBGReseed(const SATUINT32_t *puiAddIn, SATUINT32_t uiAddInLen); + +extern SATR CALDRBGGenerate(const SATUINT32_t *puiAddIn, SATUINT32_t uiAddInLen, + SATBOOL bPredResist, SATUINT32_t *puiOut, SATUINT32_t uiOutBlocks); + +extern SATR CALDRBGUninstantiate(void); + +extern SATR CALDRBGGetCtx(DRBGCTXPTR drbgCtxExt); + +extern SATR CALDRBGLoadCtx(DRBGCTXPTR drbgCtxExt); + +extern SATR CALDRBGGetbInst(void); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +extern SATR CALDrbgTrfRes(SATBOOL bBlock); + +extern void CALDrbgIni(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/drbgf5200.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/drbgf5200.h new file mode 100755 index 0000000..d7f6c4c --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/drbgf5200.h @@ -0,0 +1,120 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for F5200 DRBG function hardware implementations + in CAL. + ------------------------------------------------------------------- */ + +#ifndef DRBGF5200_H +#define DRBGF5200_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ +#define RNXEFACTOR (X52BER+2) +#define RNXIRLEN (X52BER+2) +#define RNXKEYORD (X52BER+3) +#define RNXRESPRED (X52BER+4) +#define RNXTESTSEL (X52BER+5) +#define RNXBADDIN (X52BER+6) +#define RNXPPSTR (X52BER+7) +#define RNXPCTX (X52BER+8) +#define RNXPRENT (X52BER+13) +#define RNXITMP3 (X52BER+20) +#define RNXPCTX2 (X52BER+22) +/* These use same locs as tb generator, but can change */ +#define RNXRDATA (X52BER_ENDIAN+0x24) +#define RNXAIDATAOFF 0x0062 +#define RNXAIDATA (X52BER_ENDIAN+RNXAIDATAOFF) +#define RNXCTXOFF 0x0094 +#define RNXCTX (X52FPR+RNXCTXOFF) +#define RNXCTXV (X52FPR_ENDIAN+RNXCTXOFF+6) +#define RNXCTXVMMR (X52MMR_ENDIAN+RNXCTXOFF+6) +#define RNXTESTENT (X52TSR_ENDIAN+8) + +#define RNXCTXWORDS 18 +#define RNXBLENLOC (RNXCTX+RNXCTXWORDS) +#define RNXBOUTLENLOC (RNXCTX+RNXCTXWORDS+1) + +#define RNXMAXTESTENT32 512 +#define CALDRBGMAXADDINLEN X52_BER_LEN-RNXAIDATAOFF-4 +#define CALDRBGMAXPSNONCELEN X52_BER_LEN-RNXAIDATAOFF-4 + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef DRBGF5200_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATR drbgf5200Ini(void); + +extern SATR drbgf5200TrfRes(SATBOOL bBlock); + +extern SATR drbgf5200instantiate(const SATUINT32_t *puiNonce, + SATUINT32_t uiNonceLen, const SATUINT32_t *puiPzStr, SATUINT32_t uiPzStrLen, + SATSYMKEYSIZE eStrength, SATUINT32_t uiEntropyFactor, + SATUINT32_t uiReseedLim, SATBOOL bTesting); + +extern SATR drbgf5200reseed(const SATUINT32_t *puiAddIn, + SATUINT32_t uiAddInLen); + +extern SATR drbgf5200generate(const SATUINT32_t *puiAddIn, + SATUINT32_t uiAddInLen, SATBOOL bPredResist, SATUINT32_t uiReqLen, + SATUINT32_t *puiOut); + +extern SATR drbgf5200uninstantiate(void); + +extern SATR drbgf5200getctx(DRBGCTXPTR drbgCtxExt); + +extern SATR drbgf5200loadctx(DRBGCTXPTR drbgCtxExt); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/hash.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/hash.h new file mode 100755 index 0000000..f3fd6d4 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/hash.h @@ -0,0 +1,102 @@ +/* ------------------------------------------------------------------- + $Rev: 1293 $ $Date: 2017-07-27 14:09:14 -0400 (Thu, 27 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL hash functions. + ------------------------------------------------------------------- */ + +#ifndef HASH_H +#define HASH_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ +extern const SATHASHSIZE uiHashWordLen[SATHASHTYPE_LAST]; + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef HASH_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALHash(SATHASHTYPE eHashType, const void *pMsg, + SATUINT32_t uiMsgLen, void *pHash); + +extern SATR CALHashDMA(SATHASHTYPE eHashType, const void *pMsg, + SATUINT32_t uiMsgLen, void *pHash, SATUINT32_t uiDMAChConfig); + +extern SATR CALHashCtx(const SATRESHANDLE hResource, + const SATRESCONTEXTPTR pContext, const void *pMsg, SATUINT32_t uiMsgLen, + void *pHash, const SATBOOL bFinal); + +extern SATR CALHashCtxIni(const SATRESCONTEXTPTR pContext, + const SATHASHTYPE eHashType); + +extern SATR CALHashIni(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen); + +extern SATR CALHashWrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR CALHashRead(void *pHash); + +extern SATR CALKeyTree(SATBOOL bPathSizeSel, const SATUINT32_t* puiKey, + SATUINT8_t uiOpType, const SATUINT32_t* puiPath, SATUINT32_t* puiKeyOut); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATUINT32_t iGetHashLen(SATHASHTYPE eHashType); + +extern SATUINT32_t iGetBlockLen(SATHASHTYPE eHashType); + +extern SATR CALHashCtxLoad(const SATRESHANDLE hResource, + SATRESCONTEXTPTR const pContext, SATUINT32_t uiRunLen); + +extern SATUINT32_t iGetRunLen(SATRESCONTEXTPTR const pContext); + +extern SATR CALHashTypeIni(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/mac.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/mac.h new file mode 100755 index 0000000..acdc767 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/mac.h @@ -0,0 +1,95 @@ +/* ------------------------------------------------------------------- + $Rev: 1296 $ $Date: 2017-08-01 13:54:48 -0400 (Tue, 01 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL MAC functions. + ------------------------------------------------------------------- */ + +#ifndef MAC_H +#define MAC_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef MAC_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALMAC(SATMACTYPE eMACType, const SATUINT32_t *pKey, SATUINT32_t uiKeyLen, + const void *pMsg, SATUINT32_t uiMsgLen, void *pMAC); + +extern SATR CALMACDMA(SATMACTYPE eMACType, const SATUINT32_t *pKey, + SATUINT32_t uiKeyLen, const void *pMsg, SATUINT32_t uiMsgLen, + const void *pMAC, SATUINT32_t uiDMAChConfig); + +extern SATR CALMACIni(SATMACTYPE eMACType, const SATUINT32_t *pKey, + SATUINT32_t uiKeyLen, SATUINT32_t uiMsgLen); + +extern SATR CALMACCtx(const SATRESHANDLE hResource, + const SATRESCONTEXTPTR pContext, const void *pMsg, SATUINT32_t uiMsgLen, + void *pHash, const SATUINT8_t uiFlag); + +extern SATR CALMACCtxIni(const SATRESCONTEXTPTR pContext, const SATHASHTYPE eHashType, + const SATUINT32_t *pKey, SATUINT32_t uiKeyLen); + +extern SATR CALMACWrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR CALMACRead(void *pMAC); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATUINT32_t iGetMACKeyLen(SATMACTYPE eMACType); + +extern SATR CALMACCtxLoad(const SATRESHANDLE hResource, + SATRESCONTEXTPTR const pContext, SATUINT32_t uiRunLen); + +extern SATUINT32_t iGetMACRunLen(SATRESCONTEXTPTR const pContext); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/miv-rv32i-user-crypto-lib.a b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/miv-rv32i-user-crypto-lib.a new file mode 100755 index 0000000..5fda638 Binary files /dev/null and b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/miv-rv32i-user-crypto-lib.a differ diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/miv-rv32imc-user-crypto-lib.a b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/miv-rv32imc-user-crypto-lib.a new file mode 100755 index 0000000..ee7bcf4 Binary files /dev/null and b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/miv-rv32imc-user-crypto-lib.a differ diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/nrbg.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/nrbg.h new file mode 100755 index 0000000..d517065 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/nrbg.h @@ -0,0 +1,83 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for NRBG functions for CAL. + ------------------------------------------------------------------- */ + +#ifndef NRBG_H +#define NRBG_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef NRBG_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALNRBGSetTestEntropy(SATUINT32_t * puiEntropy, + SATUINT32_t uiEntLen32); + +extern SATR CALNRBGGetEntropy(SATUINT32_t * puiEntropy, SATUINT32_t uiEntLen32, + SATBOOL bTesting); + +extern SATR CALNRBGConfig(SATUINT32_t uiWriteEn, SATUINT32_t uiCSR, + SATUINT32_t uiCntLim, SATUINT32_t uiVoTimer, SATUINT32_t uiFMsk, + SATUINT32_t* puiStatus); + +extern SATUINT32_t CALNRBGHealthStatus(void); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATUINT32_t CALNRBGGetTestEntLen(void); + +extern SATR nrbgpkxgetentropy(SATUINT32_t * puiEntropy, + SATUINT32_t uiEntLen32); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/pk.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/pk.h new file mode 100755 index 0000000..5983d9a --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/pk.h @@ -0,0 +1,302 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for for CAL PK. + ------------------------------------------------------------------- */ + +#ifndef PK_H +#define PK_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef PK_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALPKTrfRes(SATBOOL bBlock); + +extern SATR CALDSASign(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALDSASignCM(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALDSASignHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, const SATUINT32_t* puiK, + const SATUINT32_t* puiX, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, SATUINT32_t uiN, + SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALDSASignHashCM(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, const SATUINT32_t* puiK, + const SATUINT32_t* puiX, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, SATUINT32_t uiN, + SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALDSAVerify(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiY, const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, + const SATUINT32_t* puiQMu, SATUINT32_t uiN, SATUINT32_t uiL); + +extern SATR CALDSAVerifyHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, const SATUINT32_t* puiY, + const SATUINT32_t* puiR, const SATUINT32_t* puiS, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALECDHC(const SATUINT32_t* puiS, const SATUINT32_t* puiWx, + const SATUINT32_t* puiWy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t* puiK, const SATUINT32_t* puiR, + const SATUINT32_t* puiRMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiZ); + +extern SATR CALECDSASign(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALECDSASignTwist(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALECDSASignCM(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALECDSASignTwistCM(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALECDSASignHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiK, const SATUINT32_t* puiD, const SATUINT32_t* puiB, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSASignHashCM(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiK, const SATUINT32_t* puiD, const SATUINT32_t* puiB, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSASignTwistHash(const SATUINT32_t* puiMsg, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSAVerify(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS,const + SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress); + +extern SATR CALECDSAVerifyTwist(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALECDSAVerifyHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSAVerifyTwistHash(const SATUINT32_t* puiMsg, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALECMult(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECMultCM(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t* puiN, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress, SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECMultTwist(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiLen, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECMultTwistCM(const SATUINT32_t* puiMul, + const SATUINT32_t* puiPx, const SATUINT32_t* puiPy, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiMod,const SATUINT32_t* puiMu, + const SATUINT32_t* puiN, SATUINT32_t uiLen, SATUINT32_t* puiRx, + SATUINT32_t* puiRy); + +extern SATR CALECMultAdd(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiB, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen, SATUINT32_t uiPtPCompress, SATUINT32_t uiPtQCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECPtValidate(const SATUINT32_t* puiPx, const SATUINT32_t* puiPy, + const SATUINT32_t* puiB, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen); + +extern SATR CALECKeyPairGen(const SATUINT32_t* puiC, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + const SATUINT32_t* puiNM1, const SATUINT32_t* puiNM1Mu, const SATUINT32_t* puiB, + SATUINT32_t* puiD, SATUINT32_t* puiQx, SATUINT32_t* puiQy, SATUINT32_t uiLen); + +extern SATR CALExpo(const SATUINT32_t* puiBase, const SATUINT32_t* puiExpo, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALExpoCM(const SATUINT32_t* puiBase, const SATUINT32_t* puiExpo, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALMMult(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALMMultAdd(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiC, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALModRed(const SATUINT32_t* puiA, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiALen, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPreCompute(const SATUINT32_t* puiMod, SATUINT32_t* puiMu, + SATUINT32_t uiModLen); + +extern SATR CALRSACRT(const SATUINT32_t* puiCipher, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ,const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiLen, SATUINT32_t* puiPlain); + +extern SATR CALRSACRTCM(const SATUINT32_t* puiCipher, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t * puiE, const SATUINT32_t* puiP, + const SATUINT32_t* puiQ, const SATUINT32_t * puiN, + const SATUINT32_t * puiNMu, SATUINT32_t uiLen, SATUINT32_t uiELen, + SATUINT32_t* puiPlain); + +extern SATR CALRSACRTSign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + const SATUINT32_t* puiN, SATUINT32_t uiLen, SATUINT32_t* puiSig); + +extern SATR CALRSACRTSignCM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, const SATUINT32_t* puiQ, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSig); + +extern SATR CALRSACRTSignHash(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ,const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + const SATUINT32_t* puiN, SATUINT32_t uiMsgLen, SATUINT32_t uiModLen, + SATUINT32_t* puiSig, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALRSACRTSignHashCM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, const SATUINT32_t* puiQ, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, SATUINT32_t* puiSig, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALRSASign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiD, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, SATUINT32_t* puiSig); + +extern SATR CALRSASignHash(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiD, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, SATUINT32_t uiModLen, + SATUINT32_t* puiSig, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALRSAVerify(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, + const SATUINT32_t* puiSig); + +extern SATR CALRSAVerifyHash(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiE, SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, const SATUINT32_t* puiSig, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPurge52(SATBOOL bVerify); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/pkx.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/pkx.h new file mode 100755 index 0000000..c23dda4 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/pkx.h @@ -0,0 +1,409 @@ +/* ------------------------------------------------------------------- + $Rev: 1298 $ $Date: 2017-08-04 13:04:19 -0400 (Fri, 04 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for for CAL PK. + ------------------------------------------------------------------- */ + +#ifndef PKX_H +#define PKX_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* X5200 Addressing */ +#define X52BER ((volatile SATUINT32_t *) (PKX0_BASE + 0x00000000u)) +#define X52MMR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00001000u)) +#define X52TSR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00002000u)) +#define X52FPR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00003000u)) +#define X52LIR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00004000u)) +#define X52CSR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00007F80u)) +#define X52CSRMERRS ((volatile SATUINT32_t *) (PKX0_BASE + 0x00007F8Cu)) +#define X52CSRMERRT0 ((volatile SATUINT32_t *) (PKX0_BASE + 0x00007F94u)) + +#if SAT_LITTLE_ENDIAN +#define X52BER_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00008000u)) +#define X52MMR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00009000u)) +#define X52TSR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x0000A000u)) +#define X52FPR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x0000B000u)) +#define X52DMACONFIG_ENDIAN 0x8 +#else +#define X52BER_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00000000u)) +#define X52MMR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00001000u)) +#define X52TSR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00002000u)) +#define X52FPR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00003000u)) +#define X52DMACONFIG_ENDIAN 0x0 +#endif + +/* X5200 Macros */ +#define X52GO(x) (0x10 | ((x)<<8)) + +/* Counter Measures */ +#define RANDLEN 4 + +/* X5200 CSRMAIN bit field masks. */ +#define X52CSRMAINRST 1 +#define X52CSRMAINCCMPLT 2 +#define X52CSRMAINCMPLT 4 +#define X52CSRMAINBUSY 8 +#define X52CSRMAINGO 0x10 +#define X52CSRMAINPURGE 0x20 +#define X52CSRMAINECDIS 0x40 +#define X52CSRMAINALARM 0x80 +#define X52CSRMAINLIRA ((0xFFF) << 8) +#define X52CSRMERRSSEC ((0x2) << 24) +#define X52CSRMERRSA 0x1FFF + +/* Address pointers for ROM'd P-curve moduli */ +#define P192_MOD (&uiROMMods[0]) +#define P224_MOD (&uiROMMods[1]) +#define P256_MOD (&uiROMMods[2]) +#define P384_MOD (&uiROMMods[3]) +#define P521_MOD (&uiROMMods[4]) + +/* X5200 Addressing Flags */ +#define X52BYTEREVERSE_FLAG 1 +#define X52WORDREVERSE_FLAG 2 +#define X52BYTEREVERSE 0x00002000 +#define X52WORDREVERSE 0x00004000 +#define X52ADDRESSRANGE 0x2000 + +/* X5200 DMA channel configuration constants. */ +#define X52CCR_DEFAULT 0 /* BSIZE=auto, ESWP=none, PROT=user, INC=inc */ +#define X52CCR_BSIZEAUTO 0 /* BSIZE=auto */ +#define X52CCR_BSIZEBYTE 0x10 /* BSIZE=byte */ +#define X52CCR_BSIZEHWORD 0x20 /* BSIZE=half word */ +#define X52CCR_BSIZEWORD 0x30 /* BSIZE=word */ +#define X52CCR_ESWPNONE 0 /* ESWP=none */ +#define X52CCR_ESWPWORD 0x8 /* ESWP=swap bytes in word [0123]->[3210] */ +#define X52CCR_PROTUSER 0 /* PROT=user */ +#define X52CCR_PROTPRIV 0x2 /* PROT=priv */ +#define X52CCR_INCADDR 0 /* INC=inc */ +#define X52CCR_NOINCADDR 0x1 /* INC=non-inc */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef PKX_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern void CALPKXIni(void); + +extern void CALPKMem32Load(volatile SATUINT32_t * puiDst, + const SATUINT32_t * puiSrc, SATUINT32_t uiNum ); + +extern SATR CALPKXTrfRes(SATBOOL bBlock); + +extern SATR CALPKXPreCompute(const SATUINT32_t* puiMod, SATUINT32_t* puiMu, + SATUINT32_t uiModLen); + +extern SATR CALPKXExpo(const SATUINT32_t* puiBase, const SATUINT32_t* puiExpo, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALPKXExpoCM(const SATUINT32_t* puiBase, + const SATUINT32_t* puiExpo, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPKXDSASign(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXDSASignCM(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXDSASHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATUINT32_t uiDMAChConfig, const SATBOOL bCM); + +extern SATR CALPKXDSAVerify(const SATUINT32_t *puiHash, + const SATUINT32_t *puiG, const SATUINT32_t *puiY, + const SATUINT32_t *puiSigR, const SATUINT32_t *puiSigS, + const SATUINT32_t *puiP, const SATUINT32_t *puiPMu, + const SATUINT32_t *puiQ, const SATUINT32_t *puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL); + +extern SATR CALPKXDSAVHDMA(const SATUINT32_t *puiExtInput, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t *puiG, const SATUINT32_t *puiY, + const SATUINT32_t *puiSigR, const SATUINT32_t *puiSigS, + const SATUINT32_t *puiP, const SATUINT32_t *puiPMu, const SATUINT32_t *puiQ, + const SATUINT32_t *puiQMu, SATUINT32_t uiN, SATUINT32_t uiL, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXModRed(const SATUINT32_t* puiA, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiALen, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPKXMMult(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPKXMMultAdd(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiC, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALPKXECMult(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECMultTwist(const SATUINT32_t* puiMul, + const SATUINT32_t* puiPx,const SATUINT32_t* puiPy, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen, SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECMultCM(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t * puiN, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress, SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECMultTwistCM(const SATUINT32_t* puiMul, + const SATUINT32_t* puiPx, const SATUINT32_t* puiPy, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + const SATUINT32_t * puiN, SATUINT32_t uiLen, SATUINT32_t* puiRx, + SATUINT32_t* puiRy); + +extern SATR CALPKXECMultAdd(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiB, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen, SATUINT32_t uiPtPCompress, SATUINT32_t uiPtQCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECDSASign(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASignTwist(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx,const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASignCM(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASignTwistCM(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASH(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + const SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASHCM(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + const SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, SATUINT32_t uiDMAChConfig, + const SATBOOL bCM); + +extern SATR CALPKXECDSASTwistH(const SATUINT32_t* puiHash, + const SATHASHTYPE eHashType, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiK, const SATUINT32_t* puiD, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, const SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASTwistHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECDSAVerify(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVerifyTwist(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVH(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB,const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + const SATUINT32_t uiLen, const SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB,const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECDSAVTwistH(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, const SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVTwistHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECDHC(const SATUINT32_t* puiS, const SATUINT32_t* puiWx, + const SATUINT32_t* puiWy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t* puiK, const SATUINT32_t* puiR, + const SATUINT32_t* puiRMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiZ); + +extern SATR CALPKXRSACRT(const SATUINT32_t* puiCipher, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, SATUINT32_t uiLen, + SATUINT32_t* puiPlain); + +extern SATR CALPKXRSACRTCM(const SATUINT32_t* puiCipher, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiE, + const SATUINT32_t* puiP, const SATUINT32_t* puiQ, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, const SATUINT32_t uiLen, const SATUINT32_t uiELen, + SATUINT32_t* puiPlain); + +extern SATR CALPKXRSACRTSign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiCipher, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, + const SATUINT32_t* puiQMu, const SATUINT32_t* puiN, SATUINT32_t uiLen, + SATUINT32_t* puiS); + +extern SATR CALPKXRSACRTSignCM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, + const SATUINT32_t* puiP, const SATUINT32_t* puiQ, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSig); + +extern SATR CALPKXRSACRTSHDMA(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + const SATUINT32_t* puiN, SATUINT32_t uiMsgLen, SATUINT32_t uiModLen, + SATUINT32_t* puiSig, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXRSACRTSHDMACM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, + const SATUINT32_t* puiP, const SATUINT32_t* puiQ, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, SATUINT32_t uiLen, + SATUINT32_t* puiSig, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXRSASign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiD, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, SATUINT32_t* puiSig); + +extern SATR CALPKXRSASHDMA(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiD, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, SATUINT32_t* puiSig, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXRSAVerify(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, + const SATUINT32_t* puiS); + +extern SATR CALPKXRSAVHDMA(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiE,SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, const SATUINT32_t* puiS, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECPtValidate(const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiLen); + +extern SATR CALPKXECKeyPairGen(const SATUINT32_t* puiC, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + const SATUINT32_t* puiNM1, const SATUINT32_t* puiNM1Mu, const SATUINT32_t* puiB, + SATUINT32_t* puiD, SATUINT32_t* puiQx, SATUINT32_t* puiQy, SATUINT32_t uiLen); + +extern SATR CALPKXPurge52(SATBOOL bVerify); + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ +extern SATRESULT SATResults; + +/* -------- ------ --------- */ +/* External Global Constants */ +/* -------- ------ --------- */ +extern const SATUINT32_t uiROMMods[]; + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/pkxlib.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/pkxlib.h new file mode 100755 index 0000000..fb4c0fc --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/pkxlib.h @@ -0,0 +1,95 @@ +/* ------------------------------------------------------------------- + $Rev: 1434 $ $Date: 2017-10-20 16:46:16 -0400 (Fri, 20 Oct 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for PKX-5200 Library. + ------------------------------------------------------------------- */ + +#ifndef PKXLIB_H +#define PKXLIB_H + +#include "caltypes.h" +#include "calpolicy.h" + +#define PKX_JMP_NONE (0xFFFFu + PKX_OFFSET) + +/* jump table entry points: starting PC value */ +#define PKX_JMP_RECIP_PRECOMPUTE (0x0000 + PKX_OFFSET) +#define PKX_JMP_MOD_EXP (0x0002 + PKX_OFFSET) +#define PKX_JMP_RSA_CRT (0x0004 + PKX_OFFSET) +#define PKX_JMP_EC_PTMUL (0x0006 + PKX_OFFSET) +#define PKX_JMP_EC_DSA_SIGN (0x0008 + PKX_OFFSET) +#define PKX_JMP_EC_DSA_VERIFY (0x000A + PKX_OFFSET) +#define PKX_JMP_DSA_SIGN (0x000C + PKX_OFFSET) +#define PKX_JMP_DSA_VERIFY (0x000E + PKX_OFFSET) +#define PKX_JMP_MOD_MULT (0x0010 + PKX_OFFSET) +#define PKX_JMP_MOD_RED (0x0012 + PKX_OFFSET) +#define PKX_JMP_EC_PTDECOMP (0x0014 + PKX_OFFSET) +#define PKX_JMP_EC_DHC (0x0016 + PKX_OFFSET) +#define PKX_JMP_MOD_MULT_ADD (0x0018 + PKX_OFFSET) +#define PKX_JMP_EC_PTMUL_ADD (0x001A + PKX_OFFSET) +#define PKX_JMP_EC_PTVALIDATE (0x001C + PKX_OFFSET) +#define PKX_JMP_F5200_SHA (0x001E + PKX_OFFSET) +#define PKX_JMP_F5200_AES (0x0020 + PKX_OFFSET) +#define PKX_JMP_F5200_AESK (0x0022 + PKX_OFFSET) +#define PKX_JMP_F5200_GCM (0x0024 + PKX_OFFSET) +#define PKX_JMP_F5200_GHA (0x0026 + PKX_OFFSET) +#define PKX_JMP_F5200_AESKW (0x0028 + PKX_OFFSET) +#define PKX_JMP_F5200_AESKWP (0x002A + PKX_OFFSET) +#define PKX_JMP_RNG_INSTANTIATE (0x002C + PKX_OFFSET) +#define PKX_JMP_RNG_RESEED (0x002E + PKX_OFFSET) +#define PKX_JMP_RNG_GENERATE (0x0030 + PKX_OFFSET) +#define PKX_JMP_RNG_UNINSTANTIATE (0x0032 + PKX_OFFSET) +#define PKX_JMP_RNG_GETENTROPY (0x0034 + PKX_OFFSET) +#define PKX_JMP_F5200_SHA_HMAC (0x0036 + PKX_OFFSET) +#define PKX_JMP_F5200_AES_DMA (0x0038 + PKX_OFFSET) +#define PKX_JMP_RNG_CTRLSTATUS (0x003A + PKX_OFFSET) +#define PKX_JMP_F5200_SHA_DMA (0x003C + PKX_OFFSET) +#define PKX_JMP_SHX_KEYTREE (0x003E + PKX_OFFSET) +#define PKX_JMP_PKX_DSA_DMA (0x0040 + PKX_OFFSET) +#define PKX_JMP_PKX_RSACRT_SIGN (0x0042 + PKX_OFFSET) +#define PKX_JMP_PKX_RSA_SIGN (0x0044 + PKX_OFFSET) +#define PKX_JMP_PKX_RSA_VERIFY (0x0046 + PKX_OFFSET) +#define PKX_JMP_PKX_EC_DSA_DMA (0x0048 + PKX_OFFSET) +#define PKX_JMP_F5200_AES_KEYROLL (0x004A + PKX_OFFSET) +#define PKX_JMP_EXPM (0x004C + PKX_OFFSET) +#define PKX_JMP_RSACRTM (0x004E + PKX_OFFSET) +#define PKX_JMP_EC_PTMULM (0x0050 + PKX_OFFSET) +#define PKX_JMP_DSA_SIGN_M (0x0052 + PKX_OFFSET) +#define PKX_JMP_EC_DSA_SIGN_M (0x0054 + PKX_OFFSET) +#define PKX_JMP_EC_KEYPAIRGEN (0x0056 + PKX_OFFSET) +#define PKX_JMP_RSACRTCM_SIGN (0x0058 + PKX_OFFSET) +#define PKX_JMP_F5200_GCM_NEW (0x005A + PKX_OFFSET) +/* PKX PKRev 2180 */ +/* PKX SHARev 2160 */ +/* PKX AESRev 2135 */ +/* Hex Checksum: 0xd0d79866 */ + +extern const SATUINT32_t uiPKX_Flags; +extern const SATUINT32_t uiPKX_BERWords; +extern const SATUINT32_t uiPKX_LIRWords; +extern const SATUINT32_t uiPKX_Rev; +extern const SATUINT32_t uiPKX_LibSize; +extern const SATUINT32_t uiPKX_LibChksum; +extern const SATUINT32_t uiPKX_Lib[]; +extern SATBOOL bMPF300TS_ES; + +#endif diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/shaf5200.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/shaf5200.h new file mode 100755 index 0000000..da598d1 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/shaf5200.h @@ -0,0 +1,101 @@ +/* ------------------------------------------------------------------- + $Rev: 1296 $ $Date: 2017-08-01 13:54:48 -0400 (Tue, 01 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for SHA function hardware implementation for CAL. + ------------------------------------------------------------------- */ + +#ifndef SHAF5200_H +#define SHAF5200_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef SHAF5200_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATR shapkxctx(SATRESCONTEXTPTR const pContext, const void *pBuffer, + SATUINT32_t uiBufLen,void *pHash, const SATBOOL bFinal); + +extern SATR shapkxhmacctx(SATRESCONTEXTPTR const pContext, const void *pBuffer, + SATUINT32_t uiBufLen, void *pHash, const SATUINT8_t uiFlag); + +extern SATR shapkxctxload(SATRESCONTEXTPTR const pContext); + +extern void shapkxctxunload(SATRESCONTEXTPTR const pContext); + +extern SATR shapkxini(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen); + +extern SATR shapkxhmacini(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, + const void *pKey, SATUINT32_t uiKeyLen); + +extern SATR shapkxwrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR shapkxhmacwrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR shapkxread(void *pHash, SATUINT32_t uiRevFlag); + +extern SATR shapkxkeytree(SATBOOL bPathSizeSel, const SATUINT32_t* puiKey, + SATUINT8_t uiOpType, const SATUINT32_t* puiPath, SATUINT32_t* puiKeyOut); + +extern SATR shapkxdma(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, + const void *pExtSrc, const void *pExtDest, SATUINT32_t uiDMAChConfig); + +extern SATR shapkxhmacdma(SATMACTYPE eMACType, const SATUINT32_t *pKey, + SATUINT32_t uiKeyLen, const void *pMsg, SATUINT32_t uiMsgLen, + const void *pMAC, SATUINT32_t uiDMAChConfig); + +extern SATR shapkxhashtypeini(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/sym.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/sym.h new file mode 100755 index 0000000..2e07faa --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/sym.h @@ -0,0 +1,129 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for Symmetric Key Cryptography in CAL. + ------------------------------------------------------------------- */ + +#ifndef SYM_H +#define SYM_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef SYM_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALSymTrfRes(SATBOOL bBlock); + +extern SATR CALSymEncrypt(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen); + +extern SATR CALSymDecrypt(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen); + +extern SATR CALSymEncryptDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymDecryptDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymEncryptKR(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF); + +extern SATR CALSymDecryptKR(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF); + +extern SATR CALSymEncryptKRDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymDecryptKRDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymEncAuth(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen); + +extern SATR CALSymDecVerify(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen); + +extern SATR CALSymKw(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR CALSymKwp(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR CALSymEncAuthDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymDecVerifyDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen, SATUINT32_t uiDMAChConfig); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/utils.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/utils.h new file mode 100755 index 0000000..91474f0 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/utils.h @@ -0,0 +1,93 @@ +/* ------------------------------------------------------------------- + $Rev: 1300 $ $Date: 2017-08-07 11:36:02 -0400 (Mon, 07 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL utility functions. + ------------------------------------------------------------------- */ + +#ifndef UTILS_H +#define UTILS_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef UTILS_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern void CALMemCopy(void *pDst, const void *pSrc, SATUINT32_t uiNum8); + +extern void CALMemClear( void * pLoc, SATUINT32_t uiNum ); + +extern void CALMemClear32( SATUINT32_t* puiLoc, SATUINT32_t uiLen32 ); + +extern SATBOOL CALMemCmp(const void *pA, const void *pB, SATUINT32_t uiNum); + +extern void CALVol32MemLoad(volatile SATUINT32_t * puiDst, const void * pSrc, + SATUINT32_t uiNum32); + +extern void CALVol32MemRead(void * pDst, volatile SATUINT32_t * puiSrc, + SATUINT32_t uiNum32); + +extern void CALByteReverse(SATUINT32_t* puiArray, SATINT32_t iNumberBytes); + +extern void CALByteReverseWord(SATUINT32_t* puiArray, SATINT32_t iNumberWords); + +extern void CALWordReverse(SATUINT32_t *puiArray, SATINT32_t iNumberWords); + +extern void vAppendNonzero(void *puiArray, SATUINT32_t uiLen, + SATUINT32_t uiBlockSize); + +extern void vAppendZero(void *puiArray, SATUINT32_t uiLen, + SATUINT32_t uiBlockSize); + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/x52cfg_user.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/x52cfg_user.h new file mode 100755 index 0000000..c8d8648 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/middleware/cal/x52cfg_user.h @@ -0,0 +1,72 @@ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ +/* X5200 configuration */ +/* $Date: 2015-07-23 14:30:19 -0400 (Thu, 23 Jul 2015) $ $Rev: 2093 $ */ +/* ------------------------------------------------------------------- + Options: + * LIR ROM size : 4096 + * LIR RAM size : 2048 + * BER size : 1024 + * MMR size : 1024 + * TSR size : 1024 + * FPR size : 1024 + * Single error correct, dual error detect (SECDED) memory parity + * DMA enabled + * FPGA multipliers disabled + * AES enabled + - Fast key schedule generation + - GCM/GHASH enabled + - AES countermeasures enabled + * RNG enabled + * External PRNG disabled + * SHA enabled + - Fast SHA enabled + - SHA-1 enabled + - SHA-224 enabled + - SHA-256 enabled + - SHA-384 enabled + - SHA-512 enabled + - SHA-512/224 enabled + - SHA-512/256 enabled + - SHA countermeasures enabled + * P-curves populated in FCR: + - P-192 populated + - P-224 populated + - P-256 populated + - P-384 populated + - P-521 populated + * Data memory scrambling enabled + + ------------------------------------------------------------------- */ + +#ifndef X52CFG_H +#define X52CFG_H + +#define X52_CFG_MODEL 0xf5200 +#define X52_CFG_DATE 0x15072720 +#define X52_CFG_REV 0x0000082e +#define X52_CFG_OPT 0x0fd87ff9 +#define X52_CFG_OPT2 0xc0000000 +#define X52_LIR_LEN 0x1800 +#define X52_LIR_ROM_LEN 0x1000 +#define X52_LIR_RAM_LEN 0x0800 +#define X52_BER_LEN 0x400 +#define X52_MMR_LEN 0x400 +#define X52_TSR_LEN 0x400 +#define X52_FPR_LEN 0x400 + +#endif diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/README.md b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/README.md new file mode 100644 index 0000000..f7f6030 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/README.md @@ -0,0 +1,27 @@ +# Mi-V soft processor platform source code + +## Repo organization + +``` + + | + |-- drivers + | |- fpga_ip + | | | CoreGPIO + | | | CoreSysServices_PF + | | | CoreUARTapb + | | + | |- off_chip + | | | . + | | | . + | | + |-- hal + | | + |-- miv_rv32_hal + + +``` + +The drivers published here are compatible with the improved SoftConsole project folder structure being used in the latest [example projects](https://github.com/Mi-V-Soft-RISC-V/miv-rv32-bare-metal-examples). +These drivers can also be used with the legacy folder structure (projects released via Firmware Catalog) by defining the **LEGACY_DIR_STRUCTURE** macro in the SoftConsole project settings. + diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c new file mode 100644 index 0000000..1a0073f --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c @@ -0,0 +1,533 @@ +/******************************************************************************* + * (c) Copyright 2008-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file core_gpio.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreGPIO bare metal driver implementation. + * + */ +#include "coregpio_regs.h" +#include "core_gpio.h" + +/*-------------------------------------------------------------------------*//** + * + */ +#define GPIO_INT_ENABLE_MASK (uint32_t)0x00000008UL +#define OUTPUT_BUFFER_ENABLE_MASK 0x00000004UL + + +#define NB_OF_GPIO 32 + +#define CLEAR_ALL_IRQ32 (uint32_t)0xFFFFFFFF +#define CLEAR_ALL_IRQ16 (uint16_t)0xFFFF +#define CLEAR_ALL_IRQ8 (uint8_t)0xFF + +/*-------------------------------------------------------------------------*//** + * GPIO_init() + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_init +( + gpio_instance_t * this_gpio, + addr_t base_addr, + gpio_apb_width_t bus_width +) +{ + uint8_t i = 0; + addr_t cfg_reg_addr = base_addr; + + this_gpio->base_addr = base_addr; + this_gpio->apb_bus_width = bus_width; + + /* Clear configuration. */ + for( i = 0, cfg_reg_addr = base_addr; i < NB_OF_GPIO; ++i ) + { + HW_set_8bit_reg( cfg_reg_addr, 0 ); + cfg_reg_addr += 4; + } + /* Clear any pending interrupts */ + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, CLEAR_ALL_IRQ32 ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, (uint16_t)CLEAR_ALL_IRQ16 ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, (uint16_t)CLEAR_ALL_IRQ16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, (uint8_t)CLEAR_ALL_IRQ8 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_config + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_config +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint32_t config +) +{ + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + uint32_t cfg_reg_addr = this_gpio->base_addr; + cfg_reg_addr += (port_id * 4); + HW_set_32bit_reg( cfg_reg_addr, config ); + + /* + * Verify that the configuration was correctly written. Failure to read + * back the expected value may indicate that the GPIO port was configured + * as part of the hardware flow and cannot be modified through software. + * It may also indicate that the base address passed as parameter to + * GPIO_init() was incorrect. + */ + HAL_ASSERT( HW_get_32bit_reg( cfg_reg_addr ) == config ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_set_outputs + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_set_outputs +( + gpio_instance_t * this_gpio, + uint32_t value +) +{ + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, GPIO_OUT, value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, GPIO_OUT0, (uint16_t)value ); + HAL_set_16bit_reg( this_gpio->base_addr, GPIO_OUT1, (uint16_t)(value >> 16) ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT0, (uint8_t)value ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT1, (uint8_t)(value >> 8) ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT2, (uint8_t)(value >> 16) ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT3, (uint8_t)(value >> 24) ); + break; + + default: + HAL_ASSERT(0); + break; + } + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( GPIO_get_outputs( this_gpio ) == value ); +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_inputs + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_inputs +( + gpio_instance_t * this_gpio +) +{ + uint32_t gpio_in = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + gpio_in = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_IN ); + break; + + case GPIO_APB_16_BITS_BUS: + gpio_in |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_IN0 ); + gpio_in |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_IN1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + gpio_in |= HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN0 ); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN1 ) << 8); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN2 ) << 16); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return gpio_in; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_outputs + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_outputs +( + gpio_instance_t * this_gpio +) +{ + uint32_t gpio_out = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + gpio_out = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ); + break; + + case GPIO_APB_16_BITS_BUS: + gpio_out |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT0 ); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + gpio_out |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT0 ); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT1 ) << 8); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT2 ) << 16); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return gpio_out; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_set_output + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_set_output +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint8_t value +) +{ + HAL_ASSERT( port_id < NB_OF_GPIO ); + + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + { + uint32_t outputs_state; + + outputs_state = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ); + if ( 0 == value ) + { + outputs_state &= ~(1 << port_id); + } + else + { + outputs_state |= 1 << port_id; + } + HAL_set_32bit_reg( this_gpio->base_addr, GPIO_OUT, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ) == outputs_state ); + } + break; + + case GPIO_APB_16_BITS_BUS: + { + uint16_t outputs_state; + uint32_t gpio_out_reg_addr = this_gpio->base_addr + GPIO_OUT_REG_OFFSET + ((port_id >> 4) * 4); + + outputs_state = HW_get_16bit_reg( gpio_out_reg_addr ); + if ( 0 == value ) + { + outputs_state &= ~(1 << (port_id & 0x0F)); + } + else + { + outputs_state |= 1 << (port_id & 0x0F); + } + HW_set_16bit_reg( gpio_out_reg_addr, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HW_get_16bit_reg( gpio_out_reg_addr ) == outputs_state ); + } + break; + + case GPIO_APB_8_BITS_BUS: + { + uint8_t outputs_state; + uint32_t gpio_out_reg_addr = this_gpio->base_addr + GPIO_OUT_REG_OFFSET + ((port_id >> 3) * 4); + + outputs_state = HW_get_8bit_reg( gpio_out_reg_addr ); + if ( 0 == value ) + { + outputs_state &= ~(1 << (port_id & 0x07)); + } + else + { + outputs_state |= 1 << (port_id & 0x07); + } + HW_set_8bit_reg( gpio_out_reg_addr, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HW_get_8bit_reg( gpio_out_reg_addr ) == outputs_state ); + } + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_drive_inout + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_drive_inout +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + gpio_inout_state_t inout_state +) +{ + uint32_t config; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + switch( inout_state ) + { + case GPIO_DRIVE_HIGH: + /* Set output high */ + GPIO_set_output( this_gpio, port_id, 1 ); + + /* Enable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config |= OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + case GPIO_DRIVE_LOW: + /* Set output low */ + GPIO_set_output( this_gpio, port_id, 0 ); + + /* Enable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config |= OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + case GPIO_HIGH_Z: + /* Disable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config &= ~OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_enable_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_enable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t cfg_value; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + cfg_reg_addr += (port_id * 4); + cfg_value = HW_get_8bit_reg( cfg_reg_addr ); + cfg_value |= GPIO_INT_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, cfg_value ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_disable_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_disable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t cfg_value; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + cfg_reg_addr += (port_id * 4); + cfg_value = HW_get_8bit_reg( cfg_reg_addr ); + cfg_value &= ~GPIO_INT_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, cfg_value ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_clear_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_clear_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t irq_clr_value = ((uint32_t)1) << ((uint32_t)port_id); + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, irq_clr_value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, irq_clr_value >> 16 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, irq_clr_value >> 24 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_irq_sources + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_irq_sources +( + gpio_instance_t * this_gpio +) +{ + uint32_t intr_src = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + intr_src = HAL_get_32bit_reg( this_gpio->base_addr, IRQ ); + break; + + case GPIO_APB_16_BITS_BUS: + intr_src |= HAL_get_16bit_reg( this_gpio->base_addr, IRQ0 ); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + intr_src |= HAL_get_16bit_reg( this_gpio->base_addr, IRQ0 ); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ1 ) << 8); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ2 ) << 16); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return intr_src; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_clear_all_irq_sources + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_clear_all_irq_sources +( + gpio_instance_t * this_gpio, + uint32_t bitmask +) +{ + uint32_t irq_clr_value = bitmask; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, irq_clr_value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, irq_clr_value >> 16 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, irq_clr_value >> 24 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h new file mode 100644 index 0000000..88ba178 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h @@ -0,0 +1,722 @@ +/******************************************************************************* + * (c) Copyright 2008-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file core_gpio.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreGPIO bare metal driver public API. + * + */ + +/*=========================================================================*//** + @mainpage CoreGPIO Bare Metal Driver. + + @section intro_sec Introduction + The CoreGPIO hardware IP includes up to 32 general-purpose input/output GPIOs. + This driver provides a set of functions for controlling the GPIOs as part of a + bare-metal system where no operating system is available. These drivers + can be adapted for use as part of an operating system, but the implementation + of the adaptation layer between this driver and the operating system's driver + model is outside the scope of this driver. + + @section driver_configuration Driver Configuration + The individual IOs of CoreGPIO can be configured either in the hardware flow + or as part of the software application through calls to the GPIO_config() + function. GPIOs configured as part of the hardware are fixed and cannot be + modified using a call to the GPI_config() function. + + @section theory_op Theory of Operation + The CoreGPIO driver uses the Actel Hardware Abstraction Layer (HAL) to access + hardware registers. You must ensure that the Actel HAL is included as part of + your software project. The Actel HAL is available through the Actel Firmware + Catalog. + + The CoreGPIO driver functions are logically grouped into the following groups: + - Initialization + - Configuration + - Reading and writing GPIO state + - Interrupt control + + The CoreGPIO driver is initialized through a call to the GPIO_init() function. + The GPIO_init() function must be called before any other GPIO driver functions + can be called. + + Each GPIO port is individually configured through a call to the + GPIO_config() function. Configuration includes deciding if a GPIO port is + going to be used as input, output, or both. GPIO ports configured as inputs + are further configured to generate interrupts based on the state of input. + Interrupts is either level- or edge-sensitive. + Note that a CoreGPIO hardware instance is generated as part of the hardware + flow with a fixed configuration for some or all of its IOs. + Attempting to modify the configuration of such a hardware-configured IO using + the GPIO_config() function has no effect. + + The state of the GPIO ports can be read and written using the following + functions: + - GPIO_get_inputs() + - GPIO_get_outputs() + - GPIO_set_outputs() + - GPIO_drive_inout() + + Interrupts generated by GPIO ports configured as inputs are controlled using + the following functions: + - GPIO_enable_irq() + - GPIO_disable_irq() + - GPIO_clear_irq() + - GPIO_get_irq_sources() + - GPIO_clear_all_irq_sources() + + *//*=========================================================================*/ +#ifndef CORE_GPIO_H_ +#define CORE_GPIO_H_ + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + The gpio_id_t enumeration is used to identify GPIOs as part of the + parameter to functions: + - GPIO_config(), + - GPIO_drive_inout(), + - GPIO_enable_int(), + - GPIO_disable_int(), + - GPIO_clear_int() + */ +typedef enum __gpio_id_t +{ + GPIO_0 = 0, + GPIO_1 = 1, + GPIO_2 = 2, + GPIO_3 = 3, + GPIO_4 = 4, + GPIO_5 = 5, + GPIO_6 = 6, + GPIO_7 = 7, + GPIO_8 = 8, + GPIO_9 = 9, + GPIO_10 = 10, + GPIO_11 = 11, + GPIO_12 = 12, + GPIO_13 = 13, + GPIO_14 = 14, + GPIO_15 = 15, + GPIO_16 = 16, + GPIO_17 = 17, + GPIO_18 = 18, + GPIO_19 = 19, + GPIO_20 = 20, + GPIO_21 = 21, + GPIO_22 = 22, + GPIO_23 = 23, + GPIO_24 = 24, + GPIO_25 = 25, + GPIO_26 = 26, + GPIO_27 = 27, + GPIO_28 = 28, + GPIO_29 = 29, + GPIO_30 = 30, + GPIO_31 = 31 +} gpio_id_t; + +/*-------------------------------------------------------------------------*//** + Possible width of the APB bus + */ +typedef enum __gpio_apb_width_t +{ + GPIO_APB_8_BITS_BUS = 0, + GPIO_APB_16_BITS_BUS = 1, + GPIO_APB_32_BITS_BUS = 2, + GPIO_APB_UNKNOWN_BUS_WIDTH = 3 +} gpio_apb_width_t; + +/*-------------------------------------------------------------------------*//** + Structure instance holding all data regarding the CoreGPIO + */ +typedef struct __gpio_instance_t +{ + addr_t base_addr; + gpio_apb_width_t apb_bus_width; +} gpio_instance_t; + +/*-------------------------------------------------------------------------*//** + GPIO ports definitions used to identify GPIOs as part of the parameter to + function GPIO_set_outputs(). + These definitions are also be used to identity GPIO through logical operations + on the return value of function GPIO_get_inputs(). + # GPIO_0_MASK + # GPIO_1_MASK + # GPIO_2_MASK + # GPIO_3_MASK + # GPIO_4_MASK + # GPIO_5_MASK + # GPIO_6_MASK + # GPIO_7_MASK + # GPIO_8_MASK + # GPIO_9_MASK + # GPIO_10_MASK + # GPIO_11_MASK + # GPIO_12_MASK + # GPIO_13_MASK + # GPIO_14_MASK + # GPIO_15_MASK + # GPIO_16_MASK + # GPIO_17_MASK + # GPIO_18_MASK + # GPIO_19_MASK + # GPIO_20_MASK + # GPIO_21_MASK + # GPIO_22_MASK + # GPIO_23_MASK + # GPIO_24_MASK + # GPIO_25_MASK + # GPIO_26_MASK + # GPIO_27_MASK + # GPIO_28_MASK + # GPIO_29_MASK + # GPIO_30_MASK + # GPIO_31_MASK + */ +#define GPIO_0_MASK 0x00000001UL +#define GPIO_1_MASK 0x00000002UL +#define GPIO_2_MASK 0x00000004UL +#define GPIO_3_MASK 0x00000008UL +#define GPIO_4_MASK 0x00000010UL +#define GPIO_5_MASK 0x00000020UL +#define GPIO_6_MASK 0x00000040UL +#define GPIO_7_MASK 0x00000080UL +#define GPIO_8_MASK 0x00000100UL +#define GPIO_9_MASK 0x00000200UL +#define GPIO_10_MASK 0x00000400UL +#define GPIO_11_MASK 0x00000800UL +#define GPIO_12_MASK 0x00001000UL +#define GPIO_13_MASK 0x00002000UL +#define GPIO_14_MASK 0x00004000UL +#define GPIO_15_MASK 0x00008000UL +#define GPIO_16_MASK 0x00010000UL +#define GPIO_17_MASK 0x00020000UL +#define GPIO_18_MASK 0x00040000UL +#define GPIO_19_MASK 0x00080000UL +#define GPIO_20_MASK 0x00100000UL +#define GPIO_21_MASK 0x00200000UL +#define GPIO_22_MASK 0x00400000UL +#define GPIO_23_MASK 0x00800000UL +#define GPIO_24_MASK 0x01000000UL +#define GPIO_25_MASK 0x02000000UL +#define GPIO_26_MASK 0x04000000UL +#define GPIO_27_MASK 0x08000000UL +#define GPIO_28_MASK 0x10000000UL +#define GPIO_29_MASK 0x20000000UL +#define GPIO_30_MASK 0x40000000UL +#define GPIO_31_MASK 0x80000000UL + +/*-------------------------------------------------------------------------*//** + * GPIO modes + * # GPIO_INPUT_MODE + * # GPIO_OUTPUT_MODE + * # GPIO_INOUT_MODE + */ +#define GPIO_INPUT_MODE 0x0000000002UL +#define GPIO_OUTPUT_MODE 0x0000000005UL +#define GPIO_INOUT_MODE 0x0000000003UL + +/*-------------------------------------------------------------------------*//** + * Possible GPIO inputs interrupt configurations. + * # GPIO_IRQ_LEVEL_HIGH + * # GPIO_IRQ_LEVEL_LOW + * # GPIO_IRQ_EDGE_POSITIVE + * # GPIO_IRQ_EDGE_NEGATIVE + * # GPIO_IRQ_EDGE_BOTH + */ +#define GPIO_IRQ_LEVEL_HIGH 0x0000000000UL +#define GPIO_IRQ_LEVEL_LOW 0x0000000020UL +#define GPIO_IRQ_EDGE_POSITIVE 0x0000000040UL +#define GPIO_IRQ_EDGE_NEGATIVE 0x0000000060UL +#define GPIO_IRQ_EDGE_BOTH 0x0000000080UL + +/*-------------------------------------------------------------------------*//** + * Possible states for GPIO configured as INOUT + */ +typedef enum gpio_inout_state +{ + GPIO_DRIVE_LOW = 0, + GPIO_DRIVE_HIGH, + GPIO_HIGH_Z +} gpio_inout_state_t; + +/*-------------------------------------------------------------------------*//** + The GPIO_init() function initializes a CoreGPIO hardware instance and the data + structure associated with the CoreGPIO hardware instance. + Note that a CoreGPIO hardware instance is generated with a fixed configuration + for some or all of its IOs as part of the hardware flow. + Attempting to modify the configuration of such a hardware-configured IO using + the GPIO_config() function has no effect. + + @param this_gpio + Pointer to the gpio_instance_t data structure instance holding all data + regarding the CoreGPIO hardware instance being initialized. A pointer to the + same data structure is used in subsequent calls to the CoreGPIO driver + functions in order to identify the CoreGPIO instance that must perform the + operation implemented by the called driver function. + + @param base_addr + The base_addr parameter is the base address in the memory map of the + processor for the registers of the GPIO instance being initialized. + + @param bus_width + The bus_width parameter informs the driver of the APB bus width selected + during the hardware flow configuration of the CoreGPIO hardware instance. It + indicates to the driver whether the CoreGPIO hardware registers are visible + as 8, 16, or 32-bits registers. Allowed values are: + - GPIO_APB_8_BITS_BUS + - GPIO_APB_16_BITS_BUS + - GPIO_APB_32_BITS_BUS + + @return + none. + + @example + @code + #define COREGPIO_BASE_ADDR 0xC2000000 + + gpio_instance_t g_gpio; + + void system_init( void ) + { + GPIO_init( &g_gpio, COREGPIO_BASE_ADDR, GPIO_APB_32_BITS_BUS ); + } + @endcode + */ +void GPIO_init +( + gpio_instance_t * this_gpio, + addr_t base_addr, + gpio_apb_width_t bus_width +); + +/*-------------------------------------------------------------------------*//** + The GPIO_config() function is used to configure an individual GPIO port. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO port to be configured. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @param config + The config parameter specifies the configuration to be applied to the GPIO + port identified by the first parameter. It is a logical OR of GPIO mode and + interrupt mode. The interrupt mode is only relevant if the GPIO is + configured as an input. + - Possible modes are: + - GPIO_INPUT_MODE, + - GPIO_OUTPUT_MODE, + - GPIO_INOUT_MODE. + - Possible interrupt modes are: + - GPIO_IRQ_LEVEL_HIGH, + - GPIO_IRQ_LEVEL_LOW, + - GPIO_IRQ_EDGE_POSITIVE, + - GPIO_IRQ_EDGE_NEGATIVE, + - GPIO_IRQ_EDGE_BOTH + + @return + none. + + @example + For example, the following call configures GPIO 4 as an input that generates + interrupts on a low-to-high transition of the input: + @code + GPIO_config( &g_gpio, GPIO_4, GPIO_INPUT_MODE | GPIO_IRQ_EDGE_POSITIVE ); + @endcode + */ +void GPIO_config +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint32_t config +); + +/*-------------------------------------------------------------------------*//** + The GPIO_set_outputs() function is used to set the state of the GPIO ports + configured as outputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param value + The value parameter specifies the state of the GPIO ports configured as + outputs. It is a bit mask of the form (GPIO_n_MASK | GPIO_m_MASK), where n + and m are numbers identifying GPIOs. + For example, (GPIO_0_MASK | GPIO_1_MASK | GPIO_2_MASK ) specifies that the + first, second, and third GPIO must be set high and all other outputs set + low. + + @return + none. + + @example + Set GPIO 0 and 8 outputs high and all other GPIO outputs low. + @code + GPIO_set_outputs( &g_gpio, GPIO_0_MASK | GPIO_8_MASK ); + @endcode + + @example + Set GPIO 2 and 4 outputs low without affecting the other GPIO outputs. + @code + uint32_t gpio_outputs; + gpio_outputs = GPIO_get_outputs( &g_gpio ); + gpio_outputs &= ~( GPIO_2_MASK | GPIO_4_MASK ); + GPIO_set_outputs( &g_gpio, gpio_outputs ); + @endcode + + @see GPIO_get_outputs() + */ +void GPIO_set_outputs +( + gpio_instance_t * this_gpio, + uint32_t value +); + +/*-------------------------------------------------------------------------*//** + The GPIO_set_output() function is used to set the state of a single GPIO port + configured as an output. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter specifies the GPIO port that has its output set by a + call to this function. + + @param value + The value parameter specifies the desired state for the GPIO output. A value + of 0 sets the output low, and a value of 1 sets the port high. + + @return + none. + */ +void GPIO_set_output +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint8_t value +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_inputs() function is used to read the state of all GPIOs + configured as inputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @return + This function returns a 32-bit unsigned integer, where each bit represents + the state of an input. The least significant bit represents the state of + GPIO 0, and the most significant bit represents the state of GPIO 31. + */ +uint32_t GPIO_get_inputs +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_outputs() function is used to read the current state of all + GPIO outputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @return + This function returns a 32-bit unsigned integer where each bit represents + the state of an output. The least significant bit represents the state + of GPIO 0, and the most significant bit represents the state of GPIO 31. + */ +uint32_t GPIO_get_outputs +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_drive_inout() function is used to set the output state of a + GPIO configured as INOUT. An INOUT GPIO is in one of three states: + - high + - low + - high impedance + + An INOUT output is typically be used where several devices drive the state of + a signal. The high and low states are equivalent to the high and low states of + a GPIO configured as an output. The high impedance state is used to prevent + the GPIO from driving the state of the output and therefore allow reading the + state of the GPIO as an input. + Note that the GPIO port you wish to use as INOUT through this function + must be configurable through software. Therefore, the GPIO ports used as INOUT + must not have a fixed configuration selected as part of the hardware flow. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO for which this function will + change the output state. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @param inout_state + The inout_state parameter specifies the state of the I/O identified by the + first parameter. Possible states are: + - GPIO_DRIVE_HIGH, + - GPIO_DRIVE_LOW, + - GPIO_HIGH_Z (high impedance) + + @return + none. + + @example + The call to GPIO_drive_inout() below will set the GPIO 7 output to + high impedance state. + @code + GPIO_drive_inout( &g_gpio, GPIO_7, GPIO_HIGH_Z ); + @endcode + */ +void GPIO_drive_inout +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + gpio_inout_state_t inout_state +); + +/*-------------------------------------------------------------------------*//** + The GPIO_enable_irq() function is used to enable an interrupt to be + generated based on the state of the input identified as a parameter. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO input that the call to + GPIO_enable_irq() enables to generate interrupts. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + @example + The call to GPIO_enable_irq() below allows GPIO 8 to generate interrupts. + + @code + GPIO_enable_irq( &g_gpio, GPIO_8 ); + @endcode + */ +void GPIO_enable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_disable_irq() function is used to disable interrupts from being + generated based on the state of the input specified as a parameter. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO input that the call to + GPIO_disable_irq() disables from generating interrupts. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + @example + The call to GPIO_disable_irq() below prevents GPIO 8 from generating + interrupts. + @code + GPIO_disable_irq( &g_gpio, GPIO_8 ); + @endcode + */ +void GPIO_disable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_clear_irq() function is used to clear the interrupt generated by + the GPIO specified as a parameter. The GPIO_clear_irq() function must be + called as part of a GPIO interrupt service routine (ISR) in order to prevent + the same interrupt event from re-triggering a call to the GPIO ISR. + Note that interrupts may also need to be cleared in the processor's + interrupt controller. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO input for which to clear the + interrupt. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + @example + The example below demonstrates the use of the GPIO_clear_irq() function as + part of the GPIO-9 interrupt service routine. + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + GPIO_clear_irq( &g_gpio, GPIO_9 ); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +void GPIO_clear_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_irq_sources() function is used to identify the source of the + interrupt. i.e. to That is the GPIO input line, whose state change triggered + the interrupt. The GPIO_get_irq_sources() function must be called as part of + a GPIO interrupt service routine (ISR) in order to determine the interrupt + source. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @return + This function returns a 32-bit unsigned integer, where each bit represents + the pin number of a GPIO. + + @example + The example below demonstrates the use of the GPIO_get_irq_sources() + function as part of the GPIO-9 interrupt service routine. + + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + GPIO_clear_all_irq_sources(g_p_mygpio, GPIO_get_irq_sources(g_p_mygpio)); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +uint32_t GPIO_get_irq_sources +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_clear_all_irq_sources() function is used to clear all the active + interrupts generated by the GPIO specified as a parameter. The + GPIO_clear_all_irq_sources() function must be called as part of a GPIO + interrupt service routine (ISR) in order to prevent the same interrupt event + from re-triggering a call to the GPIO ISR. + Note that interrupts may also need to be cleared in the processor's + interrupt controller. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param bitmask + This bitmask parameter is a 32-bit unsigned integer where each bit + represents the GPIO pin used to clear the interrupt bit register of the + corresponding GPIO bit. The least significant bit represents the status of + GPIO 0, and the most significant bit represents the status of GPIO 31. + + @return + none. + + @example + The example below demonstrates the use of the GPIO_clear_all_irq_sources() + function as part of the GPIO-9 interrupt service routine. + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + do_interrupt_processing(); + + GPIO_clear_all_irq_sources(g_p_mygpio, GPIO_get_irq_sources(g_p_mygpio)); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +void GPIO_clear_all_irq_sources +( + gpio_instance_t * this_gpio, + uint32_t bitmask +); + +#ifdef __cplusplus +} +#endif + +#endif /* CORE_GPIO_H_ */ diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h new file mode 100644 index 0000000..41f5b7c --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h @@ -0,0 +1,45 @@ +/******************************************************************************* + * (c) Copyright 2008-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file coregpio_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreGPIO register definitions + * + */ + +#ifndef __CORE_GPIO_REGISTERS_H +#define __CORE_GPIO_REGISTERS_H 1 + +/*------------------------------------------------------------------------------ + * + */ +#define IRQ_REG_OFFSET 0x80 + +#define IRQ0_REG_OFFSET 0x80 +#define IRQ1_REG_OFFSET 0x84 +#define IRQ2_REG_OFFSET 0x88 +#define IRQ3_REG_OFFSET 0x8C + +/*------------------------------------------------------------------------------ + * + */ +#define GPIO_IN_REG_OFFSET 0x90 + +#define GPIO_IN0_REG_OFFSET 0x90 +#define GPIO_IN1_REG_OFFSET 0x94 +#define GPIO_IN2_REG_OFFSET 0x98 +#define GPIO_IN3_REG_OFFSET 0x9C + +/*------------------------------------------------------------------------------ + * + */ +#define GPIO_OUT_REG_OFFSET 0xA0 + +#define GPIO_OUT0_REG_OFFSET 0xA0 +#define GPIO_OUT1_REG_OFFSET 0xA4 +#define GPIO_OUT2_REG_OFFSET 0xA8 +#define GPIO_OUT3_REG_OFFSET 0xAC + +#endif /* __CORE_GPIO_REGISTERS_H */ diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c new file mode 100644 index 0000000..1fd3dd6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c @@ -0,0 +1,1495 @@ +/******************************************************************************* + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * CoreI2C software driver implementation. + * + */ + +#include "core_smbus_regs.h" +#include "core_i2c.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * I2C transaction direction. + */ +#define WRITE_DIR 0u +#define READ_DIR 1u + +/* -- TRANSACTIONS TYPES -- */ +#define NO_TRANSACTION 0u +#define MASTER_WRITE_TRANSACTION 1u +#define MASTER_READ_TRANSACTION 2u +#define MASTER_RANDOM_READ_TRANSACTION 3u +#define WRITE_SLAVE_TRANSACTION 4u +#define READ_SLAVE_TRANSACTION 5u + +/* -- SMBUS H/W STATES -- */ +/* -- MASTER STATES -- */ +#define ST_BUS_ERROR 0x00u /* Bus error during MST or selected slave modes */ +#define ST_I2C_IDLE 0xF8u /* No activity and no interrupt either... */ +#define ST_START 0x08u /* start condition sent */ +#define ST_RESTART 0x10u /* repeated start */ +#define ST_SLAW_ACK 0x18u /* SLA+W sent, ack received */ +#define ST_SLAW_NACK 0x20u /* SLA+W sent, nack received */ +#define ST_TX_DATA_ACK 0x28u /* Data sent, ACK'ed */ +#define ST_TX_DATA_NACK 0x30u /* Data sent, NACK'ed */ +#define ST_LOST_ARB 0x38u /* Master lost arbitration */ +#define ST_SLAR_ACK 0x40u /* SLA+R sent, ACK'ed */ +#define ST_SLAR_NACK 0x48u /* SLA+R sent, NACK'ed */ +#define ST_RX_DATA_ACK 0x50u /* Data received, ACK sent */ +#define ST_RX_DATA_NACK 0x58u /* Data received, NACK sent */ +#define ST_RESET_ACTIVATED 0xD0u /* Master reset is activated */ +#define ST_STOP_TRANSMIT 0xE0u /* Stop has been transmitted */ + +/* -- SLAVE STATES -- */ +#define ST_SLAVE_SLAW 0x60u /* SLA+W received */ +#define ST_SLAVE_SLAR_ACK 0xA8u /* SLA+R received, ACK returned */ +#define ST_SLV_LA 0x68u /* Slave lost arbitration */ +#define ST_GCA 0x70u /* GCA received */ +#define ST_GCA_LA 0x78u /* GCA lost arbitration */ +#define ST_RDATA 0x80u /* Data received */ +#define ST_SLA_NACK 0x88u /* Slave addressed, NACK returned */ +#define ST_GCA_ACK 0x90u /* Previously addresses with GCA, data ACKed */ +#define ST_GCA_NACK 0x98u /* GCA addressed, NACK returned */ +#define ST_RSTOP 0xA0u /* Stop received */ +#define ST_SLARW_LA 0xB0u /* Arbitration lost */ +#define ST_RACK 0xB8u /* Byte sent, ACK received */ +#define ST_SLAVE_RNACK 0xC0u /* Byte sent, NACK received */ +#define ST_FINAL 0xC8u /* Final byte sent, ACK received */ +#define ST_SLV_RST 0xD8u /* Slave reset state */ + + +/* I2C Channel base offset */ +#define CHANNEL_BASE_SHIFT 5u +#define CHANNEL_MASK 0x1E0u + +/* + * Maximum address offset length in slave write-read transactions. + * A maximum of two bytes will be interpreted as address offset within the slave + * tx buffer. + */ +#define MAX_OFFSET_LENGTH 2u + +/*------------------------------------------------------------------------------ + * I2C interrupts control functions implemented "i2c_interrupt.c". + * the implementation of these functions depend on the underlying hardware + * design and how the CoreI2C interrupt line is connected to the system's + * interrupt controller. + */ +void I2C_enable_irq( i2c_instance_t * this_i2c ); +void I2C_disable_irq( i2c_instance_t * this_i2c ); +static void enable_slave_if_required(i2c_instance_t * this_i2c); + +/*------------------------------------------------------------------------------ + * I2C_init() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_init +( + i2c_instance_t * this_i2c, + addr_t base_address, + uint8_t ser_address, + i2c_clock_divider_t ser_clock_speed +) +{ + psr_t saved_psr; + uint_fast16_t clock_speed = (uint_fast16_t)ser_clock_speed; + + /* + * We need to disable ints while doing this as there is no guarantee we + * have not been called already and the ISR is active. + */ + saved_psr = HAL_disable_interrupts(); + + /* + * Initialize all items of the this_i2c data structure to zero. This + * initializes all state variables to their init value. It relies on + * the fact that NO_TRANSACTION, I2C_SUCCESS and I2C_RELEASE_BUS all + * have an actual value of zero. + */ + memset(this_i2c, 0, sizeof(i2c_instance_t)); + + /* + * Set base address of I2C hardware used by this instance. + */ + this_i2c->base_address = base_address; + + /* + * Update Serial address of the device + */ + this_i2c->ser_address = ((uint_fast8_t)ser_address << 1u); + + /* + * Configure hardware. + */ + HAL_set_8bit_reg_field(this_i2c->base_address, ENS1, 0x00); /* Reset I2C hardware. */ + HAL_set_8bit_reg_field(this_i2c->base_address, ENS1, 0x01); /* set enable bit */ + HAL_set_8bit_reg_field(this_i2c->base_address, CR2, ( (clock_speed >> 2) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c->base_address, CR1, ( (clock_speed >> 1) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c->base_address, CR0, ( clock_speed & 0x01) ); + + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS, this_i2c->ser_address); + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, this_i2c->ser_address); + + /* + * Finally safe to enable interrupts. + */ + HAL_restore_interrupts( saved_psr ); +} +/*------------------------------------------------------------------------------ + * I2C_channel_init() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_channel_init +( + i2c_instance_t * this_i2c_channel, + i2c_instance_t * this_i2c, + i2c_channel_number_t channel_number, + i2c_clock_divider_t ser_clock_speed +) +{ + psr_t saved_psr; + uint_fast16_t clock_speed = (uint_fast16_t)ser_clock_speed; + + HAL_ASSERT(channel_number < I2C_MAX_CHANNELS); + HAL_ASSERT(I2C_CHANNEL_0 != channel_number); + + /* + * Cannot allow channel 0 in this function as we will trash the hardware + * base address and slave address. + */ + if ((channel_number < I2C_MAX_CHANNELS) && + (I2C_CHANNEL_0 != channel_number)) + { + /* + * We need to disable ints while doing this as the hardware should already + * be active at this stage. + */ + saved_psr = HAL_disable_interrupts(); + + /* + * Initialize channel data. + */ + memset(this_i2c_channel, 0, sizeof(i2c_instance_t)); + + this_i2c_channel->base_address = + ((this_i2c->base_address) & ~((addr_t)CHANNEL_MASK)) + | (((addr_t)channel_number) << CHANNEL_BASE_SHIFT); + + this_i2c_channel->ser_address = this_i2c->ser_address; + + HAL_set_8bit_reg_field(this_i2c_channel->base_address, ENS1, 0x00); /* Reset I2C channel hardware. */ + HAL_set_8bit_reg_field(this_i2c_channel->base_address, ENS1, 0x01); /* set enable bit */ + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR2, ( (clock_speed >> 2) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR1, ( (clock_speed >> 1) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR0, ( clock_speed & 0x01) ); + /* + * Finally safe to enable interrupts. + */ + HAL_restore_interrupts( saved_psr ); + } +} + +/*------------------------------------------------------------------------------ + * I2C_write() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_write +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * write_buffer, + uint16_t write_size, + uint8_t options +) +{ + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + saved_psr = HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_WRITE_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_WRITE_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + this_i2c->dir = WRITE_DIR; + this_i2c->master_tx_buffer = write_buffer; + this_i2c->master_tx_size = write_size; + this_i2c->master_tx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_read() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +) +{ + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + saved_psr = HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_READ_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_READ_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + + this_i2c->dir = READ_DIR; + + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_write_read() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_write_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * addr_offset, + uint16_t offset_size, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +) +{ + HAL_ASSERT(offset_size > 0u); + HAL_ASSERT(addr_offset != (uint8_t *)0); + HAL_ASSERT(read_size > 0u); + HAL_ASSERT(read_buffer != (uint8_t *)0); + + this_i2c->master_status = I2C_FAILED; + + if((read_size > 0u) && (offset_size > 0u)) + { + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + saved_psr = HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_RANDOM_READ_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_RANDOM_READ_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + + this_i2c->dir = WRITE_DIR; + + this_i2c->master_tx_buffer = addr_offset; + this_i2c->master_tx_size = offset_size; + this_i2c->master_tx_idx = 0u; + + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + + HAL_restore_interrupts( saved_psr ); + } +} + +/*------------------------------------------------------------------------------ + * I2C_get_status() + * See "core_i2c.h" for details of how to use this function. + */ +i2c_status_t I2C_get_status +( + i2c_instance_t * this_i2c +) +{ + i2c_status_t i2c_status ; + + i2c_status = this_i2c->master_status ; + + return i2c_status; +} + +/*------------------------------------------------------------------------------ + * I2C_wait_complete() + * See "core_i2c.h" for details of how to use this function. + */ +i2c_status_t I2C_wait_complete +( + i2c_instance_t * this_i2c, + uint32_t timeout_ms +) +{ + i2c_status_t i2c_status; + psr_t saved_psr; + /* + * Because we have no idea of what CPU we are supposed to be running on + * we need to guard this write to the timeout value to avoid ISR/user code + * interaction issues. Checking the status below should be fine as only a + * single byte should change in that. + */ + saved_psr = HAL_disable_interrupts(); + this_i2c->master_timeout_ms = timeout_ms; + HAL_restore_interrupts( saved_psr ); + + /* Run the loop until state returns I2C_FAILED or I2C_SUCESS*/ + do { + i2c_status = this_i2c->master_status; + } while(I2C_IN_PROGRESS == i2c_status); + return i2c_status; +} + +/*------------------------------------------------------------------------------ + * I2C_system_tick() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_system_tick +( + i2c_instance_t * this_i2c, + uint32_t ms_since_last_tick +) +{ + if(this_i2c->master_timeout_ms != I2C_NO_TIMEOUT) + { + if(this_i2c->master_timeout_ms > ms_since_last_tick) + { + this_i2c->master_timeout_ms -= ms_since_last_tick; + } + else + { + psr_t saved_psr; + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + /* + * Mark current transaction as having timed out. + */ + this_i2c->master_status = I2C_TIMED_OUT; + this_i2c->transaction = NO_TRANSACTION; + this_i2c->is_transaction_pending = 0; + + HAL_restore_interrupts( saved_psr ); + + /* + * Make sure we do not incorrectly signal a timeout for subsequent + * transactions. + */ + this_i2c->master_timeout_ms = I2C_NO_TIMEOUT; + } + } +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_tx_buffer() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_tx_buffer +( + i2c_instance_t * this_i2c, + const uint8_t * tx_buffer, + uint16_t tx_size +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + this_i2c->slave_tx_buffer = tx_buffer; + this_i2c->slave_tx_size = tx_size; + this_i2c->slave_tx_idx = 0u; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_rx_buffer() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_rx_buffer +( + i2c_instance_t * this_i2c, + uint8_t * rx_buffer, + uint16_t rx_size +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + this_i2c->slave_rx_buffer = rx_buffer; + this_i2c->slave_rx_size = rx_size; + this_i2c->slave_rx_idx = 0u; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_mem_offset_length() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_mem_offset_length +( + i2c_instance_t * this_i2c, + uint8_t offset_length +) +{ + HAL_ASSERT(offset_length <= MAX_OFFSET_LENGTH); + + /* + * Single byte update, should be interrupt safe + */ + if(offset_length > MAX_OFFSET_LENGTH) + { + this_i2c->slave_mem_offset_length = MAX_OFFSET_LENGTH; + } + else + { + this_i2c->slave_mem_offset_length = offset_length; + } +} + +/*------------------------------------------------------------------------------ + * I2C_register_write_handler() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_register_write_handler +( + i2c_instance_t * this_i2c, + i2c_slave_wr_handler_t handler +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + this_i2c->slave_write_handler = handler; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_enable_slave() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_enable_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register and slave mode flag without the I2C ISR interrupting + * us. + */ + saved_psr = HAL_disable_interrupts(); + + /* Set the Assert Acknowledge bit. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + /* Enable slave mode */ + this_i2c->is_slave_enabled = 1u; + + HAL_restore_interrupts( saved_psr ); + + /* Enable I2C IRQ*/ + I2C_enable_irq( this_i2c ); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_slave() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_disable_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + /* Reset the assert acknowledge bit. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + + /* Disable slave mode with IRQ blocked to make whole change atomic */ + this_i2c->is_slave_enabled = 0u; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * + */ +static void enable_slave_if_required +( + i2c_instance_t * this_i2c +) +{ + /* + * This function is only called from within the ISR and so does not need + * guarding on the register access. + */ + if( 0 != this_i2c->is_slave_enabled ) + { + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x01u ); + } +} +/*------------------------------------------------------------------------------ + * I2C_set_slave_second_addr() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_slave_second_addr +( + i2c_instance_t * this_i2c, + uint8_t second_slave_addr +) +{ + uint8_t second_slave_address; + + /* + This function does not support CoreI2C hardware configured with a fixed + second slave address. The current implementation of the ADDR1[0] register + bit makes it difficult for the driver to support both programmable and + fixed second slave address, so we choose to support programmable only. + With the programmable configuration, ADDR1[0] and ADDR0[0] both control + enable/disable of GCA recognition, as an effective OR of the 2 bit fields. + Therefore we set ADDR1[0] to 0 here, so that only ADDR0[0] controls GCA. + */ + second_slave_address = (uint8_t)((second_slave_addr << 1u) & (~SLAVE1_EN_MASK)); + + /* + * Single byte register write, should be interrupt safe + */ + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, second_slave_address); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_slave_second_addr() + * See "i2c.h" for details of how to use this function. + */ +void I2C_disable_slave_second_addr +( + i2c_instance_t * this_i2c +) +{ + /* + We are disabling the second slave address by setting the value of the 2nd + slave address to the primary slave address. The reason for using this method + of disabling 2nd slave address is that ADDRESS1[0] has different meaning + depending on hardware configuration. Its use would likely interfere with + the intended GCA setting. + */ + /* + * Single byte register write, should be interrupt safe + */ + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, this_i2c->ser_address); +} + +/*------------------------------------------------------------------------------ + * i2C_set_gca() + * See "i2c.h" for details of how to use this function. + */ + +void I2C_set_gca +( + i2c_instance_t * this_i2c +) +{ + /* + * This read modify write access should be interrupt safe as the address + * register is not written to in the ISR. + */ + /* accept GC addressing. */ + HAL_set_8bit_reg_field(this_i2c->base_address, GC, 0x01u); +} + +/*------------------------------------------------------------------------------ + * I2C_clear_gca() + * See "i2c.h" for details of how to use this function. + */ +void I2C_clear_gca +( + i2c_instance_t * this_i2c +) +{ + /* + * This read modify write access should be interrupt safe as the address + * register is not written to in the ISR. + */ + /* Clear GC addressing. */ + HAL_set_8bit_reg_field(this_i2c->base_address, GC, 0x00u); +} + +/*------------------------------------------------------------------------------ + * I2C_isr() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_isr +( + i2c_instance_t * this_i2c +) +{ + volatile uint8_t status; + uint8_t data; + uint8_t hold_bus; + uint8_t clear_irq = 1u; + + status = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + + switch( status ) + { + /************** MASTER TRANSMITTER / RECEIVER *******************/ + + case ST_START: /* start has been xmt'd */ + case ST_RESTART: /* repeated start has been xmt'd */ + HAL_set_8bit_reg_field( this_i2c->base_address, STA, 0x00u); + HAL_set_8bit_reg( this_i2c->base_address, DATA, this_i2c->target_addr); /* write call address */ + HAL_set_8bit_reg_field( this_i2c->base_address, DIR, this_i2c->dir); /* set direction bit */ + if(this_i2c->dir == WRITE_DIR) + { + this_i2c->master_tx_idx = 0u; + } + else + { + this_i2c->master_rx_idx = 0u; + } + + /* + * Clear the pending transaction. This condition will be true if the slave + * has acquired the bus to carry out pending master transaction which + * it had received during its slave transmission or reception mode. + */ + if(this_i2c->is_transaction_pending) + { + this_i2c->is_transaction_pending = 0u; + } + + /* + * Make sure to update proper transaction after master START + * or RESTART + */ + if(this_i2c->transaction != this_i2c->pending_transaction) + { + this_i2c->transaction = this_i2c->pending_transaction; + } + break; + + case ST_LOST_ARB: + /* Set start bit. Let's keep trying! Don't give up! */ + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + break; + + case ST_STOP_TRANSMIT: + /* Stop has been transmitted. Do nothing */ + break; + + /******************* MASTER TRANSMITTER *************************/ + case ST_SLAW_NACK: + /* SLA+W has been transmitted; not ACK has been received - let's stop. */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_FAILED; + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + case ST_SLAW_ACK: + case ST_TX_DATA_ACK: + /* data byte has been xmt'd with ACK, time to send stop bit or repeated start. */ + if (this_i2c->master_tx_idx < this_i2c->master_tx_size) + { + HAL_set_8bit_reg(this_i2c->base_address, DATA, (uint_fast8_t)this_i2c->master_tx_buffer[this_i2c->master_tx_idx++]); + } + else if ( this_i2c->transaction == MASTER_RANDOM_READ_TRANSACTION ) + { + /* We are finished sending the address offset part of a random read transaction. + * It is is time to send a restart in order to change direction. */ + this_i2c->dir = READ_DIR; + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + else /* done sending. let's stop */ + { + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + hold_bus = this_i2c->options & I2C_HOLD_BUS; + + /* Store the information of current I2C bus status in the bus_status*/ + this_i2c->bus_status = hold_bus; + if ( hold_bus == 0u ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); /*xmt stop condition */ + enable_slave_if_required(this_i2c); + } + else + { + I2C_disable_irq( this_i2c ); + clear_irq = 0u; + } + this_i2c->master_status = I2C_SUCCESS; + } + break; + + case ST_TX_DATA_NACK: + /* data byte SENT, ACK to be received + * In fact, this means we've received a NACK (This may not be + * obvious, but if we've rec'd an ACK then we would be in state + * 0x28!) hence, let's send a stop bit + */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u);/* xmt stop condition */ + this_i2c->master_status = I2C_FAILED; + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + /********************* MASTER (or slave?) RECEIVER *************************/ + + /* STATUS codes 08H, 10H, 38H are all covered in MTX mode */ + case ST_SLAR_ACK: /* SLA+R tx'ed. */ + /* Let's make sure we ACK the first data byte received (set AA bit in CTRL) unless + * the next byte is the last byte of the read transaction. + */ + if(this_i2c->master_rx_size > 1u) + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + } + else if(1u == this_i2c->master_rx_size) + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + else /* this_i2c->master_rx_size == 0u */ + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_SUCCESS; + this_i2c->transaction = NO_TRANSACTION; + } + break; + + case ST_SLAR_NACK: /* SLA+R tx'ed; let's release the bus (send a stop condition) */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_FAILED; + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + case ST_RX_DATA_ACK: /* Data byte received, ACK returned */ + /* First, get the data */ + this_i2c->master_rx_buffer[this_i2c->master_rx_idx++] = HAL_get_8bit_reg(this_i2c->base_address, DATA); + if( this_i2c->master_rx_idx >= (this_i2c->master_rx_size - 1u)) + { + /* If we're at the second last byte, let's set AA to 0 so + * we return a NACK at the last byte. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + break; + + case ST_RX_DATA_NACK: /* Data byte received, NACK returned */ + /* Get the data, then send a stop condition */ + this_i2c->master_rx_buffer[this_i2c->master_rx_idx] = HAL_get_8bit_reg(this_i2c->base_address, DATA); + + hold_bus = this_i2c->options & I2C_HOLD_BUS; + + /* Store the information of current I2C bus status in the bus_status*/ + this_i2c->bus_status = hold_bus; + if ( hold_bus == 0u ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); /*xmt stop condition */ + + /* Bus is released, now we can start listening to bus, if it is slave */ + enable_slave_if_required(this_i2c); + } + else + { + I2C_disable_irq( this_i2c ); + clear_irq = 0u; + } + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + this_i2c->master_status = I2C_SUCCESS; + break; + + /******************** SLAVE RECEIVER **************************/ + case ST_GCA_NACK: /* NACK after, GCA addressing */ + case ST_SLA_NACK: /* Re-enable AA (assert ack) bit for future transmissions */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + this_i2c->transaction = NO_TRANSACTION; + this_i2c->slave_status = I2C_SUCCESS; + + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + break; + + case ST_GCA_LA: /* Arbitr. lost (GCA rec'd) */ + case ST_SLV_LA: /* Arbitr. lost (SLA rec'd) */ + /* + * We lost arbitration and either the GCE or our address was the + * one received so pend the master operation we were starting. + */ + this_i2c->is_transaction_pending = 1u; + /* Fall through to normal ST processing as we are now in slave mode */ + + case ST_GCA: /* General call address received, ACK returned */ + case ST_SLAVE_SLAW: /* SLA+W received, ACK returned */ + this_i2c->transaction = WRITE_SLAVE_TRANSACTION; + this_i2c->slave_rx_idx = 0u; + this_i2c->random_read_addr = 0u; + /* + * If Start Bit is set clear it, but store that information since it is because of + * pending transaction + */ + if(HAL_get_8bit_reg_field(this_i2c->base_address, STA)) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + this_i2c->is_transaction_pending = 1u; + } + this_i2c->slave_status = I2C_IN_PROGRESS; +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + /* Fall through to put address as first byte in payload buffer */ +#else + /* Only break from this case if the slave address must NOT be included at the + * beginning of the received write data. */ + break; +#endif + case ST_GCA_ACK: /* DATA received; ACK sent after GCA */ + case ST_RDATA: /* DATA received; must clear DATA register */ + if((this_i2c->slave_rx_buffer != (uint8_t *)0) + && (this_i2c->slave_rx_idx < this_i2c->slave_rx_size)) + { + data = HAL_get_8bit_reg(this_i2c->base_address, DATA); + this_i2c->slave_rx_buffer[this_i2c->slave_rx_idx++] = data; + +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + if((ST_RDATA == status) || (ST_GCA_ACK == status)) + { + /* Ignore the slave address byte in the random read address + computation in the case where INCLUDE_SLA_IN_RX_PAYLOAD + is defined. */ +#endif + this_i2c->random_read_addr = (this_i2c->random_read_addr << 8) + data; +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + } +#endif + } + + if(this_i2c->slave_rx_idx >= this_i2c->slave_rx_size) + { + /* Rx buffer is full. NACK next received byte. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + break; + + case ST_RSTOP: + /* STOP or repeated START occurred. */ + /* We cannot be sure if the transaction has actually completed as + * this hardware state reports that either a STOP or repeated START + * condition has occurred. We assume that this is a repeated START + * if the transaction was a write from the master to this point.*/ + if ( this_i2c->transaction == WRITE_SLAVE_TRANSACTION ) + { + if ( this_i2c->slave_rx_idx == this_i2c->slave_mem_offset_length ) + { + this_i2c->slave_tx_idx = this_i2c->random_read_addr; + } + /* Call the slave's write transaction handler if it exists. */ + if ( this_i2c->slave_write_handler != 0u ) + { + i2c_slave_handler_ret_t h_ret; + h_ret = this_i2c->slave_write_handler( this_i2c, this_i2c->slave_rx_buffer, (uint16_t)this_i2c->slave_rx_idx ); + if ( I2C_REENABLE_SLAVE_RX == h_ret ) + { + /* There is a small risk that the write handler could + * call I2C_disable_slave() but return + * I2C_REENABLE_SLAVE_RX in error so we only enable + * ACKs if still in slave mode. */ + enable_slave_if_required(this_i2c); + } + else + { + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x0u ); + /* Clear slave mode flag as well otherwise in mixed + * master/slave applications, the AA bit will get set by + * subsequent master operations. */ + this_i2c->is_slave_enabled = 0u; + } + } + else + { + /* Re-enable address acknowledge in case we were ready to nack the next received byte. */ + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x01u ); + } + } + else /* A stop or repeated start outside a write/read operation */ + { + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * See if we need to re-enable acknowledgement as some error conditions, such + * as a master prematurely ending a transfer, can see us get here with AA set + * to 0 which will disable slave operation if we are not careful. + */ + enable_slave_if_required(this_i2c); + } + + /* Mark any previous master write transaction as complete. */ + this_i2c->slave_status = I2C_SUCCESS; + + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + + break; + + case ST_SLV_RST: /* SMBUS ONLY: timeout state. must clear interrupt */ + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction. + */ + this_i2c->transaction = NO_TRANSACTION; + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * Clear status to I2C_FAILED only if there was an operation in progress. + */ + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->slave_status = I2C_FAILED; + } + + enable_slave_if_required(this_i2c); /* Make sure AA is set correctly */ + + break; + + /****************** SLAVE TRANSMITTER **************************/ + case ST_SLAVE_SLAR_ACK: /* SLA+R received, ACK returned */ + case ST_SLARW_LA: /* Arbitration lost, and: */ + case ST_RACK: /* Data tx'ed, ACK received */ + if ( status == ST_SLAVE_SLAR_ACK ) + { + this_i2c->transaction = READ_SLAVE_TRANSACTION; + this_i2c->random_read_addr = 0u; + this_i2c->slave_status = I2C_IN_PROGRESS; + /* If Start Bit is set clear it, but store that information since it is because of + * pending transaction + */ + if(HAL_get_8bit_reg_field(this_i2c->base_address, STA)) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + this_i2c->is_transaction_pending = 1u; + } + } + if (this_i2c->slave_tx_idx >= this_i2c->slave_tx_size) + { + /* Ensure 0xFF is returned to the master when the slave specifies + * an empty transmit buffer. */ + HAL_set_8bit_reg(this_i2c->base_address, DATA, 0xFFu); + } + else + { + /* Load the data the data byte to be sent to the master. */ + HAL_set_8bit_reg(this_i2c->base_address, DATA, (uint_fast8_t)this_i2c->slave_tx_buffer[this_i2c->slave_tx_idx++]); + } + /* Determine if this is the last data byte to send to the master. */ + if (this_i2c->slave_tx_idx >= this_i2c->slave_tx_size) /* last byte? */ + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + /* Next read transaction will result in slave's transmit buffer + * being sent from the first byte. */ + this_i2c->slave_tx_idx = 0u; + } + break; + + case ST_SLAVE_RNACK: /* Data byte has been transmitted; not-ACK has been received. */ + case ST_FINAL: /* Last Data byte tx'ed, ACK received */ + /* We assume that the transaction will be stopped by the master. + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. */ + this_i2c->slave_tx_idx = 0u; + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + /* Mark previous state as complete */ + this_i2c->slave_status = I2C_SUCCESS; + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + + break; + + /* Master Reset has been activated Wait 35 ms for interrupt to be set, + * clear interrupt and proceed to 0xF8 state. */ + case ST_RESET_ACTIVATED: + case ST_BUS_ERROR: /* Bus error during MST or selected slave modes */ + default: + /* Some undefined state has encountered. Clear Start bit to make + * sure, next good transaction happen */ + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction. + */ + this_i2c->transaction = NO_TRANSACTION; + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * Clear statuses to I2C_FAILED only if there was an operation in progress. + */ + if(I2C_IN_PROGRESS == this_i2c->master_status) + { + this_i2c->master_status = I2C_FAILED; + } + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->slave_status = I2C_FAILED; + } + + break; + } + + if ( clear_irq ) + { + /* clear interrupt. */ + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + /* Read the status register to ensure the last I2C registers write took place + * in a system built around a bus making use of posted writes. */ + status = HAL_get_8bit_reg( this_i2c->base_address, STATUS); +} + +/*------------------------------------------------------------------------------ + * I2C_smbus_init() + * See "i2c.h" for details of how to use this function. + */ + +/* + * SMBSUS_NO = 1 + * SMBALERT_NO = 1 + * SMBus enable = 1 + */ +#define INIT_AND_ENABLE_SMBUS 0x54u +void I2C_smbus_init +( + i2c_instance_t * this_i2c +) +{ + /* + * Single byte register write, should be interrupt safe + */ + /* Enable SMBUS */ + HAL_set_8bit_reg(this_i2c->base_address, SMBUS, INIT_AND_ENABLE_SMBUS); +} + +/*------------------------------------------------------------------------------ + * I2C_enable_smbus_irq() + * See "i2c.h" for details of how to use this function. + */ +void I2C_enable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + if ( irq_type & I2C_SMBALERT_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_IE, 0x01u); + } + if ( irq_type & I2C_SMBSUS_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_IE, 0x01u); + } + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_smbus_irq() + * See "i2c.h" for details of how to use this function. + */ +void I2C_disable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + if ( irq_type & I2C_SMBALERT_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_IE, 0x00u); + } + if (irq_type & I2C_SMBSUS_IRQ ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_IE, 0x00u); + } + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_suspend_smbus_slave() + * See "i2c.h" for details of how to use this function. + */ +void I2C_suspend_smbus_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_NO_CONTROL, 0x00u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_resume_smbus_slave() + * See "i2c.h" for details of how to use this function. + */ +void I2C_resume_smbus_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_NO_CONTROL, 0x01u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_reset_smbus() + * See "i2c.h" for details of how to use this function. + */ +void I2C_reset_smbus +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + HAL_set_8bit_reg_field(this_i2c->base_address, SMBUS_MST_RESET, 0x01u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_smbus_alert() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_smbus_alert +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_NO_CONTROL, 0x00u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_clear_smbus_alert() + * See "i2c.h" for details of how to use this function. + */ +void I2C_clear_smbus_alert +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_NO_CONTROL, 0x01u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_get_irq_status() + * See "i2c.h" for details of how to use this function. + */ +uint8_t I2C_get_irq_status +( + i2c_instance_t * this_i2c +) +{ + uint8_t status ; + uint8_t irq_type = I2C_NO_IRQ ; + + status = HAL_get_8bit_reg(this_i2c->base_address, SMBUS); + + if( status & (uint8_t)SMBALERT_NI_STATUS_MASK ) + { + irq_type |= I2C_SMBALERT_IRQ ; + } + + if( status & (uint8_t)SMBSUS_NI_STATUS_MASK ) + { + irq_type |= I2C_SMBSUS_IRQ ; + } + + status = HAL_get_8bit_reg(this_i2c->base_address, CONTROL); + + if( status & (uint8_t)SI_MASK ) + { + irq_type |= I2C_INTR_IRQ ; + } + return(irq_type); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_addr2() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_user_data +( + i2c_instance_t * this_i2c, + void * p_user_data +) +{ + this_i2c->p_user_data = p_user_data ; +} + +/*------------------------------------------------------------------------------ + * I2C_get_user_data() + * See "i2c.h" for details of how to use this function. + */ +void * I2C_get_user_data +( + i2c_instance_t * this_i2c +) +{ + return( this_i2c->p_user_data); +} + +#ifdef __cplusplus +} +#endif + diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h new file mode 100644 index 0000000..3891ce0 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h @@ -0,0 +1,2306 @@ +/***************************************************************************//** + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * CoreI2C software driver Application Programming Interface. + * This file contains defines and function declarations allowing to interface + * with the CoreI2C software driver. + * + */ +/*=========================================================================*//** + @mainpage CoreI2C Bare Metal Driver. + The CoreI2C bare metal software driver supports I2C master and slave + operations. + + ============================================================================== + Introduction + ============================================================================== + The CoreI2C driver provides a set of functions for controlling the Microchip + CoreI2C hardware IP. The driver supports up to 16 separate I2C channels per + CoreI2C instance, with common slave address settings shared between channels + on a device. + + Optional features of the CoreI2C allow it to operate with I2C based protocols + such as System Management Bus (SMBus), Power Management Bus (PMBus), and + Intelligent Platform Management Interface (IPMI). This driver provides support + for these features when enabled in the CoreI2C IP. + + The major features provided by CoreI2C driver: + - Provides support to configuring the I2C channels of each CoreI2C peripheral device. + - I2C master operations. + - I2C slave operations. + - SMBus related operations. + + This driver is used as part of a bare metal system where no operating + system is available. The driver gets adapted as a part of an operating system, + but the implementation of the adaptation layer between the driver and the operating + system's driver model is outside the scope of this driver. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + Your application software should configure the CoreI2C driver through + calls to the I2C_init() function for each CoreI2C instance in the + hardware design. The configuration parameters include the CoreI2C hardware + instance base address and other runtime parameters, such as the I2C serial + clock frequency and the I2C device address. + + Once channel 0 of a CoreI2C peripheral has been initialized by I2C_init(), + any additional channels present should be configured by calling + I2C_channel_init() for each of the remaining channels. + + Apart from the CoreI2C hardware instance base address, no CoreI2C hardware configuration + parameters are used by the driver. Hence, no additional configuration files are required + to use the driver. + + -------------------------------- + Interrupt Control + -------------------------------- + The CoreI2C driver has to enable and disable the generation of interrupts by + CoreI2C at various times when it is operating. This enabling and disabling of + interrupts must be done through the system’s interrupt controller. For that + reason, the method of controlling the CoreI2C interrupt is system specific + and it is necessary to customize the I2C_enable_irq() and I2C_disable_irq() + functions. These functions are available in the i2c_interrupt.c file. + The default implementation calls HAL_ASSERT(0) to indicate to the application + developer that a suitable implementations for these functions must be provided. + + The implementation of the I2C_enable_irq() function should permit interrupts + generated by a CoreI2C instance to interrupt the processor. The implementation + of the I2C_disable_irq() function should prevent interrupts generated by a + CoreI2C instance from interrupting the processor. See the provided example + projects for a working implementation of these functions. + + The I2C_register_write_handler() function registers a write handler + function with the CoreI2C driver that calls on completion of an I2C write + transaction by the CoreI2C slave. It is your responsibility to create and + register the implementation of this handler function that processes or + trigger the processing of the received data. + + The SMBSUS and SMBALERT interrupts are related to the SMBus interface and are + enabled and disabled through I2C_enable_smbus_irq() and + I2C_disable_smbus_irq() respectively. It is your responsibility to create + interrupt handler functions in your application to get the desired response + for the SMBus interrupts. + + Note: You must include the path to any application header files that are + included in the i2c_interrupt.c file, as an include path in your + project's compiler settings. The details of how to do this will depend + on your development software. + + -------------------------------- + SMBus Logic Options + -------------------------------- + SMBus related APIs does not have any effect if the "Generate SMBus Logic" + is not enabled in the CoreI2C hardware configuration. Following are API's + that does not give the desired results if SMBus Logic is disabled. + + - I2C_smbus_init() + - I2C_reset_smbus() + - I2C_enable_smbus_irq() + - I2C_disable_smbus_irq() + - I2C_suspend_smbus_slave() + - I2C_resume_smbus_slave() + - I2C_set_smsbus_alert() + - I2C_clear_smsbus_alert() + - I2C_get_irq_status() + + -------------------------------- + Fixed Baud Rate Values + -------------------------------- + The serial clock frequency parameter passed to the I2C_init() and + I2C_channel_init() functions may not have any effect if fixed values were + selected for Baud rate in the hardware configuration of CoreI2C. When fixed + values are selected for these baud rates, the driver cannot overwrite + the fixed values. + + ----------------------------------- + Fixed Slave Address Options Values + ----------------------------------- + The primary slave address parameter passed to the I2C_init() function and + secondary address value passed to the I2C_set_slave_second_addr() function, + may not have the desired effect if fixed values were selected for the slave 0 + address and slave 1 address respectively. Proper operation of this version of + the driver requires the slave addresses to be programmable. + + ============================================================================== + Theory of Operation + ============================================================================== + The CoreI2C software driver is designed to allow the control of multiple + instances of CoreI2C with one or more I2C channels. Each channel in an + instance of CoreI2C in the hardware design is associated with a single + instance of the i2c_instance_t structure in the software. You must allocate + memory for one unique i2c_instance_t structure instance for each channel of + each CoreI2C hardware instance. The contents of these data structures are + initialised by calling I2C_init() and if necessary I2C_channel_init(). + A pointer to the structure is passed to the subsequent driver functions in order + to identify the CoreI2C hardware instance and channel to perform the + requested operation. + + Note: Do not attempt to directly manipulate the contents of i2c_instance_t + structures. These structures are only intended to be modified by the driver + functions. + + The CoreI2C driver functions are grouped into the following categories: + - Initialization and configuration functions + - Interrupt control + - I2C slave addressing functions + - I2C master operations functions to handle write, read, and write-read + transactions + - I2C slave operations functions to handle write, read, and write-read + transactions + - Mixed master-slave operations + - SMBus interface configuration and control + + -------------------------------- + Initialization and Configuration + -------------------------------- + The CoreI2C device is first initialized by calling the I2C_init() + function. Since each CoreI2C peripheral supports up to 16 channels, an + additional function, I2C_channel_init(), is required to initialize the + remaining channels with their own data structures. + + I2C_init() function initializes channel 0 of a CoreI2C and the i2c_instance_t + for channel 0 acts as the basis for further channel initialization as the + hardware base address and I2C serial address are same across all the channels. + Ensure to call I2C_init() function before calling any other I2C driver function + calls. The I2C_init() call for each CoreI2C takes the I2C serial address assigned + to the I2C and the serial clock divider to generate its I2C clock as configuration + parameters. + + I2C_channel_init() function takes as input parameters a pointer to the CoreI2C + i2c_instance_t which has been initialized by calling the I2C_init() and a pointer + to a separate i2c_instance_t which represents this new channel. Another input + parameter which is required by this function is serial clock divider which generates + its I2C clock. + + -------------------------------- + Interrupt Control + -------------------------------- + The CoreI2C driver is interrupt driven and it uses each channels INT + interrupt to drive the state machine which is at the heart of the driver. + The application is responsible for providing the link between the interrupt + generating hardware and the CoreI2C interrupt handler and must ensure that + the I2C_isr() function is called with the correct i2c_instance_t structure + pointer for the CoreI2C channel initiating the interrupt. + + The driver enables and disables the generation of INT interrupts by CoreI2C + at various times when it is operating through the user supplied + I2C_enable_irq() and I2C_disable_irq() functions. + + The I2C_register_write_handler() function is used to register a write + handler function with the CoreI2C driver which is called on completion + of an I2C write transaction by the CoreI2C slave. It is the user + applications responsibility to create and register the implementation of + this handler function that processes or triggers the processing of the + received data. + + The other two interrupt sources in the CoreI2C are related to SMBus + operation and are enabled and disabled through I2C_enable_smbus_irq() and + I2C_disable_smbus_irq() respectively. Due to the application specific + nature of the response to SMBus interrupts, you must design interrupt + handler functions in the application to get the desired behaviour for + SMBus related interrupts. + + If enabled, the SMBA_INT signal from the CoreI2C is asserted if an + SMBALERT condition is signalled on the SMBALERT_NI input for the channel. + + If enabled, the SMBS_INT signal from the CoreI2C is asserted if an + SMBSUSPEND condition is signalled on the SMBSUS_NI input for the channel. + + ## I2C Slave Addressing Functions + A CoreI2C peripheral responds to the following three slave addresses: + - Slave address 0 - This is the primary slave address that accesses + a CoreI2C channel when it acts as a slave in + I2C transactions. You must configure the primary slave + address using I2C_init(). + + - Slave address 1 - This is the secondary slave address which might be + required in certain application specific scenarios. + The secondary slave address is configured by + I2C_set_slave_second_addr() and is disabled by + I2C_disable_slave_second_addr(). + + - General call address - A CoreI2C slave can be configured to respond to + a broadcast command by a master transmitting the + general call address of 0x00. Use the I2C_set_gca() + function to enable the slave to respond to the general + call address. If the CoreI2C slave is not required to + respond to the general call address, disable this + address by calling I2C_clear_gca(). + + Note: All channels on a CoreI2C instance share the same slave address logic. + This means that they cannot have separate slave addresses and rely on + the separate physical I2C bus connections to distinguish them. + + -------------------------------- + Transaction Types + -------------------------------- + The I2C driver is designed to handle three types of I2C transaction: + - Write transactions + - Read transactions + - Write-read transactions + + ## Write Transaction + The master I2C device initiates a write transaction by sending a START bit + as soon as the bus becomes free. The START bit is followed by the 7-bit + serial address of the target slave device followed by the read/write bit + indicating the direction of the transaction. The slave acknowledges the + receipt of it's address with an acknowledge bit. The master sends data one + byte at a time to the slave, which must acknowledge the receipt of each byte + for the next byte to be sent. The master sends a STOP bit to complete the + transaction. The slave can abort the transaction by replying with a + non-acknowledge bit instead of an acknowledge bit. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ## Read Transaction + The master I2C device initiates a read transaction by sending a START bit + as soon as the bus becomes free. The START bit is followed by the 7-bit + serial address of the target slave device followed by the read/write bit + indicating the direction of the transaction. The slave acknowledges the + receipt of it's slave address with an acknowledge bit. The slave sends + data one byte at a time to the master, which must acknowledge the receipt of + each byte for the next byte to be sent. The master sends a non-acknowledge + bit following the last byte it wishes to read followed by a STOP bit. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ## Write-Read Transaction + The write-read transaction is a combination of a write transaction + immediately followed by a read transaction. There is no STOP bit in between + the write and read phases of a write-read transaction. A repeated START + bit is sent between the write and read phases. + + Whilst the write handler is being executed, the slave holds the clock line + low to stretch the clock until the response is ready. + + The write-read transaction is typically used to send a command or offset + in the write transaction specifying the logical data to be transferred + during the read phase. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ## Master Operations + The application can use the I2C_write(), I2C_read(), and I2C_write_read() + functions to initiate an I2C bus transaction. The application can then wait + for the transaction to complete using the I2C_wait_complete() function + or poll the status of the I2C transaction using the I2C_get_status() + function until it returns a value different from I2C_IN_PROGRESS. The + I2C_system_tick() function is used to set a time base for the + I2C_wait_complete() function's time out delay. + + ## Slave Operations + To configure the I2C driver to operate as an I2C slave requires the use + of the following functions: + - I2C_set_slave_tx_buffer() + - I2C_set_slave_rx_buffer() + - I2C_set_slave_mem_offset_length() + - I2C_register_write_handler() + - I2C_enable_slave() + + Use of all functions is not required if the slave I2C does not need to support + all types of I2C read transactions. The subsequent sections list the functions + that must be used to support each transaction type. + + ## Responding to Read Transactions + The following functions are used to configure the CoreI2C driver to + respond to I2C read transactions: + • I2C_set_slave_tx_buffer() + • I2C_enable_slave() + + The I2C_set_slave_tx_buffer() function specifies the data buffer that + is transmitted when the I2C slave is the target of an I2C read + transaction. It is then up to the application to manage the content of + that buffer to control the data that will be transmitted to the I2C + master as a result of the read transaction. + + The I2C_enable_slave() function enables the I2C hardware instance + to respond to the I2C transactions. It must be called after the I2C driver + has been configured to respond to the required transaction types. + + ## Responding to Write Transactions + The following functions are used to configure the I2C driver to respond + to I2C write transactions: + • I2C_set_slave_rx_buffer() + • I2C_register_write_handler() + • I2C_enable_slave() + + The I2C_set_slave_rx_buffer() function specifies the data buffer that + stored the data received by the I2C slave when it targets an I2C write + transaction. + + The I2C_register_write_handler() function specifies the handler function + that must be called on completion of the I2C write transaction. It is this + handler function that processes or triggers the processing of the received + data. + + The I2C_enable_slave() function enables the I2C hardware instance + to respond to I2C transactions. It must be called after the I2C driver + has been configured to respond to the required transaction types. + + ## Responding to Write-Read Transactions + The following functions are used to configure the CoreI2C driver to + respond to write-read transactions: + - I2C_set_slave_mem_offset_length() + - I2C_set_slave_tx_buffer() + - I2C_set_slave_rx_buffer() + - I2C_register_write_handler() + - I2C_enable_slave() + + The I2C_set_slave_mem_offset_length() function specifies the number of + bytes expected by the I2C slave during the write phase of the write-read + transaction. + + The I2C_set_slave_tx_buffer() function specifies the data that is + transmitted to the I2C master during the read phase of the write-read + transaction. The value received by the I2C slave during the write phase of + the transaction will be used as an index into the transmit buffer + specified by this function. It decides which part of the transmit buffer + will be transmitted to the I2C master as part of the read phase of the + write-read transaction. + + The I2C_set_slave_rx_buffer() function specifies the data buffer that + stores the data received by the I2C slave during the write phase of + the write-read transaction. This buffer must be large enough to accommodate + the number of bytes specified through the I2C_set_slave_mem_offset_length() + function. + + The I2C_register_write_handler() function can optionally be used to + specify a handler function that is called on completion of the write phase + of the I2C write-read transaction. If a handler function is registered, it + is responsible for processing the received data in the slave receive + buffer and populating the slave transmit buffer with the data that will be + transmitted to the I2C master as part of the read phase of the write-read + transaction. + + The I2C_enable_slave() function enables the CoreI2C hardware instance to + respond to the I2C transactions. It must be called after configuring the + CoreI2C driver to respond to the required transaction types. + + ## Mixed Master-Slave Operations + The CoreI2C device supports mixed master and slave operations. If the + CoreI2C slave has a transaction in progress and your application attempts to + begin a master mode transaction, the CoreI2C driver queues the master mode + transaction until the bus is released and the CoreI2C can switch to master + mode and acquire the bus. The CoreI2C master then starts the previously + queued master transaction. + + ## SMBus Control + The CoreI2C driver enables the CoreI2C peripheral’s SMBus functionality + using the I2C_smbus_init() function. + + The I2C_suspend_smbus_slave() function is used with a master mode CoreI2C + to force slave devices on the SMBus to enter their Power-Down/Suspend mode. + The I2C_resume_smbus_slave() function is used to end the suspend operation + on the SMBus. + + The I2C_reset_smbus() function is used with a master mode CoreI2C to force + all devices on the SMBus to reset their SMBUs interface. + + The I2C_set_smsbus_alert() function is used by a slave mode CoreI2C to + force communication with the SMBus master. Once communications with the + master is initiated, the I2C_clear_smsbus_alert() function clears the alert + condition. + + The I2C_enable_smbus_irq() and I2C_disable_smbus_irq() functions are used to + enable and disable the SMBSUS and SMBALERT SMBus interrupts. + + *//*=========================================================================*/ + +#ifndef CORE_I2C_H_ +#define CORE_I2C_H_ + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#include "hal_assert.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + I2C_RELEASE_BUS + ======================================= + The I2C_RELEASE_BUS constant is used to specify the options parameter to + functions I2C_read(), I2C_write() and I2C_write_read() to indicate + that a STOP bit must be generated at the end of the I2C transaction to release + the bus. + */ +#define I2C_RELEASE_BUS 0x00u + +/*-------------------------------------------------------------------------*//** + I2C_HOLD_BUS + ======================================= + The I2C_HOLD_BUS constant specify the options parameter to functions I2C_read(), + I2C_write(), and I2C_write_read() to indicate that a STOP bit must not be + generated at the end of the I2C transaction in order to retain the bus ownership. + This causes the next transaction to begin with a repeated START bit and no STOP + bit between the transactions. + */ +#define I2C_HOLD_BUS 0x01u + +/*-------------------------------------------------------------------------*//** + Interrupt Identifier Number + ======================================= + The following constants specify the interrupt identifier number which is + solely used by the driver API. This has nothing to do with hardware interrupt + line. I2C_INTR_IRQ is the primary interrupt signal which drives the state machine + of the CoreI2C driver. The I2C_SMBALERT_IRQ and I2C_SMBSUS_IRQ are used by + SMBus interrupt enable and disable functions. These IRQ numbers are also used + by I2C_get_irq_status(). + + | Constant | Description | + |--------------------|--------------------------------------------------------| + | I2C_NO_IRQ | No interrupt | + | I2C_SMBALERT_IRQ | Used by SMBus interrupt enable functions | + | I2C_SMBSUS_IRQ | Used by SMBus interrupt disable functions | + | I2C_INTR_IRQ | Primary interrupt signal which drives the state machine| + + */ +#define I2C_NO_IRQ 0x00u +#define I2C_SMBALERT_IRQ 0x01u +#define I2C_SMBSUS_IRQ 0x02u +#define I2C_INTR_IRQ 0x04u + +/*-------------------------------------------------------------------------*//** + I2C_NO_TIMEOUT + ======================================= + The I2C_wait_complete() function uses I2C_NO_TIMEOUT constant as a parameter + to indicate that the wait for completion of the transaction should not time out. + */ +#define I2C_NO_TIMEOUT 0u + +/***************************************************************************//** + The i2c_channel_number_t type is used to specify the channel number of a + CoreI2C instance. + */ +typedef enum i2c_channel_number { + I2C_CHANNEL_0 = 0u, + I2C_CHANNEL_1, + I2C_CHANNEL_2, + I2C_CHANNEL_3, + I2C_CHANNEL_4, + I2C_CHANNEL_5, + I2C_CHANNEL_6, + I2C_CHANNEL_7, + I2C_CHANNEL_8, + I2C_CHANNEL_9, + I2C_CHANNEL_10, + I2C_CHANNEL_11, + I2C_CHANNEL_12, + I2C_CHANNEL_13, + I2C_CHANNEL_14, + I2C_CHANNEL_15, + I2C_MAX_CHANNELS = 16u +} i2c_channel_number_t; + +/***************************************************************************//** + The i2c_clock_divider_t type specifies the divider to be applied + to the I2C PCLK or BCLK signal in order to generate the I2C clock. + The I2C_BCLK_DIV_8 value selects a clock frequency based on division of BCLK, + all other values select a clock frequency based on division of PCLK. + */ +typedef enum i2c_clock_divider { + I2C_PCLK_DIV_256 = 0u, + I2C_PCLK_DIV_224, + I2C_PCLK_DIV_192, + I2C_PCLK_DIV_160, + I2C_PCLK_DIV_960, + I2C_PCLK_DIV_120, + I2C_PCLK_DIV_60, + I2C_BCLK_DIV_8 +} i2c_clock_divider_t; + +/***************************************************************************//** + The i2c_status_t type is used to report the status of I2C transactions. + */ +typedef enum i2c_status +{ + I2C_SUCCESS = 0u, + I2C_IN_PROGRESS, + I2C_FAILED, + I2C_TIMED_OUT +} i2c_status_t; + +/***************************************************************************//** + The i2c_slave_handler_ret_t type is used by slave write handler functions + to indicate whether or not the received data buffer should be released. + */ +typedef enum i2c_slave_handler_ret { + I2C_REENABLE_SLAVE_RX = 0u, + I2C_PAUSE_SLAVE_RX = 1u +} i2c_slave_handler_ret_t; + +/***************************************************************************//** + This structure identifies various CoreI2C hardware instances in the system + and the I2C channels within them. The application software should declare + one instance of this structure for each channel of each instance of CoreI2C + in your system. I2C_init() and I2C_channel_init() functions initialize this + structure depending on whether it is channel 0 or one of the additional + channels, respectively. A pointer to an initialized instance of the + structure should be passed as the first parameter to the CoreI2C driver + functions, to identify which CoreI2C hardware instance and channel should + perform the requested operation. + + The contents of this data structure should not be modified or used outside of + the CoreI2C driver. Software using the CoreI2C driver should only need to + create one single instance of this data structure for each channel of each + CoreI2C hardware instance in the system then pass a pointer to these data + structures with each call to the CoreI2C driver in order to identify which + CoreI2C hardware instance to use. + */ +typedef struct i2c_instance i2c_instance_t ; +/***************************************************************************//* + Slave write handler functions prototype +/***************************************************************************//** + This defines the function prototype that must be followed by I2C slave write + handler functions. These functions are registered with the CoreI2C driver + through the I2C_register_write_handler() function. + + Declaring and Implementing Slave Write Handler Functions: + + Slave write handler functions should follow the following prototype: + @code + i2c_slave_handler_ret_t write_handler + ( + i2c_instance_t *instance, uint8_t * data, uint16_t size + ); + @endcode + + The instance parameter is a pointer to the i2c_instance_t for which this + slave write handler has been declared. + + The data parameter is a pointer to a buffer (received data buffer) holding + the data written to the I2C slave. + + Define the INCLUDE_SLA_IN_RX_PAYLOAD macro for the driver to insert the + actual address used to access the slave as the first byte in the buffer. + This allows the applications to tailor their response based on the actual + address used to access the slave (primary address, secondary address, or GCA). + + The size parameter is the number of bytes held in the received data buffer. + Handler functions must return one of the following values: + - I2C_REENABLE_SLAVE_RX + - I2C_PAUSE_SLAVE_RX + + If the handler function returns I2C_REENABLE_SLAVE_RX, the driver releases + the received data buffer and allows further I2C write transactions to the + I2C slave. + + If the handler function returns I2C_PAUSE_SLAVE_RX, the I2C slave responds + to subsequent write requests with a non-acknowledge bit (NACK), until the + received data buffer content gets processed by some other part of the + software application. + + Call the I2C_enable_slave() after returning the I2C_PAUSE_SLAVE_RX to release + the received data buffer in order to store the data received by the subsequent + I2C write transactions. + */ +typedef i2c_slave_handler_ret_t (*i2c_slave_wr_handler_t)(i2c_instance_t *instance, uint8_t *, uint16_t ); + +/***************************************************************************//** + This structure is used to identify the various CoreI2C hardware instances in + your system and the I2C channels within them. Your application software should + declare one instance of this structure for each channel of each instance of + CoreI2C in your system. The functions I2C_init() and I2C_channel_init() + initialize this structure depending on whether it is channel 0 or one of the + additional channels respectively. A pointer to an initialized instance of the + structure should be passed as the first parameter to the CoreI2C driver + functions, to identify which CoreI2C hardware instance and channel should + perform the requested operation. + + The contents of this data structure should not be modified or used outside of + the CoreI2C driver. Software using the CoreI2C driver should only need to + create one single instance of this data structure for each channel of each + CoreI2C hardware instance in the system then pass a pointer to these data + structures with each call to the CoreI2C driver in order to identify the + CoreI2C hardware instance it wishes to use. + */ +struct i2c_instance +{ + addr_t base_address; + uint_fast8_t ser_address; + + /* Transmit related info:*/ + uint_fast8_t target_addr; + + /* Current transaction type (WRITE, READ, RANDOM_READ)*/ + uint8_t transaction; + + uint_fast16_t random_read_addr; + + uint8_t options; + + /* Master TX INFO: */ + const uint8_t * master_tx_buffer; + uint_fast16_t master_tx_size; + uint_fast16_t master_tx_idx; + uint_fast8_t dir; + + /* Master RX INFO: */ + uint8_t * master_rx_buffer; + uint_fast16_t master_rx_size; + uint_fast16_t master_rx_idx; + + /* Master Status */ + volatile i2c_status_t master_status; + uint32_t master_timeout_ms; + + /* Slave TX INFO */ + const uint8_t * slave_tx_buffer; + uint_fast16_t slave_tx_size; + uint_fast16_t slave_tx_idx; + + /* Slave RX INFO */ + uint8_t * slave_rx_buffer; + uint_fast16_t slave_rx_size; + uint_fast16_t slave_rx_idx; + /* Slave Status */ + volatile i2c_status_t slave_status; + + /* Slave data: */ + uint_fast8_t slave_mem_offset_length; + i2c_slave_wr_handler_t slave_write_handler; + uint8_t is_slave_enabled; + + /* user specific data */ + void *p_user_data ; + + /* I2C bus status */ + uint8_t bus_status; + + /* Is transaction pending flag */ + uint8_t is_transaction_pending; + + /* I2C Pending transaction */ + uint8_t pending_transaction; +}; + +/*------------------------Public Function-------------------------------------*/ + +/***************************************************************************//** + The I2C_init() function configures channel 0 of a CoreI2C instance. It sets + the base hardware address which is used to locate the CoreI2C instance + in memory and also used internally by I2C_channel_init() to calculate the + register addresses for any additional channels. The slave serial address set + is shared by all channels on a CoreI2C instance. + + If only one channel is configured in a CoreI2C, the address of the + i2c_instance_t used in I2C_Init() will also be used in subsequent calls to the + CoreI2C driver functions. If more than one channel is configured in the + CoreI2C, I2C_channel_init() will be called after I2C_init(), which initializes + the i2c_instance_t data structure for a specific channel. + + @param this_i2c + Pointer to the i2c_instance_t data structure that holds all the data + related to channel 0 of the CoreI2C instance is initialized. A pointer + to this structure is used in all subsequent calls to the CoreI2C driver + functions which operates on channel 0 of this CoreI2C instance. + + @param base_address + Base address in the processor's memory map of the registers of the CoreI2C + instance being initialized. + + @param ser_address + This parameter sets the primary I2C serial address (SLAVE0 address) for the + CoreI2C to initialize. It is the principal I2C bus address to which the + CoreI2C instance will respond. CoreI2C can operate in master mode or slave + mode and the serial address is significant only in the case of I2C slave + mode. In master mode, CoreI2C does not require a serial address and the + value of this parameter is not important. If you do not intend to use the + CoreI2C device in slave mode, then provide any dummy slave address value + to this parameter. However, in systems where the CoreI2C is expected to + switch from master mode to slave mode, it is advisable to initialize the + CoreI2C device with a valid serial slave address. Call the I2C_init() + function whenever it is required to change the primary slave address as + there is no separate function to set the primary slave address of the + I2C device. The serial address initialized through this function is + basically the primary slave address or slave address0. + I2C_set_slave_second_addr() is used to set the secondary slave address + or slave address 1. + Note : ser_address parameter does not have any affect if fixed slave + address is enabled in CoreI2C hardware design. CoreI2C will + be always addressed with the hardware configured fixed slave + address. + Note : ser_address parameter will not have any affect if the CoreI2C + instance is only used in master mode. + + @param ser_clock_speed + This parameter sets the I2C serial clock frequency. It selects the divider + that generates the serial clock from the APB PCLK or from the BCLK. + It can be one of the following: + - I2C_PCLK_DIV_256 + - I2C_PCLK_DIV_224 + - I2C_PCLK_DIV_192 + - I2C_PCLK_DIV_160 + - I2C_PCLK_DIV_960 + - I2C_PCLK_DIV_120 + - I2C_PCLK_DIV_60 + - I2C_BCLK_DIV_8 + Note: serial_clock_speed value does not have any affect if the fixed baud + rate is enabled in CoreI2C hardware instance configuration dialogue + window. The fixed baud rate divider value overrides the value passed + as parameter in this function. + Note: serial_clock_speed value is not critical for devices that only operate + as slaves and can be set to any of the above values. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void system_init( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + } + @endcode + */ +void I2C_init +( + i2c_instance_t * this_i2c, + addr_t base_address, + uint8_t ser_address, + i2c_clock_divider_t ser_clock_speed +); + +/***************************************************************************//** + The I2C_channel_init() function initializes and configures hardware and data + structures of one of the additional channels of a CoreI2C instance. + I2C_init() must be called before calling this function to set the CoreI2C + instance hardware base address and I2C serial address. I2C_channel_init() also + initializes I2C serial clock divider to set the serial clock baud rate. + The pointer to data structure i2c_instance_t used for a particular channel + is used as an input parameter to subsequent CoreI2C driver functions + which operate on this channel. + + @param this_i2c_channel + Pointer to the i2c_instance_t data structure that holds all data related to + the CoreI2C channel gets initialized. A pointer to the same data structure + is used in subsequent calls to the CoreI2C driver functions in order to + identify the CoreI2C channel instance that should perform the operation + implemented by the called driver function. + + @param this_i2c + This is a pointer to an i2c_instance_t structure, previously initialized by + I2C_init(). It holds information regarding the hardware base address and + I2C serial address for the CoreI2C containing the channel to be + initialized. This information is required by I2C_channel_init() to + initialize the i2c_instance_t structure pointed by this_i2c_channel as + all channels in a CoreI2C instance share the same base address and serial + address. It is very important that the i2c_instance_t structure pointed + by this_i2c must be previously initialized by calling I2C_init(). + + @param channel_number + This parameter of type i2c_channel_number_t identifies the channel to be + initialized. + + @param ser_clock_speed + This parameter sets the I2C serial clock frequency. It selects the divider + that is used to generate the serial clock from the APB PCLK or from + the BCLK. It can be one of the following: + - I2C_PCLK_DIV_256 + - I2C_PCLK_DIV_224 + - I2C_PCLK_DIV_192 + - I2C_PCLK_DIV_160 + - I2C_PCLK_DIV_960 + - I2C_PCLK_DIV_120 + - I2C_PCLK_DIV_60 + - I2C_BCLK_DIV_8 + Note: serial_clock_speed value does not have any affect if the fixed baud + rate is enabled in CoreI2C hardware instance configuration dialogue + window. The fixed baud rate divider value will supersede the value + passed as parameter in this function. + Note: ser_clock_speed value is not critical for devices that only operate + as slaves and can be set to any of the above values. + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_SER_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + i2c_instance_t g_i2c_channel_1_inst; + + uint8_t tx_buffer[DATA_LENGTH]; + uint8_t write_length = DATA_LENGTH; + + void system_init( void ) + { + uint8_t target_slave_addr = 0x12; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize CoreI2C channel 1 with different clock speed + I2C_channel_init( &g_i2c_channel_1_inst, &g_i2c_inst, I2C_CHANNEL_1, + I2C_PCLK_DIV_224 ); + + // Write data to Channel 1 of CoreI2C instance. + I2C_write( &g_i2c_channel_1_inst, target_slave_addr, tx_buffer, + write_length, I2C_RELEASE_BUS ); + } + @endcode + +*/ +void I2C_channel_init +( + i2c_instance_t * this_i2c_channel, + i2c_instance_t * this_i2c, + i2c_channel_number_t channel_number, + i2c_clock_divider_t ser_clock_speed +); + +/***************************************************************************//** + The I2C_isr function is the CoreI2C interrupt service routine. User must + call this function from their application level CoreI2C interrupt handler + function. This function runs the I2C state machine based on previous and + current status. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREINTERRUPT_BASE_ADDR 0xCC000000u + #define COREI2C_SER_ADDR 0x10u + #define I2C_IRQ_NB 2u + + i2c_instance_t g_i2c_inst; + + void core_i2c_isr( void ) + { + I2C_isr( &g_i2c_inst ); + } + + void main( void ) + { + CIC_init( COREINTERRUPT_BASE_ADDR ); + NVIC_init(); + CIC_set_irq_handler( I2C_IRQ_NB, core_i2c_isr ); + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + NVIC_enable_interrupt( NVIC_IRQ_0 ); + } + @endcode + */ +void I2C_isr +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//* + #Master Specific Functions + + The following functions are only used within an I2C master's implementation. +/***************************************************************************//** + This function initiates an I2C master write transaction. This function returns + immediately after initiating the transaction. The content of the write buffer + passed as parameter should not be modified until the write transaction + completes. It also means that the memory allocated for the write buffer should + not be freed or should not go out of scope before the write completes. You can + check for the write transaction completion using the I2C_status() function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr + This parameter specifies the serial address of the target I2C device. + + @param write_buffer + This parameter is a pointer to a buffer holding the data to be written to + the target I2C device. Do not to release the memory used by this buffer + before the write transaction completes. For example, it is not appropriate + to return from a function allocating this buffer as an auto array variable + before the write transaction completes as this would result in the buffer's + memory being de-allocated from the stack when the function returns. This + memory could then be subsequently reused and modified causing unexpected + data to be written to the target I2C device. + + @param write_size + Number of bytes held in the write_buffer to be written to the target I2C + device. + + @param options + The options parameter is used to indicate if the I2C bus should be released + on completion of the write transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the write transaction causing the bus to be released for other I2C + devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the write + transaction, preventing other I2C devices from initiating a bus transaction. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t tx_buffer[DATA_LENGTH]; + uint8_t write_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Write data to Channel 0 of CoreI2C instance. + I2C_write( &g_i2c_inst, target_slave_addr, tx_buffer, write_length, + I2C_RELEASE_BUS ); + + // Wait for completion and record the outcome + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_write +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * write_buffer, + uint16_t write_size, + uint8_t options +); + +/***************************************************************************//** + This function initiates an I2C master read transaction. This function returns + immediately after initiating the transaction. + The contents of the read buffer passed as parameter should not be modified + until the read transaction completes. It also means that the memory allocated + for the read buffer should not be freed or should not go out of scope before + the read completes. You can check for the read transaction completion using + the I2C_status() function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr + This parameter specifies the serial address of the target I2C device. + + @param read_buffer + This is a pointer to a buffer where the data received from the target device + gets stored. Do not to release the memory used by this buffer before the read + transaction completes. For example, it is not appropriate to return from a + function allocating this buffer as an auto array variable before the read + transaction completes as this would result in the buffer's memory being + de-allocated from the stack when the function returns. This memory could + then be subsequently reallocated resulting in the read transaction + corrupting the newly allocated memory. + + @param read_size + This parameter specifies the number of bytes to read from the target device. + This size must not exceed the size of the read_buffer buffer. + + @param options + The options parameter is used to indicate if the I2C bus should be released + on completion of the read transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the read transaction causing the bus to be released for other I2C + devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the read transaction, + preventing other I2C devices from initiating a bus transaction. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t rx_buffer[DATA_LENGTH]; + uint8_t read_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Read data from target slave Channel 0 of CoreI2C instance. + I2C_read( &g_i2c_inst, target_slave_addr, rx_buffer, read_length, + I2C_RELEASE_BUS ); + + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +); + +/***************************************************************************//** + This function initiates an I2C write-read transaction where data is first + written to the target device before issuing a restart condition and changing + the direction of the I2C transaction in order to read from the target device. + + The same warnings about buffer allocation in I2C_write() and I2C_read() + applies to this function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr + This parameter specifies the serial address of the target I2C device. + + @param addr_offset + This parameter is a pointer to the buffer containing the data that is sent + to the slave during the write phase of the write-read transaction. This + data is typically used to specify an address offset specifying to the I2C + slave device what data it must return during the read phase of the + write-read transaction. + + @param offset_size + This parameter specifies the number of offset bytes to be written during the + write phase of the write-read transaction. This is typically the size of the + buffer pointed by the addr_offset parameter. + + @param read_buffer + This parameter is a pointer to the buffer where the data read from the I2C + slave will be stored. + + @param read_size + This parameter specifies the number of bytes to read from the target I2C + slave device. This size must not exceed the size of the buffer pointed by + the read_buffer parameter. + + @param options + The options parameter is used to indicate if the I2C bus should be released + on completion of the write-read transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the write-read transaction causing the bus to be released for other + I2C devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the write-read + transaction, preventing other I2C devices from initiating a bus transaction. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define TX_LENGTH 16u + #define RX_LENGTH 8u + + i2c_instance_t g_i2c_inst; + uint8_t rx_buffer[RX_LENGTH]; + uint8_t read_length = RX_LENGTH; + uint8_t tx_buffer[TX_LENGTH]; + uint8_t write_length = TX_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + I2C_write_read( &g_i2c_inst, target_slave_addr, tx_buffer, write_length, + rx_buffer, read_length, I2C_RELEASE_BUS ); + + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_write_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * addr_offset, + uint16_t offset_size, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +); + +/***************************************************************************//** + This function indicates the current state of a CoreI2C channel. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + The return value indicates the current state of a CoreI2C channel or the + outcome of the previous transaction if no transaction is in progress. + Following are the return values are: + - I2C_SUCCESS + The last I2C transaction has completed successfully. + - I2C_IN_PROGRESS + There is an I2C transaction in progress. + - I2C_FAILED + The last I2C transaction failed. + - I2C_TIMED_OUT + The request has failed to complete in the allotted time. + + @example + @code + i2c_instance_t g_i2c_inst; + + while( I2C_IN_PROGRESS == I2C_get_status( &g_i2c_inst ) ) + { + // Do something useful while waiting for I2C operation to complete + our_i2c_busy_task(); + } + + if( I2C_SUCCESS != I2C_get_status( &g_i2c_inst ) ) + { + // Something went wrong... + our_i2c_error_recovery( &g_i2c_inst ); + } + @endcode + */ +i2c_status_t I2C_get_status +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + This function waits for the current I2C transaction to complete. The return + value indicates whether the last I2C transaction was successful or not. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + @param timeout_ms + The timeout_ms parameter specifies the delay within which the current I2C + transaction should complete. The time out delay is given in + milliseconds. I2C_wait_complete() will return I2C_TIMED_OUT if the current + transaction has not completed after the time out delay has expired. This + parameter can be set to I2C_NO_TIMEOUT to indicate that I2C_wait_complete() + must not time out. + + @return + The return value indicates the outcome of the last I2C transaction. It can + be one of the following: + - I2C_SUCCESS + The last I2C transaction has completed successfully. + - I2C_FAILED + The last I2C transaction failed. + - I2C_TIMED_OUT + The last transaction failed to complete within the time out delay given + as second parameter. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t rx_buffer[DATA_LENGTH]; + uint8_t read_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Read data from Channel 0 of CoreI2C instance. + I2C_read( &g_i2c_inst, target_slave_addr, rx_buffer, read_length, + I2C_RELEASE_BUS ); + + // Wait for completion and record the outcome + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +i2c_status_t I2C_wait_complete +( + i2c_instance_t * this_i2c, + uint32_t timeout_ms +); + +/***************************************************************************//** + This function is used to control the expiration of the time out delay + specified as a parameter to the I2C_wait_complete() function. It must be + called from the interrupt service routine of a periodic interrupt source such + as the SysTick timer interrupt. It takes the period of the interrupt + source as its ms_since_last_tick parameter and uses it as the time base for + the I2C_wait_complete() function's time out delay. + + Note: This function does not need to be called if the I2C_wait_complete() + function is called with a timeout_ms value of I2C_NO_TIMEOUT. + + Note: If this function is not called then the I2C_wait_complete() function + will behave as if its timeout_ms was specified as I2C_NO_TIMEOUT and it + will not time out. + + Note: If this function is being called from an interrupt handler (for example, + SysTick) it is important that the calling interrupt have a lower priority + than the CoreI2C interrupt(s) to ensure any updates to the shared data are + protected. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + @param ms_since_last_tick + The ms_since_last_tick parameter specifies the number of milliseconds that + elapsed since the last call to I2C_system_tick(). This parameter would + typically be a constant specifying the interrupt rate of a timer used to + generate system ticks. + + @return None. + + @example + The following example shows how the I2C_system_tick() function. I2C_system_tick() + is called for each I2C channel from the SysTick timer interrupt service routine. + The following example shows how the SysTick is configured to generate an interrupt + in every 10 milliseconds. + @code + #define SYSTICK_INTERVAL_MS 10 + + void SysTick_Handler(void) + { + I2C_system_tick(&g_core_i2c0, SYSTICK_INTERVAL_MS); + I2C_system_tick(&g_core_i2c2, SYSTICK_INTERVAL_MS); + } + @endcode + */ +void I2C_system_tick +( + i2c_instance_t * this_i2c, + uint32_t ms_since_last_tick +); + +/***************************************************************************//* + #Slave Specific Functions + + The following functions are only used within the implementation of an I2C slave device. + +/***************************************************************************//** + This function specifies the memory buffer holding the data that will be sent + to the I2C master when this CoreI2C channel is the target of an I2C read or + write-read transaction. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param tx_buffer + This parameter is a pointer to the memory buffer holding the data to be + returned to the I2C master when this CoreI2C channel is the target of an + I2C read or write-read transaction. + + @param tx_size + Size of the transmit buffer pointed by the tx_buffer parameter. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Specify the transmit buffer containing the data that will be + // returned to the master during read and write-read transactions. + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + } + @endcode + */ +void I2C_set_slave_tx_buffer +( + i2c_instance_t * this_i2c, + const uint8_t * tx_buffer, + uint16_t tx_size +); + +/***************************************************************************//** + This function specifies the memory buffer that is used by the CoreI2C channel + to receive data when it is a slave. This buffer is the memory where data gets + stored when the CoreI2C channel is the target of an I2C master write + transaction (that is, when it is the slave). + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param rx_buffer + This parameter is a pointer to the memory buffer allocated by the caller + software to be used as a slave receive buffer. + + @param rx_size + Size of the slave receive buffer. This is the amount of memory allocated + to the buffer pointed by rx_buffer. + Note: Indirectly, this buffer size specifies the maximum I2C write + transaction length this CoreI2C channel targets. This is because + this CoreI2C channel responds to further received bytes with + a non-acknowledge bit (NACK) as soon as its receive buffer is + full. This causes the write transaction to fail. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_RX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_rx_buffer[SLAVE_RX_BUFFER_SIZE]; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Specify the buffer used to store the data written by the I2C master. + I2C_set_slave_rx_buffer( &g_i2c_inst, g_slave_rx_buffer, + sizeof(g_slave_rx_buffer) ); + } + @endcode + */ +void I2C_set_slave_rx_buffer +( + i2c_instance_t * this_i2c, + uint8_t * rx_buffer, + uint16_t rx_size +); + +/***************************************************************************//** + This function is used as part of the configuration of a CoreI2C channel to + operate as a slave supporting write-read transactions. It specifies the + number of bytes expected as part of the write phase of a write-read + transaction. The bytes received during the write phase of a write-read + transaction will be interpreted as an offset into the slave's transmit buffer. + This allows random access into the I2C slave transmit buffer from a remote + I2C master. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param offset_length + The offset_length parameter configures the number of bytes to be interpreted + by the CoreI2C slave as a memory offset value during the write phase of + write-read transactions. The maximum value for the offset_length parameter + is two. The value of offset_length has the following effect on the + interpretation of the received data. + • If offset_length is 0, the offset into the transmit buffer is fixed at 0. + • If offset_length is 1, a single byte of received data is interpreted as an + unsigned 8-bit offset value in the range 0 to 255. + • If offset_length is 2, 2 bytes of received data are interpreted as an + unsigned 16-bit offset value in the range 0 to 65535. The first byte + received in this case provides the high order bits of the offset and + the second byte provides the low order bits. + If the number of bytes received does not match the non 0 value of + offset_length, the transmit buffer offset is set to 0. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + I2C_set_slave_mem_offset_length( &g_i2c_inst, 1 ); + } + @endcode + */ +void I2C_set_slave_mem_offset_length +( + i2c_instance_t * this_i2c, + uint8_t offset_length +); + +/***************************************************************************//** + Register the function that is called to process the data written to this + CoreI2C channel when it is the slave in an I2C write transaction. + + Note: If a write handler is registered, it is called on completion of the + write phase of a write-read transaction and responsible for processing + the received data in the slave receive buffer and populating the slave + transmit buffer with the data that is transmitted to the I2C master + as part of the read phase of the write-read transaction. If a write + handler is not registered, the write data of a write-read transaction is + interpreted as an offset into the slave’s transmit buffer and handled by + the driver. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param handler + Pointer to the function that processes the I2C write request. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + // local function prototype + void slave_write_handler + ( + i2c_instance_t * this_i2c, + uint8_t * p_rx_data, + uint16_t rx_size + ); + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + I2C_set_slave_mem_offset_length( &g_i2c_inst, 1 ); + I2C_register_write_handler( &g_i2c_inst, slave_write_handler ); + } + @endcode +*/ +void I2C_register_write_handler +( + i2c_instance_t * this_i2c, + i2c_slave_wr_handler_t handler +); + +/***************************************************************************//** + This function enables slave mode operation for a CoreI2C channel. It enables + the CoreI2C slave to receive data when it is the target of an I2C read, write, + or write-read transaction. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + // Enable I2C slave + I2C_enable_slave( &g_i2c_inst ); + @endcode + */ +void I2C_enable_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + This function disables the slave mode operation for a CoreI2C channel. It stops + the CoreI2C slave that acknowledges the I2C read, write, or write-read + transactions targeted at it. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + // Disable I2C slave + I2C_disable_slave( &g_i2c_inst ); + @endcode + */ +void I2C_disable_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_slave_second_addr() function sets the secondary slave address for + a CoreI2C slave device. This is an additional slave address required in certain + applications, for example, to enable fail-safe operation in a system. As the + CoreI2C device supports 7-bit addressing, the highest value assigned to second + slave address is 127 (0x7F). + + Note: This function does not support CoreI2C hardware configured with a fixed + second slave address. The current implementation of the ADDR1[0] register + bit makes it difficult for the driver to support both programmable and + fixed second slave address, so we choose to support programmable only. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param second_slave_addr + The second_slave_addr parameter is the secondary slave address of the I2C + device. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SECOND_SLAVE_ADDR 0x20u + + i2c_instance_t g_i2c_inst; + void main( void ) + { + // Initialize the CoreI2C driver with its base address, primary I2C + // serial address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_second_addr( &g_i2c_inst, SECOND_SLAVE_ADDR ); + } + @endcode + */ +void I2C_set_slave_second_addr +( + i2c_instance_t * this_i2c, + uint8_t second_slave_addr +); + +/***************************************************************************//** + The I2C_disable_slave_second_addr() function disables the secondary slave + address of the CoreI2C slave device. + + Note: This version of the driver only supports CoreI2C hardware configured + with a programmable second slave address. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + i2c_instance_t g_i2c_inst; + I2C_disable_slave_second_addr( &g_i2c_inst); + @endcode + */ +void I2C_disable_slave_second_addr +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_gca() function is used to set the general call acknowledgement bit + of a CoreI2C slave device. This allows all channels of the CoreI2C slave + device to respond to a general call or broadcast message from an I2C master. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + i2c_instance_t g_i2c_inst; + + // Enable recognition of the General Call Address + I2C_set_gca( &g_i2c_inst ); + @endcode + */ +void I2C_set_gca +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_clear_gca() function is used to clear the general call acknowledgement + bit of a CoreI2C slave device. This will stop all channels of the I2C slave + device responding to any general call or broadcast message from the master. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + i2c_instance_t g_i2c_inst; + + // Disable recognition of the General Call Address + I2C_clear_gca( &g_i2c_inst ); + @endcode + */ + +void I2C_clear_gca +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//* + #I2C SMBUS Specific APIs + +/***************************************************************************//** + The I2C_smbus_init() function enables SMBus timeouts and status logic for a + CoreI2C channel. + + Note: This and any of the other SMBus related functionality will only have an + effect if the CoreI2C was instantiated with the Generate SMBus Logic + option checked. + + Note: If the CoreI2C was instantiated with the Generate IPMI Logic option + checked this function then enables the IPMI 3mS SCL low timeout but + none of the other SMBus functions will have any effect. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void system_init( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst); + } + @endcode + */ +void I2C_smbus_init +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_enable_smbus_irq() function is used to enable the CoreI2C channel’s + SMBSUS and SMBALERT SMBus interrupts. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param irq_type + The irq_type specify the SMBUS interrupt(s) which will be enabled. + The two possible interrupts are: + - I2C_SMBALERT_IRQ + - I2C_SMBSUS_IRQ + To enable both interrupts in one call, use I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ. + + @return + None + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both I2C_SMBALERT_IRQ & I2C_SMBSUS_IRQ interrupts + I2C_enable_smbus_irq( &g_i2c_inst, + (uint8_t)(I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ) ); + } + @endcode + */ +void I2C_enable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +); + +/***************************************************************************//** + The I2C_disable_smbus_irq() function disable the CoreI2C channel’s SMBSUS and + SMBALERT SMBus interrupts. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param irq_type + The irq_type specifies the SMBUS interrupt(s) which are disabled. + The two possible interrupts are: + • I2C_SMBALERT_IRQ + • I2C_SMBSUS_IRQ + To disable both ints in one call, use I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both SMBALERT & SMBSUS interrupts + I2C_enable_smbus_irq( &g_i2c_inst, + (uint8_t)(I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ)); + + ... + + // Disable the SMBALERT interrupt + I2C_disable_smbus_irq( &g_i2c_inst, I2C_SMBALERT_IRQ ); + } + @endcode + */ +void I2C_disable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +); + +/***************************************************************************//** + The I2C_suspend_smbus_slave() function forces any SMBUS slave devices + connected to a CoreI2C channel into Power-Down or Suspend mode by asserting + the channel's SMBSUS signal. The CoreI2C channel is the SMBus master in this + case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // suspend SMBus slaves + I2C_suspend_smbus_slave( &g_i2c_inst ); + + ... + + // Re-enable SMBus slaves + I2C_resume_smbus_slave( &g_i2c_inst ); + } + @endcode + */ +void I2C_suspend_smbus_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_resume_smbus_slave() function de-asserts the CoreI2C channel's SMBSUS + signal to take any connected slave devices out of the Suspend mode. The CoreI2C + channel is the SMBus master in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // suspend SMBus slaves + I2C_suspend_smbus_slave( &g_i2c_inst ); + + ... + + // Re-enable SMBus slaves + I2C_resume_smbus_slave( &g_i2c_inst ); + } + @endcode + */ +void I2C_resume_smbus_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_reset_smbus() function resets the CoreI2C channel's SMBus connection + by forcing SCLK low for 35 mS. The reset that automatically cleares after 35 ms + gets elapsed. The CoreI2C channel is the SMBus master in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Make sure the SMBus channel is in a known state by resetting it + I2C_reset_smbus( &g_i2c_inst ); + } + @endcode + */ +void I2C_reset_smbus +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_smbus_alert() function is used to force master communication with + an I2C slave device by asserting the CoreI2C channel's SMBALERT signal. The + CoreI2C channel is the SMBus slave in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Get the SMBus masters attention + I2C_set_smbus_alert( &g_i2c_inst ); + + ... + + // Once we are happy, drop the alert + I2C_clear_smbus_alert( &g_i2c_inst ); + } + @endcode + */ +void I2C_set_smbus_alert +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_clear_smbus_alert() function is used to de-assert the CoreI2C channel's + SMBALERT signal once a slave device gets a response from the master. The + CoreI2C channel is the SMBus slave in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Get the SMBus masters attention + I2C_set_smbus_alert( &g_i2c_inst ); + + ... + + // Once we are happy, drop the alert + I2C_clear_smbus_alert( &g_i2c_inst ); + } + @endcode + */ +void I2C_clear_smbus_alert +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_get_irq_status function returns information about which interrupts are + currently pending in a CoreI2C channel. + The interrupts supported by CoreI2C are: + • SMBUSALERT + • SMBSUS + • INTR + + The macros I2C_NO_IRQ, I2C_SMBALERT_IRQ, I2C_SMBSUS_IRQ, and I2C_INTR_IRQ are + provided to use with this function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + This function returns the status of the CoreI2C channel's interrupts as a + single byte bitmap where a bit is set to indicate a pending interrupt. + The following are the bit positions associated with each interrupt type: + Bit 0 - SMBUS_ALERT_IRQ + Bit 1 - SMBSUS_IRQ + Bit 2 - INTR_IRQ + It returns 0, if there are no pending interrupts. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + uint8_t irq_to_enable = I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ; + uint8_t pending_irq = 0u; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both I2C_SMBALERT_IRQ & I2C_SMBSUS_IRQ irq + I2C_enable_smbus_irq( &g_i2c_inst, irq_to_enable ); + + // Get I2C IRQ type + pending_irq = I2C_get_irq_status( &g_i2c_inst ); + + // Let's assume, in system, INTR and SMBALERT IRQ is pending. + // So pending_irq will return status of both the IRQs + + if( pending_irq & I2C_SMBALERT_IRQ ) + { + // if true, it means SMBALERT_IRQ is there in pending IRQ list + } + if( pending_irq & I2C_INTR_IRQ ) + { + // if true, it means I2C_INTR_IRQ is there in pending IRQ list + } + } + @endcode + */ +uint8_t I2C_get_irq_status +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_user_data() function allows the association of a block of application + specific data with a CoreI2C channel. The composition of the data block is an + application matter and the driver simply provides the means for the application + to set and retrieve the pointer. For example, this is used to provide additional + channel specific information to the slave write handler. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param p_user_data + The p_user_data parameter is a pointer to the user specific data block for + this channel. It is defined as void * as the driver does not know the actual + type of data being pointed to and simply stores the pointer for later + retrieval by the application. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + app_data_t channel_xdata; + + void main( void ) + { + app_data_t *p_xdata; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Store location of user data in instance structure + I2C_set_user_data( &g_i2c_inst, (void *)&channel_xdata ); + + ... + + // Retrieve location of user data and do some work on it + p_xdata = (app_data_t *)I2C_get_user_data( &g_i2c_inst ); + if( NULL != p_xdata ) + { + p_xdata->foo = 123; + } + } + @endcode + */ +void I2C_set_user_data +( + i2c_instance_t * this_i2c, + void * p_user_data +); + +/***************************************************************************//** + The I2C_get_user_data() function is used to allows the retrieval of the address + of a block of application specific data associated with a CoreI2C channel. + The composition of the data block is an application matter and the driver + simply provides the means for the application to set and retrieve the pointer. + For example, this is used to provide additional channel specific information + to the slave write handler. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + This function returns a pointer to the user specific data block for this + channel. It is defined as void * as the driver does not know the actual type + of data being pointed. If no user data has been registered for this channel + a NULL pointer is returned. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + app_data_t channel_xdata; + + void main( void ) + { + app_data_t *p_xdata; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Store location of user data in instance structure + I2C_set_user_data( &g_i2c_inst, (void *)&channel_xdata ); + + ... + + // Retrieve location of user data and do some work on it + p_xdata = (app_data_t *)I2C_get_user_data( &g_i2c_inst ); + if( NULL != p_xdata ) + { + p_xdata->foo = 123; + } + } + @endcode + */ +void * I2C_get_user_data +( + i2c_instance_t * this_i2c +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h new file mode 100644 index 0000000..b1d872d --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h @@ -0,0 +1,190 @@ +/******************************************************************************* + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + */ + +#ifndef __CORE_SMBUS_REGISTERS +#define __CORE_SMBUS_REGISTERS 1 + +/*------------------------------------------------------------------------------ + * CONTROL register details + */ +#define CONTROL_REG_OFFSET 0x00u + +/* + * CR0 bits. + */ +#define CR0_OFFSET 0x00u +#define CR0_MASK 0x01u +#define CR0_SHIFT 0u + +/* + * CR1 bits. + */ +#define CR1_OFFSET 0x00u +#define CR1_MASK 0x02u +#define CR1_SHIFT 1u + +/* + * AA bits. + */ +#define AA_OFFSET 0x00u +#define AA_MASK 0x04u +#define AA_SHIFT 2u + +/* + * SI bits. + */ +#define SI_OFFSET 0x00u +#define SI_MASK 0x08u +#define SI_SHIFT 3u + +/* + * STO bits. + */ +#define STO_OFFSET 0x00u +#define STO_MASK 0x10u +#define STO_SHIFT 4u + +/* + * STA bits. + */ +#define STA_OFFSET 0x00u +#define STA_MASK 0x20u +#define STA_SHIFT 5u + +/* + * ENS1 bits. + */ +#define ENS1_OFFSET 0x00u +#define ENS1_MASK 0x40u +#define ENS1_SHIFT 6u + +/* + * CR2 bits. + */ +#define CR2_OFFSET 0x00u +#define CR2_MASK 0x80u +#define CR2_SHIFT 7u + +/*------------------------------------------------------------------------------ + * STATUS register details + */ +#define STATUS_REG_OFFSET 0x04u + +/*------------------------------------------------------------------------------ + * DATA register details + */ +#define DATA_REG_OFFSET 0x08u + +/* + * TARGET_ADDR bits. + */ +#define TARGET_ADDR_OFFSET 0x08u +#define TARGET_ADDR_MASK 0xFEu +#define TARGET_ADDR_SHIFT 1u + +/* + * DIR bit. + */ +#define DIR_OFFSET 0x08u +#define DIR_MASK 0x01u +#define DIR_SHIFT 0u + + +/*------------------------------------------------------------------------------ + * ADDRESS register details + */ +#define ADDRESS_REG_OFFSET 0x0Cu + +/* + * GC bits. + */ +#define GC_OFFSET 0x0Cu +#define GC_MASK 0x01u +#define GC_SHIFT 0u + +/* + * ADR bits. + */ +#define OWN_SLAVE_ADDR_OFFSET 0x0Cu +#define OWN_SLAVE_ADDR_MASK 0xFEu +#define OWN_SLAVE_ADDR_SHIFT 1u + +/*------------------------------------------------------------------------------ + * SMBUS register details + */ +#define SMBUS_REG_OFFSET 0x10u + +/* + * SMBALERT_IE bits. + */ +#define SMBALERT_IE_OFFSET 0x10u +#define SMBALERT_IE_MASK 0x01u +#define SMBALERT_IE_SHIFT 0u + +/* + * SMBSUS_IE bits. + */ +#define SMBSUS_IE_OFFSET 0x10u +#define SMBSUS_IE_MASK 0x02u +#define SMBSUS_IE_SHIFT 1u + +/* + * SMB_IPMI_EN bits. + */ +#define SMB_IPMI_EN_OFFSET 0x10u +#define SMB_IPMI_EN_MASK 0x04u +#define SMB_IPMI_EN_SHIFT 2u + +/* + * SMBALERT_NI_STATUS bits. + */ +#define SMBALERT_NI_STATUS_OFFSET 0x10u +#define SMBALERT_NI_STATUS_MASK 0x08u +#define SMBALERT_NI_STATUS_SHIFT 3u + +/* + * SMBALERT_NO_CONTROL bits. + */ +#define SMBALERT_NO_CONTROL_OFFSET 0x10u +#define SMBALERT_NO_CONTROL_MASK 0x10u +#define SMBALERT_NO_CONTROL_SHIFT 4u + +/* + * SMBSUS_NI_STATUS bits. + */ +#define SMBSUS_NI_STATUS_OFFSET 0x10u +#define SMBSUS_NI_STATUS_MASK 0x20u +#define SMBSUS_NI_STATUS_SHIFT 5u + +/* + * SMBSUS_NO_CONTROL bits. + */ +#define SMBSUS_NO_CONTROL_OFFSET 0x10u +#define SMBSUS_NO_CONTROL_MASK 0x40u +#define SMBSUS_NO_CONTROL_SHIFT 6u + +/* + * SMBUS_MST_RESET bits. + */ +#define SMBUS_MST_RESET_OFFSET 0x10u +#define SMBUS_MST_RESET_MASK 0x80u +#define SMBUS_MST_RESET_SHIFT 7u + +/*------------------------------------------------------------------------------ + * SLAVE ADDRESS 1 register details + */ + +#define ADDRESS1_REG_OFFSET 0x1Cu + +/* + * SLAVE1_EN bit of Slave Address 1 . + */ +#define SLAVE1_EN_OFFSET 0x1Cu +#define SLAVE1_EN_MASK 0x01u +#define SLAVE1_EN_SHIFT 0u + +#endif /* __CORE_SMBUS_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c new file mode 100644 index 0000000..12e352d --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * CoreI2C driver interrupt control. + * + */ +#include "core_i2c.h" + +/*------------------------------------------------------------------------------ + * This function must be modified to enable interrupts generated from the + * CoreI2C instance identified as parameter. + */ +void I2C_enable_irq( i2c_instance_t * this_i2c ) +{ + HAL_ASSERT(0) +} + +/*------------------------------------------------------------------------------ + * This function must be modified to disable interrupts generated from the + * CoreI2C instance identified as parameter. + */ +void I2C_disable_irq( i2c_instance_t * this_i2c ) +{ + HAL_ASSERT(0) +} diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.c b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.c new file mode 100644 index 0000000..2e11750 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.c @@ -0,0 +1,1345 @@ +/***************************************************************************//** + * Copyright 2013-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * CoreSPI bare metal driver implementation for CoreSPI. + * + * This Core SPI driver provides functions for implementing SPI master or + * SPI slave operations with the CoreSPI version 4.2.xxx It is not compatible + * with CoreSPI version 3.0.xxx. + * + * @file core_spi.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreSPI software configuration + * + */ + +#include "core_spi.h" +#include "corespi_regs.h" +#include + +/******************************************************************************* + * Null parameters with appropriate type definitions + */ +#define NULL_ADDR ( ( addr_t ) 0u ) +#define NULL_INSTANCE ( ( spi_instance_t * ) 0u ) +#define NULL_BUFF ( ( uint8_t * ) 0u ) +#define NULL_FRAME_HANDLER ( ( spi_frame_rx_handler_t ) 0u ) +#define NULL_BLOCK_HANDLER ( ( spi_block_rx_handler_t ) 0u ) +#define NULL_SLAVE_TX_UPDATE_HANDLER ( ( spi_slave_frame_tx_handler_t ) 0u ) +#define NULL_SLAVE_CMD_HANDLER NULL_BLOCK_HANDLER + +#define SPI_ALL_INTS (0xFFu) /* For clearing all active interrupts */ + +/******************************************************************************* + * Possible states for different register bit fields + */ + +#define DISABLE 0u +#define ENABLE 1u + + +/******************************************************************************* + * Function return values + */ +enum { + FAILURE = 0u, + SUCCESS = 1u +}; + +/******************************************************************************* + * Local function declarations + */ +static void fill_slave_tx_fifo( spi_instance_t * this_spi ); +static void read_slave_rx_fifo( spi_instance_t * this_spi ); +static void recover_from_rx_overflow( const spi_instance_t * this_spi ); + +/******************************************************************************* + * SPI_init() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_init +( + spi_instance_t * this_spi, + addr_t base_addr, + uint16_t fifo_depth +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( NULL_ADDR != base_addr ); + HAL_ASSERT( SPI_MAX_FIFO_DEPTH >= fifo_depth ); + HAL_ASSERT( SPI_MIN_FIFO_DEPTH <= fifo_depth ); + + if( ( NULL_INSTANCE != this_spi ) && ( base_addr != NULL_ADDR ) ) + { + /* + * Initialize all transmit / receive buffers and handlers + * + * Relies on the fact that byte filling with 0x00 will equate + * to 0 for any non byte sized items too. + */ + + /* First fill struct with 0s */ + memset( this_spi, 0, sizeof(spi_instance_t) ); + + /* Configure CoreSPI instance attributes */ + this_spi->base_addr = (addr_t)base_addr; + + /* Store FIFO depth or fall back to minimum if out of range */ + if( ( SPI_MAX_FIFO_DEPTH >= fifo_depth ) && ( SPI_MIN_FIFO_DEPTH <= fifo_depth ) ) + { + this_spi->fifo_depth = fifo_depth; + } + else + { + this_spi->fifo_depth = SPI_MIN_FIFO_DEPTH; + } + /* Make sure the CoreSPI is disabled while we configure it */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Ensure all slaves are deselected */ + HAL_set_8bit_reg( this_spi->base_addr, SSEL, 0u ); + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Ensure RXAVAIL, TXRFM, SSEND and CMDINT are disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, 0u ); + /* + * Enable the CoreSPI in the reset default of master mode + * with TXUNDERRUN, RXOVFLOW and TXDONE interrupts disabled. + * The driver does not currently use interrupts in master mode. + */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL1, ENABLE | CTRL1_MASTER_MASK ); + } +} + +/***************************************************************************//** + * SPI_configure_slave_mode() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_configure_slave_mode +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Don't yet know what slave transfer mode will be used */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_NONE; + + /* Make sure the CoreSPI is disabled while we configure it */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Ensure RXAVAIL, TXRFM, SSEND and CMDINT are disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, 0u ); + /* + * Enable the CoreSPI in slave mode with TXUNDERRUN, RXOVFLOW and TXDONE + * interrupts disabled. The appropriate interrupts will be enabled later + * on when the transfer mode is configured. + */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL1, ENABLE ); + } +} + +/***************************************************************************//** + * SPI_configure_master_mode() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_configure_master_mode +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Disable the CoreSPI for a little while, while we configure the CoreSPI */ + HAL_set_8bit_reg_field(this_spi->base_addr, CTRL1_ENABLE, DISABLE); + + /* Reset slave transfer mode to unknown in case it has been set previously */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_NONE; + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Ensure RXAVAIL, TXRFM, SSEND and CMDINT are disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, 0u ); + + /* Enable the CoreSPI in master mode with TXUNDERRUN, RXOVFLOW and TXDONE interrupts disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL1, ENABLE | CTRL1_MASTER_MASK ); + } +} + +/***************************************************************************//** + * SPI_set_slave_select() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +) +{ + spi_slave_t temp = (spi_slave_t)(0x00u) ; + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( SPI_MAX_NB_OF_SLAVES > slave ); + + if( ( NULL_INSTANCE != this_spi ) && ( SPI_MAX_NB_OF_SLAVES > slave ) ) + { + /* This function is only intended to be used with an SPI master */ + if( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW ) ) + { + recover_from_rx_overflow( this_spi ); + } + /* Set the correct slave select bit */ + temp = (spi_slave_t)( HAL_get_8bit_reg( this_spi->base_addr, SSEL ) | ((uint32_t)1u << (uint32_t)slave) ); + HAL_set_8bit_reg( this_spi->base_addr, SSEL, (uint_fast8_t)temp ); + } + } +} + +/***************************************************************************//** + * SPI_clear_slave_select() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_clear_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +) +{ + spi_slave_t temp = (spi_slave_t) (0x00u) ; + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( SPI_MAX_NB_OF_SLAVES > slave ); + + if( ( NULL_INSTANCE != this_spi ) && ( SPI_MAX_NB_OF_SLAVES > slave ) ) + { + /* This function is only intended to be used with an SPI master. */ + if( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW) ) + { + recover_from_rx_overflow( this_spi ); + } + /* Clear the correct slave select bit */ + temp = (spi_slave_t)( HAL_get_8bit_reg( this_spi->base_addr, SSEL ) & ~((uint32_t)1u << (uint32_t)slave) ); + HAL_set_8bit_reg( this_spi->base_addr, SSEL, (uint_fast8_t)temp ) ; + } + } +} + +/***************************************************************************//** + * SPI_transfer_frame() + * See "core_spi.h" for details of how to use this function. + */ +uint32_t SPI_transfer_frame +( + spi_instance_t * this_spi, + uint32_t tx_bits +) +{ + volatile uint32_t rx_data = 0u; /* Ensure consistent return value if in slave mode */ + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI master. */ + if( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Flush the receive and transmit FIFOs by resetting both */ + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK); + + /* Send frame. */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, tx_bits ); + + /* Wait for frame Tx to complete. */ + while ( ENABLE != HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_DONE ) ) + { + ; + } + + /* Read received frame. */ + rx_data = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + } + } + + /* Finally, return the frame we received from the slave or 0 */ + return( rx_data ); +} + + +/***************************************************************************//** + * SPI_transfer_block() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_transfer_block +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_buffer, + uint16_t rx_byte_size +) +{ + uint32_t transfer_size = 0U; /* Total number of bytes to transfer. */ + uint16_t transfer_idx = 0U; /* Number of bytes transferred so far */ + uint16_t tx_idx = 0u; /* Number of valid data bytes sent */ + uint16_t rx_idx = 0u; /* Number of valid response bytes received */ + uint16_t transit = 0U; /* Number of bytes "in flight" to avoid FIFO errors */ + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI master. */ + if( ( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) && + /* Check for empty transfer as well */ + ( 0u != ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) ) ) + { + /* + * tansfer_size is one less than the real amount as we have to write + * the last frame separately to trigger the slave deselect in case + * the SPS option is in place. + */ + transfer_size = ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) - 1u; + /* Flush the receive and transmit FIFOs */ + HAL_set_8bit_reg(this_spi->base_addr, CMD, (uint32_t)(CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK )); + + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW) ) + { + recover_from_rx_overflow( this_spi ); + } + + /* Disable the Core SPI for a little bit, while we load the TX FIFO */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + while( ( tx_idx < transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out 0s to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + } + ++transit; + ++tx_idx; + } + + /* If room left to put last frame in before the off, then do it */ + if( ( tx_idx == transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data, not expecting any reply this time */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out last 0 to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + } + + ++transit; + ++tx_idx; + } + + /* FIFO is all loaded up so enable Core SPI to start transfer */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + + /* Perform the remainder of the transfer by sending a byte every time a byte + * has been received. This should ensure that no Rx overflow can happen in + * case of an interrupt occurring during this function. + * + * We break the transfer down into stages to minimise the processing in + * each loop as the SPI interface is very demanding at higher clock rates. + * This works well with FIFOs but might be less efficient if there is only + * a single frame buffer. + * + * First stage transfers remaining command bytes (if any). + * At this stage anything in the RX FIFO can be discarded as it is + * not part of a valid response. + */ + while( tx_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + /* Send another byte. */ + if( tx_idx == transfer_size ) /* Last frame is special... */ + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Read and discard. */ + HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now, we are writing dummy bytes to push through the response from + * the slave but we still have to keep discarding any read data that + * corresponds with one of our command bytes. + */ + while( transfer_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + if( tx_idx < transfer_size ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Read and discard. */ + HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now we are now only sending dummy data to push through the + * valid response data which we store in the response buffer. + */ + while( tx_idx < transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received byte. */ + rx_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* If we still need to send the last frame */ + while( tx_idx == transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received byte. */ + rx_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* + * Finally, we are now finished sending data and are only reading + * valid response data which we store in the response buffer. + */ + while( transfer_idx <= transfer_size ) + { + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received byte. */ + rx_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + } + } + } + } +} + +/***************************************************************************//** + * SPI_transfer_block_store_all_resp() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_transfer_block_store_all_resp +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_data_buffer, + uint16_t rx_byte_size, + uint8_t * cmd_response_buffer +) +{ + uint32_t transfer_size = 0U; /* Total number of bytes to transfer. */ + uint16_t transfer_idx = 0U; /* Number of bytes transferred so far */ + uint16_t tx_idx = 0u; /* Number of valid data bytes sent */ + uint16_t rx_idx = 0u; /* Number of valid response bytes received */ + uint16_t transit = 0U; /* Number of bytes "in flight" to avoid FIFO errors */ + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI master. */ + if( ( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) && + /* Check for empty transfer as well */ + ( 0u != ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) ) ) + { + /* + * tansfer_size is one less than the real amount as we have to write + * the last frame separately to trigger the slave deselect in case + * the SPS option is in place. + */ + transfer_size = ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) - 1u; + /* Flush the receive and transmit FIFOs */ + HAL_set_8bit_reg(this_spi->base_addr, CMD, (uint32_t)(CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK )); + + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW) ) + { + recover_from_rx_overflow( this_spi ); + } + + /* Disable the Core SPI for a little bit, while we load the TX FIFO */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + while( ( tx_idx < transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out 0s to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + } + ++transit; + ++tx_idx; + } + + /* If room left to put last frame in before the off, then do it */ + if( ( tx_idx == transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data, not expecting any reply this time */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out last 0 to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + } + + ++transit; + ++tx_idx; + } + + /* FIFO is all loaded up so enable Core SPI to start transfer */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + + /* Perform the remainder of the transfer by sending a byte every time a byte + * has been received. This should ensure that no Rx overflow can happen in + * case of an interrupt occurring during this function. + * + * We break the transfer down into stages to minimise the processing in + * each loop as the SPI interface is very demanding at higher clock rates. + * This works well with FIFOs but might be less efficient if there is only + * a single frame buffer. + * + * First stage transfers remaining command bytes (if any). + * At this stage anything in the RX FIFO can be discarded as it is + * not part of a valid response. + */ + while( tx_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + /* Send another byte. */ + if( tx_idx == transfer_size ) /* Last frame is special... */ + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received command byte. */ + cmd_response_buffer[transfer_idx] = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now, we are writing dummy bytes to push through the response from + * the slave, which we store in the command response buffer. + */ + while( transfer_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + if( tx_idx < transfer_size ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received command byte. */ + cmd_response_buffer[transfer_idx] = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now we are now only sending dummy data to push through the + * valid response data which we store in the data response buffer. + */ + while( tx_idx < transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received data byte. */ + rx_data_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* If we still need to send the last frame */ + while( tx_idx == transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received data byte. */ + rx_data_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* + * Finally, we are now finished sending data and are only reading + * valid response data which we store in the data response buffer. + */ + while( transfer_idx <= transfer_size ) + { + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received data byte. */ + rx_data_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + } + } + } + } +} +/***************************************************************************//** + * SPI_set_frame_rx_handler() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_frame_rx_handler +( + spi_instance_t * this_spi, + spi_frame_rx_handler_t rx_handler +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if(NULL_INSTANCE != this_spi) + { + /* This function is only intended to be used with an SPI slave. */ + if(DISABLE == HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER)) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Disable SSEND and CMD interrupts as we are not doing block transfers */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTSSEND, DISABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + + /* Disable block Rx handler as they are mutually exclusive. */ + this_spi->block_rx_handler = 0U; + + /* Keep a copy of the pointer to the Rx handler function. */ + this_spi->frame_rx_handler = rx_handler; + + if( SPI_SLAVE_XFER_FRAME != this_spi->slave_xfer_mode ) + { + /* + * Either just coming from init or were previously in block mode + * so no tx frame handler is set at this point in time... + * + * Don't allow TXDONE interrupts. + */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXDONE, DISABLE ); + } + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK); + + /* Enable Rx and FIFO error interrupts */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTRXOVFLOW, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXURUN, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTRXDATA, ENABLE ); + + /* Make sure correct mode is selected */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_FRAME; + + /* Finally re-enable the CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } + } +} + +/***************************************************************************//** + * SPI_set_slave_tx_frame() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_slave_tx_frame +( + spi_instance_t * this_spi, + uint32_t frame_value, + spi_slave_frame_tx_handler_t slave_tx_frame_handler +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI slave. */ + if( DISABLE == HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Disable SSEND and CMD interrupts as we are not doing block transfers */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTSSEND, DISABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + + if( SPI_SLAVE_XFER_FRAME != this_spi->slave_xfer_mode ) + { + /* + * Either just coming from init or were previously in block mode + * so no rx frame handler is set at this point in time... + * + * Don't allow RXDATA interrupts. + */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTRXDATA, DISABLE ); + } + + /* Disable slave block tx buffer as it is mutually exclusive with frame + * level handling. */ + this_spi->slave_tx_buffer = NULL_BUFF; + this_spi->slave_tx_size = 0U; + this_spi->slave_tx_idx = 0U; + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK); + + /* Assign the slave frame update handler - NULL_SLAVE_TX_UPDATE_HANDLER for none */ + this_spi->slave_tx_frame_handler = slave_tx_frame_handler; + + /* Keep a copy of the slave Tx frame value. */ + this_spi->slave_tx_frame = frame_value; + + /* Load one frame into Tx data register. */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, this_spi->slave_tx_frame ); + + /* Enable Tx Done interrupt in order to reload the slave Tx frame after each + * time it has been sent. */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXDONE, ENABLE ); + + /* Make sure correct mode is selected */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_FRAME; + + /* Ready to go so enable CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } + } +} + +/***************************************************************************//** + * SPI_set_slave_block_buffers() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_slave_block_buffers +( + spi_instance_t * this_spi, + const uint8_t * tx_buffer, + uint32_t tx_buff_size, + uint8_t * rx_buffer, + uint32_t rx_buff_size, + spi_block_rx_handler_t block_rx_handler +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI slave. */ + if( DISABLE == HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Make sure correct mode is selected */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_BLOCK; + /* + * No command handler should be setup at this stage so fake this + * to ensure 0 padding works. + */ + this_spi->cmd_done = 1u; + + /* Disable frame handlers as they are mutually exclusive with block Rx handler. */ + this_spi->frame_rx_handler = NULL_FRAME_HANDLER; + this_spi->slave_tx_frame_handler = NULL_SLAVE_TX_UPDATE_HANDLER; + + /* Keep a copy of the pointer to the block Rx handler function. */ + this_spi->block_rx_handler = block_rx_handler; + + /* Assign slave receive buffer */ + this_spi->slave_rx_buffer = rx_buffer; + this_spi->slave_rx_size = rx_buff_size; + this_spi->slave_rx_idx = 0U; + + /* Assign slave transmit buffer*/ + this_spi->slave_tx_buffer = tx_buffer; + this_spi->slave_tx_size = tx_buff_size; + this_spi->slave_tx_idx = 0U; + + /* Flush the receive and transmit FIFOs */ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Preload the transmit FIFO. */ + while( !(HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_TXFULL)) && + ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->slave_tx_buffer[this_spi->slave_tx_idx] ); + ++this_spi->slave_tx_idx; + } + /* + * Disable TXDATA interrupt as we will look after transmission in rx handling + * because we know that once we have read a frame it is safe to send another one. + */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTTXDATA, DISABLE ); + + /* Enable Rx, FIFO error and SSEND interrupts */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTRXOVFLOW, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXURUN, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTRXDATA, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTSSEND, ENABLE ); + + /* Disable command handler until it is set explicitly */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + + /* Now enable the CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } + } +} + +/***************************************************************************//** + * SPI_set_cmd_handler() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_cmd_handler +( + spi_instance_t * this_spi, + spi_block_rx_handler_t cmd_handler, + uint32_t cmd_size +) +{ + uint32_t ctrl2 = 0u; + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( NULL_SLAVE_CMD_HANDLER != cmd_handler ); + HAL_ASSERT( 0u < cmd_size ); + + if( ( NULL_INSTANCE != this_spi ) && ( 0u < cmd_size ) && + ( NULL_SLAVE_CMD_HANDLER != cmd_handler ) ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + /* + * Note we don't flush the FIFOs as this has been done already when + * block mode was configured. + * + * Clear this flag so zero padding is disabled until command response + * has been taken care of. + */ + this_spi->cmd_done = 0u; + + /* Assign user handler for Command received interrupt */ + this_spi->cmd_handler = cmd_handler; + + /* Configure the command size and Enable Command received interrupt */ + ctrl2 = HAL_get_8bit_reg( this_spi->base_addr, CTRL2 ); + + /* First clear the count field then insert count and int enables */ + ctrl2 &= ~(uint32_t)CTRL2_CMDSIZE_MASK; + ctrl2 |= (uint32_t)((cmd_size & CTRL2_CMDSIZE_MASK) | CTRL2_INTCMD_MASK | CTRL2_INTRXDATA_MASK); + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, ctrl2 ); + + /* Now enable the CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } +} + +/***************************************************************************//** + * SPI_set_cmd_response() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_cmd_response +( + spi_instance_t * this_spi, + const uint8_t * resp_tx_buffer, + uint32_t resp_buff_size +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( NULL_BUFF != resp_tx_buffer ); + HAL_ASSERT( 0u < resp_buff_size ); + + if( ( NULL_INSTANCE != this_spi ) && ( 0u < resp_buff_size ) && + ( NULL_BUFF != resp_tx_buffer ) ) + { + this_spi->resp_tx_buffer = resp_tx_buffer; + this_spi->resp_buff_size = resp_buff_size; + this_spi->resp_buff_tx_idx = 0u; + + fill_slave_tx_fifo(this_spi); + } +} + + +/***************************************************************************//** + * SPI_enable() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_enable +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } +} + + +/***************************************************************************//** + * SPI_disable() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_disable +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + } +} + + +/***************************************************************************//** + * SPI interrupt service routine. + */ +void SPI_isr +( + spi_instance_t * this_spi +) +{ + uint32_t rx_frame; + int32_t guard; + +/* + * The assert and the NULL check here can be commented out to reduce the interrupt + * latency once you are sure the interrupt vector code is correct. + */ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + if( NULL_INSTANCE != this_spi ) + { + /* Handle receive. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_RXDATA ) ) + { + /* + * Service receive data according to transfer mode in operation. + * + * We check block mode first as this is most likely to have back to back + * transfers with multiple bytes. + * + * Note the order of the checks here will effect interrupt latency and + * for critical timing the mode you are using most often should probably be + * be the first checked. + */ + if( SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode ) /* Block handling mode. */ + { + while( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Read irrespective to clear the RX IRQ */ + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + if( this_spi->slave_rx_idx < this_spi->slave_rx_size ) + { + this_spi->slave_rx_buffer[this_spi->slave_rx_idx] = (uint8_t)rx_frame; + } + ++this_spi->slave_rx_idx; + } + /* + * Now handle updating of tx FIFO to keep the data flowing. + * First see if there is anything in slave_tx_buffer to send. + */ + while( ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) + && ( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->slave_tx_buffer[this_spi->slave_tx_idx] ); + ++this_spi->slave_tx_idx; + } + /* + * Next see if there is anything in resp_tx_buffer to send. + */ + if( this_spi->slave_tx_idx >= this_spi->slave_tx_size ) + { + while( ( this_spi->resp_buff_tx_idx < this_spi->resp_buff_size ) + && ( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->resp_tx_buffer[this_spi->resp_buff_tx_idx] ); + ++this_spi->resp_buff_tx_idx; + } + } + /* + * Lastly, see if we are ready to pad with 0s . + */ + if( this_spi->cmd_done && ( this_spi->slave_tx_idx >= this_spi->slave_tx_size ) && + ( this_spi->resp_buff_tx_idx >= this_spi->resp_buff_size ) ) + { + guard = 1 + ((int32_t)this_spi->fifo_depth / 4); + while( ( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) + && ( 0 != guard ) ) + { + /* + * Pad TX FIFO with 0s for consistent behaviour if the master + * tries to transfer more than we expected. + */ + HAL_set_32bit_reg(this_spi->base_addr, TXDATA, 0x00u); + /* + * We use the guard count to cover the event that we are never + * seeing the TX FIFO full because the data is being pulled + * out as fast as we can stuff it in. In this case we never spend + * more than our allocated time spinning here. + */ + guard--; + } + } + } + else if( SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode ) /* Single frame handling mode. */ + { + while( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + if( NULL_FRAME_HANDLER != this_spi->frame_rx_handler ) + { + this_spi->frame_rx_handler( rx_frame ); + } + } + } + else /* Slave transfer mode not set up so discard anything in RX FIFO */ + { + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_RXFIFORST_MASK ); + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_RXDATA, ENABLE ); + } + + /* Handle transmit. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_TXDONE ) ) + { + /* + * Note, the driver only currently uses the txdone interrupt when + * in frame transmit mode. In block mode all TX handling is done by the + * receive interrupt handling code as we know that for every frame received + * a frame must be placed in the TX FIFO. + */ + if( SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode ) + { + /* Execute the user callback to update the slave_tx_frame */ + if( NULL_SLAVE_TX_UPDATE_HANDLER != this_spi->slave_tx_frame_handler ) + { + this_spi->slave_tx_frame_handler ( this_spi ); + } + + /* Reload slave tx frame into Tx data register. */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, this_spi->slave_tx_frame ); + } + else if( SPI_SLAVE_XFER_BLOCK != this_spi->slave_xfer_mode ) + { + /* Slave transfer mode not set up so discard anything in TX FIFO */ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK ); + } + else + { + /* Nothing to do, no slave mode configured */ + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_TXDONE, ENABLE ); + } + + + /* Handle receive overflow. */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, INTMASK_RXOVERFLOW)) + { + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_RXFIFORST_MASK); + HAL_set_8bit_reg_field(this_spi->base_addr, INTCLR_RXOVERFLOW, ENABLE); + } + + /* Handle transmit under run. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_TXUNDERRUN ) ) + { + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK ); + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_TXUNDERRUN, ENABLE ); + } + + /* Handle command interrupt. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_CMDINT ) ) + { + read_slave_rx_fifo( this_spi ); + + /* + * Call the command handler if one exists. + */ + if( NULL_SLAVE_CMD_HANDLER != this_spi->cmd_handler ) + { + this_spi->cmd_handler( this_spi->slave_rx_buffer, this_spi->slave_rx_idx ); + } + this_spi->cmd_done = 1u; + /* Disable command interrupt until slave select becomes de-asserted to avoid retriggering. */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_CMDINT, ENABLE ); + } + + /* Handle slave select becoming de-asserted. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_SSEND) ) + { + /* Only supposed to do all this if transferring blocks... */ + if(SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode) + { + uint32_t rx_size; + + /* Empty any remaining bytes in RX FIFO */ + read_slave_rx_fifo( this_spi ); + rx_size = this_spi->slave_rx_idx; + /* + * Re-enable command interrupt if required. + * Must be done before re loading FIFO to ensure stale response + * data is not pushed into the FIFO. + */ + if(NULL_SLAVE_CMD_HANDLER != this_spi->cmd_handler) + { + this_spi->cmd_done = 0u; + this_spi->resp_tx_buffer = 0u; + this_spi->resp_buff_size = 0u; + this_spi->resp_buff_tx_idx = 0u; + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_CMDINT, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, ENABLE ); + } + /* + * Reset the transmit index to 0 to restart transmit at the start of the + * transmit buffer in the next transaction. This also requires flushing + * the Tx FIFO and refilling it with the start of Tx data buffer. + */ + this_spi->slave_tx_idx = 0u; + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + fill_slave_tx_fifo( this_spi ); + + /* Prepare to receive next packet. */ + this_spi->slave_rx_idx = 0u; + /* + * Call the receive handler if one exists. + */ + if( NULL_BLOCK_HANDLER != this_spi->block_rx_handler ) + { + this_spi->block_rx_handler( this_spi->slave_rx_buffer, rx_size ); + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_RXDATA, ENABLE ); + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_SSEND, ENABLE ); + } + } +} + +/******************************************************************************* + * Local function definitions + */ + +/***************************************************************************//** + * Fill the transmit FIFO (used for slave block transfers). + */ +static void fill_slave_tx_fifo +( + spi_instance_t * this_spi +) +{ + /* First see if slave_tx_buffer needs transmitting */ + while( ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) && + !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->slave_tx_buffer[this_spi->slave_tx_idx] ); + ++this_spi->slave_tx_idx; + } + + /* Then see if it is safe to look at putting resp_tx_buffer in FIFO? */ + if( this_spi->slave_tx_idx >= this_spi->slave_tx_size ) + { + while( ( this_spi->resp_buff_tx_idx < this_spi->resp_buff_size ) && + !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->resp_tx_buffer[this_spi->resp_buff_tx_idx] ); + ++this_spi->resp_buff_tx_idx; + } + } +} + +/***************************************************************************//** + * + */ +static void read_slave_rx_fifo +( + spi_instance_t * this_spi +) +{ + uint32_t rx_frame; + + if( SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode ) /* Block handling mode. */ + { + while( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); /* Read irresepective to clear the RX IRQ */ + if( this_spi->slave_rx_idx < this_spi->slave_rx_size ) + { + this_spi->slave_rx_buffer[this_spi->slave_rx_idx] = (uint8_t)rx_frame; + } + ++this_spi->slave_rx_idx; + } + } + else if( SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode ) /* Frame handling mode */ + { + while( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Single frame handling mode. */ + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + if( NULL_FRAME_HANDLER != this_spi->frame_rx_handler ) + { + this_spi->frame_rx_handler( rx_frame ); + } + } + } + else /* Slave transfer mode not set up so discard anything in RX FIFO */ + { + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_RXFIFORST_MASK ); + } +} + +/***************************************************************************//** + * This function is to recover the CoreSPI from receiver overflow. + * It temporarily disables the CoreSPI from interacting with external world, flushes + * the transmit and receiver FIFOs, clears all interrupts and then re-enables + * the CoreSPI instance referred by this_spi parameter. + */ +static void recover_from_rx_overflow +( + const spi_instance_t * this_spi +) +{ + /* Disable CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Reset TX and RX FIFOs */ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Enable CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); +} + + diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.h new file mode 100644 index 0000000..c6873f7 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.h @@ -0,0 +1,1324 @@ +/***************************************************************************//** + * Copyright 2013-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Core SPI bare metal software driver public API. + * + * This Core SPI driver provides functions for implementing SPI master or + * SPI slave operations with the CoreSPI version 4.2.xxx It is not compatible + * with CoreSPI version 3.0.xxx. + * + * The Core SPI driver supports two classes of data transfer operation: + * SPI frame operation or SPI block transfer operations. + * + * Frame operations allow transferring individual SPI frames from 4 to 32-bits + * in length. Block operations allow transferring blocks of data organized as + * 8-bit frames. + * + * @file core_spi.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreSPI prototypes + * + */ + +/*=========================================================================*//** + @mainpage Core SPI Bare Metal Driver. + + ============================================================================== + Introduction + ============================================================================== + CoreSPI is an IP component that implements a full-duplex, synchronous, and + configurable serial peripheral interface (SPI) with frame sizes from 4 to 32 + bits and bus interface sizes of 8-, 16-, or 32-bit. Each CoreSPI instance + communicates with up to eight slave devices. + + This driver provides a set of functions for controlling CoreSPI as part of + the bare metal system where no operating system is available. These drivers + can be adapted to be used as a part of an operating system, but the + implementation of the adaptation layer between driver and the operating + system's driver model is outside the scope of this User's Guide. + + ============================================================================== + Driver Configuration + ============================================================================== + Your application software should configure the CoreSPI driver through calls + to the SPI_init() function for each CoreSPI instance in the hardware design. + This function configures a default set of parameters that include a CoreSPI + hardware instance base address and the depth of the FIFOs for this instance. + + The CoreSPI instance is configured at the time of instantiation in hardware + design for APB width, frame size, FIFO depth, serial clock speed, serial + clock polarity, serial clock phase, and slave select state parameters. + + CoreSPI can communicate with up to eight different slave devices that match + the CoreSPI configuration at the time of hardware instantiation. + + The functions SPI_configure_slave_mode() and SPI_configure_master_mode() are + used to configure the CoreSPI instance as a master or slave as required by + the application. + + When CoreSPI wishes to communicate with a specific slave device, call + the SPI_set_slave_select() function with the slave number as an argument. + This function selects the slave device. A previously selected slave gets + unselected by calling the SPI_clear_slave_select() function. + + ============================================================================== + Theory of Operation + ============================================================================== + The CoreSPI driver functions are grouped into the following categories: + • Initialization + • Configuration for either master or slave operations + • SPI master frame transfer control + • SPI master block transfer control + • SPI slave frame transfer control + • SPI slave block transfer control + + Frame transfers allow CoreSPI to write or read up to 32-bits of data in a + single SPI transaction. For example, a frame transfer of 12-bits might be used + to read the result of an ADC conversion from a SPI analog to digital converter. + + Block transfers allow CoreSPI to write and/or read a number of bytes in a single + SPI transaction. With the driver as is, block transfer transactions allow data + transfers in multiples of 8-bits (8, 16, 24, 32, 40,...) and the CoreSPI instance + has to be configured for 8-bit frames. For other frame sizes, the + SPI_transfer_block() code can act as a template for developing a frame block + transfer function. + Block transfers are typically used with byte oriented devices like SPI + FLASH devices. + + Note: The CoreSPI instance in the hardware design must be configured for + the frame size required by the application; configuration by driver is + not possible. + + -------------------------------- + Initialization + -------------------------------- + The CoreSPI driver is initialized through a call to the SPI_init() function. + The SPI_init() function takes a pointer to the global CoreSPI instance data + structure of type spi_instance_t and the base address of the CoreSPI instance + as defined by the hardware design. The CoreSPI instance global data structure + is used by the driver to store state information for each CoreSPI instance. + A pointer to these data structures is also used as the first parameter to + any of the driver functions to identify which CoreSPI will be used by the + called function. It is the responsibility of the application programmer to + create and maintain these global CoreSPI instance data structures. Any call + to a CoreSPI driver function should be of the form SPI_function_name + ( &g_core_spi0, ... ). + The SPI_init() function resets the transmit and receives FIFOs of CoreSPI + instance being initialized. + The SPI_init() function must be called before any other CoreSPI driver + functions can be called. + + ---------------------------------------------------- + Configuration + ---------------------------------------------------- + A CoreSPI instance can operate either as a master or as a slave SPI device. + There are two distinct functions for configuring a CoreSPI instance for + master or slave operations. + + ## Master Configuration + The SPI_configure_master_mode() function configures the specified CoreSPI + block for operations as an SPI master. This function must be called once + before the CoreSPI block communicates with an SPI slave device. + + ## Slave Configuration + The SPI_configure_slave_mode() function configures the specified CoreSPI + block for operations as a SPI slave. This function must be called after + calling the SPI_init() to configure the CoreSPI instance referred by this_spi + parameter to operate in the slave mode. + + ------------------------------------- + SPI Master Frame Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI master frame transfers: + • SPI_set_slave_select() + • SPI_transfer_frame() + • SPI_clear_slave_select() + + The master must first select the target slave or slaves to be addressed by + calling the SPI_set_slave_select() function. This causes the relevant select + line(s) to become asserted while data is clocked out onto the SPI data line. + + A function call is then made to SPI_transfer_frame() specifying the value + of the data frame to be sent and returning the value read. + + After the transfer is complete, use the SPI_clear_slave_select() function + to prevent this slave select line from being asserted during subsequent SPI + transactions. A call to this function is required only if the master is + communicating with multiple slave devices. + + ------------------------------------- + SPI Master Block Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI master block transfers: + • SPI_set_slave_select() + • SPI_transfer_block() + • SPI_clear_slave_select() + + The master must first select the target slave or slaves by calling + SPI_set_slave_select(). This causes the relevant slave select line(s) to + become asserted while data is clocked out onto the SPI data line. + Alternatively, a general purpose input/output (GPIO) can be used to control + the state of the target slave device's chip select signal. + + A call is then made to the SPI_transfer_block() function. The parameters of + this function specify the following: + • The number of bytes to be transmitted + • A pointer to the buffer containing the data to be transmitted + • The number of bytes to be received + • A pointer to the buffer where the received data gets stored + + The number of bytes to be transmitted can be set to zero to indicate that the + transfer is purely a block read transfer. The number of bytes to be received + can be set to zero to specify that the transfer is purely a block write + transfer. + + Block mode transfers as implemented by the driver are effectively half duplex + as we do not store the values received from the slave device whilst we are + transmitting. If full duplex operation is required, the driver + SPI_transfer_block() function can serve as a starting point for implementing + full duplex block transfers. + + The SPI_clear_slave_select() function can be used after the transfer is + complete to prevent this slave select line from being asserted during + subsequent SPI transactions. A call to this function is only required if + the master is communicating with multiple slave devices. + + ------------------------------------- + SPI Slave Frame Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI slave frame transfers: + • SPI_set_frame_rx_handler() + • SPI_set_slave_tx_frame() + + The SPI_set_frame_rx_handler() function specifies the receive handler + function that is called when a frame of data has been received by the + SPI when it is configured as a slave. The receive handler function specified + through this call processes the frame data written over the SPI bus to the + SPI slave by the remote SPI master. The receive handler function must be + implemented as part of the application. It is only required if the SPI slave + is the target of SPI frame write transactions. + + The SPI_set_slave_tx_frame() function specifies the frame data that is + returned to the SPI master. The frame data specified through this function + is the value that will be read over the SPI bus by the remote SPI master, + when it initiates a transaction. Call the SPI_set_slave_tx_frame() function + only if the SPI slave is the target of SPI read transactions. That is, if + data is meant to be read over CoreSPI. + + If both frame handlers are required, call the SPI_set_frame_rx_handler() + first, otherwise the initial TX frame gets discarded when SPI_set_frame_rx_handler() + clears the FIFOs as part of its initialization. + + ------------------------------------- + SPI Slave Block Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI slave block transfers: + • SPI_set_slave_block_buffers() + • SPI_set_cmd_handler() + • SPI_set_cmd_response() + + The SPI_set_slave_block_buffers() function is used to configure an SPI slave + for block transfer operations. It specifies the following: + • The buffer containing the data that will be returned to the remote SPI + master + • The buffer where data received from the remote SPI master will be + stored + • The optional handler function that will be called after the receive + buffer is filled + + The SPI_set_cmd_handler() function specifies a command handler function that + is called by the driver once a specific number of frames have been + received after the SPI chip select signal becomes active. The number of + bytes making up the command part of the transaction is specified as part of + the parameters to the SPI_set_cmd_handler() function. The command handler + function is implemented as a part of the application making use of the SPI + driver and typically calls the SPI_set_cmd_response() function. + + The SPI_set_cmd_response() function specifies the data that gets returned + to the master. Typically, the SPI_set_slave_block_buffers() function is + called as a part of the system initialisation to specify the data sent to + the master while the command bytes are being received. The transmit buffer + specified through calling the SPI_set_slave_block_buffers() function would + also typically include one or more bytes allowing the turn around time + for the command handler function to execute and call the + SPI_set_cmd_response() function. + + *//*=========================================================================*/ +#ifndef CORE_SPI_H_ +#define CORE_SPI_H_ + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#include "hal_assert.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + SPI FIFO Depth + ======================================= + SPI_MAX_FIFO_DEPTH & SPI_MIN_FIFO_DEPTH constants define the maximum and minimum + FIFO depths allowed for the CoreSPI instance. User need to inform the driver of + the FIFO depth for each CoreSPI instance to ensure that the FIFOs are managed correctly. + + | Constant | Description | + |--------------------|----------------------------------------------------| + | SPI_MAX_FIFO_DEPTH | Maximum FIFO depth allowed for the CoreSPI instance| + | SPI_MIN_FIFO_DEPTH | Minimum FIFO depth allowed for the CoreSPI instance| + + */ +#define SPI_MAX_FIFO_DEPTH 32u +#define SPI_MIN_FIFO_DEPTH 1u + +/***************************************************************************//** + Instances of this structure are used to identify the specific CoreSPI hardware + instances. A pointer to an instance of the spi_instance_t structure is passed + as the first parameter to the CoreSPI driver functions to identify which SPI + performs the requested operation. + */ +typedef struct spi_instance spi_instance_t; + +/***************************************************************************//** + This function pointer type is to assign a callback function for TX interrupt + when slave wants to send the next updated frame. + + Declaring and Implementing Slave Frame Transmit Handler Functions: + Slave transmit frame update handler functions should follow the following + prototype: + void slave_tx_frame_update_handler ( spi_instance_t * this_spi ); + The actual name of the transmit handler is unimportant. You can use any name + of your choice for the frame update handler. + + A common handler function may be used when multiple CoreSPI instances are + configured as slave, as the particular slave device currently requiring + service is indicated by the function parameter. + */ +typedef void (*spi_slave_frame_tx_handler_t)( spi_instance_t * this_spi ); + +/***************************************************************************//** + This defines the function prototype that must be followed by the SPI slave + frame receive handler functions. These functions are registered with the SPI + driver through the SPI_set_frame_rx_handler() function. + + Declaring and Implementing the Slave Frame Receive Handler Functions: + The Slave frame receive handler functions should follow the following + prototype: + void slave_frame_receive_handler(uint32_t rx_frame); + The actual name of the receive handler is unimportant. You can use any name + of your choice for the receive frame handler. The rx_frame parameter contains + the value of the received frame. + + Separate handler functions are required for each slave instance as there is + no indication of the slave requiring service passed to the handler. + + */ +typedef void (*spi_frame_rx_handler_t)( uint32_t rx_frame ); + +/***************************************************************************//** + This defines the function prototype that must be followed by SPI slave + block receive handler functions. These functions are registered with the + SPI driver through the SPI_set_slave_block_buffers() function. + + Declaring and Implementing Slave Block Receive Handler Functions: + Slave block receive handler functions should follow the following prototype: + void spi_block_rx_handler ( uint8_t * rx_buff, uint16_t rx_size ); + The actual name of the receive handler is unimportant. You can use any name + of your choice for the receive frame handler. The rx_buff parameter contains + a pointer to the start of the received block. The rx_size parameter contains + the number of bytes of the received block. + + Separate handler functions are required for each slave instance as there is + no indication of the slave requiring service passed to the handler. + + */ +typedef void (*spi_block_rx_handler_t)( uint8_t * rx_buff, uint32_t rx_size ); + +/***************************************************************************//** + This enumeration is used to select a specific SPI slave device (0 to 7). It is + used as a parameter to the SPI_configure_master_mode(), SPI_set_slave_select(), + and SPI_clear_slave_select() functions. + */ +typedef enum __spi_slave_t +{ + SPI_SLAVE_0 = 0, + SPI_SLAVE_1 = 1, + SPI_SLAVE_2 = 2, + SPI_SLAVE_3 = 3, + SPI_SLAVE_4 = 4, + SPI_SLAVE_5 = 5, + SPI_SLAVE_6 = 6, + SPI_SLAVE_7 = 7, + SPI_MAX_NB_OF_SLAVES = 8 +} spi_slave_t; + +/***************************************************************************//** + This enumeration is used to indicate the current slave mode transfer type so + that we are not relying on buffer comparisons to dictate the logic of the driver. + */ +typedef enum __spi_sxfer_mode_t +{ + SPI_SLAVE_XFER_NONE = 0, /* Not configured yet */ + SPI_SLAVE_XFER_BLOCK = 1, /* Block transfers, with SSEND delimiting end of block */ + SPI_SLAVE_XFER_FRAME = 2 /* Single frame transfers */ +} spi_sxfer_mode_t; + +/***************************************************************************//** + There is one instance of this structure for each of the core SPIs. Instances + of this structure are used to identify a specific SPI. A pointer to an + instance of the spi_instance_t structure is passed as the first parameter to + SPI driver functions to identify which SPI should perform the requested operation. + */ +struct spi_instance{ + + /* Base address in the processor's memory map for the + registers of the CoreSPI instance being initialized */ + addr_t base_addr; /* Base address of SPI hardware instance */ + + uint32_t rx_frame; /* received data */ + + /* Internal transmit state: */ + const uint8_t * slave_tx_buffer; /* Pointer to slave transmit buffer */ + uint32_t slave_tx_size; /* Size of slave transmit buffer */ + uint32_t slave_tx_idx; /* Current index into slave transmit buffer */ + + /* Slave command response buffer: */ + const uint8_t * resp_tx_buffer; + uint32_t resp_buff_size; + uint32_t resp_buff_tx_idx; + spi_block_rx_handler_t cmd_handler; + uint32_t cmd_done; /* Flag which indicates response has been set up and + it is safe to pad with 0s once the response is sent */ + + /* Internal receive state: */ + uint8_t * slave_rx_buffer; /* Pointer to buffer where data received by a slave will be stored */ + uint32_t slave_rx_size; /* Slave receive buffer size */ + uint32_t slave_rx_idx; /* Current index into slave receive buffer */ + + /* Slave received frame handler: */ + spi_frame_rx_handler_t frame_rx_handler; /* Pointer to function that will be called when a frame + is received when the SPI block is configured as slave */ + /* Slave transmitted frame handler: */ + uint32_t slave_tx_frame; /* Value of the data frame that will be transmitted + when the SPI block is configured as slave */ + spi_slave_frame_tx_handler_t slave_tx_frame_handler; /* Callback function pointer to update slave_tx_frame */ + + /* Slave block rx handler: */ + spi_block_rx_handler_t block_rx_handler; /* Pointer to the function that will be called when a data block has been received */ + + /* Per instance specific hardware information that the driver needs to know */ + uint16_t fifo_depth; /* Depth of RX and TX FIFOs in frames */ + + /* How we are expecting to deal with slave transfers */ + spi_sxfer_mode_t slave_xfer_mode; /* Current slave mode transfer configuration */ +}; + +/*------------------------Public Function-------------------------------------*/ + +/***************************************************************************//** + The SPI_init() function initializes the hardware and data structures of a + CoreSPI instance referenced by this_spi parameter. This function must be + called for each CoreSPI instance with a unique this_spi and base_addr + parameter combination. The SPI_init() function must be called before any + other CoreSPI driver functions are called. + + After calling the SPI_init() the CoreSPI is configured as a master, + all interrupt sources will be masked and all the slaves are deselected. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to be initialized. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @param base_addr + The base_addr parameter is the base address in the processor's memory map for + the registers of the CoreSPI instance being initialized. It is assumed that + any non NULL value passed in here points to a valid instance of a CoreSPI as + the driver has no way of verifying this. Failure to pass in a valid address + can result in system instability. + + @param fifo_depth + The fifo_depth parameter specifies the number of frames in the receive + and transmit FIFOs of the CoreSPI instance being initialized. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + @endcode + */ +void SPI_init +( + spi_instance_t * this_spi, + addr_t base_addr, + uint16_t fifo_depth +); + +/***************************************************************************//** + The SPI_configure_slave_mode() function is used when a CoreSPI instance is + to be configured as a SPI slave. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to be configured. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + + int main(void) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_slave_mode ( &g _spi0 ); + } + @endcode + */ +void SPI_configure_slave_mode +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_configure_master_mode() function is used when a CoreSPI instance is + to be configured as a SPI master. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to be configured. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + + int main(void) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_master_mode ( &g _spi0 ); + } + @endcode + */ +void SPI_configure_master_mode +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_set_slave_select() function is used by a CoreSPI master to select a + specific slave. This function causes the relevant slave select signal to be + asserted while data is clocked out onto the SPI data line. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param slave + The slave parameter is one of the spi_slave_t enumerated constants + identifying a slave. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + const uint32_t master_tx_frame = 0x0100A0E1; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0 ); + SPI_transfer_frame( &g_spi0, master_tx_frame ); + SPI_clear_slave_select( &g_spi0, SPI_SLAVE_0 ); + + @endcode + */ +void SPI_set_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +); + +/***************************************************************************//** + The SPI_clear_slave_select() function is used by a CoreSPI master to + deselect a specific slave. This function causes the relevant slave select + signal to be de-asserted. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param slave + The slave parameter is one of the spi_slave_t enumerated constants + identifying a slave. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + const uint32_t master_tx_frame = 0x0100A0E1; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0 ); + SPI_transfer_frame( &g_spi0, master_tx_frame ); + SPI_clear_slave_select( &g_spi0, SPI_SLAVE_0 ); + @endcode + */ +void SPI_clear_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +); + +/***************************************************************************//** + The SPI_transfer_frame() function is used by a SPI master to transmit and + receive a single frame of the size that has been configured at the time of + CoreSPI hardware instantiation. This function is typically used for + transactions with a SPI slave where the number of transmit and receive bits + are not divisible by 8 or where full duplex exchange of frames is required. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param tx_bits + The tx_bits parameter is a 32-bit word containing the value that will be + transmitted. If the frame size configured for the CoreSPI is less than 32-bits, + the upper bits will be ignored. + Note: The bit length of the value to be transmitted to the slave is + set when the CoreSPI is instantiated in the hardware design. + + @return + This function returns a 32-bit word containing the value that is received + from the slave. If the frame size configured for the CoreSPI in question is + less that 32-bits, the upper bits will be 0. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + const uint32_t master_tx_frame = 0x0100A0E1; + uint32_t master_rx; + + SPI_init(&g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ); + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0 ); + master_rx = SPI_transfer_frame( &g_spi0, master_tx_frame ); + SPI_clear_slave_select( &g_spi0, SPI_SLAVE_0 ); + @endcode + */ +uint32_t SPI_transfer_frame +( + spi_instance_t * this_spi, + uint32_t tx_bits +); + +/***************************************************************************//** + The SPI_transfer_block() function is used by the SPI master to transmit and + receive blocks of data organized as a specified number of 8-bit frames. It + can be used for the following: + • Writing a data block to a slave + • Reading a data block from a slave + • Sending a command to a slave followed by reading the outcome of + the command in a single SPI transaction. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param cmd_buffer + The cmd_buffer parameter is a pointer to the buffer that contains the data + sent by the master from the beginning of the transfer. This pointer can be + null (0) if the master does not need to send a command before reading data. + + @param cmd_byte_size + The cmd_byte_size parameter specifies the number of bytes in cmd_buffer that + will be sent. A value ‘0’ indicates that no data needs to be sent to the slave. + + @param rx_buffer + The rx_buffer parameter is a pointer to the buffer that stores the data received + from the slave after sending the command. This pointer can be null (0) if the + master does not receive any data from the slave. + + @param rx_byte_size + The rx_byte_size parameter specifies the number of bytes received from + the slave and stored in the rx_buffer. A value ‘0’ indicates that no data is + to be read from the slave. + + @return + This function does not return any value. + + @example + @code + Polled write transfer example + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + + uint8_t master_tx_buffer[MASTER_TX_BUFFER] = + { + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A + }; + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0) ; + SPI_transfer_block + ( + &g_spi0, + master_tx_buffer, + sizeof(master_tx_buffer), + 0, + 0 + ); + SPI_clear_slave_select(&g_spi0, SPI_SLAVE_0 ); + @endcode + */ +void SPI_transfer_block +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_buffer, + uint16_t rx_byte_size +); + +/***************************************************************************//** + The SPI_transfer_block_store_all_resp() function is used by the SPI master + to transmit and receive blocks of data organized as a specified number + of 8-bit frames. It can be used for the following: + • Writing a data block to a slave + • Reading a data block from a slave + • Sending a command to a slave followed by reading the outcome of + the command in a single SPI transaction + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param cmd_buffer + The cmd_buffer parameter is a pointer to the buffer that contains the data sent by + the master from the beginning of the transfer. This pointer can be null (0) + if the master does not need to send a command before reading data. + + @param cmd_byte_size + The cmd_byte_size parameter specifies the number of bytes contained in + cmd_buffer that will be sent. A value ‘0’ indicates that no data needs + to be sent to the slave. + + @param rx_data_buffer + The rx_data_buffer parameter is a pointer to the buffer that stores the data received + from the slave after sending the command. This pointer can be null (0) if the + master does not receive any data from the slave. + + @param rx_byte_size + The rx_byte_size parameter specifies the number of bytes received from + the slave and stores in the rx_buffer. A value ‘0’ indicates that no data is + to be read from the slave. + + @param cmd_response_buffer + The cmd_response_buffer parameter is a pointer to the buffer which stores the + command response from the slave, while the master is transmitting the number + of bytes indicated by cmd_byte_size parameter. + + @return + This function does not return any value. + + @example + @code + Polled write transfer example + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + + uint8_t master_tx_buffer[MASTER_TX_BUFFER] = + { + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A + }; + + uint8_t cmd_rx_buffer[CMD_RX_BUFFER]={0}; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0) ; + SPI_transfer_block_store_all_resp + ( + &g_spi0, + master_tx_buffer, + sizeof(master_tx_buffer), + 0, + 0, + cmd_response_buffer + ); + SPI_clear_slave_select(&g_spi0, SPI_SLAVE_0 ); + @endcode + */ +void SPI_transfer_block_store_all_resp +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_data_buffer, + uint16_t rx_byte_size, + uint8_t * cmd_response_buffer +); + +/***************************************************************************//** + The SPI_set_frame_rx_handler() function is used by the SPI slaves to specify + the receive handler function that is called by the SPI driver interrupt + handler when a frame of data is received by the SPI slave. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param rx_handler + The rx_handler parameter is a pointer to the frame receive handler that must + be called when a frame is received by the CoreSPI slave. Passing in a NULL + pointer disables the receive handler but does enable the receive interrupt to + ensure the RX FIFO is empty each time a frame is received. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + uint32_t g_slave_rx_frame = 0; + spi_instance_t g_spi0; + + void slave_frame_handler(uint32_t rx_frame) + { + g_slave_rx_frame = rx_frame; + } + int setup_slave( void ) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_slave_mode( &g_spi0 ); + SPI_set_frame_rx_handler( &g_spi0, slave_frame_handler ); + } + @endcode + */ +void SPI_set_frame_rx_handler +( + spi_instance_t * this_spi, + spi_frame_rx_handler_t rx_handler +); + +/***************************************************************************//** + The SPI_set_slave_tx_frame() function is used by the SPI slaves to specify + the frame that gets transmitted when a transaction is initiated by the SPI + master. This function allows you to assign a slave_tx_frame_handler function, + which will be executed upon transmit interrupt when the SPI is in slave mode. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param frame_value + The frame_value parameter contains the value of the frame to be sent to the + master. + Note: The bit length of the value to be transmitted to the master is + set when the CoreSPI is instantiated in the hardware design. + + @param slave_tx_frame_handler + The slave_tx_frame_handler function pointer is executed upon occurrence of + transmit interrupt when CoreSPI is operating in slave mode. This parameter + is optional and if set to NULL it is assumed that the frame value is static or + updated asynchronously. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + const uint32_t slave_tx_frame[2] = { 0x0110F761, 0x0110F671 }; + uint32_t master_rx; + uint32_t slave_frame_idx = 0 ; + + slave_frame_update( spi_instance_t * this_spi ) + { + this_spi->slave_tx_frame = slave_tx_frame[slave_frame_idx++]; + if( slave_frame_idx > 2 ) + slave_frame_idx = 0; + } + main() + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ) ; + SPI_set_slave_tx_frame( &g_spi0, slave_tx_frame[slave_frame_idx++], + &slave_frame_update ); + } + @endcode + */ +void SPI_set_slave_tx_frame +( + spi_instance_t * this_spi, + uint32_t frame_value, + spi_slave_frame_tx_handler_t slave_tx_frame_handler +); + +/***************************************************************************//** + The SPI_set_slave_block_buffers() function is used to configure an SPI slave + for block transfer operations. It specifies one or more of the following: + • The data that is transmitted when accessed by a master. + • The buffer where the data received from a master is stored. + • The handler function that must be called after the receive buffer has + been filled. + • The number of bytes that must be received from the master before calling + the recieve handler function. + These parameters allow the following use cases: + • Slave performing an action after receiving a block of data from a + master containing a command. This action is performed by the + receive handler based on the content of the receive data buffer. + • Slave returning a block of data to the master. The type of information + is always the same but the actual values change over time. For example, + returning the voltage of a predefined set of analog inputs. + • Slave returning data based on a command contained in the first part of + the SPI transaction. For example, reading the voltage of the analog + input specified by the first data byte by the master. This is achieved + by using the SPI_set_slave_block_buffers() function in conjunction with + functions SPI_set_cmd_handler() and SPI_set_cmd_response(). + + See the SPI_set_cmd_handler() function description for details of + this use case. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param tx_buffer + The tx_buffer parameter is a pointer to a buffer containing the data that + will be sent to the master. This parameter can be set to ‘0’ if the SPI + slave is not intended to be the target of SPI read transactions. + + @param tx_buff_size + The tx_buff_size parameter specifies the number of bytes that are + transmitted by the SPI slave. It is the number of bytes contained in the + tx_buffer. This parameter can be set to ‘0’ if the SPI slave is not + intended to be the target of SPI read transactions. The driver returns 0s + to the master if there is no buffer specified or the master reads beyond the + end of the buffer. + Note: If SPI_transfer_block() is used to read from this slave and there is + no command handler involved, the buffer size here must be at least the + combined length of the command and response specified by the master. + On receiving this data, the master discards the data bytes equal to + command length bytes from the start of the received buffer. + + @param rx_buffer + The rx_buffer parameter is a pointer to the buffer where data received + from the master is stored. This parameter can be set to ‘0’ if the + SPI slave is not intended to be the target of SPI write or write-read + transactions. + + @param rx_buff_size + The rx_buff_size parameter specifies the size of the receive buffer. It is + also the number of bytes that must be received before the receive handler + is called, if a receive handler is specified using the block_rx_handler + parameter. Any bytes received in excess of the size specified by the + rx_buff_size parameter are discarded. This parameter can be set to ‘0’ + if the SPI slave is not intended to be the target of SPI write or + write-read transactions. + + @param block_rx_handler + The block_rx_handler parameter is a pointer to a function that is called + when receive buffer has been filled or the slave select has been de-asserted. + This parameter can be set to ‘0’ if the SPI slave is not intended to be the + target of SPI write or write-read transactions. + + @return + This function does not return any value. + + @example + @code + Slave Performing Operation Based on Master Command: + In this example the SPI slave is configured to receive 10 bytes of data + or command from the SPI slave, and process the data received from the master. + + #define SPI0_BASE_ADDR 0xC2000000 + + uint32_t nb_of_rx_handler_calls = 0; + spi_instance_t g_spi0; + + void spi1_block_rx_handler_b + ( + uint8_t * rx_buff, + uint16_t rx_size + ) + { + ++nb_of_rx_handler_calls; + } + + void setup_slave( void ) + { + uint8_t slave_rx_buffer[10] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_slave_mode( &g_spi0 ); + + SPI_set_slave_block_buffers + ( + &g_spi0, + 0, + 0, + slave_rx_buffer, + sizeof( master_tx_buffer ), + spi1_block_rx_handler_b + ); + } + @endcode + */ +void SPI_set_slave_block_buffers +( + spi_instance_t * this_spi, + const uint8_t * tx_buffer, + uint32_t tx_buff_size, + uint8_t * rx_buffer, + uint32_t rx_buff_size, + spi_block_rx_handler_t block_rx_handler +); + +/***************************************************************************//** + The SPI_isr() function is the top level interrupt handler function for the + CoreSPI driver. You must call SPI_isr() from the system level + (CoreInterrupt and NVIC level) interrupt handler assigned to the interrupt + triggered by the CoreSPI SPIINT signal. Your system level interrupt handler + must also clear the system level interrupt triggered by the CoreSPI SPIINT + signal before returning, to prevent a re-assertion of the same interrupt. + + This function supports all types of interrupt triggered by CoreSPI. It is not + a complete interrupt handler by itself; rather, it is a top level wrapper that + abstracts CoreSPI command interrupt and slave mode transmit interrupt handling + by calling lower level handler functions specific to each type of CoreSPI + interrupt. You must create the lower level handler functions to suit your + application and register them with the driver through calling the + SPI_set_cmd_handler(), SPI_set_cmd_response(), and SPI_set_slave_tx_frame() + functions. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + + @example + @code + + Example of configuring a CoreInterrupt connected to the Fabric Interrupt on a + SmartFusion device to handle CoreSPI interrupt. + + #define #define SPI1_INT_IRQ_NB 0 + spi_instance_t g_spi0; + + Void CIC_irq1_handler(void) + { + SPI_isr( &g_spi0 ); + } + + void Fabric_IRQHandler( void ) + { + // Call the CoreInterrupt driver ISR to determine the source of the + // interrupt and call the relevant ISR registered to it. + CIC_irq_handler(); + + // Clear NVIC interrupt status to allow further interrupts + NVIC_ClearPendingIRQ( Fabric_IRQn ); + } + + main() + { + ... + + CIC_init( CIC_BASE_ADDR ); + + // Install handler for SPI IRQ + CIC_set_irq_handler( SPI0_INT_IRQ_NB, CIC_irq1_handler ); + + NVIC_ClearPendingIRQ( Fabric_IRQn ); + NVIC_EnableIRQ( Fabric_IRQn ); + + CIC_enable_irq( SPI1_INT_IRQ_NB ); + + ... + } + @endcode + */ +void SPI_isr +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_set_cmd_handler() function specifies a command handler function that + will be called when the number of bytes received reaches the command size + specified as cmd_size parameter. + + This function is used by the SPI slaves performing block transfers. Its + purpose is to allow an SPI slave to decide the data that will be returned to + the master while an SPI transaction is taking place. Typically, one or more + command bytes are sent by the master to request some specific data. The slave + interprets the command byte(s) while one or more turn-around bytes are + transmitted. The slave adjusts its transmit data buffer based on the command + during the turn around time. + + The following table provides an example of the use of this function where the + SPI slave returns data bytes D0 to D6 based on the value of a command. The + 3 bytes long command is made up of a command opcode byte followed by an + address byte followed by a size byte. The cmd_handler() function specified + through an earlier call to SPI_set_cmd_handler() is called by the CoreSPI + driver once the third byte is received. The cmd_handler() function + interprets the command bytes and calls SPI_set_cmd_response() to set the SPI + slave's response transmit buffer with the data to be transmitted after the + turnaround bytes (T0 to T3). The number of turnaround bytes must be + sufficient to give enough time for the cmd_handler() to execute. The number + of turnaround bytes is specified by the protocol used on top of the SPI + transport layer so that master and slave agree on the number of turn around + bytes. + +|Timestamp| SPI Transaction | Bytes | Comments | +|---------|-------------|----------------------|---------------| +| t0|COMMAND|C A S |C - command opcode byte, A - address byte, S - size byte| +|t1| TURN-AROUND|T0 T1 |cmd_handler() called here (T0 to T3 are TURN-AROUND bytes)| +|t2|TURN-AROUND|T2 T3|SPI_set_cmd_response() called here by implementation of cmd_handler() +|| | |to set the data that will be transmitted by the SPI slave.| +|t3| DATA | D0 D1 D2 D3 D4 D5 D6 |Data transmition (SPI slave return data bytes)| + + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure identifying + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @param cmd_handler + The cmd_handler parameter is a pointer to a function with the prototype: + void cmd_handler(uint8_t * rx_buff, uint32_t rx_size); + It specifies the function that will be called when the number of bytes + specified by the cmd_size parameter has been received. + + @param cmd_size + The cmd_size parameter specifies the number of bytes that must be received + before calling the command handler function specified by the cmd_handler. + The CoreSPI supports cmd_size values in the range 1 to 7. + + @return + This function does not return any value. + + @example + @code + The following example demonstrates how to configure CoreSPI to implement + the protocol given as an example above. The configure_slave() function + configures CoreSPI. It sets receive and transmit buffers. The transmit + buffer specified through the call to SPI_set_slave_block_buffers() function + specifies the data that will be returned to the master in bytes between + t0 and t3. These bytes will be sent to the master while the master transmits + the command and dummy bytes. The spi_slave_cmd_handler() function will be + called by the driver at time t1 after the 3 command bytes have been received. + The spi_block_rx_handler() function will be called by the driver at time t4, + when the transaction completes and the slave select signal becomes + de-asserted. + + #define SPI0_BASE_ADDR 0xC2000000 + #define COMMAND_SIZE 3 + #define NB_OF_DUMMY_BYTES 4 + #define MAX_TRANSACTION_SIZE 16 + + spi_instance_t g_spi0; + uint8_t slave_tx_buffer[COMMAND_SIZE + NB_OF_DUMMY_BYTES]; + uint8_t slave_rx_buffer[MAX_TRANSACTION_SIZE]; + + void configure_slave( void ) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_slave_mode( &g_spi0 ); + SPI_set_slave_block_buffers + ( + &g_spi0, + slave_tx_buffer, + COMMAND_SIZE + NB_OF_DUMMY_BYTES, + slave_rx_buffer, + sizeof(slave_rx_buffer), + spi_block_rx_handler + ); + + SPI_set_cmd_handler + ( + &g_spi0, + spi_slave_cmd_handler, + COMMAND_SIZE + ); + } + + void spi_slave_cmd_handler + ( + uint8_t * rx_buff, + uint32_t rx_size + ) + { + uint8_t command; + uint8_t address; + uint8_t size; + uint8_t * p_response; + uint32_t response_size; + + command = rx_buff[0]; + address = rx_buff[1]; + size = rx_buff[2]; + + p_response = get_response_data( command, address, size, &response_size ); + SPI_set_cmd_response( &g_spi0, p_response, response_size ); + } + + void spi_block_rx_handler + ( + uint8_t * rx_buff, + uint32_t rx_size + ) + { + process_rx_data( rx_buff, rx_size ); + } + @endcode + */ +void SPI_set_cmd_handler +( + spi_instance_t * this_spi, + spi_block_rx_handler_t cmd_handler, + uint32_t cmd_size +); + +/***************************************************************************//** + The SPI_set_cmd_response() function specifies the data that will be returned + to the master. See the description of SPI_set_cmd_handler() for details. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param resp_tx_buffer + The resp_tx_buffer parameter is a pointer to the buffer containing the data + that must be returned to the host in the data phase of an SPI transaction. + + @param resp_buff_size + The resp_buff_size parameter specifies the size of the buffer pointed by the + resp_tx_buffer parameter. + + @return + This function does not return any value. + */ +void SPI_set_cmd_response +( + spi_instance_t * this_spi, + const uint8_t * resp_tx_buffer, + uint32_t resp_buff_size +); + +/***************************************************************************//** + The SPI_enable() function enables the CoreSPI and allows it to respond to the external + signals. It is usually called to re-enable a CoreSPI instance which has been + disabled previously via by calling the SPI_disable() as the normal state of a CoreSPI + after enabling the initialization. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + */ +void SPI_enable +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_disable() function disables the CoreSPI and stops responding to the + external signals. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + */ +void SPI_disable +( + spi_instance_t * this_spi +); + +#ifdef __cplusplus +} +#endif + +#endif /* CORE_SPI_H_*/ diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreSPI/corespi_regs.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreSPI/corespi_regs.h new file mode 100644 index 0000000..a3e5b2a --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreSPI/corespi_regs.h @@ -0,0 +1,270 @@ +/***************************************************************************//** + * Copyright 2011-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file corespi_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreSPI memory map + * + */ + +#ifndef CORESPI_REGS_H_ +#define CORESPI_REGS_H_ + +/******************************************************************************* + * Control register 1: + *------------------------------------------------------------------------------ + */ +#define CTRL1_REG_OFFSET 0x00u + +#define CTRL1_ENABLE_OFFSET 0x00u +#define CTRL1_ENABLE_MASK 0x01u +#define CTRL1_ENABLE_SHIFT 0x00 + +#define CTRL1_MASTER_OFFSET 0x00u +#define CTRL1_MASTER_MASK 0x02u +#define CTRL1_MASTER_SHIFT 0x01 + +#define CTRL1_INTRXDATA_OFFSET 0x00u +#define CTRL1_INTRXDATA_MASK 0x04u +#define CTRL1_INTRXDATA_SHIFT 0x02 + +#define CTRL1_INTTXDONE_OFFSET 0x00u +#define CTRL1_INTTXDONE_MASK 0x08u +#define CTRL1_INTTXDONE_SHIFT 0x03 + +#define CTRL1_INTRXOVFLOW_OFFSET 0x00u +#define CTRL1_INTRXOVFLOW_MASK 0x10u +#define CTRL1_INTRXOVFLOW_SHIFT 0x04 + +#define CTRL1_INTTXURUN_OFFSET 0x00u +#define CTRL1_INTTXURUN_MASK 0x20u +#define CTRL1_INTTXURUN_SHIFT 0x05 + +#define CTRL1_FRAMEURUN_OFFSET 0x00u +#define CTRL1_FRAMEURUN_MASK 0x40u +#define CTRL1_FRAMEURUN_SHIFT 0x06 + +#define CTRL1_OENOFF_OFFSET 0x00u +#define CTRL1_OENOFF_MASK 0x80u +#define CTRL1_OENOFF_SHIFT 0x07 + +/******************************************************************************* + * Interrupt clear register: + *------------------------------------------------------------------------------ + */ +#define INTCLR_REG_OFFSET 0x04u + +#define INTCLR_TXDONE_OFFSET 0x04u +#define INTCLR_TXDONE_MASK 0x01u +#define INTCLR_TXDONE_SHIFT 0x00 + +#define INTCLR_RXDONE_OFFSET 0x04u +#define INTCLR_RXDONE_MASK 0x02u +#define INTCLR_RXDONE_SHIFT 0x01 + +#define INTCLR_RXOVERFLOW_OFFSET 0x04u +#define INTCLR_RXOVERFLOW_MASK 0x04u +#define INTCLR_RXOVERFLOW_SHIFT 0x02 + +#define INTCLR_TXUNDERRUN_OFFSET 0x04u +#define INTCLR_TXUNDERRUN_MASK 0x08u +#define INTCLR_TXUNDERRUN_SHIFT 0x03 + +#define INTCLR_CMDINT_OFFSET 0x04u +#define INTCLR_CMDINT_MASK 0x10u +#define INTCLR_CMDINT_SHIFT 0x04 + +#define INTCLR_SSEND_OFFSET 0x04u +#define INTCLR_SSEND_MASK 0x20u +#define INTCLR_SSEND_SHIFT 0x05 + +#define INTCLR_RXDATA_OFFSET 0x04u +#define INTCLR_RXDATA_MASK 0x40u +#define INTCLR_RXDATA_SHIFT 0x06 + +#define INTCLR_TXDATA_OFFSET 0x04u +#define INTCLR_TXDATA_MASK 0x80u +#define INTCLR_TXDATA_SHIFT 0x07 + +/******************************************************************************* + * Receive data register: + *------------------------------------------------------------------------------ + */ +#define RXDATA_REG_OFFSET 0x08u + +/******************************************************************************* + * Transmit data register: + *------------------------------------------------------------------------------ + */ +#define TXDATA_REG_OFFSET 0x0Cu + +/******************************************************************************* + * Masked interrupt status register: + *------------------------------------------------------------------------------ + */ +#define INTMASK_REG_OFFSET 0x10u + +#define INTMASK_TXDONE_OFFSET 0x10u +#define INTMASK_TXDONE_MASK 0x01u +#define INTMASK_TXDONE_SHIFT 0x00 + +#define INTMASK_RXDONE_OFFSET 0x10u +#define INTMASK_RXDONE_MASK 0x02u +#define INTMASK_RXDONE_SHIFT 0x01 + +#define INTMASK_RXOVERFLOW_OFFSET 0x10u +#define INTMASK_RXOVERFLOW_MASK 0x04u +#define INTMASK_RXOVERFLOW_SHIFT 0x02 + +#define INTMASK_TXUNDERRUN_OFFSET 0x10u +#define INTMASK_TXUNDERRUN_MASK 0x08u +#define INTMASK_TXUNDERRUN_SHIFT 0x03 + +#define INTMASK_CMDINT_OFFSET 0x10u +#define INTMASK_CMDINT_MASK 0x10u +#define INTMASK_CMDINT_SHIFT 0x04 + +#define INTMASK_SSEND_OFFSET 0x10u +#define INTMASK_SSEND_MASK 0x20u +#define INTMASK_SSEND_SHIFT 0x05 + +#define INTMASK_RXDATA_OFFSET 0x10u +#define INTMASK_RXDATA_MASK 0x40u +#define INTMASK_RXDATA_SHIFT 0x06 + +#define INTMASK_TXDATA_OFFSET 0x10u +#define INTMASK_TXDATA_MASK 0x80u +#define INTMASK_TXDATA_SHIFT 0x07 + +/******************************************************************************* + * Raw interrupt status register: + *------------------------------------------------------------------------------ + */ +#define INTRAW_REG_OFFSET 0x14u + +#define INTRAW_TXDONE_OFFSET 0x14u +#define INTRAW_TXDONE_MASK 0x01u +#define INTRAW_TXDONE_SHIFT 0x00 + +#define INTRAW_RXDONE_OFFSET 0x14u +#define INTRAW_RXDONE_MASK 0x02u +#define INTRAW_RXDONE_SHIFT 0x01 + +#define INTRAW_RXOVERFLOW_OFFSET 0x14u +#define INTRAW_RXOVERFLOW_MASK 0x04u +#define INTRAW_RXOVERFLOW_SHIFT 0x02 + +#define INTRAW_TXUNDERRUN_OFFSET 0x14u +#define INTRAW_TXUNDERRUN_MASK 0x08u +#define INTRAW_TXUNDERRUN_SHIFT 0x03 + +#define INTRAW_CMDINT_OFFSET 0x14u +#define INTRAW_CMDINT_MASK 0x10u +#define INTRAW_CMDINT_SHIFT 0x04 + +#define INTRAW_SSEND_OFFSET 0x14u +#define INTRAW_SSEND_MASK 0x20u +#define INTRAW_SSEND_SHIFT 0x05 + +#define INTRAW_RXDATA_OFFSET 0x14u +#define INTRAW_RXDATA_MASK 0x40u +#define INTRAW_RXDATA_SHIFT 0x06 + +#define INTRAW_TXDATA_OFFSET 0x14u +#define INTRAW_TXDATA_MASK 0x80u +#define INTRAW_TXDATA_SHIFT 0x07 + +/******************************************************************************* + * Control register 2: + *------------------------------------------------------------------------------ + */ +#define CTRL2_REG_OFFSET 0x18u + +#define CTRL2_CMDSIZE_OFFSET 0x18u +#define CTRL2_CMDSIZE_MASK 0x07u +#define CTRL2_CMDSIZE_SHIFT 0x00 + +#define CTRL2_INTCMD_OFFSET 0x18u +#define CTRL2_INTCMD_MASK 0x10u +#define CTRL2_INTCMD_SHIFT 0x04 + +#define CTRL2_INTSSEND_OFFSET 0x18u +#define CTRL2_INTSSEND_MASK 0x20u +#define CTRL2_INTSSEND_SHIFT 0x05 + +#define CTRL2_INTRXDATA_OFFSET 0x18u +#define CTRL2_INTRXDATA_MASK 0x40u +#define CTRL2_INTRXDATA_SHIFT 0x06 + +#define CTRL2_INTTXDATA_OFFSET 0x18u +#define CTRL2_INTTXDATA_MASK 0x80u +#define CTRL2_INTTXDATA_SHIFT 0x07 + +/******************************************************************************* + * Command register: + *------------------------------------------------------------------------------ + */ +#define CMD_REG_OFFSET 0x1Cu + +#define CMD_RXFIFORST_OFFSET 0x1Cu +#define CMD_RXFIFORST_MASK 0x01u +#define CMD_RXFIFORST_SHIFT 0x00 + +#define CMD_TXFIFORST_OFFSET 0x1Cu +#define CMD_TXFIFORST_MASK 0x02u +#define CMD_TXFIFORST_SHIFT 0x01 + +/******************************************************************************* + * Status register: + *------------------------------------------------------------------------------ + */ +#define STATUS_REG_OFFSET 0x20u + +#define STATUS_FIRSTFRAME_OFFSET 0x20u +#define STATUS_FIRSTFRAME_MASK 0x01u +#define STATUS_FIRSTFRAME_SHIFT 0x00 + +#define STATUS_DONE_OFFSET 0x20u +#define STATUS_DONE_MASK 0x02u +#define STATUS_DONE_SHIFT 0x01 + +#define STATUS_RXEMPTY_OFFSET 0x20u +#define STATUS_RXEMPTY_MASK 0x04u +#define STATUS_RXEMPTY_SHIFT 0x02 + +#define STATUS_TXFULL_OFFSET 0x20u +#define STATUS_TXFULL_MASK 0x08u +#define STATUS_TXFULL_SHIFT 0x03 + +#define STATUS_RXOVFLOW_OFFSET 0x20u +#define STATUS_RXOVFLOW_MASK 0x10u +#define STATUS_RXOVFLOW_SHIFT 0x04 + +#define STATUS_TXUNDERRUN_OFFSET 0x20u +#define STATUS_TXUNDERRUN_MASK 0x20u +#define STATUS_TXUNDERRUN_SHIFT 0x05 + +#define STATUS_SSEL_OFFSET 0x20u +#define STATUS_SSEL_MASK 0x40u +#define STATUS_SSEL_SHIFT 0x06 + +#define STATUS_ACTIVE_OFFSET 0x20u +#define STATUS_ACTIVE_MASK 0x80u +#define STATUS_ACTIVE_SHIFT 0x07 + +/******************************************************************************* + * Slave select register: + *------------------------------------------------------------------------------ + */ +#define SSEL_REG_OFFSET 0x24u + +/******************************************************************************* + * Transmit data last register: + *------------------------------------------------------------------------------ + */ +#define TXLAST_REG_OFFSET 0x28u + + +#endif /*CORESPI_REGS_H_*/ diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.c b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.c new file mode 100644 index 0000000..b8adaed --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.c @@ -0,0 +1,889 @@ +/******************************************************************************* + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * PF_System_Services driver implementation. See file "core_syservices_pf.h" for + * description of the functions implemented in this file. + * + */ + +#include "core_sysservices_pf.h" +#include "coresysservicespf_regs.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define NULL_BUFFER (( uint8_t* ) 0) + +static uint8_t execute_ss_command +( + uint8_t cmd_opcode, + const uint8_t* cmd_data, + uint16_t cmd_data_size, + const uint8_t* p_response, + uint16_t response_size, + uint16_t mb_offset, + uint16_t response_offset +); + +uint32_t g_css_pf_base_addr = 0u; + +/***************************************************************************//** + * SYS_init() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +void +SYS_init +( + uint32_t base_addr +) +{ + g_css_pf_base_addr = base_addr; +} + +/***************************************************************************//** + * SYS_get_serial_number() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_serial_number +( + const uint8_t * p_serial_number, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if (p_serial_number == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(SERIAL_NUMBER_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_serial_number, + SERIAL_NUMBER_RESP_LEN, + mb_offset, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_get_user_code() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_user_code +( + const uint8_t * p_user_code, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_user_code == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(USERCODE_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_user_code, + USERCODE_RESP_LEN, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_get_design_info() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_design_info +( + const uint8_t * p_design_info, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_design_info == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(DESIGN_INFO_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_design_info, + DESIGN_INFO_RESP_LEN, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_get_device_certificate() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_device_certificate +( + const uint8_t * p_device_certificate, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_device_certificate == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(DEVICE_CERTIFICATE_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_device_certificate, + DEVICE_CERTIFICATE_RESP_LEN, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_read_digest() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_read_digest +( + const uint8_t * p_digest, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_digest == NULL_BUFFER) + { + return status; + } + +#ifndef CORESYSSERVICES_MPFS + status = execute_ss_command(READ_DIGEST_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_digest, + READ_DIGEST_RESP_LEN, + mb_offset, + 0u); +#else + status = execute_ss_command(READ_DIGEST_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_digest, + READ_DIGEST_MPFS_RESP_LEN, + mb_offset, + 0u); +#endif + return status; + +} + +/***************************************************************************//** + * SYS_query_security() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_query_security +( + uint8_t * p_security_locks, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint8_t idx = 0u; + + if(p_security_locks == NULL_BUFFER) + { + return status; + } + +#ifndef CORESYSSERVICES_MPFS + uint8_t buf[12] = {0}; + /* Actual QUERY_SECURITY_RESP_LEN is 9 or 33 but PF_System_Services core + * needs number of words instead of number of bytes to be written to or read + * from MailBox */ + status = execute_ss_command(QUERY_SECURITY_REQUEST_CMD, + NULL_BUFFER, + 0u, + buf, + (QUERY_SECURITY_RESP_LEN + 3u), + mb_offset, + 0u); + + for (idx = 0u; idx < 9u; idx++) + { + *(p_security_locks+idx) = buf[idx]; + } + +#else + uint8_t buf[36] = {0}; + + status = execute_ss_command(QUERY_SECURITY_REQUEST_CMD, + NULL_BUFFER, + 0u, + buf, + (QUERY_SECURITY_MPFS_RESP_LEN + 3u), + mb_offset, + 0u); + + for (idx = 0u; idx < 33u; idx++) + { + *(p_security_locks+idx) = buf[idx]; + } + +#endif + + return status; +} + +/***************************************************************************//** + * SYS_read_debug_info() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_read_debug_info +( + const uint8_t * p_debug_info, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_debug_info == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(READ_DEBUG_INFO_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_debug_info, + READ_DEBUG_INFO_RESP_LEN, + mb_offset, + 0u); + return status; +} + +#ifdef CORESYSSERVICES_MPFS +/***************************************************************************//** + * SYS_read_envm_parameter() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_read_envm_parameter +( + uint8_t * p_envm_param, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_envm_param == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(READ_ENVM_PARAM_REQUEST_CMD, + NULL_BUFFER, + 0, + p_envm_param, + READ_ENVM_PARAM_RESP_LEN, + mb_offset, + 0); + return status; +} + +#endif + +/***************************************************************************//** + * SYS_puf_emulation_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_puf_emulation_service +( + const uint8_t * p_challenge, + uint8_t op_type, + uint8_t* p_response, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint8_t mb_format[20] = {0x00}; + uint8_t index = 0u; + + if((p_response == NULL_BUFFER) || (p_challenge == NULL_BUFFER)) + { + return status; + } + + /* Frame the data required for mailbox */ + mb_format[index] = op_type; + + for (index = 4u; index < 20u; index++) + { + mb_format[index] = p_challenge[index - 4u]; + } + + status = execute_ss_command(PUF_EMULATION_SERVICE_REQUEST_CMD, + mb_format, + PUF_EMULATION_SERVICE_CMD_LEN, + p_response, + PUF_EMULATION_SERVICE_RESP_LEN, + mb_offset, + 5u); /* mentioning offset to number of words instead of bytes */ + + return status; +} + +/***************************************************************************//** + * SYS_digital_signature_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_digital_signature_service +( + const uint8_t* p_hash, + uint8_t format, + uint8_t* p_response, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if((p_hash == NULL_BUFFER) || (p_response == NULL_BUFFER)) + { + return status; + } + + if (format == DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD) + { + status = execute_ss_command(DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD, + p_hash, + DIGITAL_SIGNATURE_HASH_LEN, + p_response, + DIGITAL_SIGNATURE_RAW_FORMAT_RESP_SIZE, + mb_offset, + 12u); /* mentioning offset to number of words instead of bytes */ + } + else + { + status = execute_ss_command(DIGITAL_SIGNATURE_DER_FORMAT_REQUEST_CMD, + p_hash, + DIGITAL_SIGNATURE_HASH_LEN, + p_response, + DIGITAL_SIGNATURE_DER_FORMAT_RESP_SIZE, + mb_offset, + 12u); /* mentioning offset to number of words instead of bytes */ + } + + return status; +} + +/***************************************************************************//** + * SYS_secure_nvm_write() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_secure_nvm_write +( + uint8_t format, + uint8_t snvm_module, + const uint8_t* p_data, + const uint8_t* p_user_key, + uint16_t mb_offset +) +{ + uint8_t frame[256] = {0x00}; + uint8_t* p_frame = &frame[0]; + uint16_t index = 0u; + uint8_t status = SYS_PARAM_ERR; + + HAL_ASSERT(!(NULL_BUFFER == p_data)); + HAL_ASSERT(!(snvm_module >= 221u)); + if (format != SNVM_NON_AUTHEN_TEXT_REQUEST_CMD) + { + HAL_ASSERT(!(NULL_BUFFER == p_user_key)); + } + + if ((p_data == NULL_BUFFER) || (snvm_module >= 221)) + { + return status; + } + + if ((format != SNVM_NON_AUTHEN_TEXT_REQUEST_CMD) + && (p_user_key == NULL_BUFFER)) + { + return status; + } + + if ((format != SNVM_NON_AUTHEN_TEXT_REQUEST_CMD) + && (format != SNVM_AUTHEN_TEXT_REQUEST_CMD) + && (format != SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD)) + { + return status; + } + + *p_frame = snvm_module; /* SNVMADDR - SNVM module */ + + p_frame += 4u; /* Next 3 bytes RESERVED - For alignment */ + + /* Copy user key and send the command/data to mailbox. */ + if ((format == SNVM_AUTHEN_TEXT_REQUEST_CMD) || + (format == SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD)) + { + /* Copy user data */ + for (index = 0u; index < (AUTHENTICATED_TEXT_DATA_LEN - USER_SECRET_KEY_LEN - 4u); index++) + { + *p_frame = p_data[index]; + p_frame++; + } + + /* Copy user key */ + for (index = 0u; index < USER_SECRET_KEY_LEN; index++) + { + *p_frame = p_user_key[index]; + p_frame++; + } + + status = execute_ss_command(format, + &frame[0], + AUTHENTICATED_TEXT_DATA_LEN, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + } + else + { + /* Copy user data */ + for (index = 0u; index < (NON_AUTHENTICATED_TEXT_DATA_LEN - 4u); index++) + { + *(p_frame+index) = p_data[index]; + } + + status = execute_ss_command(format, + &frame[0], + NON_AUTHENTICATED_TEXT_DATA_LEN, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + } + + return status; +} + +/***************************************************************************//** + * SYS_secure_nvm_read() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_secure_nvm_read +( + uint8_t snvm_module, + const uint8_t* p_user_key, + uint8_t* p_admin, + uint8_t* p_data, + uint16_t data_len, + uint16_t mb_offset +) +{ + /* Frame the message. */ + uint8_t frame[16] = {0x00u}; + uint8_t* p_frame = &frame[0u]; + uint8_t status = SYS_PARAM_ERR; + uint8_t response[256] = {0x00u}; + uint16_t index = 0u; + + HAL_ASSERT(!(NULL_BUFFER == p_data)); + HAL_ASSERT(!(NULL_BUFFER == p_admin)); + HAL_ASSERT(!(snvm_module > 221u)); + + HAL_ASSERT(data_len == 236u || data_len == 252u); + + if((p_data == NULL_BUFFER) || + (snvm_module >= 221) || + (p_admin == NULL_BUFFER)) + { + return status; + } + + *p_frame = snvm_module; /* SNVMADDR - SNVM module */ + + p_frame += 4u; /* RESERVED - For alignment */ + + /* Copy user key */ + if (236u == data_len) + { + HAL_ASSERT(p_user_key != NULL_BUFFER); + + if(p_user_key == NULL_BUFFER) + { + return status; + } + + for (index = 0u; index < 12u; index++) + { + *p_frame = p_user_key[index]; + p_frame++; + } + } + else + { + p_frame += 12u; + } + + status = execute_ss_command(SNVM_READ_REQUEST_CMD, + &frame[0], + 16u, + response, + (data_len + 4u), + mb_offset, + 4u); /* mentioning offset to number of words instead of bytes */ + + if (SYS_SUCCESS == status) + { + for (index = 0u; index < 4u; index++) + { + *(p_admin+index) = (uint32_t)response[index]; + } + + + /* Copy data into user buffer. */ + for (index = 4u; index < (data_len + 4u); index++) + { + *(p_data + (index - 4u)) = response[index]; + } + } + else + { + ; + } + + return status; +} + +/***************************************************************************//** + * SYS_nonce_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_nonce_service +( + const uint8_t * p_nonce, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if((p_nonce == NULL_BUFFER)) + { + return status; + } + + status = execute_ss_command(NONCE_SERVICE_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_nonce, + NONCE_SERVICE_RESP_LEN, + mb_offset, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_bitstream_authenticate_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_bitstream_authenticate_service +( + uint32_t spi_flash_address, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint32_t l_spi_flash_address = spi_flash_address; + status = execute_ss_command(BITSTREAM_AUTHENTICATE_CMD, + (uint8_t* )&l_spi_flash_address, + 4u, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_IAP_image_authenticate_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_IAP_image_authenticate_service +( + uint8_t spi_idx +) +{ + uint8_t status = SYS_PARAM_ERR; + + HAL_ASSERT(!(spi_idx == 1u)); + + if (spi_idx == 1u) + { + return status; + } + + status = execute_ss_command(IAP_BITSTREAM_AUTHENTICATE_CMD, + NULL_BUFFER, + 0u, + NULL_BUFFER, + 0u, + spi_idx, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_digest_check_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_digest_check_service +( + uint32_t options, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint32_t l_options = options; + + status = execute_ss_command(DIGEST_CHECK_CMD, + (uint8_t* )&l_options, + 4u, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_iap_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_iap_service +( + uint8_t iap_cmd, + uint32_t spiaddr, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint16_t l_mb_offset = 0u; + uint16_t cmd_data_size = 0u; + uint8_t* cmd_data = NULL_BUFFER; + bool invalid_param = false; + + if (((IAP_PROGRAM_BY_SPIIDX_CMD == iap_cmd) + || (IAP_VERIFY_BY_SPIIDX_CMD == iap_cmd)) + && (1u == spiaddr)) + { + invalid_param = true; + HAL_ASSERT(!invalid_param); + } + + if (!invalid_param) + { + switch(iap_cmd) + { + case IAP_PROGRAM_BY_SPIIDX_CMD: + case IAP_VERIFY_BY_SPIIDX_CMD: + /*In SPI_IDX based program and verify commands, + * Mailbox is not Required. Instead of mailbox offset + * SPI_IDX is passed as parameter.*/ + l_mb_offset = (uint16_t)(0xFFu & spiaddr); + break; + + case IAP_PROGRAM_BY_SPIADDR_CMD: + case IAP_VERIFY_BY_SPIADDR_CMD: + /*In SPI_ADDR based program and verify commands, + * Mailbox is Required*/ + l_mb_offset = mb_offset; + /*command data size is four bytes holding the + * SPI Address in it.*/ + cmd_data_size = 4u; + cmd_data = (uint8_t*)&spiaddr; + break; + + case IAP_AUTOUPDATE_CMD: + /*In auto update command Mailbox is not Required*/ + l_mb_offset = 0u; + break; + + default: + l_mb_offset = 0u; + + } + + status = execute_ss_command( + (uint8_t)iap_cmd, + cmd_data, + cmd_data_size, + NULL_BUFFER, + 0, + (uint16_t)l_mb_offset, + 0); + } + + return status; +} + +/***************************************************************************//** + Internal functions. +*/ +/* +This function executes the SS command. If Mailbox input data is required by the +it will first load it from cmd_data into the Mailbox. If the service requires +the response data to be read from mailbox, it will do so and store it in p_response. +*/ +static uint8_t execute_ss_command +( + uint8_t cmd_opcode, + const uint8_t* cmd_data, + uint16_t cmd_data_size, + const uint8_t* p_response, + uint16_t response_size, + uint16_t mb_offset, + uint16_t response_offset +) +{ + /* Pointer used during Writing to Mailbox memory. */ + uint32_t status = 0u; + uint16_t idx = 0u; + uint16_t ss_command = 0u; + uint32_t* word_buf; + uint16_t timeout_count = SS_TIMEOUT_COUNT; + + /* making sure that the system controller is not executing any service i.e. + SS_USER_BUSY is gone 0 */ + + while (1u == HAL_get_32bit_reg_field(g_css_pf_base_addr, SS_USER_BUSY)) + { + --timeout_count; + + if (timeout_count == 0) + { + return SS_USER_BUSY_TIMEOUT; + } + } + + /* Form the SS command: bit 0to6 is the opcode, bit 7to15 is the Mailbox offset + For some services this field has another meaning + (e.g. for IAP bitstream auth. it means spi_idx) */ + ss_command = ((mb_offset << 7u) | (cmd_opcode & 0x7Fu)); + + /* Load the command register with the SS request command code*/ + HAL_set_32bit_reg(g_css_pf_base_addr, SS_CMD, ss_command); + + if (cmd_data_size > 0u) + { + HAL_ASSERT(!(NULL_BUFFER == cmd_data)); + HAL_ASSERT(!(cmd_data_size % 4u)); + + /* Load the MBX_WCNT register with number of words */ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_WCNT, (cmd_data_size/4u)); + + /* Load the MBX_WADDR register with offset of input data (write to Mailbox) + For all the services this offset remains either 0 or Not applicable + for the services in which no Mailbox write is required.*/ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_WADDR, (0x00u + mb_offset)); + + } + + if (response_size > 0u) + { + HAL_ASSERT(!(NULL_BUFFER == p_response)); + HAL_ASSERT(!(response_size % 4u)); + + /* + Load the MBX_RWCNT register with number of words to be read from Mailbox + */ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_RCNT, (response_size/4u)); + + /* + Load the MBX_RADRDESC register with offset address within the mailbox + format for that particular service. + It will be 0 for the services where there is no output data from G5CONTROL + is expected. + This function assumes that this value is pre-calculated by service specific + functions as this value is fixed for each service. + */ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_RADDR, (response_offset + mb_offset)); + } + + /*Set the request bit in SYS_SERV_REQ register to start the service*/ + HAL_set_32bit_reg_field(g_css_pf_base_addr, SS_REQ_REQ, 0x01u); + + if (cmd_data_size > 0u) + { + word_buf = (uint32_t*)cmd_data; + + /* Write the user data into mail box. */ + for (idx = 0u; idx < (cmd_data_size/4u); idx++) + { + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_WDATA, word_buf[idx]); + } + } + + timeout_count = SS_TIMEOUT_COUNT; + if (response_size > 0u) + { + word_buf = (uint32_t*)p_response; + + for (idx = 0u; idx < (response_size/4u); idx++) + { + while (0u == HAL_get_32bit_reg_field(g_css_pf_base_addr, + SS_USER_RDVLD)) + { + --timeout_count; + + if (timeout_count == 0) + { + return SS_USER_RDVLD_TIMEOUT; + } + } + word_buf[idx] = HAL_get_32bit_reg(g_css_pf_base_addr, MBX_RDATA); + } + } + + timeout_count = SS_TIMEOUT_COUNT; + /* make sure that service is complete i.e. SS_USER_BUSY is gone 0 */ + while (1u == HAL_get_32bit_reg_field(g_css_pf_base_addr, SS_USER_BUSY)) + { + --timeout_count; + + if (timeout_count == 0) + { + return SS_USER_RDVLD_TIMEOUT; + } + } + + /* Read the status returned by System Controller */ + status = HAL_get_32bit_reg(g_css_pf_base_addr, SS_STAT); + + return (uint8_t)status; +} + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h new file mode 100644 index 0000000..8e0ebb6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h @@ -0,0 +1,1249 @@ +/******************************************************************************* + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the + * CoreSysServices_PF bare metal driver. + */ +/*=========================================================================*//** + @mainpage CoreSysServices_PF Bare Metal Driver. + + @section intro_sec Introduction + The PolarFire System Services (PF_SYSTEM_SERVICES) SgCore enables executing + the system services on the PolarFire and PolarFire SoC device. The system services + are the system controller actions initiated by the System Controller's System + Service Interface (SSI). The PolarFire System Services "SgCore" provides a + method to initiate these system services. The PF_SYSTEM_SERVICES interacts + with the system controller on SSI and Mailbox interface to initiate system + services, exchange data required for that services, and to know the successful + completion or error status. + + The PF_SYSTEM_SERVICES provides an APB interface for controlling the registers + functions for controlling the PF_SYSTEM_SERVICES as part of a bare metal system + register implemented within it. This software driver provides a set of where no + part of an operating system but the implementation of the adaptation layer + operating system is available. This driver is adapted for use in + between this driver and the operating system's driver model is outside the + scope of this driver. + + ## Features + The CoreSysServices_PF driver provides the following features: + - Executing device and design information services + - Executing design services + - Executing data security services + - Executing Fabric services + + The CoreSysServices_PF driver is provided as C source code. + + @section Driver Configuration + The application software should configure the CoreSysServices_PF driver through + calling the SYS_init() function. Only one instance of PF_SYSTEM_SERVICES SgCore is + supported. No additional configuration files are required to use the driver. + If using this driver on RT PolarFire device FPGA, define RT_DEVICE_FAMILY + macro in application. + + @section theory_op Theory of Operation + The CoreSysServices_PF driver provides access to the PolarFire system services. + These system services are grouped into the following categories: + + Device and Design Information Service + - Serial Number Service + - USERCODE Service + - Design Info Service + - Device Certificate Services + - Read Digests + - Query Security + - Read Debug Info + - Read eNVM param + + Design Services + - Bitstream authentication service + - IAP bitstream authentication service + + Data Security Services + - Digital Signature Service + - Secure NVM (SNVM) Functions + - PUF Emulation Service + - Nonce Service + + Fabric Services + - Digest Check Service + - In Application programming(IAP)/Auto-Update service + + Initialization and Configuration + + The CoreSysServices_PF driver is initialized by calling the SYS_init() + function. The SYS_init() function must be called before calling any other + CoreSysServices_PF driver functions. + + Device and Design Information Services + + The CoreSysServices_PF driver is used to read information about the device + and the design using the following functions: + - SYS_get_serial_number() + - SYS_get_user_code() + - SYS_get_design_info() + - SYS_get_device_certificate() + - SYS_read_digest() + - SYS_query_security() + - SYS_read_debug_info() + + Design Authentication Services + + The CoreSysServices_PF driver is used to execute design services using the + following functions: + - SYS_bitstream_authenticate_service() + - SYS_IAP_image_authenticate_service() + + Data Security Services + + The CoreSysServices_PF driver is used to execute data security services + using the following functions: + - SYS_digital_signature_service() + - SYS_secure_nvm_write() + - SYS_secure_nvm_read() + - SYS_puf_emulation_service () + - SYS_nonce_service () + + Executing Fabric Services + + The CoreSysServices_PF driver is used to execute fabric services using the + following functions: + - SYS_digest_check_service() + - SYS_iap_service() + + All the service execution functions return the 8-bit status, which is returned + by the system controller on executing the given service. A '0' value indicates + successful execution of that service. A non-zero value indicates error. + The error codes for each service are different. See individual function + description to know the exact meanings of the error codes for each service. + + The function descriptions in this file mainly focus on the details required + by the user to use the APIs provided by this driver to execute the services. + To know the complete details of the system services, see the + PolarFire FPGA and PolarFire SoC FPGA System Services [document](https://onlinedocs.microchip.com/pr/GUID-1409CF11-8EF9-4C24-A94E-70979A688632-en-US-3/index.html) + + *//*=========================================================================*/ +#ifndef __CORE_SYSSERV_PF_H +#define __CORE_SYSSERV_PF_H 1 + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#include "hal_assert.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** +* # Service Execution Success and Error Status Codes +* +* The following status codes are the return values from the system service functions. +* For any service, a return value '0' indicates that the service was executed +* successfully. A non-zero return value indicates that the service was not +* executed successfully. For all the services, the return value represents the +* status code returned by the system controller for the respective service, +* except the values SYS_PARAM_ERR, SS_USER_BUSY_TIMEOUT, and SS_USER_RDVLD_TIMEOUT. +* These three values indicate the error conditions detected by this driver and +* they do not overlap with the status code returned by the system controller for +* any of the system service. +* +* SYS_SUCCESS +* System service executed successfully +* +* SYS_PARAM_ERR +* System service cannot be executed as one or more parameters are not as +* expected by this driver. No read/write access is performed with the +* IP. +* +* SS_USER_BUSY_TIMEOUT +* The System service request is initiated and the driver timed-out while +* waiting for the system service to complete. The System Service +* completion is indicated by de-assertion of the SS_USER_BUSY bit by the +* IP. +* +* SS_USER_RDVLD_TIMEOUT +* The System service request is initiated and the driver timed-out while +* waiting for SS_USER_RDVLD bit, which indicates availability of data to +* be read from the mailbox, to become active. +*/ +#define SYS_SUCCESS 0u +#define SYS_PARAM_ERR 0xFFu +#define SS_USER_BUSY_TIMEOUT 0xFAu +#define SS_USER_RDVLD_TIMEOUT 0xFBu + +/** +* # System Service Timeout Count +* +* The SS_TIMEOUT_COUNT value is used by the driver as a timeout count +* while waiting for either the SS_USER_BUSY or SS_USER_RDVLD. This empirical +* value is sufficiently large so that the operations are falsely +* timeout in the normal circumstance. It is provided as a way to provide +* more debug information to the application in case there are some +* unforeseen issues. You may change this value for your need based on your +* system design. +*/ +#define SS_TIMEOUT_COUNT 40000u +/* + * SYS_DCF_DEVICE_MISMATCH + * Public key or FSN do not match device + * + * + * SYS_DCF_INVALID_SIGNATURE + * Certificate signature is invalid + * + * SYS_DCF_SYSTEM_ERROR + * PUF or storage failure + */ +#define SYS_DCF_DEVICE_MISMATCH 1u +#define SYS_DCF_INVALID_SIGNATURE 2u +#define SYS_DCF_SYSTEM_ERROR 3u + +/* + * SYS_NONCE_PUK_FETCH_ERROR + * Error fetching PUK + * + * SYS_NONCE_SEED_GEN_ERROR + * Error generating seed + */ +#define SYS_NONCE_PUK_FETCH_ERROR 1u +#define SYS_NONCE_SEED_GEN_ERROR 2u + +/** + * # Secure Nvm Write Error Codes + * + * SNVM_WRITE_INVALID_SNVMADDR + * Illegal page address + * + * SNVM_WRITE_FAILURE + * PNVM program/verify failed + * + * SNVM_WRITE_SYSTEM_ERROR + * PUF or storage failure + * + * SNVM_WRITE_NOT_PERMITTED + * Write is not permitted + */ +#define SNVM_WRITE_INVALID_SNVMADDR 1u +#define SNVM_WRITE_FAILURE 2u +#define SNVM_WRITE_SYSTEM_ERROR 3u +#define SNVM_WRITE_NOT_PERMITTED 4u + +/** + * # Secure Nvm Read Error Codes + * + * SNVM_READ_INVALID_SNVMADDR + * Illegal page address + * + * SNVM_READ_AUTHENTICATION_FAILURE + * Storage corrupt or incorrect USK + * + * SNVM_READ_SYSTEM_ERROR + * PUF or storage failure + * + */ +#define SNVM_READ_INVALID_SNVMADDR 1u +#define SNVM_READ_AUTHENTICATION_FAILURE 2u +#define SNVM_READ_SYSTEM_ERROR 3u + +/** + * # Digital Signature Service Error Codes + * + * DIGITAL_SIGNATURE_FEK_FAILURE_ERROR + * Error retrieving FEK + * + * DIGITAL_SIGNATURE_DRBG_ERROR + * Failed to generate nonce + * + * DIGITAL_SIGNATURE_ECDSA_ERROR + * ECDSA failed + */ +#define DIGITAL_SIGNATURE_FEK_FAILURE_ERROR 1u +#define DIGITAL_SIGNATURE_DRBG_ERROR 2u +#define DIGITAL_SIGNATURE_ECDSA_ERROR 3u + +/** + * # Digest Check Error Codes + * + * NOTE: When these error occur, the DIGEST tamper flag is triggered. + * + * DIGEST_CHECK_FABRICERR + * Fabric digest check error + * + * DIGEST_CHECK_CCERR + * UFS Fabric Configuration (CC) segment digest check error + * + * DIGEST_CHECK_SNVMERR + * ROM digest in SNVM segment digest check error + * + * DIGEST_CHECK_ULERR + * UFS UL segment digest check error + * + * DIGEST_CHECK_UK0ERR + * UKDIGEST0 in User Key segment digest check error + * + * DIGEST_CHECK_UK1ERR + * UKDIGEST1 in User Key segment digest check error + * + * DIGEST_CHECK_UK2ERR + * UKDIGEST2 in User Key segment (UPK1) digest check error + * + * DIGEST_CHECK_UK3ERR + * UKDIGEST3 in User Key segment (UK1) digest check error + * + * DIGEST_CHECK_UK4ERR + * UKDIGEST4 in User Key segment (DPK) digest check error + * + * DIGEST_CHECK_UK5ERR + * UKDIGEST5 in User Key segment (UPK2) digest check error + * + * DIGEST_CHECK_UK6ERR + * UKDIGEST6 in User Key segment (UK2) digest check error + * + * DIGEST_CHECK_UPERR + * UFS Permanent Lock (UPERM) segment digest check error + * + * DIGEST_CHECK_SYSERR + * M3 ROM, Factory and Factory Key Segments digest check error + * + */ +#define DIGEST_CHECK_FABRICERR 0x00u +#define DIGEST_CHECK_CCERR 0x01u +#define DIGEST_CHECK_SNVMERR 0x02u +#define DIGEST_CHECK_ULERR 0x03u +#define DIGEST_CHECK_UK0ERR 0x04u +#define DIGEST_CHECK_UK1ERR 0x05u +#define DIGEST_CHECK_UK2ERR 0x06u +#define DIGEST_CHECK_UK3ERR 0x07u +#define DIGEST_CHECK_UK4ERR 0x08u +#define DIGEST_CHECK_UK5ERR 0x09u +#define DIGEST_CHECK_UK6ERR 0x10u +#define DIGEST_CHECK_UPERR 0x11u +#define DIGEST_CHECK_SYSERR 0x12u + +/** + * # Bitstream Authentication and Iap Bitstream Authentication Return Status + * + * BSTREAM_AUTH_CHAINING_MISMATCH_ERR + * Validator or hash chaining mismatch. Incorrectly constructed bitstream or + * wrong key used. + * + * BSTREAM_AUTH_UNEXPECTED_DATA_ERR + * Unexpected data received. + * Additional data received after end of EOB component. + * + * BSTREAM_AUTH_INVALID_ENCRY_KEY_ERR + * Invalid/corrupt encryption key. + * The requested key mode is disabled or the key could not be read/reconstructed. + * + * BSTREAM_AUTH_INVALID_HEADER_ERR + * Invalid component header + * + * BSTREAM_AUTH_BACK_LEVEL_NOT_SATISFIED_ERR + * Back level not satisfied + * + * BSTREAM_AUTH_ILLEGAL_BITSTREAM_MODE_ERR + * Illegal bitstream mode. + * Requested bitstream mode is disabled by user security. + * + * BSTREAM_AUTH_DNS_BINDING_MISMATCH_ERR + * DSN binding mismatch + * + * BSTREAM_AUTH_ILLEGAL_COMPONENT_SEQUENCE_ERR + * Illegal component sequence + * + * BSTREAM_AUTH_INSUFF_DEVICE_CAPAB_ERR + * Insufficient device capabilities + * + * BSTREAM_AUTH_INCORRECT_DEVICEID_ERR + * Incorrect DEVICEID + * + * BSTREAM_AUTH_PROTOCOL_VERSION_ERR + * Unsupported bitstream protocol version (regeneration required) + * + * BSTREAM_AUTH_VERIFY_ERR + * Verify not permitted on this bitstream + * + * BSTREAM_AUTH_INVALID_DEV_CERT_ERR + * Invalid Device Certificate. + * Device SCAC is invalid or not present. + * + * BSTREAM_AUTH_INVALID_DIB_ERR + * Invalid DIB + * + * BSTREAM_AUTH_SPI_NOT_MASTER_ERR + * Device not in SPI Master Mode. + * Error may occur only when bitstream is executed through IAP mode. + * + * BSTREAM_AUTH_AUTOIAP_NO_VALID_IMAGE_ERR + * No valid images found. + * Error may occur when bitstream is executed through Auto Update mode. + * Occurs when no valid image pointers are found. + * + * BSTREAM_AUTH_INDEXIAP_NO_VALID_IMAGE_ERR + * No valid images found. + * Error may occur when bitstream is executed through IAP mode via Index Mode. + * Occurs when No valid image pointers are found. + * + * BSTREAM_AUTH_NEWER_DESIGN_VERSION_ERR + * Programmed design version is newer than AutoUpdate image found. + * Error may occur when bitstream is executed through Auto Update mode. + * + * BSTREAM_AUTH_INVALID_IMAGE_ERR + * Selected image was invalid and no recovery was performed due to valid design + * in device. + * Error may occur only when bitstream is executed through Auto Update or IAP mode + * (This error is here for completeness but only can be observed by running the + * READ_DEBUG_INFO instruction and looking at IAP Error code field). + * + * BSTREAM_AUTH_IMAGE_PROGRAM_FAILED_ERR + * Selected and Recovery image failed to program. + * Error may occur only when bitstream is executed through Auto Update or + * IAP mode + * (This error is here for completeness but only can be observed by running the + * READ_DEBUG_INFO instruction and looking at IAP Error code field). + * + * BSTREAM_AUTH_ABORT_ERR + * Abort. + * Non-bitstream instruction executed during bitstream loading. + * + * BSTREAM_AUTH_NVMVERIFY_ERR + * Fabric/UFS verification failed (min or weak limit) + * + * BSTREAM_AUTH_PROTECTED_ERR + * Device security prevented modification of non-volatile memory + * + * BSTREAM_AUTH_NOTENA + * Programming mode not enabled + * + * BSTREAM_AUTH_PNVMVERIFY + * pNVM verify operation failed + * + * BSTREAM_AUTH_SYSTEM + * System hardware error (PUF or DRBG) + * + * BSTREAM_AUTH_BADCOMPONENT + * An internal error was detected in a component payload + * + * BSTREAM_AUTH_HVPROGERR + * HV programming subsystem failure (pump failure) + * + * BSTREAM_AUTH_HVSTATE + * HV programming subsystem in unexpected state (internal error) + * + */ +#define BSTREAM_AUTH_CHAINING_MISMATCH_ERR 1 +#define BSTREAM_AUTH_UNEXPECTED_DATA_ERR 2 +#define BSTREAM_AUTH_INVALID_ENCRY_KEY_ERR 3 +#define BSTREAM_AUTH_INVALID_HEADER_ERR 4 +#define BSTREAM_AUTH_BACK_LEVEL_NOT_SATISFIED_ERR 5 +#define BSTREAM_AUTH_ILLEGAL_BITSTREAM_MODE_ERR 6 +#define BSTREAM_AUTH_DNS_BINDING_MISMATCH_ERR 7 +#define BSTREAM_AUTH_ILLEGAL_COMPONENT_SEQUENCE_ERR 8 +#define BSTREAM_AUTH_INSUFF_DEVICE_CAPAB_ERR 9 +#define BSTREAM_AUTH_INCORRECT_DEVICEID_ERR 10 +#define BSTREAM_AUTH_PROTOCOL_VERSION_ERR 11 +#define BSTREAM_AUTH_VERIFY_ERR 12 +#define BSTREAM_AUTH_INVALID_DEV_CERT_ERR 13 +#define BSTREAM_AUTH_INVALID_DIB_ERR 14 +#define BSTREAM_AUTH_SPI_NOT_MASTER_ERR 21 +#define BSTREAM_AUTH_AUTOIAP_NO_VALID_IMAGE_ERR 22 +#define BSTREAM_AUTH_INDEXIAP_NO_VALID_IMAGE_ERR 23 +#define BSTREAM_AUTH_NEWER_DESIGN_VERSION_ERR 24 +/* 25 Reserved */ +#define BSTREAM_AUTH_INVALID_IMAGE_ERR 26 +#define BSTREAM_AUTH_IMAGE_PROGRAM_FAILED_ERR 27 +#define BSTREAM_AUTH_ABORT_ERR 127 +#define BSTREAM_AUTH_NVMVERIFY_ERR 128 +#define BSTREAM_AUTH_PROTECTED_ERR 129 +#define BSTREAM_AUTH_NOTENA 130 +#define BSTREAM_AUTH_PNVMVERIFY 131 +#define BSTREAM_AUTH_SYSTEM 132 +#define BSTREAM_AUTH_BADCOMPONENT 133 +#define BSTREAM_AUTH_HVPROGERR 134 +#define BSTREAM_AUTH_HVSTATE 135 + +/***************************************************************************//** + * # Mailbox ECC Status + * Provides ECC status when the mailbox is read. The values are as follows: + * 00: No ECC errors detected, data is correct. + * 01: Exactly one bit error occurred and has been corrected. + * 10: Exactly two bits error occurred and no correction performed. + * 11: Reserved. + */ +#define SYS_MBOX_ECC_NO_ERROR_MASK 0x00u +#define SYS_MBOX_ONEBIT_ERROR_CORRECTED_MASK 0x40u +#define SYS_MBOX_TWOBIT_ERROR_MASK 0xC0u + +/***************************************************************************//** + * Service request command opcodes: +*/ +#define SERIAL_NUMBER_REQUEST_CMD 0x00u +#define USERCODE_REQUEST_CMD 0x01u +#define DESIGN_INFO_REQUEST_CMD 0x02u +#define DEVICE_CERTIFICATE_REQUEST_CMD 0x03u +#define READ_DIGEST_REQUEST_CMD 0x04u +#define QUERY_SECURITY_REQUEST_CMD 0x05u +#define READ_DEBUG_INFO_REQUEST_CMD 0x06u +#define READ_ENVM_PARAM_REQUEST_CMD 0x07u +#define SNVM_NON_AUTHEN_TEXT_REQUEST_CMD 0x10u +#define SNVM_AUTHEN_TEXT_REQUEST_CMD 0x11u +#define SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD 0x12u +#define SNVM_READ_REQUEST_CMD 0x18u +#define DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD 0x19u +#define PUF_EMULATION_SERVICE_REQUEST_CMD 0x20u +#define NONCE_SERVICE_REQUEST_CMD 0x21u +#define DIGITAL_SIGNATURE_DER_FORMAT_REQUEST_CMD 0x1Au + +#define BITSTREAM_AUTHENTICATE_CMD 0x23u +#define IAP_BITSTREAM_AUTHENTICATE_CMD 0x22u + +#define DIGEST_CHECK_CMD 0x47u + +#define IAP_PROGRAM_BY_SPIIDX_CMD 0x42u +#define IAP_VERIFY_BY_SPIIDX_CMD 0x44u +#define IAP_PROGRAM_BY_SPIADDR_CMD 0x43u +#define IAP_VERIFY_BY_SPIADDR_CMD 0x45u +#define IAP_AUTOUPDATE_CMD 0x46u + +/***************************************************************************//** + * Service request Mailbox return data length + */ +#define SERIAL_NUMBER_RESP_LEN 16u +#define USERCODE_RESP_LEN 4u +#define DESIGN_INFO_RESP_LEN 36u +#define DEVICE_CERTIFICATE_RESP_LEN 1024u +#define READ_DIGEST_RESP_LEN 416u +#define QUERY_SECURITY_RESP_LEN 9u +#define READ_DEBUG_INFO_RESP_LEN 76u +#define READ_ENVM_PARAM_RESP_LEN 256u +#define NONCE_SERVICE_RESP_LEN 32u + +#define PUF_EMULATION_SERVICE_CMD_LEN 20u +#define PUF_EMULATION_SERVICE_RESP_LEN 32u + +#define DIGITAL_SIGNATURE_HASH_LEN 48u +#define DIGITAL_SIGNATURE_RAW_FORMAT_RESP_SIZE 96u +#define DIGITAL_SIGNATURE_DER_FORMAT_RESP_SIZE 104u + +#define USER_SECRET_KEY_LEN 12u + +/* Same driver can be used on PolarFire SoC platform and the response length + * is different for PolarFire SoC. Constants defined below are used only when the + * PF System services driver is used with PolarFire SoC Platform. + */ +#define READ_DIGEST_MPFS_RESP_LEN 576u +#define QUERY_SECURITY_MPFS_RESP_LEN 33u + +/* SNVM Input data length from sNVM write. */ +#ifndef RT_DEVICE_FAMILY +/* SNVMADDR + RESERVED + PT + USK */ +#define NON_AUTHENTICATED_TEXT_DATA_LEN 256u + +/* SNVMADDR + RESERVED + PT */ +#define AUTHENTICATED_TEXT_DATA_LEN 252u +#else +/* SNVMADDR + RESERVED + PT + USK */ +#define NON_AUTHENTICATED_TEXT_DATA_LEN 224u + +/* SNVMADDR + RESERVED + PT */ +#define AUTHENTICATED_TEXT_DATA_LEN 220u +#endif + +/** + * # Digest Check Input Options + * + * DIGEST_CHECK_FABRIC + * Carry out digest check on Fabric + * + * DIGEST_CHECK_CC + * Carry out digest check on UFS Fabric Configuration (CC) segment + * + * DIGEST_CHECK_SNVM + * Carry out digest check on ROM digest in SNVM segment + * + * DIGEST_CHECK_UL + * Carry out digest check on UFS UL segment + * + * DIGEST_CHECK_UKDIGEST0 + * Carry out digest check on UKDIGEST0 in User Key segment + * + * DIGEST_CHECK_UKDIGEST1 + * Carry out digest check on UKDIGEST1 in User Key segment + * + * DIGEST_CHECK_UKDIGEST2 + * Carry out digest check on UKDIGEST2 in User Key segment (UPK1) + * + * DIGEST_CHECK_UKDIGEST3 + * Carry out digest check on UKDIGEST3 in User Key segment (UK1) + * + * DIGEST_CHECK_UKDIGEST4 + * Carry out digest check on UKDIGEST4 in User Key segment (DPK) + * + * DIGEST_CHECK_UKDIGEST5 + * Carry out digest check on UKDIGEST5 in User Key segment (UPK2) + * + * DIGEST_CHECK_UKDIGEST6 + * Carry out digest check on UKDIGEST6 in User Key segment (UK2) + * + * DIGEST_CHECK_UPERM + * Carry out digest check on UFS Permanent lock (UPERM) segment + * + * DIGEST_CHECK_SYS + * Carry out digest check on Factory and Factory Key Segments + * + */ +#define DIGEST_CHECK_FABRIC (0x01<<0x00u) /*Fabric digest*/ +#define DIGEST_CHECK_CC (0x01<<0x01u) /*UFS Fabric Configuration (CC) segment*/ +#define DIGEST_CHECK_SNVM (0x01<<0x02u) /*ROM digest in SNVM segment*/ +#define DIGEST_CHECK_UL (0x01<<0x03u) /*UFS UL segment*/ +#define DIGEST_CHECK_UKDIGEST0 (0x01<<0x04u) /*UKDIGEST0 in User Key segment*/ +#define DIGEST_CHECK_UKDIGEST1 (0x01<<0x05u) /*UKDIGEST1 in User Key segment*/ +#define DIGEST_CHECK_UKDIGEST2 (0x01<<0x06u) /*UKDIGEST2 in User Key segment (UPK1)*/ +#define DIGEST_CHECK_UKDIGEST3 (0x01<<0x07u) /*UKDIGEST3 in User Key segment (UK1)*/ +#define DIGEST_CHECK_UKDIGEST4 (0x01<<0x08u) /*UKDIGEST4 in User Key segment (DPK)*/ +#define DIGEST_CHECK_UKDIGEST5 (0x01<<0x09u) /*UKDIGEST5 in User Key segment (UPK2)*/ +#define DIGEST_CHECK_UKDIGEST6 (0x01<<0x0au) /*UKDIGEST6 in User Key segment (UK2)*/ +#define DIGEST_CHECK_UPERM (0x01<<0x0bu) /*UFS Permanent lock (UPERM) segment*/ +#define DIGEST_CHECK_SYS (0x01<<0x0cu) /*Factory and Factory Key Segments.*/ + +/***************************************************************************//** + * The function SYS_init() is used to initialize the internal data structures of + * this driver. Currently this function is empty. + * + * @param base_addr The base_addr parameter specifies the base address of the + * PF_System_services core. + * + * @return This function does not return a value. + */ +void +SYS_init +( + uint32_t base_addr +); + +/***************************************************************************//** + * The function SYS_get_serial_number() is used to execute "serial number" system + * service. + * + * @param p_serial_number The p_serial_number parameter is a pointer to a buffer + * in which the data returned by system controller + * is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t +SYS_get_serial_number +( + const uint8_t * p_serial_number, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_get_user_code() is used to execute "USERCODE" system + * service. + * @param p_user_code The p_user_code parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t +SYS_get_user_code +( + const uint8_t * p_user_code, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_get_design_info() is used to execute "Get Design Info" system + * service. + * + * @param p_design_info The p_design_info parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. Total size of debug information is 36 bytes. + * The data from the system controller includes the 256-bit + * user-defined design ID, 16-bit design version, and 16-bit + * design back level. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t +SYS_get_design_info +( + const uint8_t * p_design_info, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_get_device_certificate() is used to execute "Get Device + * Certificate" system service. + * + * @param p_device_certificate The p_device_certificate parameter is a pointer + * to a buffer in which the data returned by the + * system controller is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code means that + * the service was executed successfully. + * + */ +uint8_t +SYS_get_device_certificate +( + const uint8_t * p_device_certificate, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_read_digest() is used to execute "Read Digest" system service. + * + * @param p_digest The p_digest parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t SYS_read_digest +( + const uint8_t * p_digest, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_query_security() is used to execute "Query Security" system + * service. + * + * @param p_security_locks The p_security_locks parameter is a pointer to a buffer + * in which the data returned by system controller is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code means that + * the service was executed successfully. + */ +uint8_t SYS_query_security +( + uint8_t * p_security_locks, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_read_debug_info() is used to execute "Read Debug info" system + * service. + * + * @param p_debug_info The p_debug_info parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t SYS_read_debug_info +( + const uint8_t * p_debug_info, + uint16_t mb_offset +); + +#ifdef CORESYSSERVICES_PFSOC +/***************************************************************************//** + * The function SYS_read_envm_parameter() is used to retrieve all parameters needed + * for the eNVM operation and programming. + * + * NOTE: This service is available only on PolarFire SoC Platform. + * This service is not yet supported by PF_SYSTEM_SERVICES 3.0.100. + * + * @param p_envm_param The p_envm_param parameter is a pointer to a buffer + * in which the data returned by system controller is copied. + * This buffer stores all the eNVM parameters. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_read_envm_parameter service will return zero if the + * service executed successfully, otherwise, it will return + * one indicating error. + */ +uint8_t SYS_read_envm_parameter +( + uint8_t * p_envm_param, + uint16_t mb_offset +); +#endif +/***************************************************************************//** + * The function SYS_puf_emulation_service() is used to authenticate a device. + * + * The SYS_puf_emulation_service() function accept a challenge comprising a + * 8-bit optype and 128-bit challenge and return a 256-bit response unique to + * the given challenge and the device. + * + * @param p_challenge The p_challenge parameter specifies the 128-bit challenge + * to generate the 256-bits unique response. + * + * @param op_type The op_type parameter specifies the operational parameter + * to generate the 256-bits unique response. + * + * @param p_response The p_response parameter is a pointer to a buffer where + * the data returned which is the response by system controller + * is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_puf_emulation_service function will return zero + * if the service executed successfully, otherwise, it will + * return one indicating error. + */ +uint8_t SYS_puf_emulation_service +( + const uint8_t * p_challenge, + uint8_t op_type, + uint8_t* p_response, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_digital_signature_service() function is used to generate P-384 ECDSA + * signature based on SHA384 hash value. + * + * @param p_hash The p_hash parameter is a pointer to the buffer which + * contain the 48 bytes SHA384 Hash value (input value). + * + * @param format The format parameter specifies the output format of + * generated SIGNATURE field. The different types of output + * signature formats are as follow: + * - DIGITAL_SIGNATURE_RAW_FORMAT + * - DIGITAL_SIGNATURE_DER_FORMAT + * + * @param p_response The p_response parameter is a pointer to a buffer that + * contains the generated ECDSA signature. The field may be + * 96 bytes or 104 bytes depending upon the output format. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digital_signature_service function returns + * zero if the service executed successfully, otherwise, it + * returns non-zero values indicating error. + */ +uint8_t SYS_digital_signature_service +( + const uint8_t* p_hash, + uint8_t format, + uint8_t* p_response, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_secure_nvm_write() function writes data in the sNVM region. + * Data gets stored in the following format: + * - Non-authenticated plaintext + * - Authenticated plaintext + * - Authenticated ciphertext + * + * Note: If you are executing this function with Authenticated plaintext + * or Authenticated ciphertext on a device whose sNVM was never previously + * written to, then the service may fail. For it to work, you must first write + * Authenticated data to the sNVM using Libero along with USK client and + * custom security. This flow generates the SMK. See UG0753 PolarFire FPGA + * Security User Guide for further details. + + * @param format The format parameter specifies the format used to write + * data in sNVM region. The different type of text formats + * are as follow: + * - NON_AUTHENTICATED_PLAINTEXT_FORMAT + * - AUTHENTICATED_PLAINTEXT_FORMAT + * - AUTHENTICATED_CIPHERTEXT_FORMAT + * + * @param snvm_module The snvm_module parameter specifies the the sNVM module + * in which the data need to be written. + * + * @param p_data The p_data parameter is a pointer to a buffer which + * contains the data to be stored in sNVM region. The data + * length to be written is fixed depending on the format + * parameter. If NON_AUTHENTICATED_PLAINTEXT_FORMAT is + * selected, then you can write 252 bytes in the sNVM module. + * For other two formats the data length is 236 bytes. + * + * @param p_user_key The p_user_key parameter is a pointer to a buffer which + * contain the 96-bit key USK (user secret key). This user + * secret key will enhance the security when authentication + * is used. That is, when Authenticated plaintext and + * Authenticated ciphertext format is selected. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digital_signature_service function returns + * zero if the service executed successfully, otherwise, it + * returns non-zero values indicating error. + */ +uint8_t SYS_secure_nvm_write +( + uint8_t format, + uint8_t snvm_module, + const uint8_t* p_data, + const uint8_t* p_user_key, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_secure_nvm_read() function is used to read data present in sNVM region. + * User should provide USK key, if the data was programmed using authentication. + * If the data was written in the sNVM using the authenticated plaintext or the + * authenticated ciphertext service option then this service will return the + * valid data only when authentication is successful. For more details, see + * SYS_secure_nvm_write() function. If the data was written in + * the sNVM using the authenticated plaintext or the authenticated ciphertext + * service option then this service will return the valid data only when + * authentication is successful. For more details, see SYS_secure_nvm_write() + * function and its parameter description. + * + * @param snvm_module The snvm_module parameter specifies the sNVM module + * from which the data need to be read. + * + * @param p_user_key The p_user_key parameter is a pointer to a buffer which + * contain the 96-bit key USK (user secret key). User should + * provide same secret key which is previously used for + * authentication while writing data in sNVM region. + * + * @param p_admin The p_admin parameter is a pointer to the buffer where + * the output page admin data is stored. The page admin + * data is 4 bytes long. + * + * @param p_data The p_data parameter is a pointer to a buffer which + * contains the data read from sNVM region. User should + * provide the buffer large enough to store the read data. + * + * @param data_len The data_len parameter specifies the number of bytes to be + * read from sNVM. + * The application should know whether the data written in the + * chose sNVM module was previously stored using Authentication + * or not. + * The data_len should be 236 bytes, for authenticated data. + * For not authenticated data the data_len should be 252 bytes. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digital_signature_service function returns + * zero if the service executed successfully, otherwise, it + * returns non-zero values indicating error. + */ +uint8_t SYS_secure_nvm_read +( + uint8_t snvm_module, + const uint8_t* p_user_key, + uint8_t* p_admin, + uint8_t* p_data, + uint16_t data_len, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_nonce_service() is used to issue "Nonce Service" system + * service to the system controller. + * + * @param p_nonce The p_nonce parameter is a pointer to a buffer + * in which the data returned by system controller is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code means + * that the service was executed successfully and a non-zero + * value indicates error. See the document link + * provided in the theory of operation section to know more + * about the service and service response. + */ +uint8_t SYS_nonce_service +( + const uint8_t * p_nonce, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_bitstream_authenticate_service() function is used to authenticate + * the Bitstream which is located in SPI through a system service routine. Prior + * to using the IAP service, it may be required to first validate the new + * bitstream before committing the device to reprogramming, thus avoiding the + * need to invoke recovery procedures if the bitstream is invalid. + * + * This service is applicable to bitstreams stored in SPI Flash memory only. + * + * @param spi_flash_address + * The spi_flash_address parameter specifies the address within + * SPI Flash memory where the bit-stream is stored. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_bitstream_authenticate_service function will return + * zero if the service executed successfully and the non-zero + * response from system controller indicates error. See + * the document link provided in the theory of + * operation section to know more about the service and service + * response. + */ +uint8_t SYS_bitstream_authenticate_service +( + uint32_t spi_flash_address, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_IAP_image_authenticate_service() function is used to authenticate + * the IAP image which is located in SPI through a system service routine. The + * service checks the image descriptor and the referenced bitstream and optional + * initialization data. If the image is authenticated successfully, then the + * image is guaranteed to be valid when used by an IAP function. + * + * This service is applicable to bitstreams stored in SPI Flash memory only. + * + * @param spi_idx + * The spi_idx parameter specifies the index in the SPI directory to + * be used where the IAP bit-stream is stored. + * Note: To support recovery SPI_IDX=1 should be an empty slot and the recovery + * image should be located in SPI_IDX=0. Since SPI_IDX=1 should be an + * empty slot, it shouldn’t be passed into the system service. + * + * @return The SYS_IAP_image_authenticate_service function will return + * zero if the service executed successfully the non-zero + * response from system controller indicates error. Please + * refer to the document link provided in the theory of + * operation section to know more about the service and service + * response. + */ +uint8_t SYS_IAP_image_authenticate_service +( + uint8_t spi_idx +); + +/***************************************************************************//** + * The SYS_digest_check_service() function is used to Recalculates and compares + * digests of selected non-volatile memories. If the fabric digest is to be + * checked, then the user design must follow all prerequisite steps for the + * FlashFreeze service before invoking this service. + * This service is applicable to bitstreams stored in SPI Flash memory only. + * @param options + * The options parameter specifies the digest check options which + * indicate the area on which the digest check should be performed. + * Below is the list of options. You can OR these options to indicate + * to perform digest check on multiple segments. + * Note: The options parameter is of 2 bytes when used with PF + * device and 4 bytes when used with PolarFire SoC device. + * Options[i] | Description + * ---------------|---------------------------------- + * 0x01 | Fabric digest + * 0x02 | Fabric Configuration (CC) segment + * 0x04 | ROM digest in SNVM segment + * 0x08 | UL segment + * 0x10 | UKDIGEST0 in User Key segment + * 0x20 | UKDIGEST1 in User Key segment + * 0x40 | UKDIGEST2 in User Key segment (UPK1) + * 0x80 | UKDIGEST3 in User Key segment (UK1) + * 0x100 | UKDIGEST4 in User Key segment (DPK) + * 0x200 | UKDIGEST5 in User Key segment (UPK2) + * 0x400 | UKDIGEST6 in User Key segment (UK2) + * 0x800 | UFS Permanent lock (UPERM) segment + * 0x1000 | Factory and Factory Key Segments. + * 0x2000 | UKDIGEST7 in User Key segment (HWM) (PFSoC) + * 0x4000 | ENVMDIGEST (PFSoC only) + * 0x8000 | UKDIGEST8 for MSS Boot Info (PFSoC only) + * 0x10000 | SNVM_RW_ACCESS_MAP Digest (PFSoC only) + * 0x20000 | SBIC revocation digest (PFSoC only) + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digest_check_service function will return + * zero if the service executed successfully the non-zero + * response from system controller indicates error. Pleaes + * refer to the document link provided in the theory of + * operation section to know more about the service and service + * response. + */ +uint8_t SYS_digest_check_service +( + uint32_t options, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_iap_service() function is used to IAP service. The IAP service allows + * the user to reprogram the device without the need for an external master. The + * user design writes the bitstream to be programmed into a SPI Flash connected + * to the SPI port. When the service is invoked, the System Controller + * automatically reads the bitstream from the SPI flash and programs the device. + * The service allows the image to be executed in either VERIFY or PROGRAM modes. + * Another option for IAP is to perform the auto-update sequence. In this case + * the newest image of the first two images in the SPI directory is chosen to be + * programmed. + * + * @param iap_cmd + * The iap_cmd parameter specifies the specific IAP command which + * depends upon VERIFY or PROGRAM modes and the SPI address method. + * iap_cmd | Description + * -----------------------|------------ + * IAP_PROGRAM_BY_SPIIDX_CMD | IAP program. + * IAP_VERIFY_BY_SPIIDX_CMD | Fabric Configuration (CC) segment + * IAP_PROGRAM_BY_SPIADDR_CMD | ROM digest in SNVM segment + * IAP_VERIFY_BY_SPIADDR_CMD | UL segment + * IAP_AUTOUPDATE_CMD | UKDIGEST0 in User Key segment + * + * @param spiaddr + * The spiaddr parameter specifies either the index + * in the SPI directory or the SPI address in the SPI Flash memory. + * Below is the list of the possible meaning of spiaddr parameter + * in accordance with the iap_cmd parameter. + * iap_cmd | spiaddr + * ----------------------|----------------- + * IAP_PROGRAM_BY_SPIIDX_CMD | Index in the SPI directory. + * IAP_VERIFY_BY_SPIIDX_CMD | Index in the SPI directory. + * IAP_PROGRAM_BY_SPIADDR_CMD | SPI address in the SPI Flash memory + * IAP_VERIFY_BY_SPIADDR_CMD | SPI address in the SPI Flash memory + * IAP_AUTOUPDATE_CMD | spiaddr is ignored as No index/address required for this command. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * Note: For the IAP services with command IAP_PROGRAM_BY_SPIIDX_CMD and + * IAP_VERIFY_BY_SPIIDX_CMD To support recovery SPI_IDX=1 should be an + * empty slot and the recovery image should be located in SPI_IDX=0. + * Since SPI_IDX=1 should be an empty slot it shouldn’t be passed into + * the system service. + * + * @return The SYS_iap_service function will return zero if the service + * executed successfully and the non-zero response from system + * controller indicates error. Please refer to the document + * link provided in the theory of operation section to know + * more about the service and service response. + */ +uint8_t SYS_iap_service +( + uint8_t iap_cmd, + uint32_t spiaddr, + uint16_t mb_offset +); + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_SYSSERV_PF_H */ diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h new file mode 100644 index 0000000..8b14b7e --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h @@ -0,0 +1,149 @@ +/******************************************************************************* + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Register bit offsets and masks definitions for CoreSysServices_PF driver. + */ + +#ifndef __CORE_SYSSERV_PF_REGISTERS +#define __CORE_SYSSERV_PF_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * SYS_SERV_CMD (offset 0x04) register details + */ +#define SS_CMD_REG_OFFSET 0x04u + +#define SS_CMD_OFFSET 0x04 +#define SS_CMD_MASK 0x0000FFFFu +#define SS_CMD_SHIFT 0u + +/*------------------------------------------------------------------------------ + * SYS_SERV_STAT (offset 0x08) register details + */ +#define SS_STAT_REG_OFFSET 0x08u + +#define SS_STAT_OFFSET 0x08 +#define SS_STAT_MASK 0x0000FFFFu +#define SS_STAT_SHIFT 0u + +/*------------------------------------------------------------------------------ + * SYS_SERV_REQ (offset 0x0C) register details + */ +#define SS_REQ_REG_OFFSET 0x0Cu + + +#define SS_REQ_REQ_OFFSET 0x0Cu +#define SS_REQ_REQ_MASK 0x00000001UL +#define SS_REQ_REQ_SHIFT 0u + +#define SS_REQ_ABUSY_OFFSET 0x0Cu +#define SS_REQ_ABUSY_MASK 0x00000002UL +#define SS_REQ_ABUSY_SHIFT 1u + +#define SS_REQ_NABUSY_OFFSET 0x0Cu +#define SS_REQ_NABUSY_MASK 0x00000004UL +#define SS_REQ_NABUSY_SHIFT 2u + +#define SS_REQ_SSBUSY_OFFSET 0x0Cu +#define SS_REQ_SSBUSY_MASK 0x00000008UL +#define SS_REQ_SSBUSY_SHIFT 3u + +#define SS_REQ_AREQ_OFFSET 0x0Cu +#define SS_REQ_AREQ_MASK 0x00000010UL +#define SS_REQ_AREQ_SHIFT 4u + +#define SS_REQ_NAREQ_OFFSET 0x0Cu +#define SS_REQ_NAREQ_MASK 0x00000020UL +#define SS_REQ_NAREQ_SHIFT 5u +/*------------------------------------------------------------------------------ + * MBX_ECCSTATUS (offset 0x10) register details + */ +#define MBX_ECCSTATUS_REG_OFFSET 0x10u + +#define MBX_ECCSTATUS_OFFSET 0x10 +#define MBX_ECCSTATUS_MASK 0x03u +#define MBX_ECCSTATUS_SHIFT 0u + + +/*------------------------------------------------------------------------------ + * MBX_WCNT (offset 0x14) register details + */ +#define MBX_WCNT_REG_OFFSET 0x14u + +#define MBX_WCNT_OFFSET 0x14 +#define MBX_WCNT_MASK 0x000001FFu +#define MBX_WCNT_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_RWCNT (offset 0x18) register details + */ +#define MBX_RCNT_REG_OFFSET 0x18u + +#define MBX_RCNT_OFFSET 0x18 +#define MBX_RCNT_MASK 0x000001FFu +#define MBX_RCNT_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_WADRDESC (offset 0x1C) register details + */ +#define MBX_WADDR_REG_OFFSET 0x1Cu + +#define MBX_WADDR_OFFSET 0x1C +#define MBX_WADDR_MASK 0x000001FFu +#define MBX_WADDR_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_RADRDESC (offset 0x20) register details + */ +#define MBX_RADDR_REG_OFFSET 0x20u + +#define MBX_RADDR_OFFSET 0x20 +#define MBX_RADDR_MASK 0x000001FFu +#define MBX_RADDR_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_WDATA (offset 0x28) register details + */ +#define MBX_WDATA_REG_OFFSET 0x28u + +#define MBX_WDATA_OFFSET 0x28 +#define MBX_WDATA_MASK 0xFFFFFFFFu +#define MBX_WDATA_SHIFT 0u + + +/*------------------------------------------------------------------------------ + * MBX_RDATA (offset 0x2C) register details + */ +#define MBX_RDATA_REG_OFFSET 0x2Cu + +#define MBX_RDATA_OFFSET 0x2C +#define MBX_RDATA_MASK 0xFFFFFFFFu +#define MBX_RDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * SS_USER (offset 0x30) register details + */ +#define SS_USER_REG_OFFSET 0x30u + +#define SS_USER_BUSY_OFFSET 0x30 +#define SS_USER_BUSY_MASK 0x00000001u +#define SS_USER_BUSY_SHIFT 0u + +#define SS_USER_RDVLD_OFFSET 0x30 +#define SS_USER_RDVLD_MASK 0x00000002u +#define SS_USER_RDVLD_SHIFT 1u + +#define SS_USER_CMDERR_OFFSET 0x30 +#define SS_USER_CMDERR_MASK 0x00000004u +#define SS_USER_CMDERR_SHIFT 2u + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_SYSSERV_PF_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c new file mode 100755 index 0000000..0c0a866 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c @@ -0,0 +1,297 @@ +/******************************************************************************* + * (c) Copyright 2007-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file core_uart_apb.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreUARTapb driver implementation. See file "core_uart_apb.h" for + * description of the functions implemented in this file. + * + */ + +#include "coreuartapb_regs.h" +#include "core_uart_apb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define NULL_INSTANCE ( ( UART_instance_t* ) 0 ) +#define NULL_BUFFER ( ( uint8_t* ) 0 ) + +#define MAX_LINE_CONFIG ( ( uint8_t )( DATA_8_BITS | ODD_PARITY ) ) +#define MAX_BAUD_VALUE ( ( uint16_t )( 0x1FFF ) ) +#define STATUS_ERROR_MASK ( ( uint8_t )( STATUS_PARITYERR_MASK | \ + STATUS_OVERFLOW_MASK | \ + STATUS_FRAMERR_MASK ) ) +#define BAUDVALUE_LSB ( (uint16_t) (0x00FF) ) +#define BAUDVALUE_MSB ( (uint16_t) (0xFF00) ) +#define BAUDVALUE_SHIFT ( (uint8_t) (5) ) + +#define STATUS_ERROR_OFFSET STATUS_PARITYERR_SHIFT + +/***************************************************************************//** + * UART_init() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_init +( + UART_instance_t * this_uart, + addr_t base_addr, + uint16_t baud_value, + uint8_t line_config +) +{ + uint8_t rx_full; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( line_config <= MAX_LINE_CONFIG ) + HAL_ASSERT( baud_value <= MAX_BAUD_VALUE ) + + if( ( this_uart != NULL_INSTANCE ) && + ( line_config <= MAX_LINE_CONFIG ) && + ( baud_value <= MAX_BAUD_VALUE ) ) + { + /* + * Store lower 8-bits of baud value in CTRL1. + */ + HAL_set_8bit_reg( base_addr, CTRL1, (uint_fast8_t)(baud_value & + BAUDVALUE_LSB ) ); + + /* + * Extract higher 5-bits of baud value and store in higher 5-bits + * of CTRL2, along with line configuration in lower 3 three bits. + */ + HAL_set_8bit_reg( base_addr, CTRL2, (uint_fast8_t)line_config | + (uint_fast8_t)((baud_value & + BAUDVALUE_MSB) >> BAUDVALUE_SHIFT ) ); + + this_uart->base_address = base_addr; +#ifndef NDEBUG + { + uint8_t config; + uint8_t temp; + uint16_t baud_val; + baud_val = HAL_get_8bit_reg( this_uart->base_address, CTRL1 ); + config = HAL_get_8bit_reg( this_uart->base_address, CTRL2 ); + /* + * To resolve operator precedence between & and << + */ + temp = ( config & (uint8_t)(CTRL2_BAUDVALUE_MASK ) ); + baud_val |= (uint16_t)( (uint16_t)(temp) << BAUDVALUE_SHIFT ); + config &= (uint8_t)(~CTRL2_BAUDVALUE_MASK); + HAL_ASSERT( baud_val == baud_value ); + HAL_ASSERT( config == line_config ); + } +#endif + + /* + * Flush the receive FIFO of data that may have been received before the + * driver was initialized. + */ + rx_full = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_RXFULL_MASK; + while ( rx_full ) + { + HAL_get_8bit_reg( this_uart->base_address, RXDATA ); + rx_full = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_RXFULL_MASK; + } + + /* + * Clear status of the UART instance. + */ + this_uart->status = (uint8_t)0; + } +} + +/***************************************************************************//** + * UART_send() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_send +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +) +{ + size_t char_idx; + uint8_t tx_ready; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( tx_buffer != NULL_BUFFER ) + HAL_ASSERT( tx_size > 0 ) + + if( (this_uart != NULL_INSTANCE) && + (tx_buffer != NULL_BUFFER) && + (tx_size > (size_t)0) ) + { + for ( char_idx = (size_t)0; char_idx < tx_size; char_idx++ ) + { + /* Wait for UART to become ready to transmit. */ + do { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( !tx_ready ); + /* Send next character in the buffer. */ + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)tx_buffer[char_idx] ); + } + } +} + +/***************************************************************************//** + * UART_fill_tx_fifo() + * See "core_uart_apb.h" for details of how to use this function. + */ +size_t +UART_fill_tx_fifo +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +) +{ + uint8_t tx_ready; + size_t size_sent = 0u; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( tx_buffer != NULL_BUFFER ) + HAL_ASSERT( tx_size > 0 ) + + /* Fill the UART's Tx FIFO until the FIFO is full or the complete input + * buffer has been written. */ + if( (this_uart != NULL_INSTANCE) && + (tx_buffer != NULL_BUFFER) && + (tx_size > 0u) ) + { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + if ( tx_ready ) + { + do { + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)tx_buffer[size_sent] ); + size_sent++; + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( (tx_ready) && ( size_sent < tx_size ) ); + } + } + return size_sent; +} + +/***************************************************************************//** + * UART_get_rx() + * See "core_uart_apb.h" for details of how to use this function. + */ +size_t +UART_get_rx +( + UART_instance_t * this_uart, + uint8_t * rx_buffer, + size_t buff_size +) +{ + uint8_t new_status; + uint8_t rx_full; + size_t rx_idx = 0u; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( rx_buffer != NULL_BUFFER ) + HAL_ASSERT( buff_size > 0 ) + + if( (this_uart != NULL_INSTANCE) && + (rx_buffer != NULL_BUFFER) && + (buff_size > 0u) ) + { + rx_idx = 0u; + new_status = HAL_get_8bit_reg( this_uart->base_address, STATUS ); + this_uart->status |= new_status; + rx_full = new_status & STATUS_RXFULL_MASK; + while ( ( rx_full ) && ( rx_idx < buff_size ) ) + { + rx_buffer[rx_idx] = HAL_get_8bit_reg( this_uart->base_address, + RXDATA ); + rx_idx++; + new_status = HAL_get_8bit_reg( this_uart->base_address, STATUS ); + this_uart->status |= new_status; + rx_full = new_status & STATUS_RXFULL_MASK; + } + } + return rx_idx; +} + +/***************************************************************************//** + * UART_polled_tx_string() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_polled_tx_string +( + UART_instance_t * this_uart, + const uint8_t * p_sz_string +) +{ + uint32_t char_idx; + uint8_t tx_ready; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( p_sz_string != NULL_BUFFER ) + + if( ( this_uart != NULL_INSTANCE ) && ( p_sz_string != NULL_BUFFER ) ) + { + char_idx = 0U; + while( 0U != p_sz_string[char_idx] ) + { + /* Wait for UART to become ready to transmit. */ + do { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( !tx_ready ); + /* Send next character in the buffer. */ + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)p_sz_string[char_idx] ); + char_idx++; + } + } +} + +/***************************************************************************//** + * UART_get_rx_status() + * See "core_uart_apb.h" for details of how to use this function. + */ +uint8_t +UART_get_rx_status +( + UART_instance_t * this_uart +) +{ + uint8_t status = UART_APB_INVALID_PARAM; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + /* + * Extract UART error status and place in lower bits of "status". + * Bit 0 - Parity error status + * Bit 1 - Overflow error status + * Bit 2 - Frame error status + */ + if( this_uart != NULL_INSTANCE ) + { + status = ( ( this_uart->status & STATUS_ERROR_MASK ) >> + STATUS_ERROR_OFFSET ); + /* + * Clear the sticky status for this instance. + */ + this_uart->status = (uint8_t)0; + } + return status; +} + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h new file mode 100755 index 0000000..c016403 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h @@ -0,0 +1,451 @@ +/******************************************************************************* + * (c) Copyright 2007-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file core_uart_apb.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief This file contains the application programming interface for the + * CoreUARTapb bare metal driver. + * + */ +/*=========================================================================*//** + @mainpage CoreUARTapb Bare Metal Driver. + + @section intro_sec Introduction + CoreUARTapb is an implementation of the Universal Asynchronous + Receiver/Transmitter aimed at minimal FPGA tile usage within a Microchip FPGA. + The CoreUARTapb bare metal software driver is designed to be used in systems + with no operating system. + + The CoreUARTapb driver provides functions for basic polled transmitting and + receiving operations. It also provide functions that allow the use of the + CoreUARTapb in interrupt-driven mode but leaves the management of interrupts + to the calling application, as interrupt enabling and disabling are not + controlled through the CoreUARTapb registers. The CoreUARTapb driver is + provided as C source code. + + @section driver_configuration Driver Configuration + Your application software should configure the CoreUARTapb driver by calling + the UART_init() function for each CoreUARTapb instance in the hardware design. + The configuration parameters include the CoreUARTapb hardware instance base + address and other runtime parameters, such as baud rate, bit width, and + parity. No CoreUARTapb hardware configuration parameters are needed by the + driver, apart from the CoreUARTapb hardware instance base address. Hence, no + additional configuration files are required to use the driver. + + A CoreUARTapb hardware instance is generated with fixed baud rate, character + size, and parity configuration settings as part of the hardware flow. The + baud_value and line_config parameter values passed to the UART_init() function + have no effect if fixed values were selected for the baud rate, character + size, and parity in the hardware configuration of CoreUARTapb. When fixed + values are selected for these hardware configuration parameters, the driver is + unable to overwrite the fixed values in the CoreUARTapb control registers, + CTRL1 and CTRL2. + + @section theory_op Theory of Operation + The CoreUARTapb software driver is designed to allow the control of multiple + instances of CoreUARTapb. Each instance of CoreUARTapb in the hardware design + is associated with a single instance of the UART_instance_t structure in the + software. You need to allocate memory for one unique UART_instance_t structure + instance for each CoreUARTapb hardware instance. The contents of these data + structures are initialized while calling the UART_init() function. A pointer + to the structure is passed to the subsequent driver functions in order to + identify the CoreUARTapb hardware instance you wish to perform the requested + operation on. + + Note: Do not attempt to directly manipulate the content of UART_instance_t + structures. This structure is only intended to be modified by the driver + function. + + Once initialized, the driver transmits and receives data. Transmit is + performed using the UART_send() function. If this function blocks, then it + returns only when the data passed to it has been sent to the CoreUARTapb + hardware. Data received by the CoreUARTapb hardware is read by the user + application using the UART_get_rx() function. + + The UART_fill_tx_fifo() function is also provided as a part of the + interrupt-driven transmit. This function fills the CoreUARTapb hardware + transmit FIFO with the content of a data buffer passed as a parameter before + returning. The control of the interrupts must be implemented outside the + driver, as the CoreUARTapb hardware does not provide the ability to enable + or disable its interrupt sources. + + The UART_polled_tx_string() function is provided to transmit a NULL-terminated + string in polled mode. If this function blocks, then it returns only when the + data passed to it has been sent to the CoreUARTapb hardware. + + The UART_get_rx_status() function returns the error status of the CoreUARTapb + receiver. This is used by applications to take appropriate action in case of + receiver errors. +*//*=========================================================================*/ +#ifndef __CORE_UART_APB_H +#define __CORE_UART_APB_H 1 + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + Data Bits Length Defines + ======================== + These constants define the data length in a UART packet. + | Constant | Description | + |-------------|---------------------------------------| + | DATA_7_BITS | Data length is 7-bits | + | DATA_8_BITS | Data length is 8-bits | + */ +#define DATA_7_BITS 0x00u +#define DATA_8_BITS 0x01u + +/***************************************************************************//** + Parity Defines + ============== + These constants define parity check options. + | Constant | Description | + |-------------|---------------------------------------| + | NO_PARITY | No Parity bit | + | EVEN_PARITY | Even Parity bit | + | ODD_PARITY | ODD Parity bit | + */ +#define NO_PARITY 0x00u +#define EVEN_PARITY 0x02u +#define ODD_PARITY 0x06u + +/***************************************************************************//** + Error Status Definitions + ======================== + These constants define the different types of possible errors in UART + transmission of data. + | Constant | Description | + |-------------------------|---------------------------------------| + | UART_APB_PARITY_ERROR | Data parity error | + | UART_APB_OVERFLOW_ERROR | Data overflow error | + | UART_APB_FRAMING_ERROR | Data framing error | + | UART_APB_NO_ERROR | No error | + | UART_APB_INVALID_PARAM | Invalid parameter | + */ +#define UART_APB_PARITY_ERROR 0x01u +#define UART_APB_OVERFLOW_ERROR 0x02u +#define UART_APB_FRAMING_ERROR 0x04u +#define UART_APB_NO_ERROR 0x00u +#define UART_APB_INVALID_PARAM 0xFFu + +/***************************************************************************//** + * There should be one instance of this structure for each instance of + * CoreUARTapb in your system. This structure instance identifies various UARTs + * in a system and should be passed as first parameter to UART functions to + * identify which UART performs the requested operation. The 'status' element in + * the structure is used to provide sticky status information. + */ +typedef struct +{ + addr_t base_address; + uint8_t status; +} UART_instance_t; + +/***************************************************************************//** + * The UART_init() function initializes the UART with the configuration passed + * as parameters. The configuration parameters are the baud_value that generates + * the baud rate and the line configuration (bit length and parity). + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data regarding + * this instance of the CoreUARTapb. This pointer is used to + * identify the target CoreUARTapb hardware instance in + * subsequent calls to the CoreUARTapb functions. + * @param base_addr The base_address parameter is the base address in the + * processor's memory map for the registers of the + * CoreUARTapb instance being initialized. + * @param baud_value The baud_value parameter selects the baud rate for the + * UART. The baud value is calculated from the frequency of + * the system clock in hertz and the desired baud rate using + * the following equation: + * baud_value = (clock / (baud_rate * 16)) - 1. + * The baud_value parameter must be a value in the range 0 + * to 8191 (or 0x0000 to 0x1FFF). + * @param line_config This parameter is the line configuration, specifies the + * bit length and parity settings. This is the logical OR of: + * - DATA_7_BITS + * - DATA_8_BITS + * - NO_PARITY + * - EVEN_PARITY + * - ODD_PARITY + * For example, 8 bits even parity would be specified as + * (DATA_8_BITS | EVEN_PARITY). + * @return This function does not return a value. + * @example + * @code + * #define BAUD_VALUE_57600 25 + * + * #define COREUARTAPB0_BASE_ADDR 0xC3000000UL + * + * UART_instance_t g_uart; + * int main() + * { + * UART_init(&g_uart, COREUARTAPB0_BASE_ADDR, + BAUD_VALUE_57600, (DATA_8_BITS | EVEN_PARITY)); + * } + * @endcode + */ +void +UART_init +( + UART_instance_t * this_uart, + addr_t base_addr, + uint16_t baud_value, + uint8_t line_config +); + +/***************************************************************************//** + * The UART_send() function is used to transmit data. It transfers the content + * of the transmitter data buffer, passed as a function parameter, into the + * UART's hardware transmitter FIFO. It returns when the full content of the + * transmitter data buffer has been transferred to the UART's transmitter FIFO. + * + * Note: You should not assume that the data you are sending using this function + * has been received at the other end by the time this function returns. The + * actual transmission over the serial connection is still be taking place at + * the time of the function return. It is safe to release or reuse the memory + * used as the transmit buffer once this function returns. + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data + * regarding this instance of the CoreUARTapbUART. + * @param tx_buffer The tx_buffer parameter is a pointer to a buffer that + * contains the data to be transmitted. + * @param tx_size The tx_size parameter is the size in bytes of the + * transmitted data. + * + * @return This function does not return a value. + * + * @example + * @code + * uint8_t testmsg1[] = {"\n\r\n\r\n\rUART_send() test message 1"}; + * UART_send(&g_uart,(const uint8_t *)&testmsg1,sizeof(testmsg1)); + * @endcode + */ +void +UART_send +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +); + +/***************************************************************************//** + * The UART_fill_tx_fifo() function fills the UART's transmitter hardware FIFO + * with the data found in the transmitter buffer that is passed in as a + * function parameter. The function returns either when the FIFO is full or + * when the complete contents of the transmitter buffer have been copied into + * the FIFO. It returns the number of bytes copied into the UART's transmitter + * hardware FIFO. This function is intended to be used as part of + * interrupt-driven transmission. + * + * Note: You should not assume that the data you transmit using this function + * has been received at the other end by the time this function returns. The + * actual transmission over the serial connection is still be taking place at + * the time of the function return. + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data + * regarding this instance of the UART. + * @param tx_buffer The tx_buffer parameter is a pointer to a buffer that + * contains the data to be transmitted. + * @param tx_size The tx_size parameter is the size in bytes of the + * transmitted data. + * @return This function returns the number of bytes copied into + * the UART's transmitter hardware FIFO. + * + * @example + * @code + * void send_using_interrupt + * ( + * uint8_t * pbuff, + * size_t tx_size + * ) + * { + * size_t size_in_fifo; + * size_in_fifo = UART_fill_tx_fifo( &g_uart, pbuff, tx_size ); + * } + * @endcode + */ +size_t +UART_fill_tx_fifo +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +); + +/***************************************************************************//** + * The UART_get_rx() function reads the content of the UART's receiver hardware + * FIFO and stores it in the receiver buffer that is passed in as a function + * parameter. It copies either the full contents of the FIFO into the receiver + * buffer, or just enough data from the FIFO to fill the receiver buffer, + * depending on the size of the receiver buffer. The size of the receiver + * buffer is passed in as a function parameter. UART_get_rx() returns the number + * of bytes copied into the receiver buffer. If no data was received at the time + * the function is called, the function returns 0. + * + * Note: This function reads and accumulates the receiver status of the + * CoreUARTapb instance before reading each byte from the receiver's + * data register/FIFO. This allows the driver to maintain a sticky + * record of any receiver errors that occur as the UART receives each + * data byte; receiver errors would otherwise be lost after each read + * from the receiver's data register. A call to the UART_get_rx_status() + * function returns any receiver errors accumulated during the execution + * of the UART_get_rx() function. + * + * Note: When FIFO mode is disabled in the CoreUARTapb hardware configuration, + * the driver accumulates a sticky record of any parity errors, framing + * errors, or overflow errors. When FIFO mode is enabled, the driver + * accumulates a sticky record of overflow errors only; in this case, + * interrupts must be used to handle parity errors or framing errors. + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data + * regarding this instance of the UART. + * @param rx_buffer The rx_buffer parameter is a pointer to a buffer where + * the received data is copied. + * @param buff_size The buff_size parameter is the size of the receive + * buffer in bytes. + * @return This function returns the number of bytes copied into + * the receive buffer. + * + * @example + * @code + * #define MAX_RX_DATA_SIZE 256 + * + * uint8_t rx_data[MAX_RX_DATA_SIZE]; + * uint8_t rx_size = 0; + * + * rx_size = UART_get_rx( &g_uart, rx_data, sizeof(rx_data) ); + * @endcode + */ +size_t +UART_get_rx +( + UART_instance_t * this_uart, + uint8_t * rx_buffer, + size_t buff_size +); + +/***************************************************************************//** + * The UART_polled_tx_string() function is used to transmit a NULL ('\0') + * terminated string. Internally, it polls for the transmit ready status and + * transfers the text starting at the address pointed by p_sz_string into + * the UART's hardware transmitter FIFO. It is a blocking function and returns + * only when the complete string has been transferred to the UART's transmit + * FIFO. + * + * Note: You should not assume that the data you transmit using this function + * has been received at the other end by the time this function returns. The + * actual transmission over the serial connection is still be taking place at + * the time of the function return. + * + * @param this_uart The this_uart parameter is the pointer to a + * UART_instance_t structure, which holds all data + * regarding this instance of the UART. + * @param p_sz_string The p_sz_string parameter is a pointer to a buffer + * containing the NULL ('\0') terminated string to be + * transmitted. + * @return This function does not return a value. + * + * @example + * @code + * uint8_t testmsg1[] = {"\r\n\r\nUART_polled_tx_string() test message 1\0"}; + * UART_polled_tx_string(&g_uart,(const uint8_t *)&testmsg1); + * @endcode + */ +void +UART_polled_tx_string +( + UART_instance_t * this_uart, + const uint8_t * p_sz_string +); + +/***************************************************************************//** + * The UART_get_rx_status() function returns the receiver error status of the + * CoreUARTapb instance. It reads both the current error status of the receiver + * and the accumulated error status from preceding calls to the UART_get_rx() + * function and combines them using a bitwise OR. It returns the cumulative + * parity, framing, and overflow error status of the receiver, since the + * previous call to UART_get_rx_status() as an 8-bit encoded value. + * + * Note: The UART_get_rx() function reads and accumulates the receiver status + * of the CoreUARTapb instance before reading each byte from the receiver's data + * register/FIFO. The driver maintains a sticky record of the cumulative error + * status, which persists after the UART_get_rx() function returns. The + * UART_get_rx_status() function clears this accumulated record of receiver + * errors before returning. + * + * @param this_uart The this_uart parameter is a pointer to a + * UART_instance_t structure which holds all data regarding + * this instance of the UART. + * @return This function returns the UART receiver error status as + * an 8-bit encoded value. The return value is 0, if there + * are no receiver errors occurred. The driver provides a + * set of bit mask constants, which should be compared with + * and/or used to mask the returned value to determine the + * receiver error status. + * When the return value is compared to the following bit + * masks, a non-zero result indicates that the + * corresponding error occurred: + * UART_APB_PARITY_ERROR (bit mask = 0x01) + * UART_APB_OVERFLOW_ERROR (bit mask = 0x02) + * UART_APB_FRAMING_ERROR (bit mask = 0x04) + * When the return value is compared to the following bit + * mask, a non-zero result indicates that no error + * occurred: + * UART_APB_NO_ERROR (0x00) + * + * @example + * @code + * UART_instance_t g_uart; + * uint8_t rx_data[MAX_RX_DATA_SIZE]; + * uint8_t err_status; + * err_status = UART_get_err_status(&g_uart); + * + * if(UART_APB_NO_ERROR == err_status ) + * { + * rx_size = UART_get_rx( &g_uart, rx_data, MAX_RX_DATA_SIZE ); + * } + * @endcode + */ +uint8_t +UART_get_rx_status +( + UART_instance_t * this_uart +); + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_UART_APB_H */ diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h new file mode 100755 index 0000000..c123cc3 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h @@ -0,0 +1,133 @@ +/******************************************************************************* + * (c) Copyright 2007-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file coreuartapb_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreUARTapb register definitions + */ + +#ifndef __CORE_UART_APB_REGISTERS +#define __CORE_UART_APB_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * TxData register details + */ +#define TXDATA_REG_OFFSET 0x0u + +/* + * TxData bits. + */ +#define TXDATA_OFFSET 0x0u +#define TXDATA_MASK 0xFFu +#define TXDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * RxData register details + */ +#define RXDATA_REG_OFFSET 0x4u + +/* + * RxData bits. + */ +#define RXDATA_OFFSET 0x4u +#define RXDATA_MASK 0xFFu +#define RXDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * ControReg1 register details + */ +#define CTRL1_REG_OFFSET 0x8u + +/* + * Baud value (Lower 8-bits) + */ +#define CTRL1_BAUDVALUE_OFFSET 0x8u +#define CTRL1_BAUDVALUE_MASK 0xFFu +#define CTRL1_BAUDVALUE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * ControReg2 register details + */ +#define CTRL2_REG_OFFSET 0xCu + +/* + * Bit length + */ +#define CTRL2_BIT_LENGTH_OFFSET 0xCu +#define CTRL2_BIT_LENGTH_MASK 0x01u +#define CTRL2_BIT_LENGTH_SHIFT 0u + +/* + * Parity enable. + */ +#define CTRL2_PARITY_EN_OFFSET 0xCu +#define CTRL2_PARITY_EN_MASK 0x02u +#define CTRL2_PARITY_EN_SHIFT 1u + +/* + * Odd/even parity selection. + */ +#define CTRL2_ODD_EVEN_OFFSET 0xCu +#define CTRL2_ODD_EVEN_MASK 0x04u +#define CTRL2_ODD_EVEN_SHIFT 2u + +/* + * Baud value (Higher 5-bits) + */ +#define CTRL2_BAUDVALUE_OFFSET 0xCu +#define CTRL2_BAUDVALUE_MASK 0xF8u +#define CTRL2_BAUDVALUE_SHIFT 3u + +/*------------------------------------------------------------------------------ + * StatusReg register details + */ +#define StatusReg_REG_OFFSET 0x10u + +#define STATUS_REG_OFFSET 0x10u + +/* + * Transmit ready. + */ +#define STATUS_TXRDY_OFFSET 0x10u +#define STATUS_TXRDY_MASK 0x01u +#define STATUS_TXRDY_SHIFT 0u + +/* + * Receive full. + */ +#define STATUS_RXFULL_OFFSET 0x10u +#define STATUS_RXFULL_MASK 0x02u +#define STATUS_RXFULL_SHIFT 1u + +/* + * Parity error. + */ +#define STATUS_PARITYERR_OFFSET 0x10u +#define STATUS_PARITYERR_MASK 0x04u +#define STATUS_PARITYERR_SHIFT 2u + +/* + * Overflow. + */ +#define STATUS_OVERFLOW_OFFSET 0x10u +#define STATUS_OVERFLOW_MASK 0x08u +#define STATUS_OVERFLOW_SHIFT 3u + +/* + * Frame Error. + */ +#define STATUS_FRAMERR_OFFSET 0x10u +#define STATUS_FRAMERR_MASK 0x10u +#define STATUS_FRAMERR_SHIFT 4u + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_UART_APB_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.c b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.c new file mode 100644 index 0000000..a2f4911 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.c @@ -0,0 +1,765 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Mi-V I2C Soft IP bare-metal driver. This module is delivered as part of + * Extended Sub System(ESS) MIV_ESS. + * Please refer to miv_i2c.h file for more information. + */ + +#include "miv_i2c.h" + +#define MIV_I2C_ERROR 0xFFu + +/*------------------------------------------------------------------------------ + * MIV I2C transaction direction. + */ +#define MIV_I2C_WRITE_DIR 0u +#define MIV_I2C_READ_DIR 1u + +/* -- TRANSACTIONS TYPES -- */ +#define MIV_I2C_NO_TRANSACTION 0u +#define MIV_I2C_MASTER_WRITE_TRANSACTION 1u +#define MIV_I2C_MASTER_READ_TRANSACTION 2u +#define MIV_I2C_MASTER_SEQUENTIAL_READ_TRANSACTION 3u + +/*------------------------------------------------------------------------------ + * MIV I2C HW states + */ +#define MIV_I2C_IDLE 0x00u +#define MIV_I2C_TX_STA_CB 0x01u +#define MIV_I2C_TX_DATA 0x02u +#define MIV_I2C_RX_DATA 0x03u + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_disable_irq() disables the Mi-V I2C interrupt. + */ +void +MIV_I2C_disable_irq +( + void +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_enable_irq() enables the Mi-V I2C interrupt. + */ +void +MIV_I2C_enable_irq +( + void +); + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_init +( + miv_i2c_instance_t *this_i2c, + addr_t base_addr +) +{ + /* Assign the base address + * Clock Prescale value set + * MIV_I2C interrupt enabled + * I2C core enable + */ + psr_t processor_state; + + /* Disabling the interrupts */ + processor_state = HAL_disable_interrupts(); + + /* + * Initialize all items of the this_miv_i2c data structure to zero. This + * initializes all state variables to their init value. It relies on + * the fact that NO_TRANSACTION, MIV_I2C_SUCCESS and I2C_RELEASE_BUS all + * have an actual value of zero. + */ + memset(this_i2c, 0, sizeof(miv_i2c_instance_t)); + + this_i2c->base_addr = base_addr; + + HAL_restore_interrupts(processor_state); +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_config +( + miv_i2c_instance_t *this_i2c, + uint16_t clk_prescale +) +{ + /* Assign the base address + * Clock Prescale value set + * MIV_I2C interrupt enabled + * I2C core enable + */ + psr_t processor_state; + + /* Disabling the interrupts */ + processor_state = HAL_disable_interrupts(); + + /* Before writing to prescale reg, the core enable must be zero */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CTRL_CORE_EN, 0x00u); + + /* Set the prescale value */ + HAL_set_16bit_reg(this_i2c->base_addr, PRESCALE, clk_prescale); + + /* Enable the MIV I2C interrupts */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CTRL_IRQ_EN, 0x01u); + + /* Enable the MIV I2C core */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CTRL_CORE_EN, 0x01u); + + this_i2c->master_state = MIV_I2C_IDLE; + + HAL_restore_interrupts(processor_state); +} + +/* + * Please refer to miv_i2c.h for more info + */ +uint8_t +MIV_I2C_start +( + miv_i2c_instance_t *this_i2c +) +{ + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + /* Generate I2C start condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + HAL_restore_interrupts(processor_state); + + return 0u; +} + +/* + * Please refer to miv_i2c.h for more info + */ +uint8_t +MIV_I2C_stop +( + miv_i2c_instance_t *this_i2c +) +{ + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + /* Generate I2C stop condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + HAL_restore_interrupts(processor_state); + + return 0u; +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_write +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t bus_options, + uint8_t ack_polling_options +) +{ + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + /* I2C write flow + * + * Check I2C status for ongoing transaction + * Populate the structure with input data + * Generate start condition + * Set the write_direction and target address. + */ + + /* Update the transaction only when there is no ongoing I2C transaction */ + if (this_i2c->transaction == MIV_I2C_NO_TRANSACTION) + { + this_i2c->transaction = MIV_I2C_MASTER_WRITE_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MIV_I2C_MASTER_WRITE_TRANSACTION ; + + /* Populate the i2c instance structure */ + + /* Set the target addr */ + this_i2c->target_addr = i2c_target_addr; + this_i2c->dir = MIV_I2C_WRITE_DIR; + + /* Set up the tx buffer */ + this_i2c->master_tx_buffer = write_buffer; + this_i2c->master_tx_size = write_size; + this_i2c->master_tx_idx = 0u; + + /* Set the I2C status in progress and setup the options */ + this_i2c->bus_options = bus_options; + this_i2c->ack_polling_options = ack_polling_options; + this_i2c->master_status = MIV_I2C_IN_PROGRESS; + + + /* Generate I2C start condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* write target address and write bit */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, MIV_I2C_WRITE_DIR); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, i2c_target_addr); + + /* Set WR bit to transmit start condition and control byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + /* Set current master hw state -> transmitted start condition and + * control byte + */ + this_i2c->master_state = MIV_I2C_TX_STA_CB; + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( MIV_I2C_HOLD_BUS == this_i2c->bus_status ) + { + /* Must toggle IACK bit to clear the MIV_I2C IRQ*/ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00); + } + + MIV_I2C_enable_irq(); + + HAL_restore_interrupts(processor_state); + +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_read +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +) +{ + psr_t processor_state; + uint8_t status = MIV_I2C_SUCCESS; + + processor_state = HAL_disable_interrupts(); + + /* MIV I2C Read operation flow + * + * Check for ongoing transaction + * Populate the i2c instance structure + * Generate the start condition + * Set the READ_direction bit and target addr + */ + + uint8_t read_stat = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_TIP); + + /* Update the transaction only when there is no ongoing I2C transaction */ + if (this_i2c->transaction == MIV_I2C_NO_TRANSACTION) + { + this_i2c->transaction = MIV_I2C_MASTER_READ_TRANSACTION; + } + + this_i2c->pending_transaction = MIV_I2C_MASTER_READ_TRANSACTION; + + /* Populate the MIV I2C instance structure */ + + this_i2c->target_addr = i2c_target_addr; + this_i2c->dir = MIV_I2C_READ_DIR; + + /* Populate read buffer */ + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set the BUS and ACK polling options */ + this_i2c->bus_options = bus_options; + this_i2c->ack_polling_options = ack_polling_options; + + /* Generate the start condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* Set the DIR bit and target addr */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, MIV_I2C_READ_DIR); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, i2c_target_addr); + + /* Set the WR bit to transmit the start condition and command byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + /* Set the i2c master state and status transmitting STA and Command Byte */ + this_i2c->master_state = MIV_I2C_TX_STA_CB; + this_i2c->master_status = MIV_I2C_IN_PROGRESS; + + /* Toggle the IACK bit if required */ + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( MIV_I2C_HOLD_BUS == this_i2c->bus_status ) + { + /* Must toggle IACK bit to clear the MIV_I2C IRQ*/ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00); + } + /* Enable the I2C interrupt */ + MIV_I2C_enable_irq(); + + HAL_restore_interrupts(processor_state); +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_write_read +( + miv_i2c_instance_t *this_i2c, + uint8_t target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +) +{ + uint8_t status = MIV_I2C_SUCCESS; + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + uint8_t read_stat = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_TIP); + + /* I2C write read operation flow + * + * Used to read the data from set address offset + * + * Configure the i2c instance structure + * generate the start and configure the dir and target addr + * set wr bit to transmit the start and command byte + * + */ + + /* Update the transaction only when there is no ongoing I2C transaction */ + if (this_i2c->transaction == MIV_I2C_NO_TRANSACTION) + { + this_i2c->transaction = MIV_I2C_MASTER_READ_TRANSACTION; + } + + this_i2c->pending_transaction = MIV_I2C_MASTER_READ_TRANSACTION; + + /* Populate the I2C instance */ + + this_i2c->target_addr = target_addr; + + /* setup the i2c direction */ + this_i2c->dir = MIV_I2C_WRITE_DIR; + + /* set up transmit buffer */ + this_i2c->master_tx_buffer = write_buffer; + this_i2c->master_tx_size = write_size; + this_i2c->master_tx_idx = 0u; + + /* set up receive buffer */ + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set the bus and ack polling options */ + this_i2c->bus_options = bus_options; + this_i2c->ack_polling_options = ack_polling_options; + + /* Generate the start command */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* Set the DIR and target addr */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + /* Set the WR bit to transmit the start command and command byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + /* Set the i2c master state and status transmitting STA and Command Byte */ + this_i2c->master_state = MIV_I2C_TX_STA_CB; + this_i2c->master_status = MIV_I2C_IN_PROGRESS; + + /* + * Clear interrupt if required + */ + if ( MIV_I2C_HOLD_BUS == this_i2c->bus_status ) + { + /* Must toggle IACK bit to clear the MIV_I2C IRQ*/ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00u); + } + + /* Enable the I2C interrupt */ + MIV_I2C_enable_irq(); + + HAL_restore_interrupts(processor_state); +} + +/* MIV_I2C_isr() + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_isr +( + miv_i2c_instance_t *this_i2c +) +{ + uint8_t i2c_state; + uint8_t i2c_ack_status; + uint8_t i2c_al_status; + uint8_t hold_bus; + + /* Read the I2C master state */ + i2c_state = this_i2c->master_state; + + /* Read the ack and al status */ + i2c_ack_status = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_RXACK); + i2c_al_status = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_AL); + + switch (i2c_state) + { + /* I2C ISR State Machine + * + * Cases: + * - Transmit start condition and control byte + * - Received ACK and bus arbitration was not lost (Read or Write) + * - Received NACK + * - Bus arbitration lost + * + * - Transmit data + * - Received ACK and bus arbitration was not lost (Read or Write) + * - Received NACK + * - Bus arbitration lost + * + * - Receive data + * - Received ACK and bus arbitration was not lost (Read or Write) + * - Bus arbitration lost + */ + + case MIV_I2C_TX_STA_CB: + + /* Received ACK from target and I2C bus arbitration is not lost */ + if (i2c_ack_status == 0u && i2c_al_status == 0u) + { + /* If I2C master write operation */ + if (this_i2c->dir == MIV_I2C_WRITE_DIR) + { + /* write first byte of data and set the WR bit to transfer the data */ + HAL_set_8bit_reg(this_i2c->base_addr, TRANSMIT, + this_i2c->master_tx_buffer[this_i2c->master_tx_idx]); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + /* Increment the index */ + this_i2c->master_tx_idx++; + + /* Set the master state to TX data */ + this_i2c->master_state = MIV_I2C_TX_DATA; + } + /* Master read operation */ + else + { + if (this_i2c->master_rx_size == 1u) + { + /* Send the ACK if the rx size is 1, transmit NACK to slave + * after receiving 1 byte to indicate slave to stop sending + * the data + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_ACK, 0x01u); + } + + /* Send the RD command to slave */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_RD, 0x01u); + + /* Increment the index */ + this_i2c->master_rx_idx++; + + /* Change state to receive data */ + this_i2c->master_state = MIV_I2C_RX_DATA; + } + } + else if (i2c_ack_status == 1u) + { + if (this_i2c->ack_polling_options == MIV_I2C_ACK_POLLING_ENABLE) + { + /* Target responded with NACK and ACK polling option is enabled + * + * Re-send the start condition and control byte + * + * TO-DO: This might become infinite loop check for timeout + * options. + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + this_i2c->master_tx_idx = 0u; + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + else + { + /* Target responded with NACK and ACK polling is disabled + * Abort the transaction and move to IDLE state + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + + this_i2c->master_status = MIV_I2C_FAILED; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + + this_i2c->master_state = MIV_I2C_IDLE; + } + } + + else if (i2c_al_status == 1u) + { + /* Arbitration was lost on the BUS during the transmission of + * previous start condition and control byte. + * Re-send the STA and CB + */ + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + break; + + /* Transmit master data */ + case MIV_I2C_TX_DATA: + + /* ACK received and arbitration was not lost */ + if (i2c_ack_status == 0u && i2c_al_status == 0u) + { + uint8_t tx_buff[this_i2c->master_tx_size]; + if (this_i2c->master_tx_idx < this_i2c->master_tx_size) + { + HAL_set_8bit_reg(this_i2c->base_addr, TRANSMIT, + this_i2c->master_tx_buffer[this_i2c->master_tx_idx]); + + tx_buff[this_i2c->master_tx_idx] = this_i2c->master_tx_buffer[this_i2c->master_tx_idx]; + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + /* Increment the index */ + this_i2c->master_tx_idx++; + + /* Set the master state to TX data */ + this_i2c->master_state = MIV_I2C_TX_DATA; + } + + /* All the bytes are transmitted */ + else if (this_i2c->master_tx_idx == this_i2c->master_tx_size) + { + /* If this is a MASTER_READ_TRANSACTION, hold bus and start a + new transfer in read mode now that the read address has been + written to the slave */ + if(this_i2c->transaction == MIV_I2C_MASTER_READ_TRANSACTION) + + { + //Switch direction to READ + this_i2c->dir = MIV_I2C_READ_DIR; + + // Set the STA bit + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* Set the DIR bit and target addr */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, MIV_I2C_READ_DIR); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, this_i2c->target_addr); + + /* Set the WR bit to transmit the start condition and command byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + // Reset the buffer index + this_i2c->master_tx_idx = 0u; + this_i2c->master_rx_idx = 0u; + + /* Set the master state to RX data */ + this_i2c->master_state = MIV_I2C_RX_DATA; + } + + else + { + /* If releasing the bus, transmit the stop condition at the end + * of the transfer. + */ + hold_bus = this_i2c->bus_status & MIV_I2C_HOLD_BUS; + + if (hold_bus == 0) + { + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + } + else + { + MIV_I2C_disable_irq(); + } + this_i2c->master_status = MIV_I2C_SUCCESS; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + this_i2c->master_state = MIV_I2C_IDLE; + } + } + } + + else if (i2c_ack_status == 1u) + { + /* Received NACK from target device + * + * Release the bus and end the transfer + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + + this_i2c->master_status = MIV_I2C_FAILED; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + + this_i2c->master_state = MIV_I2C_IDLE; + } + + else if (i2c_al_status == 1u) + { + /* Arbitration was lost on the BUS during the transmission of + * previous start condition and control byte. + * Re-send the STA and CB + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, + this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + break; + + /* Receive target device data */ + case MIV_I2C_RX_DATA: + + if (i2c_al_status == 0u) + { + if (this_i2c->master_rx_idx < this_i2c->master_rx_size) + { + this_i2c->master_rx_buffer[this_i2c->master_rx_idx - 1u] = + HAL_get_8bit_reg(this_i2c->base_addr, RECEIVE); + + /* If next byte is last one + * Send NACK to target device to stop sending data + */ + if (this_i2c->master_rx_idx == (this_i2c->master_rx_size - 1u)) + { + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_ACK, 0x01u); + } + + else + { + /* Send ACK to receive next bytes */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_ACK, 0x00u); + } + + /* Set RD bit to receive next byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_RD, 0x01u); + + this_i2c->master_rx_idx++; + } + + /* Received all bytes */ + else //if (this_i2c->master_rx_idx == this_i2c->master_rx_size) + { + this_i2c->master_rx_buffer[this_i2c->master_rx_idx - 1] = + HAL_get_8bit_reg(this_i2c->base_addr, RECEIVE); + + hold_bus = this_i2c->bus_status & MIV_I2C_HOLD_BUS; + + if (hold_bus == 0) + { + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + } + else + { + MIV_I2C_disable_irq(); + } + this_i2c->master_status = MIV_I2C_SUCCESS; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + + this_i2c->master_state = MIV_I2C_IDLE; + } + } + + else if (i2c_al_status == 1u) + { + /* Arbitration was lost on the BUS during the transmission of + * previous start condition and control byte. + * Re-send the STA and CB + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, + this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + break; + } + + /* Toggle the IACK bit to clear interrupt */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00u); +} + +/* + * Please refer to miv_i2c.h for more info + */ +uint8_t +MIV_I2C_get_status +( + miv_i2c_instance_t *this_i2c +) +{ + uint8_t i2c_status; + + i2c_status = HAL_get_8bit_reg(this_i2c->base_addr, STATUS); + + return i2c_status; +} diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.h new file mode 100644 index 0000000..c5e704d --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.h @@ -0,0 +1,854 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * I2C module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(MIV_ESS). + */ + +/*=========================================================================*//** + @mainpage Mi-V I2C Bare Metal Driver + + ============================================================================== + Introduction + ============================================================================== + The Mi-V I2C driver provides a set of functions for controlling the Mi-V I2C + Soft-IP module. This module is delivered as a part of the Mi-V Extended + Sub System(MIV_ESS). The driver provides a minimal APB-driven I2C interface, + supporting initiator read and write access to peripheral I2C devices. + + The major features provided by the Mi-V I2C driver are: + - Support for configuring the I2C instance. + - I2C master operations. + - I2C ISR. + + This driver can be used as part of a bare metal system where no operating + system is available. The driver can be adapted for use as part of an + operating system, but the implementation of the adaptation layer between the + driver and the operating system's driver model is outside the scope of this + driver. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + The application software should initialize and configure the Mi-V I2C through + the call to the MIV_I2C_init() and MIV_I2C_config() function for Mi-V I2C + instance in the design. The configuration parameter include base address and + Prescaler value. + + ------------------------------ + Interrupt Control + ------------------------------ + The Mi-V I2C driver has to enable and disable the generation of interrupts by + Mi-V I2C at various times while operating. This enabling and disabling of the + interrupts must be done through the Mi-V RV32 HAL provided interrupt handlers. + For that reason, the method controlling the Mi-V I2C interrupts is system + specific and it is necessary to customize the MIV_I2C_enable_irq() and + MIV_I2C_disable_irq() functions as per requirement. + + The implementation of MIV_I2C_enable_irq() should permit the interrupts + generated by the Mi-V I2C to the processor through a call to respective miv-hal + interrupt handler. The implementation of MIV_I2C_disable_irq() should prevent + the interrupts generated by a Mi-V I2C from interrupting the processor. + Please refer to the miv_i2c_interrupt.c for more information about the + implementation. + + No MIV_I2C hardware configuration parameters are used by the driver, apart + from the MIV_I2C base address. Hence, no additional configuration files + are required to use the driver. + + ============================================================================== + Theory of Operation + ============================================================================== + The Mi-V I2C software driver is designed to allow the control of multiple + instances of Mi-V I2C. Each instance of Mi-V I2C in the hardware design is + associated with a single instance of the miv_i2c_instance_t structure in the + software. User must allocate memory for one unique miv_i2c_instance_t + structure for each instance of Mi-V I2C in the hardware. + A pointer to the structure is passed to the subsequent driver functions in + order to identify the MIV_I2C hardware instance and to perform requested + operation. + + Note: Do not attempt to directly manipulate the contents of the + miv_i2c_instance_t structure. These structures are only intended to be modified + by the driver functions. + + The Mi-V I2C driver functions are grouped into following categories: + - Initialization and configuration + - I2C master operation functions to handle write, read and write_read + operations. + - Interrupt control + + -------------------------------- + Initialization and configuration + -------------------------------- + The Mi-V I2C device is first initialized by the call to MIV_I2C_init(). This + function initializes the instance of Mi-V I2C with the base address. + MIV_I2C_init() function must be called before any other Mi-V I2C driver API. + + The configuration of the Mi-V I2C instance is done via call to the + MIV_I2C_config() function. This function will set the prescale value which is + used to set the frequency of the I2C clock(SCLK) generated by I2C module. + + --------------------------------- + Transaction types + --------------------------------- + The driver is designed to handle three types of transactions: + - Write transactions + - Read transactions + - Write-Read transaction + + ### Write Transaction + The write transaction begins with master sending a start condition, followed + by device address byte with the R/W bit set to logic '0', and then by the + word address bytes. The slave acknowledges the receipt of its address with + acknowledge bit. The master sends one byte at a time to the slave, which must + acknowledge the receipt of each byte for the next byte to be sent. The master + sends STOP condition to complete the transaction. The slave can abort the + transaction by replying with negative acknowledge. + + The application programmer can choose not to send the STOP bit at the end of + the transaction causing repetitive start conditions. + + ### Read Transaction + The master I2C device initiates a read transaction by sending a START bit + as soon as the bus becomes free. The start condition is followed by the + control byte which contains 7-bit slave address followed by R/W bit set to + logic '1'. The slave sends data one byte at a time to the master, which must + acknowledge receipt of each byte for the next byte to be sent. The master + sends a non-acknowledge bit following the last byte it wishes to read + followed by a STOP bit. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ### Write-Read Transaction + The write read transaction is a combination of a write transaction + immediately followed by a read transaction. There is no STOP condition sent + between the write and read phase of write-read transaction. A repeated START + condition is sent between the write and read phases. + + Whilst the write handler is being executed, the slave holds the clock line + low to stretch the clock until the response is ready. + + The write-read transaction is typically used to send an memory/register + address in the write transaction specifying the start address of the data to + be transferred during the read phase. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ------------------------------------- + Interrupt Control + ------------------------------------- + The Mi-V I2C driver is interrupt driven and it uses the MIV_I2C_irq() function + to drive the ISR state machine which is at the heart of the driver. The + application is responsible for providing the link between the interrupt + generating hardware and the Mi-V I2C interrupt handler and must ensure that + the MIV_I2C_isr() function is called with the correct miv_i2c_instance_t + structure pointer for the Mi-V I2C instance initiating the interrupt. + +*//*=========================================================================*/ +#ifndef MIV_I2C_H_ +#define MIV_I2C_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "miv_i2c_regs.h" +#include + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#else +#include "hal.h" +#endif + +/*-------------------------------------------------------------------------*//** + The miv_i2c_status_t type is used to report the status of I2C transactions. + */ +typedef enum miv_i2c_status +{ + MIV_I2C_SUCCESS = 0u, + MIV_I2C_IN_PROGRESS, + MIV_I2C_FAILED, + MIV_I2C_TIMED_OUT +}miv_i2c_status_t; + +/*-------------------------------------------------------------------------*//** + This structure is used to identify the MIV_I2C hardware instances in a system. + Your application software should declare one instance of this structure for + each instance of the MIV_I2C in your system. The function MIV_I2C_init() + Initializes this structure. A pointer to an initialised instance of the structure + should be passed as the first parameter to the MIV_I2C driver functions, to + identify which MIV_I2C hardware instance should perform the requested operation. + + The contents of this data structure should not be modified or used outside of + the MIV_I2C driver. Software using the MIV_I2C driver should only need to + create one single instance of this data structure for each MIV_I2C hardware + instance in the system, then pass a pointer to these data structures with each + call to the MIV_I2C driver in order to identify the MIV_I2C hardware instance + it wishes to use. +*/ + +typedef struct miv_i2c_instance +{ + addr_t base_addr; + + /* Transmit related info:*/ + uint_fast8_t target_addr; + + /* Current transaction type */ + uint8_t transaction; + + uint8_t bus_options; + + uint8_t ack_polling_options; + + /* Current State of the I2C master */ + uint8_t master_state; + + /* Master TX INFO: */ + const uint8_t * master_tx_buffer; + uint_fast16_t master_tx_size; + uint_fast16_t master_tx_idx; + uint_fast8_t dir; + + /* Master RX INFO: */ + uint8_t * master_rx_buffer; + uint_fast16_t master_rx_size; + uint_fast16_t master_rx_idx; + + /* Master Status */ + volatile miv_i2c_status_t master_status; + uint32_t master_timeout_ms; + + /* user specific data */ + void *p_user_data ; + + /* I2C bus status */ + uint8_t bus_status; + + /* Is transaction pending flag */ + uint8_t is_transaction_pending; + + /* I2C Pending transaction */ + uint8_t pending_transaction; + +}miv_i2c_instance_t; + + +/*-------------------------------------------------------------------------*//** + MIV_I2C_RELEASE_BUS + ===================== + The MIV_I2C_RELEASE_BUS constant is used to specify the bus_options parameter + for MIV_I2C_read(), MIV_I2C_write() and MIV_I2C_write_read() to indicate + that a STOP bit must be generated at the end of the I2C transaction to release + the bus. + */ +#define MIV_I2C_RELEASE_BUS 0x00u + + +/*-------------------------------------------------------------------------*//** + MIV_I2C_HOLD_BUS + ===================== + The MIV_I2C_HOLD_BUS constant is used to specify the bus_optionsparameter + for MIV_I2C_read(), MIV_I2C_write() and MIV_I2C_write_read() to indicate + that a STOP bit must not be generated at the end of the I2C transaction in + order to retain the bus ownership. This causes the next transaction to + begin with a repeated START bit and no STOP bit between the transactions. + */ +#define MIV_I2C_HOLD_BUS 0x01u + +/*-------------------------------------------------------------------------*//** + MIV_I2C_ACK_POLLING_DISABLE + ===================== + The MIV_I2C_ACK_POLLING_DISABLE constant is used to specify the + ack_polling_options parameter to functions MIV_I2C_write(), + MIV_I2C_write_read() and MIV_I2C_read(). Acknowledgment polling is used when + working with I2C memory devices such as EEPROM, which feature an internal + write cycle. + + With acknowledgment polling disabled, if the target slave device responds to the + control byte with a NACK, the MIV_I2C will abort the transfer. + */ +#define MIV_I2C_ACK_POLLING_DISABLE 0x00u + +/*-------------------------------------------------------------------------*//** + MIV_I2C_ACK_POLLING_ENABLE + ===================== + The MIV_I2C_ACK_POLLING_ENABLE constant is used to specify the + ack_polling_options parameter to functions MIV_I2C_write(), + MIV_I2C_write_read() and MIV_I2C_read(). acknowledgment polling is used when + working with I2C memory devices such as EEPROM, which feature an internal + write cycle. + + With acknowledgment polling enabled, if the slave device responds to the + control byte with a NACK, the MIV_I2C will repeatedly transmit another control + byte until the slave device accepts the connection with an ACK, or the timeout + specified in the MIV_I2C_wait_complete() function is reached. Acknowledgment + polling allows for the next read/write operation to be started as soon as the + EEPROM has completed its internal write cycle. + */ +#define MIV_I2C_ACK_POLLING_ENABLE 0x01u + +/*--------------------------------Public APIs---------------------------------*/ + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_init() function is used to initialize the Mi-V I2C module instance + with the base address. + + Note: This function should be called before calling any other Mi-V I2C + functions. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + @param base_addr + Base address of the Mi-V I2C module instance in the MIV_ESS + soft IP. + + @return + This function does not return any value. + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + } + @endcode + */ +void +MIV_I2C_init +( + miv_i2c_instance_t *this_i2c, + addr_t base_addr +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_config() function is used to configure the Mi-V I2C module. This + function will set the prescale value which is used to set the frequency of + the I2C clock(SCLK) generated by I2C module and also enables the I2C core and + interrupts. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param clk_prescale + The value used to set the frequency of Mi-V I2C serial clock + (SCLK) generated by the Mi-V I2C module instance. The + prescaler value required to set particular frequency of + Mi-V I2C can be calculated using following formula: + + prescaler = (System Clock Frequency) / (5 * (Desired I2C Clock Frequency)) - 1 + + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + } + @endcode + */ +void +MIV_I2C_config +( + miv_i2c_instance_t *this_i2c, + uint16_t clk_prescale +); + + +uint8_t +MIV_I2C_start +( + miv_i2c_instance_t *this_i2c +); + + +uint8_t +MIV_I2C_stop +( + miv_i2c_instance_t *this_i2c +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_write() is used to set up and start the Mi-V I2C master write + transaction. This function is used for all Mi-V master write operation. + + For more information about the operation, please refer to the 'theory of + operations' section at the start of this document. + + This function returns immediately after initiating the transaction. The content + of the write buffer passed as parameter should not be modified until the write + transaction completes. It also means that the memory allocated for the write + buffer should not be freed or should not go out of scope before the write + completes. + You can check for the write transaction completion by polling the master_status + from miv_i2c_instance_t structure as shown in the sample code. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param i2c_target_addr + This parameter specifies the serial address for the slave + device. + + @param write_buffer + This parameter is a pointer to the buffer holding data to be + written to target I2C device. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param write_size + Number of bytes held in the write_buffer to be written to the + I2C device. + @param bus_options: + The bus_options parameter is used to indicate if the I2C bus + should be released on completion of the write transaction. + Using the MIV_I2C_RELEASE_BUS constant for the bus_options + parameter causes a STOP bit to be generated at the end of the + write transaction causing the bus to be released for other I2C + devices to use. Using the MIV_I2C_HOLD_BUS constant as + bus_options parameter prevents a STOP bit from being generated + at the end of the write transaction, preventing other I2C + devices from initiating a bus transaction. + + @param ack_polling_options: + The ack_polling_options parameter is used to indicate how the + MIV_I2C will respond if the slave device transmits a NACK to + the I2C control byte. Using the MIV_I2C_ACK_POLLING_DISABLE + constant for the ack_polling_options parameter causes the + MIV_I2C to abort the transfer if the slave device responds to + the I2C control byte with a NACK. Using the + MIV_I2C_ACK_POLLING_ENABLE constant for the ack_polling_options + parameter causes the MIV_I2C to repeatedly transmit a control + byte to the slave device until the slave device responds with + an ACK. + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + + MIV_I2C_write (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_tx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + } + @endcode + */ +void +MIV_I2C_write +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t bus_options, + uint8_t ack_polling_options +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_read() is used to set up and start the Mi-V I2C master read + transaction. This function is used for all MIV_I2C master read operation. + + For more information about the operation, please refer to the 'theory of + operations' section at the start of this document. + + This function returns immediately after initiating the transaction. The content + of the read buffer passed as parameter should not be modified until the write + transaction completes. It also means that the memory allocated for the read + buffer should not be freed or should not go out of scope before the read + completes. + You can check for the write transaction completion by polling the master_status + from miv_i2c_instance_t structure as shown in the sample code. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param i2c_target_addr + This parameter specifies the serial address for the slave + device. + + @param read_buffer + This parameter is a pointer to the buffer where the data + received from the I2C slave device is stored. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param read_size + Number of bytes held in the write_buffer to be read from the + I2C device. + + @param bus_options: + The bus_options parameter is used to indicate if the I2C bus + should be released on completion of the write transaction. + Using the MIV_I2C_RELEASE_BUS constant for the bus_options + parameter causes a STOP bit to be generated at the end of the + write transaction causing the bus to be released for other I2C + devices to use. Using the MIV_I2C_HOLD_BUS constant as + bus_options parameter prevents a STOP bit from being generated + at the end of the write transaction, preventing other I2C + devices from initiating a bus transaction. + + @param ack_polling_options: + The ack_polling_options parameter is used to indicate how the + MIV_I2C will respond if the slave device transmits a NACK to + the I2C control byte. Using the MIV_I2C_ACK_POLLING_DISABLE + constant for the ack_polling_options parameter causes the + MIV_I2C to abort the transfer if the slave device responds to + the I2C control byte with a NACK. Using the + MIV_I2C_ACK_POLLING_ENABLE constant for the ack_polling_options + parameter causes the MIV_I2C to repeatedly transmit a control + byte to the slave device until the slave device responds with + an ACK. + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + + MIV_I2C_write (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_tx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + + // reset miv_i2c_status variable + miv_i2c_status = 0u; + + MIV_I2C_read (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_rx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + } + @endcode + */ +void +MIV_I2C_read +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_write_read() is used to set up and start the Mi-V I2C master + write_read transaction. This function is used for all MIV_I2C master write_read + operation. + + This function is used in cases where data is being requested from a specific + address offset inside the target I2C slave device. + In this type of I2C operation, the I2C master starts by initiating a write + operation. During this write operation, the specific address offset is written + to the I2C slave. Once the address offset has been written to the I2C slave, + the I2C master transmits a repeated start, and initiates a read operation to + read data from the set address. + + For more information about the operation, please refer to the 'theory of + operations' section at the start of this document. + + This function returns immediately after initiating the transaction. The content + of the write and read buffer passed as parameter should not be modified until + the write transaction completes. It also means that the memory allocated for + the write and read buffer should not be freed or should not go out of scope + before the operation completes. + You can check for the write_read transaction completion by polling the + master_status from miv_i2c_instance_t structure. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param i2c_target_addr + This parameter specifies the serial address for the slave + device. + + @param write_buffer + This parameter is a pointer to the buffer holding data to be + written to target I2C device. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param write_size + Number of bytes held in the write_buffer to be written to the + I2C device. + + @param read_buffer + This parameter is a pointer to the buffer where the data + received from the I2C slave device is stored. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param read_size + Number of bytes held in the write_buffer to be read from the + I2C device. + + @param bus_options: + The bus_options parameter is used to indicate if the I2C bus + should be released on completion of the write transaction. + Using the MIV_I2C_RELEASE_BUS constant for the bus_options + parameter causes a STOP bit to be generated at the end of the + write transaction causing the bus to be released for other I2C + devices to use. Using the MIV_I2C_HOLD_BUS constant as + bus_options parameter prevents a STOP bit from being generated + at the end of the write transaction, preventing other I2C + devices from initiating a bus transaction. + + @param ack_polling_options: + The ack_polling_options parameter is used to indicate how the + MIV_I2C will respond if the slave device transmits a NACK to + the I2C control byte. Using the MIV_I2C_ACK_POLLING_DISABLE + constant for the ack_polling_options parameter causes the + MIV_I2C to abort the transfer if the slave device responds to + the I2C control byte with a NACK. Using the + MIV_I2C_ACK_POLLING_ENABLE constant for the ack_polling_options + parameter causes the MIV_I2C to repeatedly transmit a control + byte to the slave device until the slave device responds with + an ACK or the timeout specified in the MIV_I2C_wait_complete() + function is reached. + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + + MIV_I2C_write (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_tx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + + // reset miv_i2c_status variable + miv_i2c_status = 0u; + + uint8_t addr_offset[2] = {0x00, 0x00}; + MIV_I2C_write_read(&miv_i2c, + DUALEE_SLAVEADDRESS_1, + addr_offset, + sizeof(addr_offset), + i2c_rx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + } + @endcode + */ +void +MIV_I2C_write_read +( + miv_i2c_instance_t *this_i2c, + uint8_t target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_isr() function contains the MIV_I2C's interrupt service routine. + This ISR is at the heart of the MIV_I2C driver, and is used to control the + interrupt-driven, byte-by-byte I2C read and write operations. + + The ISR operates as a Finite State Machine (FSM), which uses the previously + completed I2C operation and its result to determine which I2C operation will + be performed next. + + The ISR operation is divided into following categories: + - MIV_I2C_IDLE + - MIV_I2C_TX_STA_CB + - MIV_I2C_TX_DATA + - MIV_I2C_RX_DATA + + ##### MIV_I2C_IDLE + The MIV_I2C_IDLE is entered on reset, or when an I2C master operation has been + completed or aborted. + Upon entering, the FSM will remain in this state until a write, read, or + write-read operation is requested + + ##### MIV_I2C_STA_CB + The MIV_I2C_TX_STA_CB operation is performed when the start condition and + control byte(i2c target address(7-bit) and direction of transaction(1-bit)) is + transmitted by the Mi-V I2C master device to the slave. + If the target I2C slave device responded to the previous START Condition + + Control Byte with an ACK, the MIV_I2C will start the requested I2C + read/write operation. + If the target slave I2C slave device responds with NACK, the MIV_I2C will + remain in this state or return to the idle state based on ack_polling + configuration. + + ##### MIV_I2C_TX_DATA + The MIV_I2C_TX_DATA state is entered after the target slave device accepts a + write request with an ACK. + This state is used to handle the byte-by-byte MIV_I2C write operations. + The FSM will remain in this state until either all data bytes have been + written to the target slave device, or an error occurs during the write + operation. + + ##### MIV_I2C_RX_DATA + The MIV_I2C_RX_DATA state is entered after the target slave device accepts a + read request with an ACK. + This state is used to handle the byte-by-byte MIV_I2C read operations. + The FSM will remain in this state until either all data bytes have been + received from the target slave device, or an error occurs. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + */ +void +MIV_I2C_isr +( + miv_i2c_instance_t *this_i2c +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_get_status() returns the 8-bit Mi-V I2C status register value. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + @return + This function returns 8-bit Mi-V I2C status register value. + */ +uint8_t +MIV_I2C_get_status +( + miv_i2c_instance_t *this_i2c +); + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_I2C_H_ */ diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_interrupt.c b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_interrupt.c new file mode 100644 index 0000000..871eafe --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_interrupt.c @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains functions used for MIV_I2C driver interrupt control. + * User should enable and disable the interrupts according to their design. + * Please refer to miv_i2c.h file for more information. + */ + +#include "miv_rv32_hal/miv_rv32_hal.h" + +void MIV_I2C_disable_irq(void) +{ +/* Disable I2C interrupt */ + MRV_disable_local_irq(MRV32_MSYS_EIE2_IRQn); +} + +void MIV_I2C_enable_irq(void) +{ +/* Enable I2C interrupt */ + MRV_enable_local_irq(MRV32_MSYS_EIE2_IRQn); +} + + diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_regs.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_regs.h new file mode 100644 index 0000000..9a4bfbf --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_regs.h @@ -0,0 +1,158 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP I2C module driver. This module is delivered as a part of Mi-V extended + * Sub-System(MIV_ESS). + */ + +#ifndef MIV_I2C_APB_REGISTERS +#define MIV_I2C_APB_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * Prescale register details + */ +#define PRESCALE_REG_OFFSET 0x00u + +/* Prescale register bits */ +#define PRESCALE_OFFSET 0x00u +#define PRESCALE_MASK 0xFFFFu +#define PRESCALE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Control register details + */ +#define CONTROL_REG_OFFSET 0x04u + +/* Control register bits */ +#define CONTROL_OFFSET 0x04u +#define CONTROL_MASK 0xC0u +#define CONTROL_SHIFT 0u + +/* Control register Core Enable Bit */ +#define CTRL_CORE_EN_OFFSET 0x04u +#define CTRL_CORE_EN_MASK 0x80u +#define CTRL_CORE_EN_SHIFT 7u + +/* Control register IRQ Enable bit */ +#define CTRL_IRQ_EN_OFFSET 0x04u +#define CTRL_IRQ_EN_MASK 0x40u +#define CTRL_IRQ_EN_SHIFT 6u + +/*------------------------------------------------------------------------------ + * Transmit register details + */ +#define TRANSMIT_REG_OFFSET 0x08u + +/* Transmit register bits */ +#define TRANSMIT_OFFSET 0x08u +#define TRANSMIT_MASK 0xFFu +#define TRANSMIT_SHIFT 0u + +/* Transmit register DIR bit */ +#define TX_DIR_OFFSET 0x08u +#define TX_DIR_MASK 0x01u +#define TX_DIR_SHIFT 0u + +/* Transmit register TARGET_ADDR bit */ +#define TX_TARGET_ADDR_OFFSET 0x08u +#define TX_TARGET_ADDR_MASK 0xFEu +#define TX_TARGET_ADDR_SHIFT 1u + +/*------------------------------------------------------------------------------ + * Receive register details + */ +#define RECEIVE_REG_OFFSET 0x0Cu + +/* Receive register bits */ +#define RECEIVE_OFFSET 0x0Cu +#define RECEIVE_MASK 0xFFu +#define RECEIVE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Command register details + */ +#define COMMAND_REG_OFFSET 0x10u + +/* Command register bits */ +#define COMMAND_OFFSET 0x10u +#define COMMAND_MASK 0xF9u +#define COMMAND_SHIFT 0u + +/* Command register IACK bit */ +#define CMD_IACK_OFFSET 0x10u +#define CMD_IACK_MASK 0x01u +#define CMD_IACK_SHIFT 0u + +/* Command register ACK bit */ +#define CMD_ACK_OFFSET 0x10u +#define CMD_ACK_MASK 0x08u +#define CMD_ACK_SHIFT 3u + +/* Command register WR bit */ +#define CMD_WR_OFFSET 0x10u +#define CMD_WR_MASK 0x10u +#define CMD_WR_SHIFT 4u + +/* Command register RD bit */ +#define CMD_RD_OFFSET 0x10u +#define CMD_RD_MASK 0x20u +#define CMD_RD_SHIFT 5u + +/* Command register STO bit */ +#define CMD_STO_OFFSET 0x10u +#define CMD_STO_MASK 0x40u +#define CMD_STO_SHIFT 6u + +/* Command register STA bit */ +#define CMD_STA_OFFSET 0x10u +#define CMD_STA_MASK 0x80u +#define CMD_STA_SHIFT 7u + +/*------------------------------------------------------------------------------ + * Status register details + */ +#define STATUS_REG_OFFSET 0x14u + +/* Command register bits */ +#define STATUS_OFFSET 0x14u +#define STATUS_MASK 0xFFu +#define STATUS_SHIFT 0u + +/* Status register Interrupt Flag(IF) bit */ +#define STAT_IF_OFFSET 0x14u +#define STAT_IF_MASK 0x01u +#define STAT_IF_SHIFT 0u + +/* Status register Transfer in Progress(TIP) bit */ +#define STAT_TIP_OFFSET 0x14u +#define STAT_TIP_MASK 0x02u +#define STAT_TIP_SHIFT 1u + +/* Status register Arbitration Lost(AL) bit */ +#define STAT_AL_OFFSET 0x14u +#define STAT_AL_MASK 0x20u +#define STAT_AL_SHIFT 5u + +/* Status register Busy(BUSY) bit */ +#define STAT_BUSY_OFFSET 0x14u +#define STAT_BUSY_MASK 0x40u +#define STAT_BUSY_SHIFT 6u + +/* Status register Ack received(RXACK) bit */ +#define STAT_RXACK_OFFSET 0x14u +#define STAT_RXACK_MASK 0x80u +#define STAT_RXACK_SHIFT 7u + + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_I2C_APB_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.c b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.c new file mode 100644 index 0000000..903f029 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.c @@ -0,0 +1,283 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * MI-V Soft IP fabric bare-metal driver for Mi-V PLIC module. This module is + * delivered as a part of Mi-V Extended Sub System(MIV_ESS). + * Please refer to miv_plic.h file for more information. + */ + +#include "miv_plic.h" + +/***************************************************************************//** + * Mi-V PLIC interrupt handler function declaration. + * These functions are called by the external interrupt handler of the MIV_RV32 + * core base on the PLIC source causing the interrupt. + */ +uint8_t Invalid_IRQHandler(void); +uint8_t MIV_PLIC_EXT0_IRQHandler(void); +uint8_t MIV_PLIC_EXT1_IRQHandler(void); +uint8_t MIV_PLIC_EXT2_IRQHandler(void); +uint8_t MIV_PLIC_EXT3_IRQHandler(void); +uint8_t MIV_PLIC_EXT4_IRQHandler(void); +uint8_t MIV_PLIC_EXT5_IRQHandler(void); +uint8_t MIV_PLIC_EXT6_IRQHandler(void); +uint8_t MIV_PLIC_EXT7_IRQHandler(void); +uint8_t MIV_PLIC_EXT8_IRQHandler(void); +uint8_t MIV_PLIC_EXT9_IRQHandler(void); +uint8_t MIV_PLIC_EXT10_IRQHandler(void); +uint8_t MIV_PLIC_EXT11_IRQHandler(void); +uint8_t MIV_PLIC_EXT12_IRQHandler(void); +uint8_t MIV_PLIC_EXT13_IRQHandler(void); +uint8_t MIV_PLIC_EXT14_IRQHandler(void); +uint8_t MIV_PLIC_EXT15_IRQHandler(void); +uint8_t MIV_PLIC_EXT16_IRQHandler(void); +uint8_t MIV_PLIC_EXT17_IRQHandler(void); +uint8_t MIV_PLIC_EXT18_IRQHandler(void); +uint8_t MIV_PLIC_EXT19_IRQHandler(void); +uint8_t MIV_PLIC_EXT20_IRQHandler(void); +uint8_t MIV_PLIC_EXT21_IRQHandler(void); +uint8_t MIV_PLIC_EXT22_IRQHandler(void); +uint8_t MIV_PLIC_EXT23_IRQHandler(void); +uint8_t MIV_PLIC_EXT24_IRQHandler(void); +uint8_t MIV_PLIC_EXT25_IRQHandler(void); +uint8_t MIV_PLIC_EXT26_IRQHandler(void); +uint8_t MIV_PLIC_EXT27_IRQHandler(void); +uint8_t MIV_PLIC_EXT28_IRQHandler(void); +uint8_t MIV_PLIC_EXT29_IRQHandler(void); +uint8_t MIV_PLIC_EXT30_IRQHandler(void); + +/***************************************************************************//** + * MIV_PLIC interrupt handler for external interrupts. + * The array of the function pointers pointing to the weak handler of the Mi-V + * PLIC interrupt handlers. + * These functions are called by the external interrupt handler of the MIV_RV32 + * core base on the PLIC source causing the interrupt. + */ +uint8_t (* const ext_irq_handler_table[32]) (void) = +{ + Invalid_IRQHandler, + MIV_PLIC_EXT0_IRQHandler, + MIV_PLIC_EXT1_IRQHandler, + MIV_PLIC_EXT2_IRQHandler, + MIV_PLIC_EXT3_IRQHandler, + MIV_PLIC_EXT4_IRQHandler, + MIV_PLIC_EXT5_IRQHandler, + MIV_PLIC_EXT6_IRQHandler, + MIV_PLIC_EXT7_IRQHandler, + MIV_PLIC_EXT8_IRQHandler, + MIV_PLIC_EXT9_IRQHandler, + MIV_PLIC_EXT10_IRQHandler, + MIV_PLIC_EXT11_IRQHandler, + MIV_PLIC_EXT12_IRQHandler, + MIV_PLIC_EXT13_IRQHandler, + MIV_PLIC_EXT14_IRQHandler, + MIV_PLIC_EXT15_IRQHandler, + MIV_PLIC_EXT16_IRQHandler, + MIV_PLIC_EXT17_IRQHandler, + MIV_PLIC_EXT18_IRQHandler, + MIV_PLIC_EXT19_IRQHandler, + MIV_PLIC_EXT20_IRQHandler, + MIV_PLIC_EXT21_IRQHandler, + MIV_PLIC_EXT22_IRQHandler, + MIV_PLIC_EXT23_IRQHandler, + MIV_PLIC_EXT24_IRQHandler, + MIV_PLIC_EXT25_IRQHandler, + MIV_PLIC_EXT26_IRQHandler, + MIV_PLIC_EXT27_IRQHandler, + MIV_PLIC_EXT28_IRQHandler, + MIV_PLIC_EXT29_IRQHandler, + MIV_PLIC_EXT30_IRQHandler +}; + +/* Mi-V PLIC interrupt weak handlers */ +__attribute__((weak)) uint8_t Invalid_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT0_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT1_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT2_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT3_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT4_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT5_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT6_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT7_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT8_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT9_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT10_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT11_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT12_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT13_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT14_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT15_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT16_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT17_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT18_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT19_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT20_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT21_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT22_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT23_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT24_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT25_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT26_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT27_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT28_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT29_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT30_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +/*-------------------------------------------------------------------------*//** + * Please refer to miv_plic.h for more information about this function. +*/ +void +MIV_PLIC_isr +( + miv_plic_instance_t *this_plic +) +{ + unsigned long hart_id = read_csr(mhartid); + + /* claim the interrupt from PLIC controller */ + + uint32_t int_num = HAL_get_32bit_reg(this_plic->base_addr + + (0x1000 * hart_id), INT_CLAIM_COMPLETE); + + uint8_t disable = EXT_IRQ_KEEP_ENABLED; + disable = ext_irq_handler_table[int_num](); + + /* Indicate the PLIC controller that the interrupt is processed and claim is + * complete. */ + HAL_set_32bit_reg(this_plic->base_addr + + (0x1000 * hart_id), INT_CLAIM_COMPLETE, int_num); + + if (EXT_IRQ_DISABLE == disable) + { + MIV_PLIC_disable_irq(this_plic, (miv_plic_irq_num_t)int_num); + } +} diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.h new file mode 100644 index 0000000..f5d64cd --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.h @@ -0,0 +1,425 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * PLIC module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(ESS). + */ + /*=========================================================================*//** + @mainpage Mi-V PLIC Bare Metal Driver + + ============================================================================== + Introduction + ============================================================================== + The Mi-V driver provides a set of functions for controlling the Mi-V PLIC + (platform level interrupt controller) soft-IP module. This module is delivered + as a part of the MIV_ESS. The PLIC multiplexes external interrupt signals into + a single interrupt signal that is connected to an external interrupt of the + processor. + + The major features provided by the driver are: + - Support for configuring the PLIC instances. + - Enabling and Disabling interrupts + - Interrupt Handling + + This driver can be used as part of a bare metal system where no operating + system is available. The driver can be adapted for use as part of an + operating system, but the implementation of the adaptation layer between the + driver and the operating system's driver model is outside the scope of this + driver. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + The application software should initialize the Mi-V PLIC through the call to + the MIV_PLIC_init() function for Mi-V PLIC instance in the design. + + No Mi-V PLIC hardware configuration parameters are used by the driver, apart + from the Mi-V PLIC base address. Hence, no additional configuration files + are required to use the driver. + + ============================================================================== + Theory of Operation + ============================================================================== + The operation of Mi-V PLIC driver is divided into following steps: + - Initialization + - Enabling and Disabling interrupts + - Interrupt control + + -------------------------------------------- + Initialization + -------------------------------------------- + The Mi-V PLIC module is first initialized by the call to MIV_PLIC_init(). This + function takes a pointer to the Mi-V PLIC instance data structure and the base + address of the Mi-V PLIC instance is defined by the hardware design. The + instance data structure is used to store the base address of the Mi-V PLIC + module and a pointer to the Mi-V PLIC register data structure. The Mi-V PLIC + register data structure maps the address of the Mi-V PLIC registers. + + --------------------------------------------- + Enabling and Disabling interrupts + --------------------------------------------- + The MIV_PLIC_enable_irq() function enables the specific interrupt provided by + user. A call to this function will allow the enabling of each of the global + interrupts corresponding to the bit in the interrupt enable register of Mi-V + PLIC. + The MIV_PLIC_disable_irq() function disables the specific interrupt provided + by the user. This function can be used to disable the interrupts from outside + of the external interrupt handler. + + ---------------------------------------- + Interrupt Control + ---------------------------------------- + When an interrupt occurs on an enabled interrupt, the PLIC gateway captures + the interrupt and asserts the corresponding interrupt pending bit. Once + the enable bit and pending bit are asserted, then the PLIC_IRQ signal asserts + until the interrupt is claimed by the driver interrupt handler MIV_PLIC_irq() + function. + When multiple interrupts assert then the lowest interrupt number will be + serviced first, for example, if interrupt 1 and 6 assert at the same time, + interrupt 1 will be serviced first, followed by interrupt 6. + +*/ + +#ifndef MIV_PLIC_H_ +#define MIV_PLIC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "miv_plic_regs.h" + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#include "miv_rv32_hal/miv_rv32_hal.h" +#else +#include "hal.h" +#include "miv_rv32_hal.h" +#endif + +/*-------------------------------------------------------------------------*//** + This enumeration is used to select a specific Mi-V PLIC interrupt. It is + used as a parameter to enable or disable the interrupt. +*/ +typedef enum miv_plic_irq_num +{ + NoInterrupt_IRQn = 0, + MIV_PLIC_EXT0_IRQn = 1, + MIV_PLIC_EXT1_IRQn = 2, + MIV_PLIC_EXT2_IRQn = 3, + MIV_PLIC_EXT3_IRQn = 4, + MIV_PLIC_EXT4_IRQn = 5, + MIV_PLIC_EXT5_IRQn = 6, + MIV_PLIC_EXT6_IRQn = 7, + MIV_PLIC_EXT7_IRQn = 8, + MIV_PLIC_EXT8_IRQn = 9, + MIV_PLIC_EXT9_IRQn = 10, + MIV_PLIC_EXT10_IRQn = 11, + MIV_PLIC_EXT11_IRQn = 12, + MIV_PLIC_EXT12_IRQn = 13, + MIV_PLIC_EXT13_IRQn = 14, + MIV_PLIC_EXT14_IRQn = 15, + MIV_PLIC_EXT15_IRQn = 16, + MIV_PLIC_EXT16_IRQn = 17, + MIV_PLIC_EXT17_IRQn = 18, + MIV_PLIC_EXT18_IRQn = 19, + MIV_PLIC_EXT19_IRQn = 20, + MIV_PLIC_EXT20_IRQn = 21, + MIV_PLIC_EXT21_IRQn = 22, + MIV_PLIC_EXT22_IRQn = 23, + MIV_PLIC_EXT23_IRQn = 24, + MIV_PLIC_EXT24_IRQn = 25, + MIV_PLIC_EXT25_IRQn = 26, + MIV_PLIC_EXT26_IRQn = 27, + MIV_PLIC_EXT27_IRQn = 28, + MIV_PLIC_EXT28_IRQn = 29, + MIV_PLIC_EXT29_IRQn = 30, + MIV_PLIC_EXT30_IRQn = 31 +} miv_plic_irq_num_t; + +/*--------------------------------------------------------------------------*//* + * This structure maps the priority threshold and claim complete register in + * the memory. + */ +typedef struct +{ + volatile uint32_t PRIORITY_THRESHOLD; + volatile uint32_t CLAIM_COMPLETE; + volatile uint32_t reserved[1022]; +} IRQ_Target_Type; + +/*--------------------------------------------------------------------------*//* + * This structure maps the Interrupt enable sources from 0 - 1023 for one + * context. + */ +typedef struct +{ + volatile uint32_t ENABLES[32]; +} Target_Enables_Type; + +/*-------------------------------------------------------------------------*//** + This structure holds the base address of the Mi-V PLIC module. This structure + is used by all the functions to access the Mi-V PLIC registers. +*/ +typedef struct miv_plic_instance +{ + addr_t base_addr; +} miv_plic_instance_t; + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_isr is the top level interrupt handler function for the Mi-V PLIC + * driver. You must call the MIV_PLIC_isr() from the system level interrupt + * handler(External_IRQHandler). + * This function must be called from the external interrupt handler function + * provided by the processor hardware abstraction layer. In case of MIV_RV32 + * soft processor, it must be called from External_IRQHandler() function + * provided by MIV_RV32 HAL. + * + * The MIV_PLIC_isr() function claims the interrupt number + * that triggered the interrupt and then invokes the appropriate PLIC interrupt + * handler. + * After handling the PLIC interrupt, this function will complete the interrupt + * by clearing the claim complete bit for the particular interrupt source. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * + * @return + * This function does not return any value. + * + * Example: + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * uint8_t MIV_PLIC_EXT0_IRQHandler(void) + * { + * *** ISR operation *** + * + * return(EXT_IRQ_KEEP_ENABLED); + * } + * + * void External_IRQHandler(void) + * { + * uint32_t reg_val = read_csr(mip); + * MIV_PLIC_isr(&g_plic); + * } + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * } + * @endcode + */ +void MIV_PLIC_isr(miv_plic_instance_t *this_plic); + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_init() function initializes the Mi-V PLIC instance with base + * address. This function resets the PLIC controller by disabling all the PLIC + * interrupts. + * + * Note: This function must be called before calling any other Mi-V PLIC driver + * function. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * + * @param base_addr + * Base address of the Mi-V PLIC instance in the MIV_ESS soft-IP. + * + * @param ext_intr_sources + * Number of interrupts initialized in the design. + * + * @return + * This function does not return any value. + * + * Example + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * } + * @endcode + */ +static inline void +MIV_PLIC_init +( + miv_plic_instance_t *this_plic, + addr_t base_addr, + uint8_t ext_intr_sources +) +{ + uint32_t inc; + unsigned long hart_id = read_csr(mhartid); + + this_plic->base_addr = base_addr; + + /* Disable all interrupts for the current hart. + * The PLIC_EXT_INTR_SOURCES should be defined in the hw_platform.h. This + * macro holds the number of PLIC interrupts enabled in the design. + */ + for(inc = 0; inc < ((ext_intr_sources + 32u) / 32u); ++inc) + { + HAL_set_32bit_reg( + (this_plic->base_addr + inc + (hart_id * 128)), INT_ENABLE , 0x0u); + } +} + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_enable_irq() function enables the PLIC interrupt provided with + * IRQn parameter. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * @param IRQn + * Number of PLIC interrupt to enable. + * + * @return + * This function does not return any value. + * + * Example + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * } + * @endcode + */ +static inline void +MIV_PLIC_enable_irq +( + miv_plic_instance_t *this_plic, + miv_plic_irq_num_t IRQn +) +{ + unsigned long hart_id = read_csr(mhartid); + + uint32_t current = HAL_get_32bit_reg( + (this_plic->base_addr + (IRQn/32) + (hart_id * 128)) , INT_ENABLE); + + current |= (uint32_t)1 << (IRQn % 32); + + HAL_set_32bit_reg( + (this_plic->base_addr + (IRQn/32) + (hart_id * 128)), INT_ENABLE, current); + +} + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_disable_irq() function disables the PLIC interrupt provided with + * IRQn parameter. + * + * NOTE: + * This function can be used to disable the PLIC interrupt from outside the + * external interrupt handler functions. + * If you wish to disable the PLIC interrupt from the external interrupt handler, + * you should use the return value of EXT_IRQ_DISABLE. This will disable the + * selected PLIC interrupt from the Mi-V PLIC driver interrupt handler. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * @param IRQn + * Number of PLIC interrupt to disable. + * + * @return + * This function does not return any value. + * + * Example + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * } + * @endcode + */ +static inline void +MIV_PLIC_disable_irq +( + miv_plic_instance_t *this_plic, + miv_plic_irq_num_t IRQn +) +{ + unsigned long hart_id = read_csr(mhartid); + + uint32_t current = HAL_get_32bit_reg((this_plic->base_addr + (IRQn/32) + (hart_id * 128)) , INT_ENABLE); + + current &= ~((uint32_t)1 << (IRQn % 32)); + + HAL_set_32bit_reg((this_plic->base_addr + (IRQn/32) + (hart_id * 128)), INT_ENABLE, current); + +} + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_PLIC_H_ */ diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic_regs.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic_regs.h new file mode 100644 index 0000000..76cbc0b --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic_regs.h @@ -0,0 +1,31 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP PLIC module driver. This module is delivered as a part of Mi-V extended + * Sub-System(MIV_ESS). + */ + +#ifndef MIV_PLIC_REGISTERS +#define MIV_PLIC_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Interrupt pending register offset */ +#define INT_PENDING_REG_OFFSET 0x1000u + +/* Interrupt enable register */ +#define INT_ENABLE_REG_OFFSET 0x2000u + +/* Interrupt claim complete register */ +#define INT_CLAIM_COMPLETE_REG_OFFSET 0x200004u + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_PLIC_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_timer/miv_timer.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_timer/miv_timer.h new file mode 100644 index 0000000..5f00889 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_timer/miv_timer.h @@ -0,0 +1,329 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Mi-V Timer Soft IP bare-metal driver. This module is delivered as part of + * the Mi-V Extended Sub System(ESS) MIV_ESS. + */ + +/*=========================================================================*//** + @mainpage Mi-V Timer Bare Metal Driver. + The Mi-V Timer bare metal software driver supports the timer module which + serves as a system timer for the Mi-V Extended Sub System(ESS). + + @section intro_sec Introduction + The MI-V Timer driver supports set of functions for controlling the Mi-V + Timer module. + The Mi-V Timer can generate a timer interrupt signal for the system based on + special system clock intervals specified by the parameters that can be passed + in by the user. + + The major features provided by Mi-V Timer driver are: + - Support for Mi-V Timer instance for each Mi-V Timer peripheral. + - Read current time + - Write to the machine time compare register + + @section hw_dependencies Hardware Flow dependency + The application should configure the Mi-V Timer driver through calls to + MIV_TIMER_init() functions for each MIV_TIMER instance in the hardware + design. The configuration parameter include the MIV_TIMER hardware instance, + base address and number of ticks to generate timer interrupt. + + MIV_RV32 core offers flexibility in terms of generating the MTIME and MTIMECMP + registers internal to the core or using external time reference. + When MIV_ESS is interfaced with MIV_RV32 core, the timer module in the MIV_ESS + can be configured as follows: + - Internal MTIME External MTIME IRQ + Generate the MTIME internally(MIV_RV32) and have a timer interrupt input + to the core as external pin(from MIV_ESS). + + - External MTIME Internal MTIME IRQ + Generate the time value externally(from MIV_ESS), in this case a 64-bit + port will open in the MIV_RV32 core as input and MIV_ESS will output the + 64-bit TIME_COUNT value. The generation of mtimecmp and interrupt is + done internally(MIV_RV32). + + - External MTIME External MTIME IRQ + Generate both the time and timer interrupt externally. + In this case 64-bit port will be available on the Mi-V RV32 core as input + and a 1 pin port will be available for timer interrupt. + + The design must be configured accordingly to use these combinations in the + firmware. + + No MIV_TIMER hardware configuration parameters are used by the driver, apart + from MIV_TIMER base address. Hence, no additional configuration files are + required to use the driver. + + @section theory_op Theory of Operation + + The MIV_TIMER module is a simple systick timer which can generate a timer + interrupt signal for the system at specific intervals specified by the + parameters that can be passed by the user. + These interrupt signal are then fed to the MIV_RV32 core via timer interrupt. + + The operation of MIV_TIMER is divided into following steps: + - Initialization + - Configuration + - Read/Write TIME + + ## Initialization + The MIV_TIMER is first initialized by a call to MIV_TIMER_init(). This + function initializes the instance of Mi-V TIMER with the base address. + The MIV_TIMER_init() function must be called before any other Mi-V Timer driver + function. + + ## Configuration + The Mi-V TIMER configuration includes writing the mtimecmp register with the + initial time value at which timer interrupt should be generated. + When the mtime register value becomes greater than or equal to mtimecmp value, + a timer interrupt signal(TIMER_IRQ) is generated. + + ## Read/Write TIME + The time value can be read by reading the mtime register via call to the + MIV_TIMER_read_mtime(). This function reads the MTIME register which contains + the 64-bit value of the timer count. The count increments by 1 every time the + prescale ticks. This function returns 64-bit MTIME_COUNT value which is the + current value of timer count. + + The time value read in the MIV_TIMER_read_mtime() function can be written to + the mtimecmp register by calling MIV_TIMER_write_mtimecmp() to generate + periodic interrupts. + The writing of the mtimecmp register should be done in the systick_handler() + function. + */ + +#ifndef MIV_TIMER_H_ +#define MIV_TIMER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#endif +/*-------------------------------------------------------------------------*//** +MIV_TIMER_SUCCESS +===================== + +The MIV_TIMER_SUCCESS constant indicates successful configuration of +Mi-V Timer module. +*/ +#define MIV_TIMER_SUCCESS 0u + +/*-------------------------------------------------------------------------*//** +MIV_TIMER_ERROR +===================== + +The MIV_TIMER_ERROR constant indicates that there is an error with +configuring the Mi-V Timer module. +*/ +#define MIV_TIMER_ERROR 1u + +/*-------------------------------------------------------------------------*//* +MIV_TIMER_MASK_32BIT +===================== + +32-bit mask constant used in calculation of 64-bit register value. +*/ +#define MIV_TIMER_MASK_32BIT 0xFFFFFFFFu + +/*-------------------------------------------------------------------------*//* +Mi-V Timer register offsets +===================== +The MTIMECMP is the 64-bit timer compare register, it pre-sets the threshold +which needs to be reached by the timer count register. +This 64-bit register is accessed with 2 32-bit address offset, lower 32-bits +and higher 32-bits. + - MIV_TIMER_MTIMECMP_L_REG_OFFSET + - MIV_TIMER_MTIMECMP_H_REG_OFFSET + +The MTIME is the 64-bit register that contains the 64-bit timer count. The +count increments by 1 every time the prescaler ticks. +This 64-bit register is accessed with 2 32-bit address offset, lower 32-bits +and higher 32-bits. + - MIV_TIMER_MTIME_L_REG_OFFSET + - MIV_TIMER_MTIME_H_REG_OFFSET + +The PRESCALE register is used to determine the amount of clock cycles the +selected clock needs to go through, for MTIME register to increment count. + - MIV_TIMER_PRESCALAR_REG_OFFSET +*/ + +/// @cond private +#define MIV_TIMER_MTIMECMP_L_REG_OFFSET 0x4000u +#define MIV_TIMER_MTIMECMP_H_REG_OFFSET 0x4004u + +#define MIV_TIMER_MTIME_L_REG_OFFSET 0xBFF8u +#define MIV_TIMER_MTIME_H_REG_OFFSET 0xBFFCu + +#define MIV_TIMER_PRESCALAR_REG_OFFSET 0x5000u +/// @endcond + +/*-------------------------------------------------------------------------*//** + This structure holds the base address of the Mi-V Timer module and instance + of the Mi-V Timer register structure. +*/ +typedef struct miv_timer_instance +{ + addr_t base_addr; +} miv_timer_instance_t; + +/** The MIV_TIMER_init() is used to initialize the Mi-V Timer module. This + function will assign the base addresses of the Mi-V Timer module. + User should call this function before calling any of the Mi-V Timer driver + APIs. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @param base_address + Base address of the Mi-V Timer module. + + @return + This function does not return any value. + */ +static inline void +MIV_TIMER_init +( + miv_timer_instance_t* this_timer, + addr_t base_addr +) +{ + this_timer->base_addr = base_addr; +} + +/** MIV_TIMER_read_current_time() is used to read the mtimecmp register values. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @return + This function returns 64-bit mtimecmp register value. + */ +static inline uint64_t +MIV_TIMER_read_current_time +( + miv_timer_instance_t* this_timer +) +{ + volatile uint64_t read_data = 0u; + volatile uint32_t mtime_hi = 0u; + volatile uint32_t mtime_lo = 0u; + + /* when mtime lower word is 0xFFFFFFFF, there will be rollover and + * returned value could be wrong. */ + do { + mtime_hi = HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIME_H); + mtime_lo = HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIME_L); + + } while(mtime_hi != HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIME_H)); + + read_data = mtime_hi; + + return(((read_data) << 32u) | mtime_lo); +} + +/** MIV_TIMER_write_compare_time() is used to write to the MTIMECMP register in + the event of interrupt. User must use this function in the interrupt handler + to de-assert the MIV_TIMER interrupt. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @param write_value + Value to write into the mtimecmp register. + + @return + This function does not return any value. + */ +static inline void +MIV_TIMER_write_compare_time +( + miv_timer_instance_t* this_timer, + uint64_t compare_reg_value +) +{ + HAL_set_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIMECMP_H, MIV_TIMER_MASK_32BIT); + + HAL_set_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIMECMP_L, + (compare_reg_value & MIV_TIMER_MASK_32BIT)); + + HAL_set_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIMECMP_H, + ((compare_reg_value >> 32u) & MIV_TIMER_MASK_32BIT)); +} + +/** The MIV_TIMER_config() is used to configure the MIV_ESS Timer module. The + prescale value serves to divide the count of clock cycles for the timer and + provides control over what point in time, the timer interrupt gets + asserted. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @param ticks + Number of ticks after which interrupt will be generated. + + @return + This function returns Mi-V Timer configuration status. + */ +static inline uint32_t +MIV_TIMER_config +( + miv_timer_instance_t* this_timer, + uint64_t ticks +) +{ + uint32_t ret_val = MIV_TIMER_ERROR; + uint64_t mtime_val = 0u; + uint32_t prescalar = 0u; + uint64_t miv_timer_increment = 0U; + + prescalar = HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_PRESCALAR); + + miv_timer_increment = (uint64_t)(ticks) / prescalar; + + if (miv_timer_increment > 0U) + { + mtime_val = MIV_TIMER_read_current_time(this_timer); + + MIV_TIMER_write_compare_time(this_timer ,(mtime_val + miv_timer_increment)); + + ret_val = MIV_TIMER_SUCCESS; + } + + return ret_val; +} + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_TIMER_H */ diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c new file mode 100644 index 0000000..cbd9652 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c @@ -0,0 +1,109 @@ +/******************************************************************************* + * (c) Copyright 2022-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Mi-V uDMA Soft IP bare-metal driver. This module is delivered as part of + * Mi-V Extended Sub System(MIV_ESS) + */ + +#include "miv_udma_regs.h" +#include "miv_udma.h" + +/***************************************************************************//** + * MIV_uDMA_init() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_init +( + miv_udma_instance_t* this_udma, + addr_t base_addr +) +{ + /* Assign the Mi-V uDMA base address to the uDMA instance structure */ + this_udma->base_address = base_addr; +} + +/***************************************************************************//** + * MIV_uDMA_config() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_config +( + miv_udma_instance_t* this_udma, + addr_t src_addr, + addr_t dest_addr, + uint32_t transfer_size, + uint32_t irq_config +) +{ + /* Source memory start address */ + HAL_set_32bit_reg(this_udma->base_address, SRC_START_ADDR, src_addr); + + /* Destination memory start address */ + HAL_set_32bit_reg(this_udma->base_address, DEST_START_ADDR, dest_addr); + + /* Data transfer size */ + HAL_set_32bit_reg(this_udma->base_address, BLK_SIZE, transfer_size); + + /* Configure the uDMA IRQ */ + HAL_set_32bit_reg(this_udma->base_address, IRQ_CFG, irq_config); +} + +/***************************************************************************//** + * MIV_uDMA_start() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_start +( + miv_udma_instance_t* this_udma +) +{ + /* Start the uDMA transfer */ + HAL_set_32bit_reg(this_udma->base_address, CONTROL_SR, CTRL_START_TX_MASK); +} + +/***************************************************************************//** + * MIV_uDMA_reset() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_reset +( + miv_udma_instance_t* this_udma +) +{ + /* Toggle the uDMA_reset bit to reset the uDMA. + * Resetting the uDMA will clear all the configuration made by + * MIV_uDMA_config(). + * + * This function should be called from the interrupt handler to clear the + * IRQ. + */ + HAL_set_32bit_reg_field(this_udma->base_address, CTRL_RESET_TX, 0x1u); + HAL_set_32bit_reg_field(this_udma->base_address, CTRL_RESET_TX, 0x0u); +} + +/***************************************************************************//** + * MIV_uDMA_read_status() + * See "miv_udma.h" for details of how to use this function. + */ +uint32_t +MIV_uDMA_read_status +( + miv_udma_instance_t* this_udma +) +{ + uint32_t status = 0u; + + /* Read the status of the uDMA transfer. + * The transfer status register can be Error or Busy depending on the + * current uDMA transfer. + */ + status = HAL_get_32bit_reg(this_udma->base_address, TX_STATUS); + + return status; +} diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h new file mode 100644 index 0000000..efa8731 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h @@ -0,0 +1,290 @@ +/******************************************************************************* + * Copyright 2022-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * uDMA module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(MIV_ESS). + */ + +/*=========================================================================*//** + @mainpage Mi-V uDMA Bare Metal Driver. + The Mi-V uDMA bare metal software driver. + + @section intro_sec Introduction + The Mi-V uDMA driver provides a set of functions to control the Mi-V uDMA + module in the Mi-V Extended Subsystem (MIV_ESS) soft-IP. The Mi-V uDMA module + allows peripherals with AHB interfaces to transfer data independently of the + MIV_RV32 RISC-V processor. + + Following are the major features provided by the Mi-V uDMA driver: + - Initialization and configuration + - Start and reset the transaction + + This driver can be used as part of a bare metal system where no operating + system is available. The driver can be adapted for use as part of an + operating system, but the implementation of the adaptation layer between the + driver and the operating system's driver model is outside the scope of this + driver. + + @section hw_dependencies Hardware Flow Dependency + The application software should initialize and configure the Mi-V uDMA through + calling the MIV_uDMA_init() and MIV_uDMA_config() functions for each Mi-V + uDMA instance in the design. + + The uDMA can operate in two possible transfer configurations: + + - AHBL Read -> AHBL Write: + In this configuration, the uDMA reads data from the source memory over an + AHBL (mirrored main/initiator) read interface and writes data to the + destination memory over an AHBL (mirrored main/initiator) write interface. + + - AHBL Read -> TAS Write: + In this configuration, the uDMA reads data from the source memory over an + AHBL (mirrored main/initiator) read interface and writes data to the + destination memory over the TAS (mirrored main/initiator) write interface. + + Note: The AHBL Read -> TAS Write configuration is out of scope for this + driver. + + @section theory_op Theory of Operation + The uDMA module in the Mi-V Extended Sub System (MIV_ESS) is a single-channel + uDMA module that allows peripherals to perform read-write operations between + source and destination memory. The Mi-V uDMA driver is used in + interrupt-driven mode and uses the Mi-V uDMA IRQ signal to drive the + interrupt service routine (ISR), which signifies a transfer has completed. + The status is checked in the ISR to ensure the transfer is completed + successfully. + The reset operation in the ISR resets the Mi-V uDMA controller. Once the Mi-V + uDMA transfer is complete, Mi-V uDMA retires. To initiate another + transaction, Mi-V uDMA needs to be configured again. + + The operation of the Mi-V uDMA driver is divided into the following + categories: + - Initialization + - Configuration + - Start and reset the transfer + + Initialization and configuration: + Mi-V uDMA is first initialized by calling MIV_uDMA_init() function. This + function initializes the instance of Mi-V uDMA with the base address. The + MIV_uDMA_init() function must be called before calling any other Mi-V uDMA + driver functions. + + The Mi-V uDMA is configured by calling MIV_uDMA_config() function. This + function configures the source_addr and dest_addr registers of the Mi-V + uDMA with source and destination addresses for Mi-V uDMA transfers. + This function also configures the transfer size and interrupt preference for + successful transfers using Mi-V uDMA. + + Start and reset the transfer: + Once the Mi-V uDMA is configured, initiate the transfers by calling the + MIV_uDMA_start() function. Once the Mi-V uDMA transfer is started, it cannot + be aborted, and the status of the transfer should be read from the ISR by + calling the MIV_uDMA_read_status() function. + + Reset the Mi-V uDMA to the default state by calling the MIV_uDMA_reset() + function. After performing the reset operation, reconfigure the Mi-V uDMA to + perform transfers as MIV_uDMA_reset() resets the Mi-V uDMA controller. + */ + +#ifndef MIV_uDMA_H_ +#define MIV_uDMA_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#include "hal/cpu_types.h" + +#else +#include "hal.h" +#include "cpu_types.h" +#endif + +/*-------------------------------------------------------------------------*//** + MIV_uDMA_CTRL_IRQ_CONFIG + ===================== + + The MIV_uDMA_CTRL_IRQ_CONFIG macro is used to assert the uDMA IRQ when an error + occurs during a uDMA transfer or on the completion of a uDMA transfer. + */ +#define MIV_uDMA_CTRL_IRQ_CONFIG 1u + +/*-------------------------------------------------------------------------*//** + MIV_uDMA_STATUS_BUSY + ===================== + + The MIV_uDMA_STATUS_BUSY macro is used to indicate that the uDMA transfer is + in progress. + */ +#define MIV_uDMA_STATUS_BUSY 1u + +/*-------------------------------------------------------------------------*//** + MIV_uDMA_STATUS_ERROR + ===================== + + The MIV_uDMA_STATUS_ERROR macro is used to indicate that the last uDMA + transfer has caused an error. + */ +#define MIV_uDMA_STATUS_ERROR 2u + +/***************************************************************************//** + * This structure holds the base of the Mi-V uDMA module, which is used in the + * other functions of the driver to access the uDMA registers. + */ +typedef struct miv_udma_instance +{ + addr_t base_address; +} miv_udma_instance_t; + +/***************************************************************************//** + * The MIV_uDMA_init() function assigns the base address of the Mi-V uDMA module + * to the uDMA instance structure. + * This address is used in a later part of the driver to access the uDMA + * registers. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure. + * + * @param base_addr + * Base address of the Mi-V uDMA module. + * + * @return + * This function does not return a value. + */ +void +MIV_uDMA_init +( + miv_udma_instance_t* this_udma, + addr_t base_addr +); + +/***************************************************************************//** + * The MIV_uDMA_config() function is used to configure the Mi-V uDMA controller. + * This function will set the source address, destination address, block size, + * and IRQ configuration register. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @param base_addr + * Base address of the Mi-V uDMA. + * + * @param src_addr + * Source address of memory from where the uDMA reads the data. + * + * @param dest_addr + * Destination address where the data is written from src_addr. + * + * @param transfer_size + * Number of 32-bit words to transfer. + * + * @param irq_config + * uDMA IRQ configuration + * - When set, the IRQ is asserted when an error occurs during a uDMA + * transfer or on the completion of the uDMA transfer. + * - When clear, the IRQ is only asserted when an error occurs during a + * uDMA transfer. + * + * @return + * This function does not return any value. + */ +void +MIV_uDMA_config +( + miv_udma_instance_t* this_udma, + addr_t src_addr, + addr_t dest_addr, + uint32_t transfer_size, + uint32_t irq_config +); + +/***************************************************************************//** + * The MIV_uDMA_start() function is used to start the uDMA transfer. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @return + * This function does not return any value. + */ +void +MIV_uDMA_start +( + miv_udma_instance_t* this_udma +); + +/***************************************************************************//** + * The MIV_uDMA_reset() function is used to clear the uDMA interrupt and reset + * the uDMA transfer. + * + * This function should be called from the interrupt handler to reset the values + * set during MIV_uDMA_config(). + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @return + * This function does not return any value. + */ +void +MIV_uDMA_reset +( + miv_udma_instance_t* this_udma +); + +/***************************************************************************//** + * The MIV_uDMA_read_status() function is used to read the status of the uDMA + * transfer. When interrupt is enabled, this function can be called from the + * interrupt handler to know the reason for a uDMA interrupt. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @return + * The return value indicates an error due to the busy status of the uDMA + * channel. + * + * |Bit Number| Name | Description | + * |----------|---------|------------------------------------------------------| + * | 0 | Busy | When set indicates that uDMA transfer is in progress| + * | 1 | Error | When set indicates that last uDMA transfer caused an| + * | | | error. | + */ +uint32_t +MIV_uDMA_read_status +( + miv_udma_instance_t* this_pdma +); + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_uDMA_H_ */ diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h new file mode 100644 index 0000000..14d0759 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h @@ -0,0 +1,94 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP uDMA module driver. This module is delivered as a part of Mi-V + * extended Sub-System(ESS) MIV_ESS. + */ + +#ifndef MIV_UDMA_APB_REGISTERS +#define MIV_UDMA_APB_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/**************************************************************************//** + * Control start/Reset register details + */ + +#define CONTROL_SR_REG_OFFSET 0x0u + +/* Control start/Reset register bits */ +#define CONTROL_SR_OFFSET 0x00u +#define CONTROL_SR_MASK 0x03u +#define CONTROL_SR_SHIFT 0u + +/* uDMA Control Start Transfer */ + +#define CTRL_START_TX_OFFSET 0x00u +#define CTRL_START_TX_MASK 0x01u +#define CTRL_START_TX_SHIFT 0u + +/* uDMA Control Reset Transfer */ +#define CTRL_RESET_TX_OFFSET 0x00u +#define CTRL_RESET_TX_MASK 0x02u +#define CTRL_RESET_TX_SHIFT 1u + +/**************************************************************************//** + * IRQ Configuration register details + */ +#define IRQ_CFG_REG_OFFSET 0x4u + +/* Control start/Reset register bits */ +#define IRQ_CFG_OFFSET 0x04u +#define IRQ_CFG_MASK 0x01u +#define IRQ_CFG_SHIFT 0u + +/***************************************************************************//** + * Transfer Status register details + */ +#define TX_STATUS_REG_OFFSET 0x08u + +/* Transfer status register bits */ +#define TX_STATUS_OFFSET 0x08u +#define TX_STATUS_MASK 0x03u +#define TX_STATUS_SHIFT 0u + +/***************************************************************************//** + * Source Memory Start Address Register + */ +#define SRC_START_ADDR_REG_OFFSET 0x0cu + +/* Source Memory Start Address Register bits */ +#define SRC_START_ADDR_OFFSET 0x0cu +#define SRC_START_ADDR_MASK 0xFFFFFFFFu +#define SRC_START_ADDR_SHIFT 0u + +/***************************************************************************//** + * Destination Memory Start Address register details + */ +#define DEST_START_ADDR_REG_OFFSET 0x10u + +/* Destination Memory Start Address register bits */ +#define DEST_START_ADDR_OFFSET 0x10u +#define DEST_START_ADDR_MASK 0xFFFFFFFFu +#define DEST_START_ADDR_SHIFT 0x0u + +/***************************************************************************//** + * Block Size register details + */ +#define BLK_SIZE_REG_OFFSET 0x14u + +/* Destination Memory Start Address register bits */ +#define BLK_SIZE_OFFSET 0x14u +#define BLK_SIZE_MASK 0xFFFFFFFFu +#define BLK_SIZE_SHIFT 0x0u + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_UDMA_APB_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c new file mode 100644 index 0000000..525928a --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Mi-V Watchdog Soft IP bare-metal driver. This module is delivered as part of + * Extended Sub System(ESS) MIV_ESS. + * Please refer to miv_watchdog.h file for more information. + */ + +#include "miv_watchdog.h" + +addr_t g_this_wdog; + +/***************************************************************************//* + * Please refer to miv_watchdog.h for more info about this function + */ +void +MIV_WDOG_init +( + addr_t base_addr +) +{ + /* Register the Mi-V Watchdog base address to the driver */ + g_this_wdog = base_addr; +} + +/***************************************************************************//* + * Please refer to miv_watchdog.h for more info about this function + */ +uint8_t MIV_WDOG_configure +( + const miv_wdog_config_t *config +) +{ + uint8_t error = 0u; + + /* check load value and trigger max value */ + if (config->timeout_val <= MIV_WDOG_TRIGGER_MAX) + { + HAL_set_32bit_reg(g_this_wdog, WDOGTRIG,(config->timeout_val)); + } + else + { + error = 1u; + } + + if (config->time_val <= MIV_WDOG_TIMER_MAX) + { + HAL_set_32bit_reg(g_this_wdog, WDOGMSVP,(config->mvrp_val)); + } + else + { + error = 1u; + } + + HAL_set_32bit_reg_field(g_this_wdog, WDOGCNTL_NEXT_ENFORBIDDEN, + config->forbidden_en); + + /* Reload watchdog with new load if it is not in forbidden window */ + if (!(WDOGSTAT_FORBIDDEN_MASK & (HAL_get_32bit_reg(g_this_wdog, WDOGSTAT)))) + { + HAL_set_32bit_reg(g_this_wdog, WDOGRFSH, MIV_WDOG_REFRESH_KEY); + } + else + { + error = 1u; + } + + return (error); +} + +/***************************************************************************//* + * Please refer to miv_watchdog.h for more info about this function + */ +void MIV_WDOG_get_config +( + miv_wdog_config_t *config +) +{ + if (0 != g_this_wdog) + { + + config->time_val = HAL_get_32bit_reg(g_this_wdog, WDOGTIME); + + config->timeout_val = HAL_get_32bit_reg(g_this_wdog, WDOGTRIG); + + config->mvrp_val = HAL_get_32bit_reg(g_this_wdog, WDOGMSVP); + + config->forbidden_en = HAL_get_32bit_reg_field(g_this_wdog, + WDOGCNTL_NEXT_ENFORBIDDEN); + } +} + diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h new file mode 100644 index 0000000..8877e55 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h @@ -0,0 +1,553 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * Watchdog module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(MIV_ESS). + */ +/*=========================================================================*//** + @mainpage MiV Watchdog Bare Metal Driver + + ============================================================================== + Introduction + ============================================================================== + The Mi-V Watchdog module in the MIV_ESS is used to generate a reset for the + system automatically if the software doesn't periodically update or refresh + the timer countdown register. This software driver provides set of functions + for controlling Mi-V Watchdog module as a part of bare metal system where no + operating system is available. The driver can be adapted for use as a part of + an operating system, but the implementation of the adaptation layer between + the driver and the operating system's driver model is outside the scope of the + driver. + + Mi-V Watchdog provides following features: + - Initializing the Mi-V Watchdog + - Reading current value and status of watchdog timer + - Refreshing the watchdog timer value + - Enabling, disabling and clearing timeout and Maximum Value up to which + Refresh is Permitted (MVRP) interrupts. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + The application software should initialize and configure the Mi-V Watchdog + module the the call to the MIV_WDOG_init() and MIV_WDOG_configure() functions. + + No MIV_WDOG hardware configuration parameter are used by the driver, apart + from the MIV_WDOG base address. Hence, no additional configuration files are + required to use the driver. + + ============================================================================== + Theory of Operation + ============================================================================== + The Mi-V Watchdog driver functions are grouped into the following categories: + - Initialization and configuration + - Reading the current value and status of the watchdog timer + - Refreshing the watchdog timer value + - Support for enabling, disabling and clearing time-out and MVRP interrupts. + + -------------------------------- + Initialization and Configuration + -------------------------------- + The MIV_WDOG_init() function stores the base of MIV_WDT module in the MIV_ESS. + This base address is used by rest of the functions to access the Mi-V Watchdog + registers. Please make call this function before calling any other function + from this driver. + Note: The Mi-V Watchdog driver supports only one instance of MIV_WDT in the + hardware. + The Mi-V Watchdog driver provides the MIV_WDOG_configure() function to + configure the MIV_WDOG module with desired configuration values. It also + provides the MIV_WDOG_get_config() to read back the current configuration of + the MIV_WDOG. You can use this function to retrieve the current configurations + and then overwrite them with the application specific values, such as initial + watchdog timer value, Maximum Value (up to which) Refresh (is) Permitted, + watchdog time-out value, enable/disable forbidden region, enable/disable + MVRP interrupt and interrupt type. + + -------------------------------------------- + Reading the Watchdog Timer Value and Status + -------------------------------------------- + Mi-V Watchdog is a down counter. A refresh forbidden window can be created by + configuring the watchdog Maximum Value up to which Refresh is Permitted (MVRP). + When the current value of the watchdog timer is greater than the MVRP value, + refreshing the watchdog is forbidden. Attempting to refresh the watchdog timer + in the forbidden window will assert a timeout interrupt. The + MIV_WDOG_forbidden_status() function can be used to know whether the watchdog + timer is in forbidden window or has crossed it. By default, the forbidden + window is disabled. It can be enabled by providing an appropriate value as + parameter to the MIV_WDOG_configure() function. When the forbidden window is + disabled, any attempt to refresh the watchdog timer is ignored and the counter + keeps on down counting. + + The current value of the watchdog timer can be read using the + MIV_WDOG_current_value() function. This function can be called at any time. + + -------------------------------------------- + Refreshing the Watchdog Timer Value + -------------------------------------------- + The watchdog timer value is refreshed using the MIV_WDOG_reload() function. + The value reloaded into the watchdog timer down-counter is specified at the + configuration time with an appropriate value as parameter to the + MIV_WDOG_get_config() function. + + -------------------------------------------- + Interrupt Control + -------------------------------------------- + The Mi-V Watchdog generates two interrupts, The MVRP interrupt and + the timeout interrupt. + The MVRP interrupt is generated when the watchdog down-counter crosses the + Maximum Value up to which Refresh is Permitted (MVRP). Following functions to + control MVRP interrupt: + - MIV_WDOG_enable_mvrp_irq + - MIV_WDOG_disable_mvrp_irq + - MIV_WDOG_clear_mvrp_irq + + The timeout interrupt is generated when the watchdog down-counter crosses the + watchdog timeout value. The timeout value is a non-zero value and it can be + set to a maximum of MIV_WDOG_TRIGGER_MAX. The non-maskable interrupt is + generated when the watchdog crosses this timeout value, the down counter + keeps on down counting and a reset signal is generated when reaches zero. + Following functions to control timeout interrupt: + - MIV_WDOG_enable_timeout_irq + - MIV_WDOG_disable_timeout_irq + - MIV_WDOG_clear_timeout_irq + +*//*=========================================================================*/ + +#ifndef MIV_WATCHDOG_H_ +#define MIV_WATCHDOG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "miv_watchdog_regs.h" + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#else +#include "hal.h" +#endif + +/****************************************************************************//* + * The following constants can be used to configure the Mi-V Watchdog where a + * zero or non-zero value such as enable or disable is to be provided as a input + * parameter as shown below: + */ +#define MIV_WDOG_ENABLE 1u +#define MIV_WDOG_DISABLE 0u + +/***************************************************************************//** + The miv_wdog_config_t type for the watchdog Configuration structure. This + type is used as a parameter for the MIV_WDOG_configure() and the + MIV_WDOG_get_config() functions. + + Following are the values as part of this structure +| Parameter | Description | +|------------------|-----------------------------------------------------------| +| time_val | The value from which the watchdog timer counts down | +| mvrp_val | The Watchdog MVRP value | +| timeout_val | The watchdog timeout value | +| forbidden_en | Enable/disable the forbidden window | +| | When set, if a refresh occurs in the forbidden window, | +| | the watchdog timeout interrupt will be generated. | + +Time calculation example: + + time_val = 0xFFFFF0u + mvrp_val = 0x989680u + timeout_val = 0x3e8u + + A prescaler = 256 is used. + Considering clock = 50Mhz + + The MVRP interrupt will happen after + (0xFFFFF0 - 0x989680) * ( 1/(50MHz/256)) + mvrp interrupt will happen after 34 sec. after system reset + + (0xFFFFF0 - 0x3e8) * ( 1/(50MHz/256)) + timeout interrupt will happen after 85 sec. after system reset + */ +typedef struct miv_wdog_config +{ + uint32_t time_val; + uint32_t mvrp_val; + uint32_t timeout_val; + uint32_t forbidden_en; + uint32_t intr_type; +}miv_wdog_config_t; + +extern addr_t g_this_wdog; + +/***************************************************************************//* + Internal constants and types +*******************************************************************************/ + +/// @cond private +#define MIV_WDOG_TRIGGER_MAX 4095u +#define MIV_WDOG_TIMER_MAX 16777200u +/// @endcond + +/*-------------------------------------------------------------------------*//* +MIV_WDOG_REFRESH_KEY +===================== + +The MIV_WDOG_REFRESH_KEY macro holds the magic value which will cause a +reload of the watchdog's down counter when written to the watchdog's +WDOGREFRESH register. +*/ +#define MIV_WDOG_REFRESH_KEY (uint32_t)0xDEADC0DEU + +/*-------------------------------------------------------------------------*//* +MIV_WDOG_FORCE_RESET_KEY +===================== +The MIV_WDOG_FORCE_RESET_KEY macro holds the magic value which will force a +reset if the watchdog is already timeout. Writing any other value or writing +TRIGGER register at other times will trigger the watchdog NMI sequence +(i.e raise a timeout interrupt) + */ +#define MIV_WDOG_FORCE_RESET_KEY (uint32_t)0xDEADU + +/***************************************************************************//** + * The MIV_WDOG_init() is used to register the Mi-V Watchdog module base + * address to the driver. + * + * Note: User should call this function before calling any other Mi-V watchdog + * driver function. + * + * @param base_addr + * The base address of the Mi-V watchdog module. This address is used by + * rest of the watchdog driver functions to access the registers. + * + * @return + * This function does not return any value. + */ +void +MIV_WDOG_init +( + addr_t base_addr +); + +/***************************************************************************//** + * The MIV_WDOG_get_config() function returns the current configurations of the + * Mi-V Watchdog. The Mi-V Watchdog is pre-initialized by the flash + * bits at the design time. When used for the first time before calling the + * MIV_WDOG_configure() function, this function will return the default + * configurations as configured at the design time. + * + * @param config + * The config parameter is used to store the current configuration of the Mi-V + * Watchdog. + * + * Please see the description of miv_wdog_config_t for details. + * + * @return + * This function does not return any value. + * + * Example: + */ +void +MIV_WDOG_get_config +( + miv_wdog_config_t* config +); + +/***************************************************************************//** + * The MIV_WDOG_configure() function configures the watchdog module. The + * Watchdog module is pre-initialized by the flash bits at the design time to the + * default values. You can reconfigure the Watchdog module using + * MIV_WDOG_configure() function. + * + * Note that the MIV_WDOG_configure() function can be used only once, as it + * writes into the TIME register. After a write into the TIME register, the TIME, + * TRIGGER and MSVP register values are frozen and can't be altered again unless + * a system reset happens. + * + * Note also that the Mi-V Watchdog is not enabled at reset, calling this function + * will start the watchdog, it cannot then be disabled and must be refreshed + * periodically. + * + * @param config + * The config parameter is the input parameter in which the configurations to + * be applied to the watchdog module are provided by the application. + * Please see the description of miv_wdog_config_t for details. + * + * @return + * This function returns a zero value when executed successfully. A non-zero + * value is returned when the configuration values are out of bound. + * + * Example: + */ +uint8_t +MIV_WDOG_configure +( + const miv_wdog_config_t * config +); + +/***************************************************************************//** + * The MIV_WDOG_reload() function causes the watchdog to reload its down-counter + * timer with the load value configured through interrupt handler. This function + * must be called regularly to avoid a system reset or a watchdog interrupt. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_reload +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg(g_this_wdog, WDOGRFSH, MIV_WDOG_REFRESH_KEY); + } +} + +/***************************************************************************//** + * The MIV_WDOG_current_value() function returns the current value of the + * watchdog's down-counter. + * + * @param + * Void + * + * @return + * This function returns the current value of the watchdog’s down-counter as + * a 32-bit unsigned integer. + */ +static inline uint32_t +MIV_WDOG_current_value +( + void +) +{ + return (HAL_get_32bit_reg(g_this_wdog, WDOGRFSH)); +} + +/***************************************************************************//** + * The MIV_WDOG_forbidden_status() function returns the refresh status of the + * Mi-V Watchdog. + * + * @param + * Void + * + * @return + * This function returns the refresh status of the watchdog. A value of 1 + * indicates that watchdog's down-counter is within the forbidden window and + * that a reload should not be done. A value of 0 indicates that the watchdog's + * down counter is within the permitted window and that a reload is allowed. + */ +static inline uint32_t +MIV_WDOG_forbidden_status +( + void +) +{ + return (HAL_get_32bit_reg_field(g_this_wdog, WDOGSTAT_FORBIDDEN)); +} + +/***************************************************************************//** + * The MIV_WDOG_enable_mvrp_irq() function enables the MVRP interrupt. + * This interrupt is asserted when the timer countdown register leaves the + * maximum value up to which refresh is permitted (MVRP) window. + * + * @param + * Void + * + * @return + * This function does not return a value. + * + * Example: + */ +static inline void +MIV_WDOG_enable_mvrp_irq +( + void +) +{ + + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGCNTL_NEXT_INTENT_MSVP, 0x01u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_disable_mvrp_irq() function disables the generation of the + * MVRP interrupt. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_disable_mvrp_irq +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGCNTL_NEXT_INTENT_MSVP, 0x0u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_clear_timeout_irq() function clears the watchdog’s timeout + * interrupt which is connected to the MIV-RV32 interrupt. Calling + * MIV_WDOG_clear_timeout_irq() results in clearing the MIV-RV32 interrupt. + * Note: You must call the MIV_WDOG_clear_timeout_irq() function as part of your + * implementation of the interrupt handler in order to prevent the same + * interrupt event re-triggering a call to the timeout ISR. + * + * @param + * Void + * + * @return + * This function does not return any value. + * + */ +static inline void +MIV_WDOG_clear_timeout_irq +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_WDOG_TRIPPED, 0x01u); + /* + * Perform a second write to ensure that the first write completed before + * returning from this function. This is to account for posted writes across + * the AHB matrix. The second write ensures that the first write has + * completed and that the interrupt line has been de-asserted by the time + * the function returns. Omitting the second write may result in a delay + * in the de-assertion of the interrupt line going to the RISC-V and a + * retriggering of the interrupt. + */ + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_WDOG_TRIPPED, 0x01u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_clear_mvrp_irq() function clears the mvrp interrupt. + * + * Note: You must call the MIV_WDOG_clear_mvrp_irq() function as part of your + * implementation of the interrupt service routine (ISR) in order to + * prevent the same interrupt event re-triggering a call to the mvrp ISR. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_clear_mvrp_irq +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_MSVP_TRIPPED, 0x01u); + /* + * Perform a second write to ensure that the first write completed before + * returning from this function. This is to account for posted writes across + * the AHB matrix. The second write ensures that the first write has + * completed and that the interrupt line has been de-asserted by the time + * the function returns. Omitting the second write may result in a delay + * in the de-assertion of the interrupt line going to the RISC-V and a + * re-triggering of the interrupt. + */ + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_MSVP_TRIPPED, 0x01u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_timeout_occured() function reports the occurrence of a timeout + * event. + * + * @param + * Void + * + * @return + * A zero value indicates no watchdog timeout event occurred. A value of 1 + * indicates that a timeout event occurred. + */ +static inline uint32_t +MIV_WDOG_timeout_occured +( + void +) +{ + return (HAL_get_32bit_reg_field(g_this_wdog, WDOGSTAT_TRIGGERED)); +} + +/***************************************************************************//** + * The MIV_WDOG_force_reset() function is used to force an immediate reset + * if the watchdog has already triggered. Writing any value in this condition + * will result in watchdog timeout. + * The time out interrupt WDOG_IRQ will be set to high and watchdog timer + * countdown register updated with watchdog trigger timeout register value. + * If the Watchdog has timed out, a special 16-bit value needs to be written + * to the register to force a reset on CPU_RESETN, 0xDEAD + * Then the Watchdog countdown is reset/updated with the top Watchdog Runtime + * register value. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_force_reset +( + void +) +{ + if (WDOGSTAT_TRIGGERED_MASK == + HAL_get_32bit_reg_field(g_this_wdog, WDOGSTAT_TRIGGERED)) + + { + HAL_set_32bit_reg(g_this_wdog, WDOGFORCE, MIV_WDOG_FORCE_RESET_KEY); + } + + else + { + HAL_set_32bit_reg(g_this_wdog, WDOGFORCE, 0x0u); + } +} + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_WATCHDOG_H_ */ diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h new file mode 100644 index 0000000..2fca983 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h @@ -0,0 +1,122 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP watchdog module driver. This module is delivered as a part of Mi-V + * extended Sub-System(ESS) MIV_ESS. + */ + +#ifndef MIV_WDOG_REGISTERS +#define MIV_WDOG_REGISTERS 1u + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * Refresh register details + */ +#define WDOGRFSH_REG_OFFSET 0x00u + +/* Refresh register bits */ +#define WDOGRFSH_OFFSET 0x00u +#define WDOGRFSH_MASK 0xFFFFFFFFu +#define WDOGRFSH_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Control register details + */ +#define WDOGCNTL_REG_OFFSET 0x04u + +/* Control register next intent msvp bit */ +#define WDOGCNTL_NEXT_INTENT_MSVP_OFFSET 0x04u +#define WDOGCNTL_NEXT_INTENT_MSVP_MASK 0x01u +#define WDOGCNTL_NEXT_INTENT_MSVP_SHIFT 0u + +/* Control register next intent wdog bit */ +#define WDOGCNTL_NEXT_INTENT_WDOG_OFFSET 0x04u +#define WDOGCNTL_NEXT_INTENT_WDOG_MASK 0x02u +#define WDOGCNTL_NEXT_INTENT_WDOG_SHIFT 1u + +/* Control register next enforbidden bit */ +#define WDOGCNTL_NEXT_ENFORBIDDEN_OFFSET 0x04u +#define WDOGCNTL_NEXT_ENFORBIDDEN_MASK 0x10u +#define WDOGCNTL_NEXT_ENFORBIDDEN_SHIFT 4u + +/*------------------------------------------------------------------------------ + * Watchdog status register + */ +#define WDOGSTAT_REG_OFFSET 0x08u + +/* msvp_tripped bit */ +#define WDOGSTAT_MSVP_TRIPPED_OFFSET 0x08u +#define WDOGSTAT_MSVP_TRIPPED_MASK 0x01u +#define WDOGSTAT_MSVP_TRIPPED_SHIFT 0u + +/* WDOG Tripped bit */ +#define WDOGSTAT_WDOG_TRIPPED_OFFSET 0x08u +#define WDOGSTAT_WDOG_TRIPPED_MASK 0x02u +#define WDOGSTAT_WDOG_TRIPPED_SHIFT 1u + +/* Forbidden bit */ +#define WDOGSTAT_FORBIDDEN_OFFSET 0x08u +#define WDOGSTAT_FORBIDDEN_MASK 0x04u +#define WDOGSTAT_FORBIDDEN_SHIFT 2u + +/* Triggered bit */ +#define WDOGSTAT_TRIGGERED_OFFSET 0x08u +#define WDOGSTAT_TRIGGERED_MASK 0x08u +#define WDOGSTAT_TRIGGERED_SHIFT 3u + +/* wdoglocked bit */ +#define WDOGSTAT_WDOGLOCKED_OFFSET 0x08u +#define WDOGSTAT_WDOGLOCKED_MASK 0x10u +#define WDOGSTAT_WDOGLOCKED_SHIFT 4u + +/*------------------------------------------------------------------------------ + * Watchdog runtime register + */ +#define WDOGTIME_REG_OFFSET 0x0Cu + +/* wdogmsvp bit */ +#define WDOGTIME_WDOGVALUE_OFFSET 0x0Cu +#define WDOGTIME_WDOGVALUE_MASK 0xFFFFFFu +#define WDOGTIME_WDOGVALUE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Watchdog MVRP register + */ +#define WDOGMSVP_REG_OFFSET 0x10u + +/* wdogmsvp bit */ +#define WDOGMSVP_OFFSET 0x10u +#define WDOGMSVP_MASK 0xFFFFFFu +#define WDOGMSVP_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Watchdog Trigger Timeout register + */ +#define WDOGTRIG_REG_OFFSET 0x14u + +/* wdogmsvp bit */ +#define WDOGTRIG_WDOGRST_OFFSET 0x14u +#define WDOGTRIG_WDOGRST_MASK 0xFFFFFFu +#define WDOGTRIG_WDOGRST_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Watchdog Force Reset register details + */ +#define WDOGFORCE_REG_OFFSET 0x18u + +/* Refresh register bits */ +#define WDOGFORCE_OFFSET 0x18u +#define WDOGFORCE_MASK 0xFFFFFFFFu +#define WDOGFORCE_SHIFT 0u + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_WATCHDOG_REGS_H_ */ diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/hal/cpu_types.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/hal/cpu_types.h new file mode 100755 index 0000000..ef8ab20 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/hal/cpu_types.h @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file cpu_types.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Type definitions which can be commonly used by the fabric-ip drivers. + * + */ +#ifndef __CPU_TYPES_H +#define __CPU_TYPES_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned int size_t; + +/*------------------------------------------------------------------------------ + * addr_t: address type. + * Used to specify the address of peripherals present in the processor's memory + * map. + */ +typedef unsigned int addr_t; + +/*------------------------------------------------------------------------------ + * psr_t: processor state register. + * Used by HAL_disable_interrupts() and HAL_restore_interrupts() to store the + * processor's state between disabling and restoring interrupts. + */ +typedef unsigned int psr_t; + +#ifdef __cplusplus +} +#endif + +#endif /* CPU_TYPES_H */ + diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/hal/hal.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/hal/hal.h new file mode 100755 index 0000000..7eec17a --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/hal/hal.h @@ -0,0 +1,235 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file hal.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware abstraction layer functions for peripheral register accesses. + * + */ +#ifndef __HAL_H +#define __HAL_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include "cpu_types.h" +#include "hw_reg_access.h" +#include "hal_assert.h" +/***************************************************************************//** + * Enable all interrupts at the processor level. + */ +void HAL_enable_interrupts( void ); + +/***************************************************************************//** + * Disable all interrupts at the processor core level. + * Return the interrupts enable state before disabling occurred so that it can + * later be restored. + */ +psr_t HAL_disable_interrupts( void ); + +/***************************************************************************//** + * Restore the interrupts enable state at the processor core level. + * This function is normally passed the value returned from a previous call to + * HAL_disable_interrupts(). + */ +void HAL_restore_interrupts( psr_t saved_psr ); + +/***************************************************************************//** + */ +#define FIELD_OFFSET(FIELD_NAME) (FIELD_NAME##_OFFSET) +#define FIELD_SHIFT(FIELD_NAME) (FIELD_NAME##_SHIFT) +#define FIELD_MASK(FIELD_NAME) (FIELD_NAME##_MASK) + +/***************************************************************************//** + * The macro HAL_set_32bit_reg() allows writing a 32 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint32_t containing the value to write. + */ +#define HAL_set_32bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_32bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_32bit_reg() is used to read the value of a 32 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint32_t value. + */ +#define HAL_get_32bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_32bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)) )) + +/***************************************************************************//** + * The macro HAL_set_32bit_reg_field() is used to write a field within a + * 32 bits wide register. The field written can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * VALUE: A variable of type uint32_t containing the field value to write. + */ +#define HAL_set_32bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_32bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_32bit_reg_field() is used to read a register field from + * within a 32 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint32_t value. + */ +#define HAL_get_32bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_32bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +/***************************************************************************//** + * The macro HAL_set_16bit_reg() allows writing a 16 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint_fast16_t containing the value to write. + */ +#define HAL_set_16bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_16bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_16bit_reg() is used to read the value of a 16 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint16_t value. + */ +#define HAL_get_16bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_16bit_reg( (BASE_ADDR) + (REG_NAME##_REG_OFFSET) )) + +/***************************************************************************//** + * The macro HAL_set_16bit_reg_field() is used to write a field within a + * 16 bits wide register. The field written can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * VALUE: A variable of type uint16_t containing the field value to write. + */ +#define HAL_set_16bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_16bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_16bit_reg_field() is used to read a register field from + * within a 8 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint16_t value. + */ +#define HAL_get_16bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_16bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +/***************************************************************************//** + * The macro HAL_set_8bit_reg() allows writing a 8 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint_fast8_t containing the value to write. + */ +#define HAL_set_8bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_8bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_8bit_reg() is used to read the value of a 8 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint8_t value. + */ +#define HAL_get_8bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_8bit_reg( (BASE_ADDR) + (REG_NAME##_REG_OFFSET) )) + +/***************************************************************************//** + */ +#define HAL_set_8bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_8bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_8bit_reg_field() is used to read a register field from + * within a 8 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint8_t value. + */ +#define HAL_get_8bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_8bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +#ifdef __cplusplus +} +#endif + +#endif /*HAL_H*/ + diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/hal/hal_assert.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/hal/hal_assert.h new file mode 100755 index 0000000..1e18b54 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/hal/hal_assert.h @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hal_assert.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief HAL assert functions + */ +#ifndef __HAL_ASSERT_HEADER +#define __HAL_ASSERT_HEADER 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Disable assertions if we do not recognize the compiler. */ +#if defined ( __GNUC__ ) +#if defined(NDEBUG) +/***************************************************************************//** + * HAL_ASSERT() is defined out when the NDEBUG symbol is used. + ******************************************************************************/ +#define HAL_ASSERT(CHECK) + +#else + +/***************************************************************************//** + * Default behavior for HAL_ASSERT() macro: + *------------------------------------------------------------------------------ + The behavior is toolchain specific and project setting specific. + ******************************************************************************/ +#define HAL_ASSERT(CHECK)\ + do { \ + if (!(CHECK)) \ + { \ + __asm__ volatile ("ebreak"); \ + }\ + } while(0); + +#endif /* NDEBUG */ +#endif /*__GNUC__*/ + +#ifdef __cplusplus +} +#endif +#endif /* __HAL_ASSERT_HEADER */ + diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/hal/hal_irq.c b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/hal/hal_irq.c new file mode 100755 index 0000000..95a0775 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/hal/hal_irq.c @@ -0,0 +1,45 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hal_irq.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Legacy interrupt control functions for the Microchip driver library + * hardware abstraction layer. + * + */ +#include "hal.h" +#include "miv_rv32_hal/miv_rv32_hal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * + */ +void HAL_enable_interrupts(void) { + MRV_enable_interrupts(); +} + +/*------------------------------------------------------------------------------ + * + */ +psr_t HAL_disable_interrupts(void) { + psr_t psr; + psr = read_csr(mstatus); + MRV_disable_interrupts(); + return(psr); +} + +/*------------------------------------------------------------------------------ + * + */ +void HAL_restore_interrupts(psr_t saved_psr) { + write_csr(mstatus, saved_psr); +} + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/hal/hw_macros.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/hal/hw_macros.h new file mode 100755 index 0000000..189609c --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/hal/hw_macros.h @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hw_macros.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware registers access macros. + * + * THE MACROS DEFINED IN THIS FILE ARE DEPRECATED. DO NOT USE FOR NEW + * DEVELOPMENT. + * + * These macros are used to access peripheral registers. They allow access to + * 8, 16 and 32 bit wide registers. All accesses to peripheral registers should + * be done through these macros in order to ease porting across different + * processors/bus architectures. + * + * Some of these macros also allow access to a specific register field. + * + */ +#ifndef __HW_REGISTER_MACROS_H +#define __HW_REGISTER_MACROS_H 1 +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * 32 bits registers access: + */ +#define HW_get_uint32_reg(BASE_ADDR, REG_OFFSET) (*((uint32_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint32_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint32_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint32_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint32_t) \ + ( \ + (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint32_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint32_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 32 bits memory access: + */ +#define HW_get_uint32(BASE_ADDR) (*((uint32_t volatile *)(BASE_ADDR))) + +#define HW_set_uint32(BASE_ADDR, VALUE) (*((uint32_t volatile *)(BASE_ADDR)) = (VALUE)) + +/*------------------------------------------------------------------------------ + * 16 bits registers access: + */ +#define HW_get_uint16_reg(BASE_ADDR, REG_OFFSET) (*((uint16_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint16_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint16_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint16_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint16_t) \ + ( \ + (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint16_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint16_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 8 bits registers access: + */ +#define HW_get_uint8_reg(BASE_ADDR, REG_OFFSET) (*((uint8_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint8_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint8_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint8_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint8_t) \ + ( \ + (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint8_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint8_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 8 bits memory access: + */ +#define HW_get_uint8(BASE_ADDR) (*((uint8_t volatile *)(BASE_ADDR))) + +#define HW_set_uint8(BASE_ADDR, VALUE) (*((uint8_t volatile *)(BASE_ADDR)) = (VALUE)) + +#ifdef __cplusplus +extern "C" { +#endif + +#endif /* __HW_REGISTER_MACROS_H */ + diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/hal/hw_reg_access.S b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/hal/hw_reg_access.S new file mode 100755 index 0000000..dd29223 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/hal/hw_reg_access.S @@ -0,0 +1,215 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hw_reg_access.S + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware registers access functions. + * The implementation of these function is platform and toolchain specific. + * The functions declared here are implemented using assembler as part of the + * processor/toolchain specific HAL. This implementation is for the combination + * of the 32 bit RISC-V processors and GNU tool chain. + * + */ + +.section .text + .globl HW_set_32bit_reg + .globl HW_get_32bit_reg + .globl HW_set_32bit_reg_field + .globl HW_get_32bit_reg_field + .globl HW_set_16bit_reg + .globl HW_get_16bit_reg + .globl HW_set_16bit_reg_field + .globl HW_get_16bit_reg_field + .globl HW_set_8bit_reg + .globl HW_get_8bit_reg + .globl HW_set_8bit_reg_field + .globl HW_get_8bit_reg_field + + +/***************************************************************************//** + * HW_set_32bit_reg is used to write the content of a 32 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint32_t value + */ +HW_set_32bit_reg: + sw a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_32bit_reg is used to read the content of a 32 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + + * @return 32 bits value read from the peripheral register. + */ +HW_get_32bit_reg: + lw a0, 0(a0) + ret + +/***************************************************************************//** + * HW_set_32bit_reg_field is used to set the content of a field in a 32 bits + * wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint32_t mask + * a3: uint32_t value + */ +HW_set_32bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lw t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sw t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_32bit_reg_field is used to read the content of a field out of a + * 32 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint32_t mask + * + * @return 32 bits value containing the register field value specified + * as parameter. + */ +HW_get_32bit_reg_field: + lw a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +/***************************************************************************//** + * HW_set_16bit_reg is used to write the content of a 16 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint_fast16_t value + */ +HW_set_16bit_reg: + sh a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_16bit_reg is used to read the content of a 16 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + + * @return 16 bits value read from the peripheral register. + */ +HW_get_16bit_reg: + lh a0, (a0) + ret + +/***************************************************************************//** + * HW_set_16bit_reg_field is used to set the content of a field in a 16 bits + * wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast16_t mask + * a3: uint_fast16_t value + * @param value Value to be written in the specified field. + */ +HW_set_16bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lh t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sh t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_16bit_reg_field is used to read the content of a field from a + * 16 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast16_t mask + * + * @return 16 bits value containing the register field value specified + * as parameter. + */ +HW_get_16bit_reg_field: + lh a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +/***************************************************************************//** + * HW_set_8bit_reg is used to write the content of a 8 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint_fast8_t value + */ +HW_set_8bit_reg: + sb a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_8bit_reg is used to read the content of a 8 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + + * @return 8 bits value read from the peripheral register. + */ +HW_get_8bit_reg: + lb a0, 0(a0) + ret + +/***************************************************************************//** + * HW_set_8bit_reg_field is used to set the content of a field in a 8 bits + * wide peripheral register. + * + * a0: addr_t reg_addr, + * a1: int_fast8_t shift + * a2: uint_fast8_t mask + * a3: uint_fast8_t value + */ +HW_set_8bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lb t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sb t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_8bit_reg_field is used to read the content of a field from a + * 8 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast8_t mask + * + * @return 8 bits value containing the register field value specified + * as parameter. + */ +HW_get_8bit_reg_field: + lb a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +.end diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/hal/hw_reg_access.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/hal/hw_reg_access.h new file mode 100755 index 0000000..1a24309 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/hal/hw_reg_access.h @@ -0,0 +1,239 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hw_reg_access.S + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware registers access functions. + * The implementation of these function is platform and tool-chain specific. + * The functions declared here are implemented using assembler as part of the + * processor/tool-chain specific HAL. This implementation is for the combination + * of the 32 bit RISC-V processors and GNU tool chain. + * + */ +#ifndef __HW_REG_ACCESS +#define __HW_REG_ACCESS +#ifdef __cplusplus +extern "C" { +#endif + +#include "cpu_types.h" +/***************************************************************************//** + * HW_set_32bit_reg is used to write the content of a 32 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_32bit_reg +( + addr_t reg_addr, + uint32_t value +); + +/***************************************************************************//** + * HW_get_32bit_reg is used to read the content of a 32 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 32 bits value read from the peripheral register. + */ +uint32_t +HW_get_32bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_32bit_reg_field is used to set the content of a field in a 32 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void +HW_set_32bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint32_t mask, + uint32_t value +); + +/***************************************************************************//** + * HW_get_32bit_reg_field is used to read the content of a field out of a + * 32 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 32 bits value containing the register field value specified + * as parameter. + */ +uint32_t +HW_get_32bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint32_t mask +); + +/***************************************************************************//** + * HW_set_16bit_reg is used to write the content of a 16 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_16bit_reg +( + addr_t reg_addr, + uint_fast16_t value +); + +/***************************************************************************//** + * HW_get_16bit_reg is used to read the content of a 16 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 16 bits value read from the peripheral register. + */ +uint16_t +HW_get_16bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_16bit_reg_field is used to set the content of a field in a 16 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void HW_set_16bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast16_t mask, + uint_fast16_t value +); + +/***************************************************************************//** + * HW_get_16bit_reg_field is used to read the content of a field from a + * 16 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 16 bits value containing the register field value specified + * as parameter. + */ +uint16_t HW_get_16bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast16_t mask +); + +/***************************************************************************//** + * HW_set_8bit_reg is used to write the content of a 8 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_8bit_reg +( + addr_t reg_addr, + uint_fast8_t value +); + +/***************************************************************************//** + * HW_get_8bit_reg is used to read the content of a 8 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 8 bits value read from the peripheral register. + */ +uint8_t +HW_get_8bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_8bit_reg_field is used to set the content of a field in a 8 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void HW_set_8bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast8_t mask, + uint_fast8_t value +); + +/***************************************************************************//** + * HW_get_8bit_reg_field is used to read the content of a field from a + * 8 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 8 bits value containing the register field value specified + * as parameter. + */ +uint8_t HW_get_8bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast8_t mask +); + +#ifdef __cplusplus +} +#endif + +#endif /* __HW_REG_ACCESS */ + diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld new file mode 100644 index 0000000..474eb43 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld @@ -0,0 +1,154 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-execute-in-place.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * image executing from a one address space whereas the data, sdata and stack + * sections are placed in another address space. This could be used in cases such + * as: + * 1) When using MIV_RV32, the reset vector points to the LSRAM at address + * 0x80000000 and the data, sdata, bss and stack sections are placed in the + * TCM region. + * + * 2) Executing from a Non Volatile memory. The actual memory will depend on + * the FPGA platform. For exameple, it could be the eNVM on SmartFusion2, + * Igloo2 or on-board non-volatile memory which supports code execution. + * + * NOTE: Modify the memory section addresses and the sizes according to your + * Libero design. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + + +MEMORY +{ + rom (rx) : ORIGIN = 0x80000000, LENGTH = 16k + ram (rwx) : ORIGIN = 0x80004000, LENGTH = 16k +} + +STACK_SIZE = 1k; /* needs to be calculated for your application */ +HEAP_SIZE = 1k; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > rom + + .text : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.text.entry))) + . = ALIGN(0x10); + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } >rom + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } >ram AT>rom + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } >ram AT>rom + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram +} + diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv-rv32-ram.ld b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv-rv32-ram.ld new file mode 100755 index 0000000..53076a0 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv-rv32-ram.ld @@ -0,0 +1,150 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-ram.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * debug image executing in SRAM. + * + * This linker script assumes that a RAM is connected at on Mi-V soft processor + * memory space pointed by the reset vector address. + * + * NOTE : Modify the memory section address and the size according to your + * Libero design. + * For example: + * 1) If you want to download and step debug at a different RAM memory address in + * your design (For example TCM base address) than the one provided in this file. + * 2) The MIV_RV32, when used with MIV_ESS IP, provides ways to copy the executable + * HEX file from external Non-Volatile memory into the TCM at reset. In this + * case your executable must be linked to the TCM address. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +MEMORY +{ + ram (rwx) : ORIGIN = 0x80000000, LENGTH = 32k +} + +STACK_SIZE = 2k; /* needs to be calculated for your application */ +HEAP_SIZE = 1k; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > ram + + .text : ALIGN(0x10) + { + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } > ram + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } > ram + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } > ram + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram +} + diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv_rv32_assert.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv_rv32_assert.h new file mode 100644 index 0000000..b3912ed --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv_rv32_assert.h @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * MIV_RV32 HAL Embedded Software + * + */ +#ifndef MIV_RV32_ASSERT_HEADER +#define MIV_RV32_ASSERT_HEADER + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + * ASSERT() implementation. + ******************************************************************************/ +/* Disable assertions if we do not recognize the compiler. */ +#if defined ( __GNUC__ ) +#if defined(NDEBUG) +#define ASSERT(CHECK) +#else +#define ASSERT(CHECK)\ + do { \ + if (!(CHECK)) \ + { \ + __asm__ volatile ("ebreak"); \ + }\ + } while(0); + +#endif /* NDEBUG check */ +#endif /* compiler check */ + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_RV32_ASSERT_HEADER */ + diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv_rv32_entry.S b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv_rv32_entry.S new file mode 100755 index 0000000..0ea3172 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv_rv32_entry.S @@ -0,0 +1,590 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_entry.S + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor vectors, trap handling and startup code. + * + */ +#ifndef ENTRY_S +#define ENTRY_S + +#define A_EXTENSION_MASK 0x00000001u +#define MTVEC_MODE_BIT_MASK 0x00000003u +#define MTVEC_VECTORED_MODE_VAL 0x00000001u + +#define MTIMEH_ADDR 0x200BFFCu + + +#if __riscv_xlen == 64 +# define LREG ld +# define SREG sd +# define REGBYTES 8 +#else +# define LREG lw +# define SREG sw +# define REGBYTES 4 +#endif + +#if defined(MIV_FP_CONTEXT_SAVE) && defined(__riscv_flen) +#define SP_SHIFT_OFFSET 64 +#else +#define SP_SHIFT_OFFSET 32 +#endif + +.macro STORE_CONTEXT + addi sp, sp, -SP_SHIFT_OFFSET*REGBYTES + SREG x1, 0 * REGBYTES(sp) + SREG x1, 0 * REGBYTES(sp) + SREG x2, 1 * REGBYTES(sp) + SREG x3, 2 * REGBYTES(sp) + SREG x4, 3 * REGBYTES(sp) + SREG x5, 4 * REGBYTES(sp) + SREG x6, 5 * REGBYTES(sp) + SREG x7, 6 * REGBYTES(sp) + SREG x8, 7 * REGBYTES(sp) + SREG x9, 8 * REGBYTES(sp) + SREG x10, 9 * REGBYTES(sp) + SREG x11, 10 * REGBYTES(sp) + SREG x12, 11 * REGBYTES(sp) + SREG x13, 12 * REGBYTES(sp) + SREG x14, 13 * REGBYTES(sp) + SREG x15, 14 * REGBYTES(sp) + SREG x16, 15 * REGBYTES(sp) + SREG x17, 16 * REGBYTES(sp) + SREG x18, 17 * REGBYTES(sp) + SREG x19, 18 * REGBYTES(sp) + SREG x20, 19 * REGBYTES(sp) + SREG x21, 20 * REGBYTES(sp) + SREG x22, 21 * REGBYTES(sp) + SREG x23, 22 * REGBYTES(sp) + SREG x24, 23 * REGBYTES(sp) + SREG x25, 24 * REGBYTES(sp) + SREG x26, 25 * REGBYTES(sp) + SREG x27, 26 * REGBYTES(sp) + SREG x28, 27 * REGBYTES(sp) + SREG x29, 28 * REGBYTES(sp) + SREG x30, 29 * REGBYTES(sp) + SREG x31, 30 * REGBYTES(sp) + + #ifdef __riscv_flen + #ifdef MIV_FP_CONTEXT_SAVE + fsw f0, 31*REGBYTES(sp) + fsw f1, 32*REGBYTES(sp) + fsw f2, 33*REGBYTES(sp) + fsw f3, 34*REGBYTES(sp) + fsw f4, 35*REGBYTES(sp) + fsw f5, 36*REGBYTES(sp) + fsw f6, 37*REGBYTES(sp) + fsw f7, 38*REGBYTES(sp) + fsw f8, 39*REGBYTES(sp) + fsw f9, 40*REGBYTES(sp) + fsw f10, 41*REGBYTES(sp) + fsw f11, 42*REGBYTES(sp) + fsw f12, 43*REGBYTES(sp) + fsw f13, 44*REGBYTES(sp) + fsw f14, 45*REGBYTES(sp) + fsw f15, 46*REGBYTES(sp) + fsw f16, 47*REGBYTES(sp) + fsw f17, 48*REGBYTES(sp) + fsw f18, 49*REGBYTES(sp) + fsw f19, 50*REGBYTES(sp) + fsw f20, 51*REGBYTES(sp) + fsw f21, 52*REGBYTES(sp) + fsw f22, 53*REGBYTES(sp) + fsw f23, 54*REGBYTES(sp) + fsw f24, 55*REGBYTES(sp) + fsw f25, 56*REGBYTES(sp) + fsw f26, 57*REGBYTES(sp) + fsw f27, 58*REGBYTES(sp) + fsw f28, 59*REGBYTES(sp) + fsw f29, 60*REGBYTES(sp) + fsw f30, 61*REGBYTES(sp) + fsw f31, 62*REGBYTES(sp) + #endif /* __riscv_flen */ + #endif /* MIV_FP_CONTEXT_SAVE */ +.endm + + .section .entry, "ax" + .globl _start + +_start: + j handle_reset + +/* Some of the Mi-V soft IP cores support compressed 'C' extension. If the Mi-V + core in your design doesn't support 'C' extension and you enable 'C' extension + in firmware project compiler options, then it would result in a trap. For this + case, we are avoiding compressed instruction here so you can put a breakpoint + at the jump and you can at least look at mcause, mepc and get some hints + about the crash. */ +trap_entry: +.option push +.option norvc +j generic_trap_handler +.option pop + .word 0 + .word 0 + +sw_trap_entry: + j vector_sw_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + +tmr_trap_entry: + j vector_tmr_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + +ext_trap_entry: + j vector_ext_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + .word 0 + +#ifndef MIV_LEGACY_RV32 +MGEUI_trap_entry: + j vector_MGEUI_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MGECI_trap_entry: + j vector_MGECI_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + .word 0 + +#ifndef MIV_RV32_V3_0 +MSYS_MIE22_trap_entry: +#ifndef MIV_RV32_V3_0 + j vector_SUBSYSR_IRQHandler +#endif /*MIV_RV32_V3_0*/ +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE23_trap_entry: + j vector_SUBSYS_IRQHandler +#ifdef __riscv_compressed + .2byte 0 +#endif +#endif /*MIV_RV32_V3_0*/ + +MSYS_MIE24_trap_entry: + j vector_MSYS_EI0_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE25_trap_entry: + j vector_MSYS_EI1_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE26_trap_entry: + j vector_MSYS_EI2_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE27_trap_entry: + j vector_MSYS_EI3_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE28_trap_entry: + j vector_MSYS_EI4_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE29_trap_entry: + j vector_MSYS_EI5_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE30_trap_entry: +#ifndef MIV_RV32_V3_0 + j vector_MSYS_EI6_trap_handler +#else + j vector_SUBSYS_IRQHandler +#endif +#ifdef __riscv_compressed + .2byte 0 +#endif + +#ifndef MIV_RV32_V3_0 +MSYS_MIE31_trap_entry: + j vector_MSYS_EI7_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif +#endif /* MIV_RV32_V3_0 */ +#endif /* MIV_LEGACY_RV32 */ + +.align 4 +generic_trap_handler: + STORE_CONTEXT + csrr a0, mcause + csrr a1, mepc + jal handle_trap + j generic_restore + +vector_sw_trap_handler: + STORE_CONTEXT + jal handle_m_soft_interrupt + j generic_restore + +vector_tmr_trap_handler: + STORE_CONTEXT + jal handle_m_timer_interrupt + j generic_restore + +vector_ext_trap_handler: + STORE_CONTEXT +#ifdef MIV_LEGACY_RV32 + jal handle_m_ext_interrupt +#else + jal External_IRQHandler +#endif /* MIV_LEGACY_RV32 */ + j generic_restore + +#ifndef MIV_LEGACY_RV32 +vector_MGEUI_trap_handler: + STORE_CONTEXT + jal MGEUI_IRQHandler + j generic_restore + +vector_MGECI_trap_handler: + STORE_CONTEXT + jal MGECI_IRQHandler + j generic_restore + +vector_MSYS_EI0_trap_handler: + STORE_CONTEXT + jal MSYS_EI0_IRQHandler + j generic_restore + +vector_MSYS_EI1_trap_handler: + STORE_CONTEXT + jal MSYS_EI1_IRQHandler + j generic_restore + +vector_MSYS_EI2_trap_handler: + STORE_CONTEXT + jal MSYS_EI2_IRQHandler + j generic_restore + +vector_MSYS_EI3_trap_handler: + STORE_CONTEXT + jal MSYS_EI3_IRQHandler + j generic_restore + +vector_MSYS_EI4_trap_handler: + STORE_CONTEXT + jal MSYS_EI4_IRQHandler + j generic_restore + +vector_MSYS_EI5_trap_handler: + STORE_CONTEXT + jal MSYS_EI5_IRQHandler + j generic_restore + +vector_SUBSYS_IRQHandler: + STORE_CONTEXT + jal SUBSYS_IRQHandler + j generic_restore + +#ifndef MIV_RV32_V3_0 +vector_MSYS_EI6_trap_handler: + STORE_CONTEXT + jal MSYS_EI6_IRQHandler + j generic_restore + +vector_MSYS_EI7_trap_handler: + STORE_CONTEXT + jal MSYS_EI7_IRQHandler + j generic_restore + + +vector_SUBSYSR_IRQHandler: + STORE_CONTEXT + jal SUBSYSR_IRQHandler + j generic_restore + +#endif /*MIV_RV32_V3_0*/ +#endif /* MIV_LEGACY_RV32 */ + +generic_restore: + LREG x1, 0 * REGBYTES(sp) + LREG x2, 1 * REGBYTES(sp) + LREG x3, 2 * REGBYTES(sp) + LREG x4, 3 * REGBYTES(sp) + LREG x5, 4 * REGBYTES(sp) + LREG x6, 5 * REGBYTES(sp) + LREG x7, 6 * REGBYTES(sp) + LREG x8, 7 * REGBYTES(sp) + LREG x9, 8 * REGBYTES(sp) + LREG x10, 9 * REGBYTES(sp) + LREG x11, 10 * REGBYTES(sp) + LREG x12, 11 * REGBYTES(sp) + LREG x13, 12 * REGBYTES(sp) + LREG x14, 13 * REGBYTES(sp) + LREG x15, 14 * REGBYTES(sp) + LREG x16, 15 * REGBYTES(sp) + LREG x17, 16 * REGBYTES(sp) + LREG x18, 17 * REGBYTES(sp) + LREG x19, 18 * REGBYTES(sp) + LREG x20, 19 * REGBYTES(sp) + LREG x21, 20 * REGBYTES(sp) + LREG x22, 21 * REGBYTES(sp) + LREG x23, 22 * REGBYTES(sp) + LREG x24, 23 * REGBYTES(sp) + LREG x25, 24 * REGBYTES(sp) + LREG x26, 25 * REGBYTES(sp) + LREG x27, 26 * REGBYTES(sp) + LREG x28, 27 * REGBYTES(sp) + LREG x29, 28 * REGBYTES(sp) + LREG x30, 29 * REGBYTES(sp) + LREG x31, 30 * REGBYTES(sp) + + #ifdef __riscv_flen + #ifdef MIV_FP_CONTEXT_SAVE + flw f0, 0 * REGBYTES(sp) + flw f1, 1 * REGBYTES(sp) + flw f2, 2 * REGBYTES(sp) + flw f3, 3 * REGBYTES(sp) + flw f4, 4 * REGBYTES(sp) + flw f5, 5 * REGBYTES(sp) + flw f6, 6 * REGBYTES(sp) + flw f7, 7 * REGBYTES(sp) + flw f8, 8 * REGBYTES(sp) + flw f9, 9 * REGBYTES(sp) + flw f10, 10 * REGBYTES(sp) + flw f11, 11 * REGBYTES(sp) + flw f12, 12 * REGBYTES(sp) + flw f13, 13 * REGBYTES(sp) + flw f14, 14 * REGBYTES(sp) + flw f15, 15 * REGBYTES(sp) + flw f16, 16 * REGBYTES(sp) + flw f17, 17 * REGBYTES(sp) + flw f18, 18 * REGBYTES(sp) + flw f19, 19 * REGBYTES(sp) + flw f20, 20 * REGBYTES(sp) + flw f21, 21 * REGBYTES(sp) + flw f22, 22 * REGBYTES(sp) + flw f23, 23 * REGBYTES(sp) + flw f24, 24 * REGBYTES(sp) + flw f25, 25 * REGBYTES(sp) + flw f26, 26 * REGBYTES(sp) + flw f27, 27 * REGBYTES(sp) + flw f28, 28 * REGBYTES(sp) + flw f29, 29 * REGBYTES(sp) + flw f30, 30 * REGBYTES(sp) + flw f31, 31 * REGBYTES(sp) + #endif /* __riscv_flen */ + #endif /* MIV_FP_CONTEXT_SAVE */ + + addi sp, sp, SP_SHIFT_OFFSET*REGBYTES + mret + + .section .text, "ax" +handle_reset: +/* Ensure instructions are not relaxed, since gp is not yet set */ +.option push +.option norelax + +#ifndef MIV_RV32_V3_0 + csrwi mstatus, 0 + csrwi mie, 0 + la ra, _start + +/* Clearnig this to be on safer side as RTL doesnt seem to clear it on reset. */ +#ifndef MIV_LEGACY_RV32 + li t0, MTIMEH_ADDR + sw x0, 0(t0) +#endif + + csrr t0, misa + andi t0, t0, A_EXTENSION_MASK + bnez t0, ima_cores_setup /* Jump to IMA core handling */ + + +/* For MIV_RV32 cores the mtvec exception base address is fixed at Reset vector + address + 0x4. Check the mode bits. */ +/* In the MIV_RV32 v3.1, the MTVEC exception base address is WARL, and can be + configured by the user at runtime */ + + csrr t0, mtvec + andi t0, t0, MTVEC_MODE_BIT_MASK + li t1, MTVEC_VECTORED_MODE_VAL + bne t0, t1, ima_cores_setup /* Jump to IMA core handling */ + + /* When mode = 1 => this is vectored mode on MIV_RV32 core. + Verify that the trap_handler address matches the configuration in MTVEC */ + csrr t0, mtvec + andi t0, t0, 0xFFFFFFFC + la t1, trap_entry + bne t0, t1, vector_address_not_matching + j generic_reset_handling + +#else /* MIV_RV32_V3_0 */ + +/* Clearnig this to be on safer side as RTL doesnt seem to clear it on reset. */ +#ifndef MIV_LEGACY_RV32 + li t0, MTIMEH_ADDR + sw x0, 0(t0) +#endif + +/* In the MIV_RV32 v3.1, the MTVEC exception base address is WARL, and can be + configured by the user at runtime */ + csrr t0, mtvec + andi t0, t0, MTVEC_MODE_BIT_MASK + li t1, MTVEC_VECTORED_MODE_VAL + bne t0, t1, ima_cores_setup /* Jump to IMA core handling */ + +/* When mode = 1 => this is vectored mode on MIV_RV32 core. + Verify that the trap_handler address matches the configuration in MTVEC */ + csrr t0, mtvec + andi t0, t0, 0xFFFFFFFC + la t1, trap_entry + bne t0, t1, vector_address_not_matching + j generic_reset_handling +#endif /*MIV_RV32_V3_0*/ + +ima_cores_setup: + la t0, trap_entry + +#ifdef MIV_LEGACY_RV32_VECTORED_INTERRUPTS + addi t0, t0, 0x01 /* Set the mode bit for IMA cores. + For both MIV_RV32 v3.1 and v3.0 cores this is done by configurator. */ +#endif + csrw mtvec, t0 + +generic_reset_handling: +/* Copy sdata section first so that the gp is set and linker relaxation can be + used */ + la a4, __sdata_load + la a5, __sdata_start + la a6, __sdata_end + beq a4, a5, 1f /* Exit if source and dest are same */ + beq a5, a6, 1f /* Exit if section start and end addresses are same */ + call block_copy + +1: + /* initialize global pointer */ + la gp, __global_pointer$ + +.option pop + +/* Floating point support configuration */ +#ifdef __riscv_flen + csrr t0, mstatus + lui t1, 0xffffa + addi t1, t1, -1 + and t0, t0, t1 + lui t1, 0x4 + or t1, t0, t1 + csrw mstatus, t1 + + lui t0, 0x0 + fscsr t0 +#endif + call initializations + /* Initialize stack pointer */ + la sp, __stack_top + + /* Jump into C code */ + j _init + +/* Error: trap_entry is not at the expected address of reset_vector+mtvec offset + as configured in the MIV_RV32 core vectored mode */ +vector_address_not_matching: + ebreak + +initializations: +/* Initialize the .bss section */ + mv t0, ra /* Store ra for future use */ + la a5, __bss_start + la a6, __bss_end + beq a5, a6, 1f /* Section start and end address are the same */ + call zeroize_block + +1: +/* Initialize the .sbss section */ + la a5, __sbss_start + la a6, __sbss_end + beq a5, a6, 1f /* Section start and end address are the same */ + call zeroize_block + +/* Clear heap */ + la a5, __heap_start + la a6, __heap_end + beq a5, a6, 1f /* Section start and end address are the same */ + call zeroize_block + +1: +/* Copy data section */ + la a4, __data_load + la a5, __data_start + la a6, __data_end + beq a4, a5, 1f /* Exit early if source and dest are same */ + beq a5, a6, 1f /* Section start and end addresses are the same */ + call block_copy + +1: + mv ra, t0 /* Retrieve ra */ + ret + +zeroize_block: + bltu a6, a5, block_copy_error /* Error. End address is less than start */ + or a7, a6, a5 /* Check if start or end is unalined */ + andi a7, a7, 0x03u + bgtz a7, block_copy_error /* Unaligned addresses error*/ +zeroize_loop: + sw x0, 0(a5) + add a5, a5, __SIZEOF_POINTER__ + blt a5, a6, zeroize_loop + ret + +block_copy: + bltu a6, a5, block_copy_error /* Error. End address is less than start */ + or a7, a6, a5 /* Check if start or end is unalined */ + andi a7, a7, 0x03u + bgtz a7, block_copy_error /* Unaligned addresses error*/ +block_copy_loop: + lw a7, 0(a4) + sw a7, 0(a5) + addi a5, a5, 0x04 + addi a4, a4, 0x04 + blt a5, a6, block_copy_loop + j block_copy_exit + +block_copy_error: + j block_copy_error + +block_copy_exit: + ret + +#endif /*ENTRY_S*/ diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv_rv32_hal.c b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv_rv32_hal.c new file mode 100755 index 0000000..a112821 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv_rv32_hal.c @@ -0,0 +1,410 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_hal.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Implementation of Hardware Abstraction Layer for Mi-V soft processors + * + */ +#include +#include "miv_rv32_hal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SUCCESS 0U +#define ERROR 1U +#define MASK_32BIT 0xFFFFFFFFu + +/*------------------------------------------------------------------------------ + * Write in a sequence recommended by privileged spec to avoid spurious + * interrupts + + # New comparand is in a1:a0. + li t0, -1 + sw t0, mtimecmp # No smaller than old value. + sw a1, mtimecmp+4 # No smaller than new value. + sw a0, mtimecmp # New value. + */ +#ifndef MIV_RV32_EXT_TIMECMP +#define WRITE_MTIMECMP(value) MTIMECMPH = MASK_32BIT; \ + MTIMECMP = value & MASK_32BIT;\ + MTIMECMPH = (value >> 32u) & MASK_32BIT; +#else +#define WRITE_MTIMECMP(value) +#endif + +#ifndef MIV_RV32_EXT_TIMER +#define WRITE_MTIME(value) MTIME = value & MASK_32BIT;\ + MTIMEH = (value >> 32u) & MASK_32BIT; +#else +#define WRITE_MTIME(value) +#endif + +extern void Software_IRQHandler(void); + +#ifdef MIV_LEGACY_RV32 +#define MTIME_PRESCALER 100UL +/*------------------------------------------------------------------------------ + * + */ +uint8_t Invalid_IRQHandler(void); +uint8_t External_1_IRQHandler(void); +uint8_t External_2_IRQHandler(void); +uint8_t External_3_IRQHandler(void); +uint8_t External_4_IRQHandler(void); +uint8_t External_5_IRQHandler(void); +uint8_t External_6_IRQHandler(void); +uint8_t External_7_IRQHandler(void); +uint8_t External_8_IRQHandler(void); +uint8_t External_9_IRQHandler(void); +uint8_t External_10_IRQHandler(void); +uint8_t External_11_IRQHandler(void); +uint8_t External_12_IRQHandler(void); +uint8_t External_13_IRQHandler(void); +uint8_t External_14_IRQHandler(void); +uint8_t External_15_IRQHandler(void); +uint8_t External_16_IRQHandler(void); +uint8_t External_17_IRQHandler(void); +uint8_t External_18_IRQHandler(void); +uint8_t External_19_IRQHandler(void); +uint8_t External_20_IRQHandler(void); +uint8_t External_21_IRQHandler(void); +uint8_t External_22_IRQHandler(void); +uint8_t External_23_IRQHandler(void); +uint8_t External_24_IRQHandler(void); +uint8_t External_25_IRQHandler(void); +uint8_t External_26_IRQHandler(void); +uint8_t External_27_IRQHandler(void); +uint8_t External_28_IRQHandler(void); +uint8_t External_29_IRQHandler(void); +uint8_t External_30_IRQHandler(void); +uint8_t External_31_IRQHandler(void); + + +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for external interrupts. + */ +uint8_t (* const mrv_ext_irq_handler_table[32])(void) = +{ + + Invalid_IRQHandler, + External_1_IRQHandler, + External_2_IRQHandler, + External_3_IRQHandler, + External_4_IRQHandler, + External_5_IRQHandler, + External_6_IRQHandler, + External_7_IRQHandler, + External_8_IRQHandler, + External_9_IRQHandler, + External_10_IRQHandler, + External_11_IRQHandler, + External_12_IRQHandler, + External_13_IRQHandler, + External_14_IRQHandler, + External_15_IRQHandler, + External_16_IRQHandler, + External_17_IRQHandler, + External_18_IRQHandler, + External_19_IRQHandler, + External_20_IRQHandler, + External_21_IRQHandler, + External_22_IRQHandler, + External_23_IRQHandler, + External_24_IRQHandler, + External_25_IRQHandler, + External_26_IRQHandler, + External_27_IRQHandler, + External_28_IRQHandler, + External_29_IRQHandler, + External_30_IRQHandler, + External_31_IRQHandler +}; + +#else +/*------------------------------------------------------------------------------ + * Interrupt handlers as mapped into the MIE register of the MIV_RV32 + */ +extern void Reserved_IRQHandler(void); +extern void External_IRQHandler(void); +extern void MGEUI_IRQHandler(void); +extern void MGECI_IRQHandler(void); +extern void MSYS_EI0_IRQHandler(void); +extern void MSYS_EI1_IRQHandler(void); +extern void MSYS_EI2_IRQHandler(void); +extern void MSYS_EI3_IRQHandler(void); +extern void MSYS_EI4_IRQHandler(void); +extern void MSYS_EI5_IRQHandler(void); +extern void SUBSYS_IRQHandler(void); + +#ifndef MIV_RV32_V3_0 /*For MIV_RV32 v3.1*/ +extern void MSYS_EI6_IRQHandler(void); +extern void MSYS_EI7_IRQHandler(void); +extern void SUBSYSR_IRQHandler(void); // @suppress("Unused function declaration") +#endif /*MIV_RV32_V3_0*/ + +#endif /* MIV_LEGACY_RV32 */ + +/*------------------------------------------------------------------------------ + * Increment value for the mtimecmp register in order to achieve a system tick + * interrupt as specified through the MRV_systick_config() function. + */ +static uint64_t g_systick_increment = 0U; +static uint64_t g_systick_cmp_value = 0U; + +/*------------------------------------------------------------------------------ + * Configure the machine timer to generate an interrupt. + */ +uint32_t MRV_systick_config(uint64_t ticks) +{ + uint32_t ret_val = ERROR; + uint64_t remainder = ticks; + g_systick_increment = 0U; + g_systick_cmp_value = 0U; + + while (remainder >= MTIME_PRESCALER) + { + remainder -= MTIME_PRESCALER; + g_systick_increment++; + } + + g_systick_cmp_value = g_systick_increment + MRV_read_mtime(); + + if (g_systick_increment > 0U) + { + WRITE_MTIMECMP(g_systick_cmp_value); + set_csr(mie, MIP_MTIP); + MRV_enable_interrupts(); + ret_val = SUCCESS; + } + + return ret_val; +} + +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for machine timer interrupts. + */ +void handle_m_timer_interrupt(void) +{ + clear_csr(mie, MIP_MTIP); + + uint64_t mtime_at_irq = MRV_read_mtime(); + +#ifndef NDEBUG + static volatile uint32_t d_tick = 0u; +#endif + + while(g_systick_cmp_value < (mtime_at_irq + MTIME_DELTA)) { + g_systick_cmp_value = g_systick_cmp_value + g_systick_increment; + +#ifndef NDEBUG + d_tick += 1; +#endif + } +/***************************************************************************//** + /* + * Note: If d_tick > 1 it means, that a system timer interrupt has been + * missed. + * Please ensure that interrupt handlers are as short as possible to prevent + * them stopping other interrupts from being handled. For example, if a + * system timer interrupt occurs during a software interrupt, the system + * timer interrupt will not be handled until the software interrupt handling + * is complete. If the software interrupt handling time is more than one + * systick interval, it will result in d_tick > 1. + * If you are running the program using the debugger and halt the CPU at a + * breakpoint, MTIME will continue to increment and interrupts will be + * missed; resulting in d_tick > 1. + */ + + WRITE_MTIMECMP(g_systick_cmp_value); + + SysTick_Handler(); + + set_csr(mie, MIP_MTIP); +} + +void handle_m_soft_interrupt(void) +{ + Software_IRQHandler(); + MRV_clear_soft_irq(); +} +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for software interrupts. + */ +#ifdef MIV_LEGACY_RV32 +void handle_m_ext_interrupt(void) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; + uint8_t disable = EXT_IRQ_KEEP_ENABLED; + + if (0u !=int_num) + { + disable = mrv_ext_irq_handler_table[int_num](); + + PLIC->TARGET[hart_id].CLAIM_COMPLETE = int_num; + + if(EXT_IRQ_DISABLE == disable) + { + MRV_PLIC_disable_irq((IRQn_Type)int_num); + } + } +} +#else + +/*------------------------------------------------------------------------------ + * MSYS local interrupts table + */ +void (* const local_irq_handler_table[16])(void) = +{ +#ifndef MIV_RV32_V3_0 + MGEUI_IRQHandler, + MGECI_IRQHandler, + SUBSYS_IRQHandler, + SUBSYSR_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + MSYS_EI0_IRQHandler, + MSYS_EI1_IRQHandler, + MSYS_EI2_IRQHandler, + MSYS_EI3_IRQHandler, + MSYS_EI4_IRQHandler, + MSYS_EI5_IRQHandler, + MSYS_EI6_IRQHandler, + MSYS_EI7_IRQHandler +#else + MGEUI_IRQHandler, + MGECI_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + MSYS_EI0_IRQHandler, + MSYS_EI1_IRQHandler, + MSYS_EI2_IRQHandler, + MSYS_EI3_IRQHandler, + MSYS_EI4_IRQHandler, + MSYS_EI5_IRQHandler, + SUBSYS_IRQHandler, + Reserved_IRQHandler, +#endif +}; + +/*------------------------------------------------------------------------------ + * Jump to interrupt table containing local interrupts + */ +void handle_local_ei_interrupts(uint8_t irq_no) +{ + uint64_t mhart_id = read_csr(mhartid); + ASSERT(irq_no <= MIV_LOCAL_IRQ_MAX) + ASSERT(irq_no >= MIV_LOCAL_IRQ_MIN) + + uint8_t ei_no = (uint8_t)(irq_no - MIV_LOCAL_IRQ_MIN); + (*local_irq_handler_table[ei_no])(); +} +#endif /* MIV_LEGACY_RV32 */ + + +/*------------------------------------------------------------------------------ + * Trap handler. This function is invoked in the non-vectored mode. + */ +void handle_trap(uintptr_t mcause, uintptr_t mepc) +{ + uint64_t is_interrupt = mcause & MCAUSE_INT; + + if (is_interrupt) + { +#ifndef MIV_LEGACY_RV32 + if (((mcause & MCAUSE_CAUSE) >= MIV_LOCAL_IRQ_MIN) && ((mcause & MCAUSE_CAUSE) <= MIV_LOCAL_IRQ_MAX)) + { + handle_local_ei_interrupts((uint8_t)(mcause & MCAUSE_CAUSE)); + } + else if ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT) +#else + if ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT) +#endif + { +#ifndef MIV_LEGACY_RV32 + External_IRQHandler(); +#else + handle_m_ext_interrupt(); +#endif + } + else if ((mcause & MCAUSE_CAUSE) == IRQ_M_SOFT) + { + handle_m_soft_interrupt(); + } + else if ((mcause & MCAUSE_CAUSE) == IRQ_M_TIMER) + { + handle_m_timer_interrupt(); + } + } + else + { +#ifndef NDEBUG + /* + Arguments supplied to this function are mcause, mepc (exception PC) and + stack pointer. + Based on privileged-isa specification mcause values and meanings are: + + 0 Instruction address misaligned (mtval/mtval is the address) + 1 Instruction access fault (mtval/mtval is the address) + 2 Illegal instruction (mtval/mtval contains the + offending instruction opcode) + 3 Breakpoint + 4 Load address misaligned (mtval/mtval is the address) + 5 Load address fault (mtval/mtval is the address) + 6 Store/AMO address fault (mtval/mtval is the address) + 7 Store/AMO access fault (mtval/mtval is the address) + 8 Environment call from U-mode + 9 Environment call from S-mode + A Environment call from M-mode + B Instruction page fault + C Load page fault (mtval/mtval is the address) + E Store page fault (mtval/mtval is the address) + + # Please note: mtval is the newer name for register mbadaddr + # If you get a compile failure here, use the older name. + # At this point, both are supported in latest compiler, older compiler + # versions only support mbadaddr. + # See: https://github.com/riscv/riscv-gcc/issues/133 + */ + + /* interrupt pending */ + uintptr_t mip = read_csr(mip); + + /* additional info and meaning depends on mcause */ + uintptr_t mtval = read_csr(mtval); + + /* trap vector */ + uintptr_t mtvec = read_csr(mtvec); + + /* temporary, sometimes might hold temporary value of a0 */ + uintptr_t mscratch = read_csr(mscratch); + + /* status contains many smaller fields: */ + uintptr_t mstatus = read_csr(mstatus); + + /* PC value when the exception was taken*/ + uintptr_t mmepc = read_csr(mepc); + + /* breakpoint */ + __asm__("ebreak"); +#else + _exit(1 + mcause); +#endif /* NDEBUG */ + } +} + +#ifdef __cplusplus +} +#endif + diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv_rv32_hal.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv_rv32_hal.h new file mode 100755 index 0000000..9ce9ef6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv_rv32_hal.h @@ -0,0 +1,773 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_hal.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware Abstraction Layer functions for Mi-V soft processors + * + */ + +/*=========================================================================*//** + @mainpage MIV_RV32 Hardware Abstraction Layer + + ============================================================================== + Introduction + ============================================================================== + This document describes the Hardware Abstraction Layer (HAL) for the MIV_RV32 + Soft IP Core. This release of the HAL corresponds to the Soft IP core MIV_RV32 + v3.1 release. It also supports earlier versions of the MIV_RV32 as well as the + legacy RV32 IP cores. + The preprocessor macros provided with the MIV_RV32 HAL are used to customize + it to target the Soft Processor IP version being used in your project. + + The term "MIV_RV32" represents following two cores: + - MIV_RV32 v3.0 and later (the latest and greatest Mi-V soft processor) + - MIV_RV32IMC v2.1 (MIV_RV32 v3.0 is a drop in replacement for this core) + It is highly recommended to migrate your design to MIV_RV32 v3.1 + + The term, Legacy RV32 IP cores, represents following IP cores: + - MIV_RV32IMA_L1_AHB + - MIV_RV32IMA_L1_AXI + - MIV_RV32IMAF_L1_AHB + + These legacy RV32 IP cores are deprecated. It is highly recommended to migrate + your designs to MIV_RV32 v3.1 (and subsequent IP releases) for the latest + enhancements, bug fixes, and support. + + -------------------------------- + MIV_RV32 V3.1 + -------------------------------- + This is the latest release of the MIV_RV32 Soft IP core. For more details, + refer to the MIV_RV32 User [Guide](https://www.microchip.com/en-us/products/fpgas-and-plds/ip-core-tools/miv-rv32) + + The MIV_RV32 Core as well as this document use the terms defined below: + + -------------------------------- + - SUBSYS - Processor Subsystem for RISC-V + - OPSRV - Offload Processor Subsystem for RISC-V + - GPR - General Purpose Registers + - MGECIE - Machine GPR ECC Correctable Interrupt Enable + - MGEUIE - Machine GPR ECC Uncorrectable Interrupt Enable + - MTIE - Machine Timer Interrupt Enable + - MEIE - Machine External Interrupt Enable + - MSIE - Machine Software Interrupt Enable + - ISR - Interrupt Service Routine + + ============================================================================== + Customizing MIV_RV32 HAL + ============================================================================== + To use the HAL with older releases of MIV_RV32, preprocessor macros have been + provided. Using these macros, any of the IP version is targeted. + The HAL is used to target any of the mentioned platforms by adding the + following macros in the way : + Project Properties > C/C++ Build > Settings > Preprocessor in Assembler and + Compiler settings. + The table below shows the macros corresponding to the MIV Core being used in + your libero project. By default, the HAL targets v3.1 of the IP core and no + macros need to be set for this configutation. + + | Libero MI-V Soft IP Version | SoftConsole Macro | + |-----------------------------|-------------------| + | MIV_RV32 v3.1 | no macro required | + | MIV_RV32 v3.0 | MIV_CORE_V3_0 | + | Legacy RV32 Cores | MIV_LEGACY_RV32 | + + -------------------------------- + Interrupt Handling + -------------------------------- + The MIE Register is defined as a enum in the HAL, and the table below is used + as a reference when the vectored interrupts are enabled in the GUI core + configurator. + + The MIE register is a RISC-V Control and Status Register (CSR), which stands + for the Machine Interrupt Enable. This is used to enable the machine mode + interrupts in the MIV_RV32 hart. Refer to the RISC-V Priv spec for more details. + + The following table shows the trap entry addresses when an interrupt occurs and + the vectored interrupts are enabled in the GUI configurator. + + | MIE Register Bit | Interrupt Enable | Vector Address | + |-------------------|------------------|----------------| + | 31 | MSYS_IE7 | mtvec.BASE + 0x7C | + | 30 | MSYS_IE6 | mtvec.BASE + 0x78 | + | 29 | MSYS_IE5 | mtvec.BASE + 0x74 | + | 28 | MSYS_IE4 | mtvec.BASE + 0x70 | + | 27 | MSYS_IE3 | mtvec.BASE + 0x6C | + | 26 | MSYS_IE2 | mtvec.BASE + 0x68 | + | 25 | MSYS_IE1 | mtvec.BASE + 0x64 | + | 24 | MSYS_IE0 | mtvec.BASE + 0x60 | + | 23 | SUBSYS_EI | mtvec.BASE + 0x5C | + | 22 | SUBSYSR | mtvec.BASE + 0x58 | + | 17 | MGECIE | mtvec.BASE + 0x44 | + | 16 | MGEUIE | mtvec.BASE + 0x40 | + | 11 | MEIE | mtvec.BASE + 0x2C | + | 7 | MTIE | mtvec.BASE + 0x1C | + | 3 | MSIE | mtvec.BASE + 0x0C | + + + For changes in MIE register map, see the [MIE Register Map for MIV_RV32 v3.0] + (#mie-register-map-for-miv_rv32-v3.0) section. + + SUBSYSR is currently not being used by the core and is Reserved for future use. + + The mtvec.BASE field corresponds to the bits [31:2], where mtvec stands for + Machine Trap Vector, and all traps set the PC to the the value stored in the + mtvec.BASE field when in Non-Vectored mode. In this case, a generic trap + handler is as an interrupt service routine. + + When Vectored interrupts are enabled, use this formula to calculate the trap + address: (mtvec.BASE + 4*cause), where cause comes from the mcause CSR. The + mcause register is written with a code indicating the event that caused the trap. + For more details, see the RISC-V priv specification. + + The MIV_RV32 Soft IP core does not contain a Platfrom Level Interrup Controller + (PLIC). It is advised to use the PLIC contained within the MIV_ESS sub-system. + Connect the PLIC interrupt output of the MIV_ESS to the EXT_IRQ pin on the + MIV_RV32. + + The following table is the MIE register map for the MIV_RV32 Core V3.0. It only + highlights the differences between the V3.0 and V3.1 of the core. + + -------------------------------- + MIE Register Map for MIV_RV32 V3.0 + -------------------------------- + + | MIE Register Bit | Target Interrupt | Vector Address | + |-------------------|------------------|----------------| + | 31 | Not in use | top table | + | 30 | SUBSYS_EI | addr + 0x78 | + | 23 | Not in use | Not in use | + | 22 | Not in use | Not in use | + + Other interrupt bit postions like the MGEUIE and MSYS_IE5 to MSYS_IE0 remain + unchanged. + + -------------------------------- + Floating Point Interrupt Support + -------------------------------- + When an interrupt is taken and Floating Point instructions are used in the + ISR, the floating point register context must be saved to resume the application + correctly. To use this feature, enable the provided macro in the + Softconsole build settings. + This feature is turned off by default as it adds overhead which is not required + when the ISR does not used FP insturctions and saving the general purpose + register context is sufficient. + + | Macro Name | Definition | + |--------------------------|-------------------------------------------------| + | MIV_FP_CONTEXT_SAVE | Define to save the FP register file | + + + -------------------------------- + SUBSYS - SubSystem for RISC-V + -------------------------------- + SUBSYS stands for SubSystem for RISC-V. This was previously (MIV_RV32 v3.0) + known as OPSRV, which stands for "Offload Processor Subsystem + for RISC-V". See the earlier versions of the handbook for more details. + In the latest release of the MIV_RV32 IP core v3.1, OPSRV has been renamed to + SUBSYS. The MIV_RV32 HAL now uses SUBSYS instead of OPSRV. + + *//*=========================================================================*/ +#ifndef RISCV_HAL_H +#define RISCV_HAL_H + +#include "miv_rv32_regs.h" +#include "miv_rv32_plic.h" +#include "miv_rv32_assert.h" +#include "miv_rv32_subsys.h" + +#ifndef LEGACY_DIR_STRUCTURE +#include "fpga_design_config/fpga_design_config.h" +#else +#include "hw_platform.h" +#endif /*LEGACY_DIR_STRUCTURE*/ + +#ifdef __cplusplus +extern "C" { +#endif +/*-------------------------------------------------------------------------*//** + SUBSYS Backwards Compatibility + ======================================= + For application code using the older macro names and API functions, these macros + act as a compatibility layer and applications which use OPSRV API features work + due to these macro definitions. However, it is adviced to update your + application code to use the SUBSYS macros and API functions. + + | Macro Name | Now Called | + |-------------------------|--------------------------| + | OPSRV_TCM_ECC_CE_IRQ | SUBSYS_TCM_ECC_CE_IRQ | + | OPSRV_TCM_ECC_UCE_IRQ | SUBSYS_TCM_ECC_UCE_IRQ | + | OPSRV_AXI_WR_RESP_IRQ | SUBSYS_AXI_WR_RESP_IRQ | + | MRV32_MSYS_OPSRV_IRQn | MRV32_SUBSYS_IRQn | + | MRV32_opsrv_enable_irq | MRV32_subsys_enable_irq | + | MRV32_opsrv_disable_irq | MRV32_subsys_disable_irq | + | MRV32_opsrv_clear_irq | MRV32_subsys_clear_irq | + | OPSRV_IRQHandler | SUBSYS_IRQHandler | + */ + +/*-------------------------------------------------------------------------*//** + MTIME Timer Interrupt Constants + ======================================= + These values contain the register addresses for the registers used by the + machine timer interrupt + + MTIME_PRESCALER is not defined on the MIV_RV32IMC v2.0 and v2.1. By using this + definition the system crashes. For those core, use the following definition: + + #define MTIME_PRESCALER 100u + + MTIME and MTIMECMP + -------------------------------- + MIV_RV32 core offers flexibility in terms of generating MTIME and MTIMECMP + registers internal to the core or using external time reference. There four + possible combinations: + + - Internal MTIME and Internal MTIME IRQ enabled Generate the MTIME and MTIMECMP + registers internally. (The only combination available on legacy RV32 cores) + + - Internal MTIME enabled and Internal MTIME IRQ disabled Generate the MTIME + internally and have a timer interrupt input to the core as external pin. In + this case, 1 pin port will be available on MIV_RV32 for timer interrupt. + + - When the internal MTIME is disabled, and the Internal MTIME IRQ is enabled, the + system generates the time value externally and generates the mtimecmp and + interrupt internally (for example, a multiprocessor system with a shared time + between all cores). In this case, a 64-bit port is available on the MIV_RV32 + core as input. + + - Internal MTIME and Internal MTIME IRQ disabled Generate both the time and + timer interrupts externally. In this case a 64 bit port will be available on + the MIV_RV32 core as input, and a 1 pin port will be available for timer + interrupt. + + To handle all these combinations in the firmware, the following constants must + be defined in accordance with the configuration that you have made on your + MIV_RV32 core design. + + MIV_RV32_EXT_TIMER + -------------------------------- + When defined, it means that the MTIME register is not available internal to + the core. In this case, a 64 bit port will be available on the MIV_RV32 core as + input. When this macro is not defined, it means that the MTIME register is + available internally to the core. + + MIV_RV32_EXT_TIMECMP + -------------------------------- + When defined, it means the MTIMECMP register is not available internally to + the core and the Timer interrupt input to the core comes as an external pin. + When this macro is not defined it means the that MTIMECMP register exists + internal to the core and that the timer interrupt is generated internally. + +NOTE: All these macros must not be defined if you are using a MIV_RV32 core. + */ + +#define OPSRV_TCM_ECC_CE_IRQ SUBSYS_TCM_ECC_CE_IRQ +#define OPSRV_TCM_ECC_UCE_IRQ SUBSYS_TCM_ECC_UCE_IRQ +#define OPSRV_AXI_WR_RESP_IRQ SUBSYS_AXI_WR_RESP_IRQ +#define MRV32_MSYS_OPSRV_IRQn MRV32_SUBSYS_IRQn +#define MRV32_opsrv_enable_irq MRV32_subsys_enable_irq +#define MRV32_opsrv_disable_irq MRV32_subsys_disable_irq +#define MRV32_opsrv_clear_irq MRV32_subsys_clear_irq +#define OPSRV_IRQHandler SUBSYS_IRQHandler + +/*-------------------------------------------------------------------------*//** + External IRQ + ======================================= + Return value from External IRQ handler. This is used to disable the + External Interrupt. + + | Macro Name | Value | Description| + |-------------------|--------|----------------| + | EXT_IRQ_KEEP_ENABLED | 0 | Keep external interrupts enabled | + | EXT_IRQ_DISABLE | 1 | Disable external interrupts | + */ +#define EXT_IRQ_KEEP_ENABLED 0U +#define EXT_IRQ_DISABLE 1U + +#define MTIME_DELTA 5 +#ifdef MIV_LEGACY_RV32 +#define MSIP (*(uint32_t*)0x44000000UL) +#define MTIMECMP (*(uint32_t*)0x44004000UL) +#define MTIMECMPH (*(uint32_t*)0x44004004UL) +#define MTIME (*(uint32_t*)0x4400BFF8UL) +#define MTIMEH (*(uint32_t*)0x4400BFFCUL) + +/* To maintain backward compatibility with FreeRTOS config code */ +#define PRCI_BASE 0x44000000UL +#else /* MIV_LEGACY_RV32 */ + +/* To maintain backward compatibility with FreeRTOS config code */ +#define PRCI_BASE 0x02000000UL + +#ifndef MIV_RV32_EXT_TIMECMP +#define MTIMECMP (*(volatile uint32_t*)0x02004000UL) +#define MTIMECMPH (*(volatile uint32_t*)0x02004004UL) +#else +#define MTIMECMP (0u) +#define MTIMECMPH (0u) +#endif + +#define MTIME_PRESCALER (*(volatile uint32_t*)0x02005000UL) + +#ifndef MIV_RV32_EXT_TIMER +#define MTIME (*(volatile uint32_t*)0x0200BFF8UL) +#define MTIMEH (*(volatile uint32_t*)0x0200BFFCUL) + +/***************************************************************************//** + MIMPID Register + The MIMPID register is a RISC-V Control and Status Register In the v3.0 of + MIV_RV32, the value of `MIMPID = 0x000540AD`. In the v3.1 of MIV_RV32, the + value if `MIMPID = 0xE5010301` corresponding to (E)mbedded (5)ystem(01) core + version (03).(01) this terminology will be followed in the subsequent releases + of the core read the csr value and store it in a varible which may be used to + check the MIV_RV32 core version during runtime. + + Future releases of the core will increment the 03 and 01 as major and minor + releases respectively and the register can be read at runtime to find the + Soft IP core version. + + | Core Version | Register | Value | Notes | + |----------------|------------|---------|---------| + | MIV_RV32 V3.1 | mimpid | 0xE5010301 | implimentation ID | + | MIV_RV32 V3.0 | mimpid | 0x000540AD | implimentation ID | + */ +#define MIMPID read_csr(mimpid) + +/*Used as a mask to read and write to mte mtvec.BASE address*/ +#define MTVEC_BASE_ADDR_MASK 0xFFFFFFFC + +#else +#define MTIME (0u) +#define MTIMEH (0u) +#endif /*MIV_RV32_EXT_TIMER*/ + +/*-------------------------------------------------------------------------*//** + RISC-V Specification Interrupts + ======================================= + These definitions are provided for easy identification of the interrupt + in the MIE/MIP registers. + Apart from the standard software, timer, and external interrupts, the names + of the additional interrupts correspond to the names as used in the MIV_RV32 + handbook. Please refer the MIV_RV32 handbook for more details. + + All the interrups, provided by the MIV_RV32 core, follow the interrupt priority + order and register description as mentioned in the RISC-V spec. + + | Macro Name | Value | Description| + |-------------------|--------|----------------| + | MRV32_SOFT_IRQn | MIE_3_IRQn | Software interrupt enable | + | MRV32_TIMER_IRQn | MIE_7_IRQn | Timer interrupt enable | + | MRV32_EXT_IRQn | MIE_11_IRQn | External interrupt enable | + + */ +#define MRV32_SOFT_IRQn MIE_3_IRQn +#define MRV32_TIMER_IRQn MIE_7_IRQn +#define MRV32_EXT_IRQn MIE_11_IRQn + +/***************************************************************************//** + Interrupt numbers: + This enum represents the interrupt enable bits in the MIE register. + */ +enum +{ + MIE_0_IRQn = (0x01u), + MIE_1_IRQn = (0x01u<<1u), + MIE_2_IRQn = (0x01u<<2u), + MIE_3_IRQn = (0x01u<<3u), /*MSIE 0xC*/ + MIE_4_IRQn = (0x01u<<4u), + MIE_5_IRQn = (0x01u<<5u), + MIE_6_IRQn = (0x01u<<6u), + MIE_7_IRQn = (0x01u<<7u), /*MTIE 0x1C*/ + MIE_8_IRQn = (0x01u<<8u), + MIE_9_IRQn = (0x01u<<9u), + MIE_10_IRQn = (0x01u<<10u), + MIE_11_IRQn = (0x01u<<11u), /*MEIE 0x2C*/ + MIE_12_IRQn = (0x01u<<12u), + MIE_13_IRQn = (0x01u<<13u), + MIE_14_IRQn = (0x01u<<14u), + MIE_15_IRQn = (0x01u<<15u), + MIE_16_IRQn = (0x01u<<16u), /*MGEUIE ECC Uncorrectable 0x40*/ + MIE_17_IRQn = (0x01u<<17u), /*MGECIE ECC Correctable 0x44*/ + MIE_18_IRQn = (0x01u<<18u), + MIE_19_IRQn = (0x01u<<19u), + MIE_20_IRQn = (0x01u<<20u), + MIE_21_IRQn = (0x01u<<21u), + MIE_22_IRQn = (0x01u<<22u), /*SUBSYSR 0x58 (R)eserved*/ + MIE_23_IRQn = (0x01u<<23u), /*SUBSYS_IE 0x5C for MIV_RV32 v3.1*/ + MIE_24_IRQn = (0x01u<<24u), /*MSYS_IE0 0x60*/ + MIE_25_IRQn = (0x01u<<25u), /*MSYS_IE1 0x64*/ + MIE_26_IRQn = (0x01u<<26u), /*MSYS_IE2 0x68*/ + MIE_27_IRQn = (0x01u<<27u), /*MSYS_IE3 0x6C*/ + MIE_28_IRQn = (0x01u<<28u), /*MSYS_IE4 0x70*/ + MIE_29_IRQn = (0x01u<<29u), /*MSYS_IE5 0x74*/ + MIE_30_IRQn = (0x01u<<30u), /*MSYS_IE6 0x78, read comment below*/ + MIE_31_IRQn = (0x01u<<31u) /*MSYS_IE7 0x7C*/ +} MRV_LOCAL_IRQn_Type; + +#define MRV32_MGEUIE_IRQn MIE_16_IRQn +#define MRV32_MGECIE_IRQn MIE_17_IRQn +#define MRV32_MSYS_EIE0_IRQn MIE_24_IRQn +#define MRV32_MSYS_EIE1_IRQn MIE_25_IRQn +#define MRV32_MSYS_EIE2_IRQn MIE_26_IRQn +#define MRV32_MSYS_EIE3_IRQn MIE_27_IRQn +#define MRV32_MSYS_EIE4_IRQn MIE_28_IRQn +#define MRV32_MSYS_EIE5_IRQn MIE_29_IRQn +#ifndef MIV_RV32_V3_0 /*For MIV_RV32 v3.1*/ +#define MRV32_SUBSYSR_IRQn MIE_22_IRQn +#define MRV32_SUBSYS_IRQn MIE_23_IRQn +#define MRV32_MSYS_EIE6_IRQn MIE_30_IRQn +#define MRV32_MSYS_EIE7_IRQn MIE_31_IRQn +#else +#define MRV32_SUBSYS_IRQn MIE_30_IRQn +#endif /*MIV_RV32_V3_0*/ + +/*--------------------------------Public APIs---------------------------------*/ + +/***************************************************************************//** + The MRV32_clear_gpr_ecc_errors() function clears single bit ECC errors on the + GPRs. The ECC block does not write back corrected data to memory. Hence, when + ECC is enabled for the GPRs and if that data has a single bit error then the + data coming out of the ECC block is corrected and will not have the error, but + the data source will still have the error. Therefore, if data has a single bit + error, then the corrected data must be written back to prevent the single bit + error from becoming a double bit error. Clear the pending interrupt bit after + this using MRV32_mgeci_clear_irq() function to complete the ECC error handling. + + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline void MRV32_clear_gpr_ecc_errors(void) +{ + uint32_t temp; + + __asm__ __volatile__ ( + "sw x31, %0" + :"=m" (temp)); + + __asm__ volatile ( + "mv x31, x1;" + "mv x1, x31;" + + "mv x31, x2;" + "mv x2, x31;" + + "mv x31, x3;" + "mv x3, x31;" + + "mv x31, x4;" + "mv x4, x31;" + + "mv x31, x5;" + "mv x5, x31;" + + "mv x31, x6;" + "mv x6, x31;" + + "mv x31, x7;" + "mv x7, x31;" + + "mv x31, x8;" + "mv x8, x31;" + + "mv x31, x9;" + "mv x9, x31;" + + "mv x31, x10;" + "mv x10, x31;" + + "mv x31, x11;" + "mv x11, x31;" + + "mv x31, x12;" + "mv x12, x31;" + + "mv x31, x13;" + "mv x13, x31;" + + "mv x31, x14;" + "mv x14, x31;" + + "mv x31, x15;" + "mv x15, x31;" + + "mv x31, x16;" + "mv x16, x31;" + + "mv x31, x17;" + "mv x17, x31;" + + "mv x31, x18;" + "mv x18, x31;" + + "mv x31, x19;" + "mv x19, x31;" + + "mv x31, x20;" + "mv x20, x31;" + + "mv x31, x21;" + "mv x21, x31;" + + "mv x31, x22;" + "mv x22, x31;" + + "mv x31, x23;" + "mv x23, x31;" + + "mv x31, x24;" + "mv x24, x31;" + + "mv x31, x25;" + "mv x25, x31;" + + "mv x31, x26;" + "mv x26, x31;" + + "mv x31, x27;" + "mv x27, x31;" + + "mv x31, x28;" + "mv x28, x31;" + + "mv x31, x29;" + "mv x29, x31;" + + "mv x31, x30;" + "mv x30, x31;"); + + __asm__ __volatile__ ( + "lw x31, %0;" + : + :"m" (temp)); +} + + +/***************************************************************************//** + The MRV32_mgeui_clear_irq() function clears the GPR ECC Uncorrectable + Interrupt. MGEUI interrupt is available only when ECC is enabled in the MIV_RV32 + IP configurator. + + @return + This function does not return any value. + */ +static inline void MRV32_mgeui_clear_irq(void) +{ + clear_csr(mip, MRV32_MGEUIE_IRQn); +} + +/***************************************************************************//** + The MRV32_mgeci_clear_irq() function clears the GPR ECC Correctable Interrupt + MGECI interrupt is available only when ECC is enabled in the MIV_RV32 IP + configurator. + + @return + This function does not return any value. + */ +static inline void MRV32_mgeci_clear_irq(void) +{ + clear_csr(mip, MRV32_MGECIE_IRQn); +} + +/***************************************************************************//** + The MRV_enable_local_irq() function enables the local interrupts. It takes a + mask value as input. For each set bit in the mask value, the corresponding + interrupt bit in the MIE register is enabled. + + MRV_enable_local_irq( MRV32_SOFT_IRQn | MRV32_TIMER_IRQn | MRV32_EXT_IRQn | + MRV32_MSYS_EIE0_IRQn | + MRV32_MSYS_SUBSYS_IRQn); + */ +static inline void MRV_enable_local_irq(uint32_t mask) +{ + set_csr(mie, mask); +} + +/***************************************************************************//** + The MRV_disable_local_irq() function disables the local interrupts. It takes a + mask value as input. For each set bit in the mask value, the corresponding + interrupt bit in the MIE register is disabled. + + MRV_disable_local_irq( MRV32_SOFT_IRQn | MRV32_TIMER_IRQn | MRV32_EXT_IRQn | + MRV32_MSYS_EIE0_IRQn | + MRV32_MSYS_SUBSYS_IRQn); + */ +static inline void MRV_disable_local_irq(uint32_t mask) +{ + clear_csr(mie, mask); +} +#endif /* MIV_LEGACY_RV32 */ + +/***************************************************************************//** + The MRV_enable_interrupts() function enables all interrupts by setting the + machine mode interrupt enable bit in MSTATUS register. + + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline void MRV_enable_interrupts(void) +{ + set_csr(mstatus, MSTATUS_MIE); +} + +/***************************************************************************//** + The MRV_disable_interrupts() function disables all interrupts by clearing the + machine mode interrupt enable bit in MSTATUS register. + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline void MRV_disable_interrupts(void) +{ + clear_csr(mstatus, MSTATUS_MPIE); + clear_csr(mstatus, MSTATUS_MIE); +} + +/***************************************************************************//** + The MRV_read_mtvec_base() function reads the mtvec base value, which is the + addr used when an interrupt/trap occurs. In the mtvec register, [31:2] is the + BASE address. NOTE: The BASE address must be aligned on a 4B boundary. + + @param + The function does not take any parameters. + + @return + The function returns the value of the BASE field [31:2] as an unsigned 32-bit + value. + */ + +#ifndef MIV_LEGACY_RV32 +#ifndef MIV_RV32_v3_0 +static inline uint32_t MRV_read_mtvec_base (void) +{ + uint32_t mtvec_addr_base = read_csr(mtvec); + return mtvec_addr_base & MTVEC_BASE_ADDR_MASK; +} + +/***************************************************************************//** + The MRV_set_mtvec_base() function takes the mtvec_base address as a unsigned int + and writes the value into the BASE field [31:2] in the mtvec CSR, MODE[1:0] + is Read-only. BASE is 4B aligned, so the lowest 2 bits of mtvec_base are + ignored. + + @param mtvec_base + Any legal value is passed into the function, and it is used as the trap_entry + for interrupts. The PC jumps to this address provided when an interrupt occurs. + In case of vectored interrupts, the address value mentioned in the vector + table under the MIE Register Map is updated to the value passed to this + function parameter. + + @return + This function does not return any value. + */ +static inline void MRV_set_mtvec_base (uint32_t mtvec_base) +{ + mtvec_base = mtvec_base & MTVEC_BASE_ADDR_MASK; + write_csr(mtvec, mtvec_base); +} +#endif /*MIV_RV32_v3_0*/ +#endif /*MIV_LEGACY_RV32*/ + +/***************************************************************************//** + The MRV_read_mtime() function returns the current MTIME register value. + */ +static inline uint64_t MRV_read_mtime(void) +{ + volatile uint32_t hi = 0u; + volatile uint32_t lo = 0u; + + /* when mtime lower word is 0xFFFFFFFF, there will be rollover and + * returned value could be wrong. */ + do { + hi = MTIMEH; + lo = MTIME; + } while(hi != MTIMEH); + + return((((uint64_t)MTIMEH) << 32u) | lo); +} + +/***************************************************************************//** + The MRV_raise_soft_irq() function raises a synchronous software interrupt + by writing into the MSIP register. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV_raise_soft_irq(void) +{ + set_csr(mie, MIP_MSIP); /* Enable software interrupt bit */ + +#ifdef MIV_LEGACY_RV32 + /* You need to make sure that the global interrupt is enabled */ + MSIP = 0x01; /* raise soft interrupt */ +#else + /* Raise soft IRQ on MIV_RV32 processor */ + SUBSYS->soft_reg |= SUBSYS_SOFT_IRQ; +#endif +} + +/***************************************************************************//** + The MRV_clear_soft_irq() function clears a synchronous software interrupt + by clearing the MSIP register. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV_clear_soft_irq(void) +{ +#ifdef MIV_LEGACY_RV32 + MSIP = 0x00u; /* clear soft interrupt */ +#else + /* Clear soft IRQ on MIV_RV32 processor */ + SUBSYS->soft_reg &= ~SUBSYS_SOFT_IRQ; +#endif +} + +/***************************************************************************//** + System tick handler. This handler function gets called when the Machine + timer interrupt asserts. An implementation of this function must be provided + by the application to implement the application specific machine timer + interrupt handling. If application does not provide such implementation, the + weakly linked handler stub function implemented in riscv_hal_stubs.c gets + linked. + */ +void SysTick_Handler(void); + +/***************************************************************************//** + System timer tick configuration. + Configures the machine timer to generate a system tick interrupt at regular + intervals. Takes the number of system clock ticks between interrupts. + + Though this function can take any valid ticks value as parameter, we expect + that, for all practical purposes, a small tick value (to generate periodic + interrupts every few miliseconds) is passed. If you need to generate periodic + events in the range of seconds or more, you may use the SysTick_Handler() to + further count the number of interrupts and hence the larger time intervals. + + @param ticks + This is the number of ticks or clock cycles which are counted down from the + interrupt to be triggered. + + @return + Returns 0 if successful. + Returns 1 if the interrupt interval is not achieved. + */ +uint32_t MRV_systick_config(uint64_t ticks); + +#ifdef __cplusplus +} +#endif +#endif /* RISCV_HAL_H */ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv_rv32_hal_version.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv_rv32_hal_version.h new file mode 100644 index 0000000..4922bf2 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv_rv32_hal_version.h @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_hal_version.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware Abstraction Layer functions for Mi-V soft processors + * + */ + +#ifndef MIV_RV32_HAL_VERSION_H +#define MIV_RV32_HAL_VERSION_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MIV_RV32_HAL_VERSION_MAJOR 4 +#define MIV_RV32_HAL_VERSION_MINOR 2 +#define MIV_RV32_HAL_VERSION_PATCH 100 + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv_rv32_init.c b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv_rv32_init.c new file mode 100755 index 0000000..85f8aca --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv_rv32_init.c @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_init.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor memory section initializations and start-up code. + * + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern void main(void); + +void _init(void) +{ + /* This function is a placeholder for the case where some more hardware + * specific initializations are required before jumping into the application + * code. You can implement it here. */ + + /* Jump to the application code after all initializations are completed */ + main(); +} + +/* Function called after main() finishes */ +void +_fini(void) +{ +} + +#ifdef __cplusplus +} +#endif + diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv_rv32_plic.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv_rv32_plic.h new file mode 100755 index 0000000..3fd4103 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv_rv32_plic.h @@ -0,0 +1,214 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_plic.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V legacy RV32 soft processor PLIC access data structures and + * functions. + * Legacy RV32 soft processors are DEPRICATED. + * Migrate to MIV_RV32 v3.0 or later. + * + */ +#ifndef RISCV_PLIC_H +#define RISCV_PLIC_H + +#include +#include "miv_rv32_regs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================== + * Interrupt numbers: + */ +#ifdef MIV_LEGACY_RV32 +typedef enum +{ + MRV_NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + External_3_IRQn = 3, + External_4_IRQn = 4, + External_5_IRQn = 5, + External_6_IRQn = 6, + External_7_IRQn = 7, + External_8_IRQn = 8, + External_9_IRQn = 9, + External_10_IRQn = 10, + External_11_IRQn = 11, + External_12_IRQn = 12, + External_13_IRQn = 13, + External_14_IRQn = 14, + External_15_IRQn = 15, + External_16_IRQn = 16, + External_17_IRQn = 17, + External_18_IRQn = 18, + External_19_IRQn = 19, + External_20_IRQn = 20, + External_21_IRQn = 21, + External_22_IRQn = 22, + External_23_IRQn = 23, + External_24_IRQn = 24, + External_25_IRQn = 25, + External_26_IRQn = 26, + External_27_IRQn = 27, + External_28_IRQn = 28, + External_29_IRQn = 29, + External_30_IRQn = 30, + External_31_IRQn = 31 +} IRQn_Type; + +#define EXT_INTR_SOURCES 31 + +/*============================================================================== + * PLIC: Platform Level Interrupt Controller + */ +#define PLIC_BASE_ADDR 0x40000000UL + +typedef struct +{ + volatile uint32_t PRIORITY_THRESHOLD; + volatile uint32_t CLAIM_COMPLETE; + volatile uint32_t reserved[1022]; +} MRV_IRQ_Target_Type; + +typedef struct +{ + volatile uint32_t ENABLES[32]; +} MRV_Target_Enables_Type; + +typedef struct +{ + /*-------------------- Source Priority --------------------*/ + volatile uint32_t SOURCE_PRIORITY[1024]; + + /*-------------------- Pending array --------------------*/ + volatile const uint32_t PENDING_ARRAY[32]; + volatile uint32_t RESERVED1[992]; + + /*-------------------- Target enables --------------------*/ + volatile MRV_Target_Enables_Type TARGET_ENABLES[15808]; + + volatile uint32_t RESERVED2[16384]; + + /*--- Target Priority threshold and claim/complete---------*/ + MRV_IRQ_Target_Type TARGET[15872]; + +} PLIC_Type; + +#define PLIC ((PLIC_Type *)PLIC_BASE_ADDR) + +/*============================================================================== + * The function MRV_PLIC_init() initializes the PLIC controller and enables + * the global external interrupt bit. + */ +static inline void MRV_PLIC_init(void) +{ + uint32_t inc; + unsigned long hart_id = read_csr(mhartid); + + /* Disable all interrupts for the current hart. */ + for(inc = 0; inc < ((EXT_INTR_SOURCES + 32u) / 32u); ++inc) + { + PLIC->TARGET_ENABLES[hart_id].ENABLES[inc] = 0; + } + + /* Set priorities to zero. */ + for(inc = 0; inc < EXT_INTR_SOURCES; ++inc) + { + PLIC->SOURCE_PRIORITY[inc] = 0; + } + + /* Set the threshold to zero. */ + PLIC->TARGET[hart_id].PRIORITY_THRESHOLD = 0; + + /* Enable machine external interrupts. */ + set_csr(mie, MIP_MEIP); +} + +/*============================================================================== + * The function MRV_PLIC_enable_irq() enables the external interrupt for the + * interrupt number indicated by the parameter IRQn. + */ +static inline void MRV_PLIC_enable_irq(IRQn_Type IRQn) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t current = PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32]; + current |= (uint32_t)1 << (IRQn % 32); + PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32] = current; +} + +/*============================================================================== + * The function MRV_PLIC_disable_irq() disables the external interrupt for + * the interrupt number indicated by the parameter IRQn. + + * NOTE: + * This function can be used to disable the external interrupt from outside + * external interrupt handler function. + * This function MUST NOT be used from within the External Interrupt handler. + * If you wish to disable the external interrupt while the interrupt handler + * for that external interrupt is executing then you must use the return value + * EXT_IRQ_DISABLE to return from the extern interrupt handler. + */ +static inline void MRV_PLIC_disable_irq(IRQn_Type IRQn) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t current = PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32]; + + current &= ~((uint32_t)1 << (IRQn % 32)); + + PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32] = current; +} + +/*============================================================================== + * The function MRV_PLIC_set_priority() sets the priority for the external + * interrupt for the interrupt number indicated by the parameter IRQn. + */ +static inline void MRV_PLIC_set_priority(IRQn_Type IRQn, uint32_t priority) +{ + PLIC->SOURCE_PRIORITY[IRQn] = priority; +} + +/*============================================================================== + * The function MRV_PLIC_get_priority() returns the priority for the external + * interrupt for the interrupt number indicated by the parameter IRQn. + */ +static inline uint32_t MRV_PLIC_get_priority(IRQn_Type IRQn) +{ + return PLIC->SOURCE_PRIORITY[IRQn]; +} + +/***************************************************************************//** + * MRV_PLIC_clear_pending_irq(void) + * This is only called by the startup hart and only once + * Clears any pending interrupts as PLIC can be in unknown state on startup + */ +static inline void MRV_PLIC_clear_pending_irq(void) +{ + unsigned long hart_id = read_csr(mhartid); + volatile uint32_t int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; + volatile int32_t wait_possible_int; + + while (MRV_NoInterrupt_IRQn != int_num) + { + PLIC->TARGET[hart_id].CLAIM_COMPLETE = int_num; + wait_possible_int = 0xFU; + while (wait_possible_int) + { + wait_possible_int--; + } + + int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; + } +} + +#endif /* MIV_LEGACY_RV32 */ + +#ifdef __cplusplus +} +#endif + +#endif /* RISCV_PLIC_H */ diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv_rv32_regs.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv_rv32_regs.h new file mode 100755 index 0000000..07d58e7 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv_rv32_regs.h @@ -0,0 +1,520 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor register bit mask and shift constants encodings. + * + */ +#ifndef MIV_RV32_REGS_H +#define MIV_RV32_REGS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MSTATUS_UIE 0x00000001UL +#define MSTATUS_SIE 0x00000002UL +#define MSTATUS_HIE 0x00000004UL +#define MSTATUS_MIE 0x00000008UL +#define MSTATUS_UPIE 0x00000010UL +#define MSTATUS_SPIE 0x00000020UL +#define MSTATUS_HPIE 0x00000040UL +#define MSTATUS_MPIE 0x00000080UL +#define MSTATUS_SPP 0x00000100UL +#define MSTATUS_HPP 0x00000600UL +#define MSTATUS_MPP 0x00001800UL +#define MSTATUS_FS 0x00006000UL +#define MSTATUS_XS 0x00018000UL +#define MSTATUS_MPRV 0x00020000UL +#define MSTATUS_SUM 0x00040000UL +#define MSTATUS_MXR 0x00080000UL +#define MSTATUS_TVM 0x00100000UL +#define MSTATUS_TW 0x00200000UL +#define MSTATUS_TSR 0x00400000UL +#define MSTATUS_RES 0x7F800000UL +#define MSTATUS32_SD 0x80000000UL +#define MSTATUS64_SD 0x8000000000000000UL + +#define MCAUSE32_CAUSE 0x7FFFFFFFUL +#define MCAUSE64_CAUSE 0x7FFFFFFFFFFFFFFFUL +#define MCAUSE32_INT 0x80000000UL +#define MCAUSE64_INT 0x8000000000000000UL + +#define MIP_SSIP (1u << IRQ_S_SOFT) +#define MIP_HSIP (1u << IRQ_H_SOFT) +#define MIP_MSIP (1u << IRQ_M_SOFT) +#define MIP_STIP (1u << IRQ_S_TIMER) +#define MIP_HTIP (1u << IRQ_H_TIMER) +#define MIP_MTIP (1u << IRQ_M_TIMER) +#define MIP_SEIP (1u << IRQ_S_EXT) +#define MIP_HEIP (1u << IRQ_H_EXT) +#define MIP_MEIP (1u << IRQ_M_EXT) + +#define PRV_M 3U + +#define VM_MBARE 0U +#define VM_MBB 1U +#define VM_MBBID 2U +#define VM_SV32 8U +#define VM_SV39 9U +#define VM_SV48 10U + +#define IRQ_S_SOFT 1U +#define IRQ_H_SOFT 2U +#define IRQ_M_SOFT 3U +#define IRQ_S_TIMER 5U +#define IRQ_H_TIMER 6U +#define IRQ_M_TIMER 7U +#define IRQ_S_EXT 9U +#define IRQ_H_EXT 10U +#define IRQ_M_EXT 11U + +#define DEFAULT_RSTVEC 0x00001000 +#define DEFAULT_NMIVEC 0x00001004 +#define DEFAULT_MTVEC 0x00001010 +#define CONFIG_STRING_ADDR 0x0000100C +#define EXT_IO_BASE 0x40000000 +#define DRAM_BASE 0x80000000 + +#ifdef __riscv + +#if __riscv_xlen == 64 +# define MSTATUS_SD MSTATUS64_SD +# define SSTATUS_SD SSTATUS64_SD +# define MCAUSE_INT MCAUSE64_INT +# define MCAUSE_CAUSE MCAUSE64_CAUSE +# define RISCV_PGLEVEL_BITS 9 +#else +# define MSTATUS_SD MSTATUS32_SD +# define SSTATUS_SD SSTATUS32_SD +# define RISCV_PGLEVEL_BITS 10 +# define MCAUSE_INT MCAUSE32_INT +# define MCAUSE_CAUSE MCAUSE32_CAUSE +#endif + +#define RISCV_PGSHIFT 12U +#define RISCV_PGSIZE (1U << RISCV_PGSHIFT) + +#ifndef __ASSEMBLER__ + +#ifdef __GNUC__ + +#define read_csr(reg) ({ unsigned long __tmp; \ + __asm__ volatile ("csrr %0, " #reg : "=r"(__tmp)); \ + __tmp; }) + +#define write_csr(reg, val) ({ \ + __asm__ volatile ("csrw " #reg ", %0" :: "rK"(val)); }) + +#define swap_csr(reg, val) ({ unsigned long __tmp; \ + __asm__ volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "rK"(val)); \ + __tmp; }) + +#define set_csr(reg, bit) ({ unsigned long __tmp; \ + __asm__ volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ + __tmp; }) + +#define clear_csr(reg, bit) ({ unsigned long __tmp; \ + __asm__ volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ + __tmp; }) + +#ifdef __riscv_atomic + +#define MASK(nr) (1UL << nr) +#define MASK_NOT(nr) (~(1UL << nr)) + +/** + * atomic_read - read atomic variable + * @v: pointer of type int + * + * Atomically reads the value of @v. + */ +static inline int atomic_read(const int *v) +{ + return *((volatile int *)(v)); +} + +/** + * atomic_set - set atomic variable + * @v: pointer of type int + * @i: required value + * + * Atomically sets the value of @v to @i. + */ +static inline void atomic_set(int *v, int i) +{ + *v = i; +} + +/** + * atomic_add - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v. + */ +static inline void atomic_add(int i, int *v) +{ + __asm__ __volatile__ ( + "amoadd.w zero, %1, %0" + : "+A" (*v) + : "r" (i)); +} + +static inline int atomic_fetch_add(unsigned int mask, int *v) +{ + int out; + + __asm__ __volatile__ ( + "amoadd.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_sub - subtract integer from atomic variable + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v. + */ +static inline void atomic_sub(int i, int *v) +{ + atomic_add(-i, v); +} + +static inline int atomic_fetch_sub(unsigned int mask, int *v) +{ + int out; + + __asm__ __volatile__ ( + "amosub.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_add_return - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v and returns the result + */ +static inline int atomic_add_return(int i, int *v) +{ + register int c; + __asm__ __volatile__ ( + "amoadd.w %0, %2, %1" + : "=r" (c), "+A" (*v) + : "r" (i)); + return (c + i); +} + +/** + * atomic_sub_return - subtract integer from atomic variable + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v and returns the result + */ +static inline int atomic_sub_return(int i, int *v) +{ + return atomic_add_return(-i, v); +} + +/** + * atomic_inc - increment atomic variable + * @v: pointer of type int + * + * Atomically increments @v by 1. + */ +static inline void atomic_inc(int *v) +{ + atomic_add(1, v); +} + +/** + * atomic_dec - decrement atomic variable + * @v: pointer of type int + * + * Atomically decrements @v by 1. + */ +static inline void atomic_dec(int *v) +{ + atomic_add(-1, v); +} + +static inline int atomic_inc_return(int *v) +{ + return atomic_add_return(1, v); +} + +static inline int atomic_dec_return(int *v) +{ + return atomic_sub_return(1, v); +} + +/** + * atomic_sub_and_test - subtract value from variable and test result + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v and returns + * true if the result is zero, or false for all + * other cases. + */ +static inline int atomic_sub_and_test(int i, int *v) +{ + return (atomic_sub_return(i, v) == 0); +} + +/** + * atomic_inc_and_test - increment and test + * @v: pointer of type int + * + * Atomically increments @v by 1 + * and returns true if the result is zero, or false for all + * other cases. + */ +static inline int atomic_inc_and_test(int *v) +{ + return (atomic_inc_return(v) == 0); +} + +/** + * atomic_dec_and_test - decrement and test + * @v: pointer of type int + * + * Atomically decrements @v by 1 and + * returns true if the result is 0, or false for all other + * cases. + */ +static inline int atomic_dec_and_test(int *v) +{ + return (atomic_dec_return(v) == 0); +} + +/** + * atomic_add_negative - add and test if negative + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v and returns true + * if the result is negative, or false when + * result is greater than or equal to zero. + */ +static inline int atomic_add_negative(int i, int *v) +{ + return (atomic_add_return(i, v) < 0); +} + +static inline int atomic_xchg(int *v, int n) +{ + register int c; + __asm__ __volatile__ ( + "amoswap.w %0, %2, %1" + : "=r" (c), "+A" (*v) + : "r" (n)); + return c; +} + +/** + * atomic_and - Atomically clear bits in atomic variable + * @mask: Mask of the bits to be retained + * @v: pointer of type int + * + * Atomically retains the bits set in @mask from @v + */ +static inline void atomic_and(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoand.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_and(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoand.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_or - Atomically set bits in atomic variable + * @mask: Mask of the bits to be set + * @v: pointer of type int + * + * Atomically sets the bits set in @mask in @v + */ +static inline void atomic_or(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoor.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_or(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoor.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_xor - Atomically flips bits in atomic variable + * @mask: Mask of the bits to be flipped + * @v: pointer of type int + * + * Atomically flips the bits set in @mask in @v + */ +static inline void atomic_xor(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoxor.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_xor(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoxor.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * test_and_set_bit - Set a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_set_bit(int nr, volatile unsigned long *addr) +{ + unsigned long __res, __mask; + __mask = MASK(nr); + __asm__ __volatile__ ( \ + "amoor.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to clear + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_clear_bit(int nr, volatile unsigned long *addr) +{ + unsigned long __res, __mask; + __mask = MASK_NOT(nr); + __asm__ __volatile__ ( \ + "amoand.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * test_and_change_bit - Change a bit and return its old value + * @nr: Bit to change + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_change_bit(int nr, volatile unsigned long *addr) +{ + + unsigned long __res, __mask; + __mask = MASK(nr); + __asm__ __volatile__ ( \ + "amoxor.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * set_bit - Atomically set a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * This function is atomic and may not be reordered. + */ + +static inline void set_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOOR.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK(nr))); +} + +/** + * clear_bit - Clears a bit in memory + * @nr: Bit to clear + * @addr: Address to start counting from + * + * clear_bit() is atomic and may not be reordered. + */ +static inline void clear_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOAND.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK_NOT(nr))); +} + +/** + * change_bit - Toggle a bit in memory + * @nr: Bit to change + * @addr: Address to start counting from + * + * change_bit() is atomic and may not be reordered. + */ +static inline void change_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOXOR.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK(nr))); +} + +#endif /* __riscv_atomic */ + +#endif /* __GNUC__ */ + +#endif /* __ASSEMBLER__ */ + +#endif /* __riscv */ + +#ifdef __cplusplus +} +#endif + +#endif /* RISCV_REGS_H */ diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv_rv32_stubs.c b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv_rv32_stubs.c new file mode 100755 index 0000000..e26ecfc --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv_rv32_stubs.c @@ -0,0 +1,243 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_stubs.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Stubs for the Mi-V soft processor Interrupt handler. + * + * The functions below will only be linked with the application code if the user + * does not provide an implementation for these functions. These functions are + * defined with weak linking so that they can be overridden by a function with + * same prototype in the user's application code. + * + */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +__attribute__((weak)) void Software_IRQHandler(void) +{ + _exit(10); +} + +__attribute__((weak)) void SysTick_Handler(void) +{ + /* Default handler */ +} + +#ifdef MIV_LEGACY_RV32 +__attribute__((weak)) uint8_t Invalid_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_1_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_2_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_3_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_4_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_5_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_6_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_7_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_8_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_9_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_10_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_11_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_12_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_13_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_14_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_15_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_16_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_17_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_18_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_19_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_20_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_21_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_22_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_23_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_24_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_25_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_26_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_27_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_28_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_29_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_30_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_31_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +#else +__attribute__((weak)) void External_IRQHandler(void) +{ +} +__attribute__((weak)) void MGECI_IRQHandler(void) +{ +} +__attribute__((weak)) void MGEUI_IRQHandler(void) +{ +} +__attribute__((weak)) void SUBSYS_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI0_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI1_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI2_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI3_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI4_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI5_IRQHandler(void) +{ +} +__attribute__((weak)) void Reserved_IRQHandler(void) +{ + _exit(10); +} +#ifndef MIV_RV32_V3_0 /* For MIV_RV32 v3.0 */ +__attribute__((weak)) void MSYS_EI6_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI7_IRQHandler(void) +{ +} +__attribute__((weak)) void SUBSYSR_IRQHandler(void) +{ +} +#endif /* MIV_RV32_V3_0 */ +#endif /* MIV_LEGACY_RV32 */ + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv_rv32_subsys.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv_rv32_subsys.h new file mode 100644 index 0000000..509f13b --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv_rv32_subsys.h @@ -0,0 +1,293 @@ +/******************************************************************************* + * Copyright 2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_subsys.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor SUBSYS regsiter description and API fuctions. + * + */ +#ifndef MIV_RV32_SUBSYS_H +#define MIV_RV32_SUBSYS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef MIV_LEGACY_RV32 +#define MGEUI 16U +#define MGECI 17U +#define MSYS_EI0 24U +#define MSYS_EI1 25U +#define MSYS_EI2 26U +#define MSYS_EI3 27U +#define MSYS_EI4 28U +#define MSYS_EI5 29U + +#define MGEUI_MEIP (1u << MGEUI) +#define MGECI_MEIP (1u << MGECI) +#define MSYS_EI0IP (1u << MSYS_EI0) +#define MSYS_EI1IP (1u << MSYS_EI1) +#define MSYS_EI2IP (1u << MSYS_EI2) +#define MSYS_EI3IP (1u << MSYS_EI3) +#define MSYS_EI4IP (1u << MSYS_EI4) +#define MSYS_EI5IP (1u << MSYS_EI5) + +#define MIV_LOCAL_IRQ_MIN 16 +#ifndef MIV_RV32_V3_0 /*For MIV_RV32 v3.1*/ +#define SUBSYSR 22U +#define SUBSYS_EI 23U +#define MSYS_EI6 30U +#define MSYS_EI7 31U +#define MIV_SUBSYSR (1u << SUBSYSR) +#define MIV_SUBSYS (1u << SUBSYS_EI) +#define MSYS_EI6IP (1u << MSYS_EI6) +#define MSYS_EI7IP (1u << MSYS_EI7) +#define MIV_LOCAL_IRQ_MAX 31 + +#else /* MIV_RV32_V3_0 */ +#define MIV_LOCAL_IRQ_MAX 29 +#define SUBSYS_EI 30U +#define MIP_SUBSYS_REG (1u << SUBSYS_EI) + +#endif /* MIV_RV32_V3_0 */ +#endif /* MIV_LEGACY_RV32 */ + +#ifdef MIV_LEGACY_RV32 +#define MIV_LOCAL_IRQ_MAX 0U +#define MIV_LOCAL_IRQ_MIN 0U +#endif /* MIV_LEGACY_RV32 */ + +#ifdef __cplusplus +} +#endif + +/*-------------------------------------------------------------------------*//** + SUBSYS Register Configuration + ======================================= + For the SUBSYS registers configutation, the following definitions are used in + the SUBSUS API functions. For example, to raise soft interrupts, enable parity + checks, soft reset, and so on. + + | Configuration | Value | Description | + |--------------------------|-------|------------------------------------------------| + | SUBSYS_SOFT_REG_GRP_DED | 0x04 | Mask for the Core GPR DED Reset Register | + | SUBSYS_CFG_PARITY_CHECK | 0x01 | Use to set or clear the parity check on the TCM | + | SUBSYS_SOFT_RESET | 0x01 | Use the SUBSYS soft reset the MIV_RV32 IP core | + | SUBSYS_SOFT_IRQ | 0x02 | Use to raise a software interrupt through SUBSYS| + */ +/*Mask for the Core GPR DED Reset Register*/ +#define SUBSYS_SOFT_REG_GRP_DED 0x04U + +/*Use to set or clear the parity check on the TCM*/ +#define SUBSYS_CFG_PARITY_CHECK 0x01U + +/*Use the SUBSYS soft reset the MIV_RV32 IP core*/ +#define SUBSYS_SOFT_RESET 0x01U + +/*Use to raise a software interrupt through SUBSYS*/ +#define SUBSYS_SOFT_IRQ 0x02U + +/*-------------------------------------------------------------------------*//** + SUBSYS Interrupt Request Masks + ======================================= + The following values correspond to the bit value of the SUBSYS interrupt + enable and interrupt pending register. + + | Interrupt Mask | Value | Description | + |----------------------------|---------|-------------------------------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | TCM ECC controllable error irq enable | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | TCM ECC uncontrollable error irq enable | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | AXI write response error irq enable | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | Icache ECC Correctable error irq | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | Icache ECC Uncorrectable error irq | + | SUBSYS_BASE_ADDR | 0x6000u | Base address of the SUBSYS | + */ +/* TCM ECC correctable error irq enable mask value */ +#define SUBSYS_TCM_ECC_CE_IRQ 0x01u + +/* TCMECC uncorrectable error irq enable */ +#define SUBSYS_TCM_ECC_UCE_IRQ 0x02u + +/* AXI write response error irq enable */ +#define SUBSYS_AXI_WR_RESP_IRQ 0x10u + +/*Icache ECC Correctable error irq*/ +#define SUBSYS_ICACHE_ECC_CE_IRQ 0x40u + +/*Icache ECC Uncorrectable error irq*/ +#define SUBSYS_ICACHE_ECC_UCE_IRQ 0x80u + +/*Base address of the SUBSYS*/ +#define SUBSYS_BASE_ADDR 0x00006000UL + +/***************************************************************************//** + Subsys contains interrupt enable, interrupt pending and Subsys registers + which can be used to enable SUBSYS specific features such as ECC for vaious + memories. For more available features refer to the MIV_RV32 User Guide +*/ +typedef struct +{ + volatile uint32_t cfg; /*Parity is not supported by MIV_RV32 v3.1 and MIV_RV32 v3.0.100*/ + volatile uint32_t reserved0[3]; + volatile uint32_t irq_en; /*offset 0x10*/ + volatile uint32_t irq_pend; + volatile uint32_t reserved1[2]; + volatile uint32_t soft_reg; /*offset 0x20*/ +} SUBSYS_Type; + +#define SUBSYS ((SUBSYS_Type *)SUBSYS_BASE_ADDR) + +/***************************************************************************//** + The MRV32_subsys_enable_irq() function initializes the SUBSYS interrupts. It + takes the logical OR of the following defined IRQ masks as a parameter. + + @param irq_mask + | irq_mask | Value | + |------------------------|------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | + Use logical OR values of one or more interrupts to enable them in the SUBSYS + @return + This function does not return any value. + */ +static inline void MRV32_subsys_enable_irq(uint32_t irq_mask) +{ + SUBSYS->irq_en |= irq_mask; +} + +/***************************************************************************//** + The MRV32_subsys_disable_irq() function disables the SUBSYS interrupts. It + takes the logical OR of the following defined IRQ masks as a parameter. + + @param irq_mask + | irq_mask | Value | + |------------------------|------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | + Use logical OR values of one or more interrupts to disable them in the SUBSYS + @return + This function does not return any value. + */ +static inline void MRV32_subsys_disable_irq(uint32_t irq_mask) +{ + SUBSYS->irq_en &= ~irq_mask; +} + +/***************************************************************************//** + The MRV32_subsys_clear_irq() function clears the SUBSYS interrupts, which was + triggered. It takes the logical OR of the following defined IRQ masks as a + parameter. + @param irq_mask + | irq_mask | Value | + |------------------------|------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | + Use logical OR values of one or more interrupts to disable them in the SUBSYS + @return + This function does not return any value. + */ +static inline void MRV32_subsys_clear_irq(uint32_t irq_mask) +{ + SUBSYS->irq_pend |= irq_mask; +} + +/***************************************************************************//** + The MRV32_subsys_irq_cause() function returns the irq_pend register value which + is present in the SUBSYS. This is be used to check which irq_mask value + caused the SUBSYS interrupt to occur. + @param + This function does not take any parameters + + @return + This function returns the irq_pend regsiter value. +*/ +static inline uint32_t MRV32_subsys_irq_cause() +{ + return SUBSYS->irq_pend; +} + +/***************************************************************************//** + The MRV32_is_gpr_ded() function returns the core_gpr_ded_reset_reg bit value. + When ECC is enabled, the core_gpr_ded_reset_reg is set when the core was + reset due to GPR DED error. + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline uint32_t MRV32_is_gpr_ded(void) +{ + return((SUBSYS->soft_reg & SUBSYS_SOFT_REG_GRP_DED) >> 0x02u); +} + +/***************************************************************************//** + The MRV32_clear_gpr_ded() function must be used to clear the + core_gpr_ded_reset_reg bit. When ECC is enabled, the core_gpr_ded_reset_reg is + set when the core was previously reset due to GPR DED error. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV32_clear_gpr_ded(void) +{ + SUBSYS->soft_reg &= ~SUBSYS_SOFT_REG_GRP_DED; +} + +/***************************************************************************//** + The MRV32_enable_parity_check() function is used to enable parity check on + the TCM and it's interface transactions. This feature is not available on + MIV_RV32 v3.1 and MIV_RV32 v3.0.100 + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV32_enable_parity_check(void) +{ + SUBSYS->cfg |= SUBSYS_CFG_PARITY_CHECK; +} + +/***************************************************************************//** + The MRV32_disable_parity_check() function is used to disable parity check on + the TCM and it's interface transactions. + @param + This function does not take any parameters + + @return + This function does not return any value. + + */ +static inline void MRV32_disable_parity_check(void) +{ + SUBSYS->cfg &= ~SUBSYS_CFG_PARITY_CHECK; +} + +/***************************************************************************//** + The MRV32_cpu_soft_reset() function is used to cause a soft cpu reset on + the MIV_RV32 soft processor core. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV32_cpu_soft_reset(void) +{ + SUBSYS->soft_reg |= SUBSYS_SOFT_RESET; +} +#endif /* MIV_RV32_SUBSYS_H */ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv_rv32_syscall.c b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv_rv32_syscall.c new file mode 100755 index 0000000..bd2f881 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/miv_rv32_syscall.c @@ -0,0 +1,364 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_syscall.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Stubs for system calls. + * + */ +#include +#include +#include +#include +#include "miv_rv32_hal.h" + +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +#include + +#ifndef LEGACY_DIR_STRUCTURE +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" +#else +#include "core_uart_apb.h" +#endif + +#endif /*MSCC_STDIO_THRU_CORE_UART_APB*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + +/*------------------------------------------------------------------------------ + * CoreUARTapb instance data for the CoreUARTapb instance used for standard + * output. + */ +static UART_instance_t g_stdio_uart; + +/*============================================================================== + * Flag used to indicate if the UART driver needs to be initialized. + */ +static int g_stdio_uart_init_done = 0; + +/* + * Disable semihosting apis + */ +#pragma import(__use_no_semihosting_swi) + +/*============================================================================== + * sendchar() + */ +int sendchar(int ch) +{ + /*-------------------------------------------------------------------------- + * Initialize the UART driver if it is the first time this function is + * called. + */ + if ( !g_stdio_uart_init_done ) + { + /****************************************************************************** + * Baud value: + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + UART_init( &g_stdio_uart, + MSCC_STDIO_UART_BASE_ADDR, + ((SYS_CLK_FREQ/(16 * MSCC_STDIO_BAUD_VALUE))-1), + (DATA_8_BITS | NO_PARITY)); + + g_stdio_uart_init_done = 1; + } + + /*-------------------------------------------------------------------------- + * Output text to the UART. + */ + UART_send( &g_stdio_uart, (uint8_t *)&ch, 1 ); + + return (ch); +} + +/*============================================================================== + * getachar() + */ +int getachar(void) +{ + uint8_t rx_size; + uint8_t rx_byte; + + if ( !g_stdio_uart_init_done ) + { + /****************************************************************************** + * Baud value: + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + UART_init( &g_stdio_uart, + MSCC_STDIO_UART_BASE_ADDR, + ((SYS_CLK_FREQ/(16 * MSCC_STDIO_BAUD_VALUE))-1), + (DATA_8_BITS | NO_PARITY)); + + g_stdio_uart_init_done = 1; + } + + do + { + rx_size = UART_get_rx(&g_stdio_uart, &rx_byte, 1); + } while(0u == rx_size); + + return rx_byte; +} + +#endif /*MSCC_STDIO_THRU_CORE_UART_APB*/ + +#undef errno +static int errno; + +static char *__env[1] = { 0 }; +char **environ = __env; + +void write_hex(int fd, uint32_t hex) +{ + char towrite; + + write( fd , "0x", 2U ); + + for (uint32_t ii = 8U ; ii > 0U; ii--) + { + uint32_t jj = ii-1U; + uint8_t digit = ((hex & (0xFU << (jj*4U))) >> (jj*4U)); + towrite = digit < 0xAU ? (0x48U + digit) : (0x65U + (digit - 0xAU)); + write( fd, &towrite, 1U); + } +} + + +#ifdef GDB_TESTING +void __attribute__((optimize("O0"))) _exit(int code) +#else +void _exit(int code) +#endif +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + const char * message = "\nProgam has exited with code:"; + + write(STDERR_FILENO, message, strlen(message)); + write_hex(STDERR_FILENO, code); +#endif + + while (1){}; +} + +void *_sbrk(ptrdiff_t incr) +{ + extern char _end; + extern char _heap_end; + extern char __heap_start; + extern char __heap_end; + static char *curbrk = &_end; + void * ret = NULL; + + /* + * Did we allocated memory for the heap in the linker script? + * You need to set HEAP_SIZE to a non-zero value in your linker script if + * the following assertion fires. + */ + ASSERT(&__heap_end > &__heap_start); + + if (((curbrk + incr) < &_end) || ((curbrk + incr) > &_heap_end)) + { + errno = ENOMEM; + ret = ((char *) - 1); + } + else + { + curbrk += incr; + ret = curbrk - incr; + } + + /* + * Did we run out of heap? + * You need to increase the heap size in the linker script if the following + * assertion fires. + * */ + ASSERT(curbrk <= &__heap_end); + + return(ret); +} + +int _isatty(int fd) +{ + int ret = 0; + + if (fd <= 2) /* one of stdin, stdout, stderr */ + { + ret = 1; + } + else + { + errno = EBADF; + ret = 0; + } + + return(ret); +} + +static int stub(int err) +{ + errno = err; + return -1; +} + +int _open(const char* name, int flags, int mode) +{ + return stub(ENOENT); +} + +int _openat(int dirfd, const char* name, int flags, int mode) +{ + return stub(ENOENT); +} + +int _close(int fd) +{ + return stub(EBADF); +} + +int _execve(const char* name, char* const argv[], char* const env[]) +{ + return stub(ENOMEM); +} + +int _fork(void) +{ + return stub(EAGAIN); +} + +int _fstat(int fd, struct stat *st) +{ + int ret = 0; + + if (isatty(fd)) + { + st->st_mode = S_IFCHR; + ret = 0; + } + else + { + ret = stub(EBADF); + } + + return ret; +} + +int _getpid(void) +{ + return 1; +} + +int _kill(int pid, int sig) +{ + return stub(EINVAL); +} + +int _link(const char *old_name, const char *new_name) +{ + return stub(EMLINK); +} + +off_t _lseek(int fd, off_t ptr, int dir) +{ + off_t ret = 0; + if (_isatty(fd)) + { + ret = 0; + } + else + { + ret = stub(EBADF); + } + + return ret; +} + +ssize_t _read(int fd, void* ptr, size_t len) +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + + char* ptr1 = (char*)ptr; + + if (_isatty(fd)) + { + int count; + + for (count = 0; count < len; count++) + { + ptr1[count] = getachar(); + sendchar(ptr1[count]); + + /* Return partial buffer if we get EOL */ + if (('\r' == ptr1[count])||('\n' == ptr1[count])) + { + ptr1[count] = '\n'; + return count; + } + } + + return count; /* Filled the buffer */ + } +#endif + + return stub(EBADF); +} + +int _stat(const char* file, struct stat* st) +{ + return stub(EACCES); +} + +clock_t _times(struct tms* buf) +{ + return stub(EACCES); +} + +int _unlink(const char* name) +{ + return stub(ENOENT); +} + +int _wait(int* status) +{ + return stub(ECHILD); +} + +ssize_t _write(int fd, const void* ptr, size_t len) +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + int count_out; + char* ptr1 = (char*)ptr; + + /*-------------------------------------------------------------------------- + * Output text to the UART. + */ + count_out = 0; + while(len--) + { + sendchar(ptr1[count_out]); + count_out++; + } + + errno = 0; + return count_out; + +#else /* MSCC_STDIO_THRU_CORE_UART_APB */ + + return stub(EBADF); + +#endif /* MSCC_STDIO_THRU_CORE_UART_APB */ + +} + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/sample_fpga_design_config.h b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/sample_fpga_design_config.h new file mode 100644 index 0000000..a380d96 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ecdsa-services/src/platform/miv_rv32_hal/sample_fpga_design_config.h @@ -0,0 +1,167 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file sample_fpga_design_config.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Sample design configuration settings + * + */ + /*========================================================================*//** + @mainpage + Example file detailing how the fpga_design_config.h should be constructed + for the SoftConsole project targeted for Mi-V processors. + + @section intro_sec Introduction + The SoftConsole project targeted for Mi-V processors now have an improved + folder structure. Detailed description of the folder structure is available + at https://github.com/Mi-V-Soft-RISC-V/miv-rv32-documentation. + + The fpga_design_config.h must be stored as shown below + /boards//fpga_design_config.h + + Currently this file must be hand crafted when using the Mi-V Soft Processor. + In future, all the design and soft IP configurations will be automatically + generated from the Libero design description data. + + You can use this sample file as an example. + Rename this file from sample_fpga_design_config.h to fpga_design_config.h + and then customize it per your hardware design. + + @section Project configuration Instructions + 1. Change SYS_CLK_FREQ define to frequency of Mi-V Soft processor clock + 2 Add all the soft IP core BASE addresses + 3. Add the peripheral Core Interrupts to Mi-V Soft processor IRQ number + mappings + 4. Define MSCC_STDIO_UART_BASE_ADDR if you want a CoreUARTapb mapped to + STDIO + + **NOTE** + In the legacy folder structures, the file hw_config.h as was used at the + root of the project folder. This file is now depricated. + +*//*=========================================================================*/ + +#ifndef FPGA_DESIGN_CONFIG_H_ +#define FPGA_DESIGN_CONFIG_H_ + +/***************************************************************************//** + * Soft-processor clock definition + * This is the only clock brought over from the Mi-V Libero design. + */ +#ifndef SYS_CLK_FREQ +#define SYS_CLK_FREQ 50000000UL +#endif + +/***************************************************************************//** + * Peripheral base addresses. + * Format of define is: + * __BASE_ADDR + * The field is optional if there is only one instance of the core + * in the design + * MIV_ESS is an extended peripheral subsystem IP core with peripherals + * connections as defined below. + * The system can be further extended by attaching APB peripherals to the + * empty APB slots. + */ +#define MIV_ESS_PLIC_BASE_ADDR 0x70000000UL +#define COREUARTAPB0_BASE_ADDR 0x71000000UL +#define MIV_MTIMER_BASE_ADDR 0x72000000UL +#define MIV_ESS_APBSLOT3_BASE_ADDR 0x73000000UL +#define MIV_ESS_APBSLOT4_BASE_ADDR 0x74000000UL +#define COREGPIO_OUT_BASE_ADDR 0x75000000UL +#define CORESPI_BASE_ADDR 0x76000000UL +#define MIV_ESS_uDMA_BASE_ADDR 0x78000000UL +#define MIV_ESS_WDOG_BASE_ADDR 0x79000000UL +#define MIV_ESS_I2C_BASE_ADDR 0x7A000000UL +#define MIV_ESS_APBSLOTB_BASE_ADDR 0x7B000000UL +#define MIV_ESS_APBSLOTC_BASE_ADDR 0x7C000000UL +#define MIV_ESS_APBSLOTD_BASE_ADDR 0x7D000000UL +#define MIV_ESS_APBSLOTE_BASE_ADDR 0x7E000000UL +#define MIV_ESS_APBSLOTF_BASE_ADDR 0x7F000000UL + +/***************************************************************************//** + * Peripheral Interrupts are mapped to the corresponding Mi-V Soft processor + * interrupt in the Libero design. + * + * On the legacy RV32 cores, there can be up to 31 external interrupts (IRQ[30:0] + * pins). The legacy RV32 Soft processor external interrupts are defined in the + miv_rv32_plic.h + * + * These are of the form + * typedef enum +{ + NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + . + . + . + External_31_IRQn = 31 +} IRQn_Type; + + On the legacy RV32 processors, the PLIC identifies the interrupt and passes it + on to the processor core. The interrupt 0 is not used. The pin IRQ[0] should + map to External_1_IRQn likewise IRQ[30] should map to External_31_IRQn + +e.g + +#define TIMER0_IRQn External_30_IRQn +#define TIMER1_IRQn External_31_IRQn + + The MIV_RV32 soft processor has up to six optional system interrupts, MSYS_EI[n] + in addition to one EXT_IRQ. + The MIV_RV32 does not have an inbuilt PLIC and all the interrupts are directly + delivered to the processor core, hence unlike legacy RV32 cores, no interrupt + number mapping is necessary on MIV_RV32 core. + */ + +/**************************************************************************** + * Baud value to achieve a 115200 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ +#define BAUD_VALUE_115200 ((SYS_CLK_FREQ / (16 * 115200)) - 1) + +/****************************************************************************** + * Baud value to achieve a 57600 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + #define BAUD_VALUE_57600 ((SYS_CLK_FREQ / (16 * 57600)) - 1) + +/***************************************************************************//** + * Define MSCC_STDIO_THRU_CORE_UART_APB in the project settings if you want the + * standard IOs to be redirected to a terminal via UART. + */ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +/* + * A base address mapping for the STDIO printf/scanf mapping to CortUARTapb + * must be provided if it is being used + * + * e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR + */ +#define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB0_BASE_ADDR + +#ifndef MSCC_STDIO_UART_BASE_ADDR +#error MSCC_STDIO_UART_BASE_ADDR not defined- e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR +#endif + +#ifndef MSCC_STDIO_BAUD_VALUE +/* + * The MSCC_STDIO_BAUD_VALUE define should be set in your project's settings to + * specify the baud value used by the standard output CoreUARTapb instance for + * generating the UART's baud rate if you want a different baud rate from the + * default of 115200 baud + */ +#define MSCC_STDIO_BAUD_VALUE 115200 +#endif /*MSCC_STDIO_BAUD_VALUE*/ + +#endif /* end of MSCC_STDIO_THRU_CORE_UART_APB */ +/******************************************************************************* + * End of user edit section + */ +#endif /* FPGA_DESIGN_CONFIG_H_ */ diff --git a/applications/user-crypto/miv-rv32-key-agreement/.cproject b/applications/user-crypto/miv-rv32-key-agreement/.cproject new file mode 100644 index 0000000..c82262a --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/.cproject @@ -0,0 +1,333 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-key-agreement/.gitignore b/applications/user-crypto/miv-rv32-key-agreement/.gitignore new file mode 100644 index 0000000..f1b6b72 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/.gitignore @@ -0,0 +1,3 @@ +/.settings/ +/*miv-rv32-imc-debug*/ +/*miv-rv32-imc-release*/ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-key-agreement/.project b/applications/user-crypto/miv-rv32-key-agreement/.project new file mode 100644 index 0000000..76406e6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/.project @@ -0,0 +1,26 @@ + + + miv-rv32-key-agreement + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/applications/user-crypto/miv-rv32-key-agreement/README.md b/applications/user-crypto/miv-rv32-key-agreement/README.md new file mode 100644 index 0000000..8ebd9be --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/README.md @@ -0,0 +1,144 @@ +PolarFire User Crypto Key Agreement service +================================================================================ +This example project demonstrates the use of the PolarFire User Crypto key +agreement Services using the following functions + + - CALPreCompute() + - CALExpo() + +There are two different build configurations provided with this project which +configure this SoftConsole project for RISC-V IMC instruction extension. +The following configurations are provided with the example: + + - miv-rv32-imc-debug + - miv-rv32-imc-release + +Mi-V Soft Processor +-------------------------------------------------------------------------------- +This example uses Mi-V SoftProcessor MiV_RV32.The design is built for debugging +MiV_RV32 through the PolarFire FPGA programming JTAG port using a FlashPro5. +To achieve this the CoreJTAGDebug IP is used to connect to the JTAG port of the +MiV_RV32. + +All the platform/design specific definitions such as peripheral base addresses, +system clock frequency etc. are included in fpga_design_config.h. The +fpga_design_config.h is located at the root folder of this project. + +The Mi-V Soft Processor MiV_RV32 firmware projects needs the miv_rv32_hal and +the hal firmware(RISC-V HAL). + +The RISC-V HAL is available at GitHub [Mi-V-Soft-RISC-V](https://mi-v-ecosystem.github.io/redirects/platform). + +How to use this example +-------------------------------------------------------------------------------- +This example project is targeted at a MIV_RV32 design running on a PolarFire-Eval-Kit +connected via a USB-UART serial cable to a host PC running a terminal emulator +such as TeraTerm or Putty configured as follows: + + - 115200 baud + - 8 data bits + - 1 stop bit + - no parity + - no flow control. + +Run the example project using a debugger. A greeting message will appear over the +UART terminal.This program displays the return shared secret key data from User +Crypto processor. + +This example project demonstrates the use of User Cyrpto – key agreement service +to derive the shared secret key. It is primarily used as a method of exchanging +cryptography keys for use in symmetric encryption algorithms such as AES. This +service reads the base value, modules, private key of user A, public key of user +B, and derive the secret key, which can be used for encryption/decryption of +data and also displayed on the UART terminal. + +fpga_design_config (formerly known as hw_config.h) +-------------------------------------------------------------------------------- +The SoftConsole project targeted for Mi-V processors now use an improved +directory structure. The fpga_design_config.h must be stored as shown below + +` + /boards//fpga_design_config/fpga_design_config.h +` + +Currently, this file must be hand crafted when using the Mi-V Soft Processor. +In future, all the design and soft IP configurations will be automatically +generated from the Libero design description data. + +You can use the sample file provided with MIV_RV32 HAL as an example. Rename it +from sample_fpga_design_config.h to fpga_design_config.h and then customize it +per your hardware design such as SYS_CLK_FREQ, peripheral BASE addresses, +interrupt numbers, definition of MSCC_STDIO_UART_BASE_ADDR if you want a +CoreUARTapb mapped to STDIO, etc. + +### Configurations + +The CAL library needs a config_user.h containing the configuration data. +This application provides following settings as per CAL requirement + 1. A variable which provides the base address of the User Crypto hardware block + is defined in main.c + + `uint32_t g_user_crypto_base_addr = 0x62000000UL;` + + 2. A symbol INC_STDINT_H is defined in project preprocessor setting. + For more detail, please refer to caltypes.h file present in CAL folder. + +**NOTE**: +1. There is no direct function to calculate shared secret using Diffie-Hellman + key agreement algorithm. +2. You must enter all input data as whole bytes. If you enter the 128-bit key + {1230...0} as 0x12 0x3 and press return, this will be treated as + byte0 = 0x12, byte1 = 0x30, byte2-127 = 0x00. + +### Test script + +A test script is provided with this example which automatically enters the NIST +vectors and associated data to verify the functionality. You can use +RV32_Key_agreement.ttl Tera Term Macro script present in project directory for +testing key agreement example project. + +**NOTE:** +1. Tera Term Macros don’t work with Windows 10 build 14393.0. You should update + to Windows 10 build 14393.0.105 or [later.](https://osdn.net/ticket/browse.php?group_id=1412&tid=36526) +2. Before running Tera Term Macro script, set language as English + (Setup->General->Language). Also setup transmit delay in (Setup->Serial port) + to 5msec/char and 5msec/line. +3. By default, Tera Term log will be stored in Tera Term installation Directory. + +## Target hardware + +This project was tested on PolarFire-Eval-Kit with CFG4 configuration of the +MIV_RV32 design available [here](https://github.com/Mi-V-Soft-RISC-V/PolarFire-Eval-Kit/tree/main/Libero_Projects) + +All the design specific definitions such as peripheral base addresses, system +clock frequency etc. are included in fpga_design_config.h. + +The firmware projects needs the HAL and the MIV_RV32 HAL firmware components. + +This example project can be used with another design using a different hardware +configurations. This can be achieved by overwriting the content of this example +project's "fpga_design_config.h" file with the correct data per your Libero design. + +### Booting the system + +Currently the example project is configured to use FlashPro debugger to execute +from LSRAM in both Debug and Release mode. + +In the release mode build configuration, following setting is used +`--change-section-lma *-0x80000000` under +Tool Settings > Cross RISCV GNU Create Flash Image > General > Other flags. + +This will allow you to attach the release mode executable as the memory +initialization client in Libero when you want to execute it from non-volatile memory. + +## Silicon revision dependencies + +This example is tested on PolarFire MPF300TS device. + +### CAL library src + +To obtain the CAL source code and a SoftConsole project to generate the CAL +library archive file (*.a) refer [SoftConsole Documentation](https://mi-v-ecosystem.github.io/SoftConsole-Documentation/SoftConsole-v2021.3/using_softconsole/other.html#crypto-application-library). +The CAL source code is bound by license agreement and it will be available as +part of the SoftConsole installation if the CAL specific license was agreed +while installing it. \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-key-agreement/RV32_Key_agreement.ttl b/applications/user-crypto/miv-rv32-key-agreement/RV32_Key_agreement.ttl new file mode 100644 index 0000000..e7381ff --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/RV32_Key_agreement.ttl @@ -0,0 +1,103 @@ +; Tera Term Setting: +; 1. Before running Tera Term Macro script, you should set language as English +; and transmit delay in Serial port setup to 5msec/char and 5msec/line. +; 2. By default, Tera Term log will be stored in Tera Term installation Directory. +changedir '.' +logopen "KEY_AGREEMENT.log" 0 0 0 1 + +settitle 'PolarFire User Crypto Key Agreement service' + +setsync 1 + +; Set baud rate to 115200 +setbaud 115200 + +; local echo off +setecho 0 + +; ---------------------------------------------------------------------------------------------------------------------------------------------------------- +; INPUT +; P = +; a25cb1199622be09d9f473695114963cbb3b109f92df6da1b1dcab5e8511e9a117e2881f30a78f04d6a3472b8064eb6416c +; dfd7bb8b9891ae5b5a1f1ee1da0cace11dab3ac7a50236b22e105dbeef9e45b53e0384c45c3078acb6ee1ca983511795801 +; da3d14fa9ed82142ec47ea25c0c0b7e86647d41e9f55955b8c469e7e298ea30d88feacf43ade05841008373605808a2f8f8 +; 910b195f174bd8af5770e7cd85380d198f4ed2a0c3a2f373436ae6ce9567846a79275765ef829abbc6171718f7746ebd167 +; d406e2546acdea7299194a613660d5ef721cd77e7722095c4ca42b29db3d4436325b47f850af05d411c7a95ccc54555c193 +; 384a6eeebb47e6f0f +; +; Q = a944d488de8c89567b602bae44478632604f8bf7cb4deb851cf6e22d +; G = +; 1e2b67448a1869df1ce57517dc5e797b62c5d2c832e23f954bef8bcca74489db6caed2ea496b52a52cb664a168374cb176d +; dc4bc0068c6eef3a746e561f8dc65195fdaf12b363e90cfffdac18ab3ffefa4b2ad1904b45dd9f6b76b477ef8816802c7bd +; 7cb0c0ab25d378098f5625e7ff737341af63f67cbd00509efbc6470ec38c17b7878a463cebda80053f36558a308923e6b41 +; f465385a4f24fdb303c37fb998fc1e49e3c09ce345ff7cea18e9cd1457eb93daa87dba8a31508fa5695c32ce485962eb183 +; 4144413b41ef936db71b79d6fe985c018ac396e3af25054dbbc95e56ab5d4d4b7b61a70670e789c336b46b9f7be43cf6eb0 +; e68b40e33a55d55cc +; XstatCAVS = 74162ac74759e85654e0e7762c2cdd2689009b24dae06d0a85260b81 +; YstatCAVS = +; 23ed27e3e655e0a15027d8e75dc97d72756875ff7caab2c3882f0461bacfe599e1391567f2f1406ba841b7ce366a7726ee1 +; f3b56912de4c11f83d8d4096fffe4290ebfe3ffc3c11e9d6a2a1683d16222504d188a2265d678892ed39feaa17aae98ef39 +; cbbce0a765ec9a16d79f369a65c47f93ecdf3a2c6f15e5d112dd197c9593532953a2518cf1c6d336b77ad20aba67e150c3e +; 94037aced49d557d63c48958253c2dc0d66bec9d0bc93739f300d1e1785d58ce3b7a50e65b3742e4de26c3a3db3e66055ae +; 59117464d8dcea7435a6a95396e595146f61cffe6f5650b2d5231f629966e54630ed80b7d6dc03144bf379cf85acf13dd28 +; 5a1ee2bab4fe996a2 +; XstatIUT = 8280294a47d4748d853da60d016d1b03320b64df43188c882204f371 +; YstatIUT = +; 86c59d66dc53689cdc6b60ca7628afa58759b27ffa0856d0037d390d60c14d86385bde5ed5bc6f7e0ab8e5f07d08a47b648 +; abd10865d9f4c9ee7cf5f7982c63a52a33b96482a94b1ece4a99022ec4aa41c7453648089152093a84d16e16039d71db9aa +; a2aa701f483f6297c4d2647079290a2b94c9bf9ecaa6715758135898504130e381795adf7352b37d1be696012a03dcea475 +; 0e963365a7698355364cbedf1715abcb31e3b2aa072dfe15ffd4c2e7d69c8ed7dbb138522536b5e74495724fe4e74b662b9 +; af8c5a35616b9dde39c80041cc6ac62aeae2b802f91b62e9be27dae8006797529db42b2ad8a16353ba6a5d25ea25d443126 +; 9ea6fc397de3f16ed +; +; OUTPUT +; Z = +; 59ae47dfd2893b37bb229b05f19ec181b8bc7bace31d0ac37b27e364ea4ca179bb574d91fc554009195ee13bfd3877baa54 +; ed390eab7aa3dfd6f3a35a776a80f58999d7931a9f0d842eb9bad51a24f2d052e56d09ade631f5e3ba64e957e4d583e20ad +; 35d5336708482dd59b80a351e664a724cdf28a7796d2e93fffc7b113a8288be2b562af9dc3f980c917d56a723351b7f4be2 +; d7384b51f69335cf6a2fde5fa4f151be66529a4c8e8850b9c98dcae3a84d0ac231845e2b3771b9c5583960490994a58ff0d +; 748333f92d835f2886ff26b81ebf4b7d7dd6d052d3f2f3062f137ef3fcab8c95771ad837b0af0378d75285126151db08fd0 +; cea5aa9933ffebc50 +; ---------------------------------------------------------------------------------------------------------------------------------------------------------- + +pause 1 + +;G +pause 1 +send '1e2b67448a1869df1ce57517dc5e797b62c5d2c832e23f954bef8bcca74489db6caed2ea496b52a52cb664a168374cb176dd' +send 'c4bc0068c6eef3a746e561f8dc65195fdaf12b363e90cfffdac18ab3ffefa4b2ad1904b45dd9f6b76b477ef8816802c7bd7c' +send 'b0c0ab25d378098f5625e7ff737341af63f67cbd00509efbc6470ec38c17b7878a463cebda80053f36558a308923e6b41f46' +send '5385a4f24fdb303c37fb998fc1e49e3c09ce345ff7cea18e9cd1457eb93daa87dba8a31508fa5695c32ce485962eb1834144' +send '413b41ef936db71b79d6fe985c018ac396e3af25054dbbc95e56ab5d4d4b7b61a70670e789c336b46b9f7be43cf6eb0e68b4' +send '0e33a55d55cc' +pause 5 + +;XstatCAVS +pause 2 +send '74162ac74759e85654e0e7762c2cdd2689009b24dae06d0a85260b81' + +;P +pause 2 +send 'a25cb1199622be09d9f473695114963cbb3b109f92df6da1b1dcab5e8511e9a117e2881f30a78f04d6a3472b8064eb6416c' +send 'dfd7bb8b9891ae5b5a1f1ee1da0cace11dab3ac7a50236b22e105dbeef9e45b53e0384c45c3078acb6ee1ca983511795801' +pause 2 +send 'da3d14fa9ed82142ec47ea25c0c0b7e86647d41e9f55955b8c469e7e298ea30d88feacf43ade05841008373605808a2f8f8' +send '910b195f174bd8af5770e7cd85380d198f4ed2a0c3a2f373436ae6ce9567846a79275765ef829abbc6171718f7746ebd167' +pause 2 +send 'd406e2546acdea7299194a613660d5ef721cd77e7722095c4ca42b29db3d4436325b47f850af05d411c7a95ccc54555c193' +send '384a6eeebb47e6f0f' + +;YstatIUT +pause 2 +send '86c59d66dc53689cdc6b60ca7628afa58759b27ffa0856d0037d390d60c14d86385bde5ed5bc6f7e0ab8e5f07d08a47b648' +send 'abd10865d9f4c9ee7cf5f7982c63a52a33b96482a94b1ece4a99022ec4aa41c7453648089152093a84d16e16039d71db9aa' +pause 4 +send 'a2aa701f483f6297c4d2647079290a2b94c9bf9ecaa6715758135898504130e381795adf7352b37d1be696012a03dcea475' +send '0e963365a7698355364cbedf1715abcb31e3b2aa072dfe15ffd4c2e7d69c8ed7dbb138522536b5e74495724fe4e74b662b9' +send 'af8c5a35616b9dde39c80041cc6ac62aeae2b802f91b62e9be27dae8006797529db42b2ad8a16353ba6a5d25ea25d443126' +pause 4 +send '9ea6fc397de3f16ed' +send 13 + +pause 10 +logclose \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-key-agreement/miv-rv32-key-agreement hw Debug.launch b/applications/user-crypto/miv-rv32-key-agreement/miv-rv32-key-agreement hw Debug.launch new file mode 100644 index 0000000..c0b696e --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/miv-rv32-key-agreement hw Debug.launch @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/user-crypto/miv-rv32-key-agreement/miv-rv32-key-agreement hw attach.launch b/applications/user-crypto/miv-rv32-key-agreement/miv-rv32-key-agreement hw attach.launch new file mode 100644 index 0000000..a4a7540 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/miv-rv32-key-agreement hw attach.launch @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/application/helper.c b/applications/user-crypto/miv-rv32-key-agreement/src/application/helper.c new file mode 100644 index 0000000..4a78569 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/application/helper.c @@ -0,0 +1,312 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file helper.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Helper function for PolarFire User Crypto- Cryptography service example. + * + */ +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" +#include "helper.h" + +extern UART_instance_t g_uart; + +static const uint8_t g_separator[] = +"\r\n\ +------------------------------------------------------------------------------"; + + +/*============================================================================== + Function to clear local variable and array. + */ +static void clear_variable(uint8_t *p_var, uint16_t size) +{ + uint16_t inc; + + for(inc = 0; inc < size; inc++) + { + *p_var = 0x00; + p_var++; + } +} + +/*============================================================================== + Function to get the input data from user. + */ +uint16_t get_input_data +( + uint8_t* location, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +) +{ + uint16_t count = 0u; + + /* Clear the memory location. */ + clear_variable(location, size); + + /* Read data from UART terminal. */ + count = get_data_from_uart(location, size, msg, msg_size); + + return count; +} + +/*============================================================================== + Function to get the key from user. + */ +void get_key +( + uint8_t key_type, + uint8_t* location, + uint8_t size, + const uint8_t* msg, + uint8_t msg_size +) +{ + uint8_t status = 0u; + const uint8_t invalid_ms[] = "\r\n Invalid key type. "; + + if(status == VALID) + { + /* Read the 16 bytes of input data from UART terminal. */ + get_input_data(location, size, msg, msg_size); + } + else + { + UART_send(&g_uart, invalid_ms, sizeof( invalid_ms)); + } +} + +/*============================================================================== + Convert ASCII value to hex value. + */ +uint8_t convert_ascii_to_hex(uint8_t* dest, const uint8_t* src) +{ + uint8_t error_flag = 0u; + + if((*src >= '0') && (*src <= '9')) + { + *dest = (*src - '0'); + } + else if((*src >= 'a') && (*src <= 'f')) + { + *dest = (*src - 'a') + 10u; + } + else if((*src >= 'A') && (*src <= 'F')) + { + *dest = (*src - 'A') + 10u; + } + else if(*src != 0x00u) + { + UART_send(&g_uart, (const uint8_t *)"\r\n Invalid data.", sizeof("\r\n Invalid data.")); + error_flag = 1u; + } + return error_flag; +} + +/*============================================================================== + Validate the input hex value . + */ +uint8_t validate_input(uint8_t ascii_input) +{ + uint8_t valid_key = 0u; + + if(((ascii_input >= 'A') && (ascii_input <= 'F')) || \ + ((ascii_input >= 'a') && (ascii_input <= 'f')) || \ + ((ascii_input >= '0') && (ascii_input <= '9'))) + { + valid_key = 1u; + } + else + { + valid_key = 0u; + } + return valid_key; +} + +const uint8_t hex_chars[16] = { '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + +/*============================================================================== + Display content of buffer passed as parameter as hex values. + */ +void display_output +( + uint8_t* in_buffer, + uint32_t byte_length +) +{ + uint32_t inc; + uint8_t byte = 0; + + UART_send(&g_uart, (const uint8_t*)" ", sizeof(" ")); + for(inc = 0; inc < byte_length; ++inc) + { + if((inc > 1u) &&(0u == (inc % 16u))) + { + UART_send(&g_uart, (const uint8_t*)"\r\n ", sizeof("\r\n ")); + } + + byte = in_buffer[inc]; + UART_send(&g_uart, &hex_chars[((byte & 0xF0) >> 4) ], 1); + UART_send(&g_uart, &hex_chars[(byte & 0x0F)], 1); + } + +} + +/*============================================================================== + Function to read data from UART terminal and stored it. + */ +uint16_t get_data_from_uart +( + uint8_t* src_ptr, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +) +{ + uint8_t complete = 0u; + uint8_t rx_buff[1]; + uint8_t rx_size = 0u; + uint16_t count = 0u; + uint16_t ret_size = 0u; + uint8_t first = 0u; + uint16_t src_ind = 0u; + uint8_t prev = 0; + uint8_t curr = 0; + uint8_t temp = 0; + uint8_t next_byte = 0; + uint16_t read_data_size = 0; + + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, msg, msg_size); + + if(size != 1) + { + read_data_size = size * 2; + } + else + { + read_data_size = size; + } + + /* Read the key size sent by user and store it. */ + count = 0u; + while(!complete) + { + rx_size = UART_get_rx(&g_uart, rx_buff, sizeof(rx_buff)); + if(rx_size > 0u) + { + /* Is it to terminate from the loop */ + if(ENTER == rx_buff[0]) + { + complete = 1u; + } + /* Is entered key valid */ + else if(validate_input(rx_buff[0]) != 1u) + { + UART_send(&g_uart, rx_buff, sizeof(rx_buff)); + UART_send(&g_uart, (const uint8_t *)"\r\n Invalid input.", + sizeof("\r\n Invalid input.")); + UART_send(&g_uart, msg, msg_size); + complete = 0u; + count = 0u; + first = 0u; + clear_variable(src_ptr, 4); + } + else + { + if(next_byte == 0) + { + convert_ascii_to_hex(&src_ptr[src_ind], &rx_buff[0]); + prev = src_ptr[src_ind]; + next_byte = 1; + } + else + { + convert_ascii_to_hex(&curr, &rx_buff[0]); + temp = ((prev << 4) & 0xF0); + src_ptr[src_ind] = (temp | curr); + next_byte = 0; + src_ind++; + } + + + /* Switching to next line after every 8 bytes */ + if(((count % 32u) == 0x00u) && (count > 0x00u) && (complete != 0x01u)) + { + UART_send(&g_uart, (const uint8_t *)"\n\r", sizeof("\n\r")); + first = 0u; + } + + if(first == 0u) + { + UART_send(&g_uart, (const uint8_t *)" ", sizeof(" ")); + first++; + } + UART_send(&g_uart, rx_buff, sizeof(rx_buff)); + count++; + if(read_data_size == count) + { + complete = 1u; + } + } + } + } + + if((count%2) == 0) + { + ret_size = count/2; + } + else + { + if(size!=1) + { + temp = src_ptr[src_ind]; + src_ptr[src_ind] = ((temp << 4) & 0xF0); + + ret_size = (count/2)+1; + } + else + { + ret_size = 1; + } + } + + return ret_size; +} + +/*============================================================================== + Function to get the key from user. + */ +uint8_t enable_dma +( + const uint8_t* msg, + uint8_t msg_size +) +{ + volatile uint8_t invalid_ip = 1u; + uint8_t dma_enable = 0; + + const uint8_t invalid_ms[] = "\r\n Invalid input. "; + + while(invalid_ip != 0) + { + /* Read the 16 bytes of input data from UART terminal. */ + get_input_data(&dma_enable, 1, msg, msg_size); + + if(dma_enable >= 2) + { + UART_send(&g_uart, invalid_ms, sizeof( invalid_ms)); + } + else + { + invalid_ip = 0; + } + } + + return dma_enable; +} diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/application/helper.h b/applications/user-crypto/miv-rv32-key-agreement/src/application/helper.h new file mode 100644 index 0000000..7f21b6e --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/application/helper.h @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file helper.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Helper function public API. + * + */ +#ifndef __HELPER_H_ +#define __HELPER_H_ 1 + +/****************************************************************************** + * Maximum buffer size. + *****************************************************************************/ +#define MAX_RX_DATA_SIZE 256 +#define MASTER_TX_BUFFER 10 + +/*============================================================================== + Macro + */ +#define VALID 0U +#define INVALID 1U +#define ENTER 13u + +/****************************************************************************** + * CoreUARTapb instance data. + *****************************************************************************/ + +uint16_t get_input_data +( + uint8_t* location, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +); +void get_key +( + uint8_t key_type, + uint8_t* location, + uint8_t size, + const uint8_t* msg, + uint8_t msg_size +); +uint16_t get_data_from_uart +( + uint8_t* src_ptr, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +); +uint8_t enable_dma +( + const uint8_t* msg, + uint8_t msg_size +); +void display_output +( + uint8_t* in_buffer, + uint32_t byte_length +); +#endif /* __HELPER_H_ */ diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/application/main.c b/applications/user-crypto/miv-rv32-key-agreement/src/application/main.c new file mode 100644 index 0000000..0e9c17b --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/application/main.c @@ -0,0 +1,169 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file main.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief This example project demonstrates the usage of PolarFire User Crypto + * Diffie-Hellman Key Agreement services. + * + */ +#include +#include +#include +#include "stdint.h" +#include "helper.h" +#include "hal/hal.h" +#include "fpga_design_config/fpga_design_config.h" +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" + +#include "cal/calpolicy.h" +#include "cal/pk.h" +#include "cal/pkx.h" +#include "cal/pkxlib.h" +#include "cal/calini.h" +#include "cal/utils.h" +#include "cal/hash.h" +#include "cal/drbgf5200.h" +#include "cal/drbg.h" +#include "cal/nrbg.h" +#include "cal/sym.h" +#include "cal/shaf5200.h" +#include "cal/calenum.h" + +/*private utility function */ +static SATR CAL_EXECUTE(SATR result) { + + return (result == SATR_SUCCESS) ? CALPKTrfRes(SAT_TRUE) : result; +} + +/****************************************************************************** + * CoreUARTapb instance data. + *****************************************************************************/ +UART_instance_t g_uart; + +uint32_t g_user_crypto_base_addr = 0x62000000UL; +/*============================================================================== + Messages displayed over the UART. + */ +const uint8_t g_greeting_msg[] = +"\r\n\r\n\ +******************************************************************************\r\n\ +******** PolarFire User Athena Key Agreement Service Example Project *********\r\n\ +******************************************************************************\r\n\ + This example project demonstrates the use of the PolarFire User Crypto \r\n\ + Athena Key Agreement Service for generating shared secret key.\r\n"; + +static const uint8_t g_separator[] = +"\r\n\ +------------------------------------------------------------------------------"; + +/*============================================================================== + Global Variables. + */ +static uint8_t Pmod_2048[256] ={ 0x00 }; +static uint8_t G_2048[256] = { 0x00 }; +static uint32_t PrePmod_2048[65]; +static uint32_t PublicKey_A[100]; +static uint32_t SharedSecret[65]; +static uint8_t PublicKey_B[400] = { 0x00 }; +static uint8_t E_2048[28] = { 0x00 }; + +/*============================================================================== + Display greeting message when application is started. + */ +static void display_greeting(void) +{ + UART_send(&g_uart, g_greeting_msg,sizeof(g_greeting_msg)); +} + +/*============================================================================== + Diffie-Hellman key agreement algorithm. + */ +static void dh_key_agreement(void) +{ + const uint8_t base_value_msg[] = + "\r\n Enter base value (G) 256 bytes: \r\n"; + const uint8_t read_mod_param[] = + "\r\n Enter modulus value: \r\n"; + const uint8_t read_private_key_usrA[] = + "\r\n Enter private key of user A: \r\n"; + const uint8_t read_userB_public_key[] = + "\r\n Enter user B public key: \r\n"; + + /* Read base value value. */ + get_input_data((uint8_t*)&G_2048, sizeof(G_2048), base_value_msg, + sizeof(base_value_msg)); + + /* Read private key of user A. i.e.puiExp parameter. */ + get_input_data((uint8_t*)&E_2048, sizeof(E_2048), read_private_key_usrA, + sizeof(read_private_key_usrA)); + + /* Read modulus parameter. */ + get_input_data((uint8_t*)&Pmod_2048, sizeof(Pmod_2048), read_mod_param, + sizeof(read_mod_param)); + + /* Read shared secret key from user B. */ + get_input_data((uint8_t*)&PublicKey_B, sizeof(PublicKey_B), + read_userB_public_key, sizeof(read_userB_public_key)); + + /* Change the endianness of received parameter from UART terminal.*/ + CALWordReverse((uint32_t*)&G_2048, 64); + CALByteReverseWord((uint32_t*)&G_2048, 64); + CALWordReverse((uint32_t*)&E_2048, 7); + CALByteReverseWord((uint32_t*)&E_2048, 7); + CALWordReverse((uint32_t*)&Pmod_2048, 64); + CALByteReverseWord((uint32_t*)&Pmod_2048, 64); + CALWordReverse((uint32_t*)&PublicKey_B, 64); + CALByteReverseWord((uint32_t*)&PublicKey_B, 64); + + /* Initiate generation of pre-compute value. */ + CAL_EXECUTE(CALPreCompute((uint32_t*)&Pmod_2048, PrePmod_2048, 64u)); + + /* Initiate modular exponentiation operation - Generate Public key for + * PARTY-A. */ + CAL_EXECUTE(CALExpo((uint32_t*)&G_2048, (uint32_t*)&E_2048, + (uint32_t*)&Pmod_2048, PrePmod_2048, 7u, 64u, + PublicKey_A)); + + /* Generate shared secret key using PARTY-B public key. */ + CAL_EXECUTE(CALExpo((uint32_t*)&PublicKey_B, (uint32_t*)&E_2048, SAT_NULL, + SAT_NULL, 7u, 64u, SharedSecret)); + + /* Display Shared secret key on UART terminal.*/ + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, (const uint8_t *)"\r\n Secret key value: \r\n", + sizeof("\r\n Secret key value:\r\n")); + CALWordReverse((uint32_t*)&SharedSecret, 64); + CALByteReverseWord((uint32_t*)&SharedSecret, 64); + display_output((uint8_t*)&SharedSecret[0], 256); + + UART_send(&g_uart, g_separator, sizeof(g_separator)); +} + +/****************************************************************************** + * main function. + *****************************************************************************/ +int main( void ) +{ + + /* Initialize CoreUARTapb with its base address, baud value, and line + configuration. */ + UART_init(&g_uart, COREUARTAPB0_BASE_ADDR, BAUD_VALUE_115200, + (DATA_8_BITS | NO_PARITY)); + + /* Initializes the Athena Processor */ + CALIni(); + + /* Display greeting message. */ + display_greeting(); + + /* Calculate shared secret using Diffie-Hellman key agreement algorithm.*/ + dh_key_agreement(); + + for(;;) + { + ; + } +} diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h b/applications/user-crypto/miv-rv32-key-agreement/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h new file mode 100644 index 0000000..3fd1438 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h @@ -0,0 +1,156 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file fpga_design_config.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Sample design configuration settings. + * + */ + /*========================================================================*//** + @mainpage + Example file detailing how the fpga_design_config.h should be constructed + for the SoftConsole project targeted for Mi-V processors. + + @section intro_sec Introduction + The SoftConsole project targeted for Mi-V processors now have an improved + folder structure. Detailed description of the folder structure is available + at https://github.com/Mi-V-Soft-RISC-V/miv-rv32-documentation. + + The fpga_design_config.h must be stored as shown below + /boards//fpga_design_config.h + + Currently this file must be hand crafted when using the Mi-V Soft Processor. + In future, all the design and soft IP configurations will be automatically + generated from the Libero design description data. + + You can use this sample file as an example. + Rename this file from sample_fpga_design_config.h to fpga_design_config.h + and then customize it per your hardware design. + + @section Project configuration Instructions + 1. Change SYS_CLK_FREQ define to frequency of Mi-V Soft processor clock + 2 Add all the soft IP core BASE addresses + 3. Add the peripheral Core Interrupts to Mi-V Soft processor IRQ number + mappings + 4. Define MSCC_STDIO_UART_BASE_ADDR if you want a CoreUARTapb mapped to + STDIO + + **NOTE** + In the legacy folder structures, the file hw_config.h as was used at the + root of the project folder. This file is now depricated. + +*//*=========================================================================*/ + +#ifndef FPGA_DESIGN_CONFIG_H_ +#define FPGA_DESIGN_CONFIG_H_ + +/***************************************************************************//** + * Soft-processor clock definition + * This is the only clock brought over from the Mi-V Libero design. + */ +#ifndef SYS_CLK_FREQ +#define SYS_CLK_FREQ 83000000UL +#endif + +/***************************************************************************//** + * Peripheral base addresses. + * Format of define is: + * __BASE_ADDR + * The field is optional if there is only one instance of the core + * in the design + * MIV_ESS is an extended peripheral subsystem IP core with peripherals + * connections as defined below. + * The system can be further extended by attaching APB peripherals to the + * empty APB slots. + */ +#define COREUARTAPB0_BASE_ADDR 0x70000000UL +#define COREGPIO_OUT_BASE_ADDR 0x70001000UL +#define CORESPI_BASE_ADDR 0x70002000UL +#define CORESYS_SERV_BASE_ADDR 0x70003000UL + +/***************************************************************************//** + * Peripheral Interrupts are mapped to the corresponding Mi-V Soft processor + * interrupt in the Libero design. + * + * On the legacy RV32 cores, there can be up to 31 external interrupts (IRQ[30:0] + * pins). The legacy RV32 Soft processor external interrupts are defined in the + miv_rv32_plic.h + * + * These are of the form + * typedef enum +{ + NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + . + . + . + External_31_IRQn = 31 +} IRQn_Type; + + On the legacy RV32 processors, the PLIC identifies the interrupt and passes it + on to the processor core. The interrupt 0 is not used. The pin IRQ[0] should + map to External_1_IRQn likewise IRQ[30] should map to External_31_IRQn + +e.g + +#define TIMER0_IRQn External_30_IRQn +#define TIMER1_IRQn External_31_IRQn + + The MIV_RV32 soft processor has up to six optional system interrupts, MSYS_EI[n] + in addition to one EXT_IRQ. + The MIV_RV32 does not have an inbuilt PLIC and all the interrupts are directly + delivered to the processor core, hence unlike legacy RV32 cores, no interrupt + number mapping is necessary on MIV_RV32 core. + */ + +/**************************************************************************** + * Baud value to achieve a 115200 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ +#define BAUD_VALUE_115200 ((SYS_CLK_FREQ / (16 * 115200)) - 1) + +/****************************************************************************** + * Baud value to achieve a 57600 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + #define BAUD_VALUE_57600 ((SYS_CLK_FREQ / (16 * 57600)) - 1) + +/***************************************************************************//** + * Define MSCC_STDIO_THRU_CORE_UART_APB in the project settings if you want the + * standard IOs to be redirected to a terminal via UART. + */ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +/* + * A base address mapping for the STDIO printf/scanf mapping to CortUARTapb + * must be provided if it is being used + * + * e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR + */ +#define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB0_BASE_ADDR + +#ifndef MSCC_STDIO_UART_BASE_ADDR +#error MSCC_STDIO_UART_BASE_ADDR not defined- e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR +#endif + +#ifndef MSCC_STDIO_BAUD_VALUE +/* + * The MSCC_STDIO_BAUD_VALUE define should be set in your project's settings to + * specify the baud value used by the standard output CoreUARTapb instance for + * generating the UART's baud rate if you want a different baud rate from the + * default of 115200 baud + */ +#define MSCC_STDIO_BAUD_VALUE 115200 +#endif /*MSCC_STDIO_BAUD_VALUE*/ + +#endif /* end of MSCC_STDIO_THRU_CORE_UART_APB */ +/******************************************************************************* + * End of user edit section + */ +#endif /* FPGA_DESIGN_CONFIG_H_ */ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld b/applications/user-crypto/miv-rv32-key-agreement/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld new file mode 100644 index 0000000..8541db6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld @@ -0,0 +1,160 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-ram.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * debug image executing in SRAM. + * + * This linker script assumes that a RAM is connected at on Mi-V soft processor + * memory space pointed by the reset vector address. + * + * NOTE : Modify the memory section address and the size according to your + * Libero design. + * For example: + * 1) If you want to download and step debug at a different RAM memory address in + * your design (For example TCM base address) than the one provided in this file. + * 2) The MIV_RV32, when used with MIV_ESS IP, provides ways to copy the executable + * HEX file from external Non-Volatile memory into the TCM at reset. In this + * case your executable must be linked to the TCM address. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +MEMORY +{ + ram (rwx) : ORIGIN = 0x80000000, LENGTH = 64k + crypto_ram (rw) : ORIGIN = 0x61000000, LENGTH = 32k +} + +RAM_START_ADDRESS = 0x80000000; /* Must be the same value MEMORY region ram ORIGIN above. */ +RAM_SIZE = 64k; /* Must be the same value MEMORY region ram LENGTH above. */ +STACK_SIZE = 2k; /* needs to be calculated for your application */ +HEAP_SIZE = 0k; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > ram + + .text : ALIGN(0x10) + { + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } > ram + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } > ram + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } > ram + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram + + . = 0x61000000; + .crypto_data : ALIGN(0x10) + { + . = ALIGN(0x10); + *(.crypto_data) + } > crypto_ram +} + diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/aesf5200.h b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/aesf5200.h new file mode 100644 index 0000000..889dddd --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/aesf5200.h @@ -0,0 +1,104 @@ +/* ------------------------------------------------------------------- + $Rev: 1293 $ $Date: 2017-07-27 14:09:14 -0400 (Thu, 27 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for F5200 AES function hardware implementation for + CAL. + ------------------------------------------------------------------- */ + +#ifndef AESF5200_H +#define AESF5200_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef AESF5200_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATR aesf5200aes (SATSYMTYPE eSymType, SATSYMMODE eMode, + void *pIV, SATBOOL bLoadIV, const void *pSrc, void *pDest, SATUINT32_t uiLen, + SATBOOL bDecrypt); + +extern SATR aesf5200aesk (SATSYMTYPE eSymType, const SATUINT32_t *puiKey); + +extern SATR aesf5200gcm (SATSYMTYPE eSymType, SATSYMMODE eMode, void *pIV, + const void *pSrc, void *pDest, SATUINT32_t uiEncLen, + const void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, SATUINT32_t uiMACLen, + SATBOOL bDecrypt); + +extern SATR aesf5200gcmdma(SATSYMTYPE eSymType, SATSYMMODE eMode, void *pIV, + const void *pSrc, void *pDest, SATUINT32_t uiEncLen, const void *pAuth, + SATUINT32_t uiAuthLen, void *pMAC, SATUINT32_t uiMACLen, SATBOOL bDecrypt, + SATUINT32_t uiDMAChConfig); + +extern SATR aesf5200kw(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR aesf5200kwp(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR aesf5200kr(SATSYMTYPE eSymType, SATSYMMODE eMode, + const SATUINT32_t *puiKey, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKrf, SATBOOL bDecrypt); + +extern SATR aesf5200dma(SATSYMTYPE eSymType, SATSYMMODE eMode, void *pIV, + SATBOOL bLoadIV, const void *pExtSrc, void *pExtDest, SATUINT32_t uiLen, + SATUINT32_t uiDMAChConfig, SATBOOL bDecrypt); + +extern SATR aesf5200krdma(SATSYMTYPE eSymType, SATSYMMODE eMode, + const SATUINT32_t *puiKey, void *pIV, SATBOOL bLoadIV, const void *pExtSrc, + void *pExtDest, SATUINT32_t uiLen, SATUINT32_t uiKrf, + SATUINT32_t uiDMAChConfig, SATBOOL bDecrypt); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/calcontext.h b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/calcontext.h new file mode 100644 index 0000000..fc408c2 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/calcontext.h @@ -0,0 +1,88 @@ +/* ------------------------------------------------------------------- + $Rev: 1298 $ $Date: 2017-08-04 13:04:19 -0400 (Fri, 04 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL context management functions. + ------------------------------------------------------------------- */ + +#ifndef CALCONTEXT_H +#define CALCONTEXT_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* Function resource handle. */ +/* ----- ------ ------- ---- */ +#define SATRES_DEFAULT (SATRESHANDLE)0U +#define SATRES_CALSW (SATRESHANDLE)1U + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ +typedef struct{ + SATUINT32_t uiBase; + SATRESCONTEXTPTR pContext; + }SATRESHANDLESTRUCT; + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALCONTEXT_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATRESCONTEXTPTR CALContextCurrent(const SATRESHANDLE hResource); + +extern SATR CALContextLoad(const SATRESHANDLE hResource, + const SATRESCONTEXTPTR pContext); + +extern SATR CALContextRemove(const SATRESHANDLE hResource); + +extern SATR CALContextUnload(const SATRESHANDLE hResource); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern void init_reshandles(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/calenum.h b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/calenum.h new file mode 100644 index 0000000..6281f3f --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/calenum.h @@ -0,0 +1,289 @@ +/* ------------------------------------------------------------------- + $Rev: 1566 $ $Date: 2018-09-14 11:04:30 -0400 (Fri, 14 Sep 2018) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + This file defines common types in the CAL. + + Most CAL types and constants are defined with the "SAT" prefix to + reduce the chance of name space collisions with other users. + ------------------------------------------------------------------- */ + +#ifndef CALENUM_H +#define CALENUM_H + +/* -------- */ +/* Includes */ +/* -------- */ + +/* CAL base types. */ +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ +/* NULL definitions. */ +#define SAT_NULL 0 + +/* Boolean definitions. */ +#define SAT_TRUE ((SATBOOL)1) +#define SAT_FALSE ((SATBOOL)0) + + +/* Major cipher key/SSP type. */ +/* ----- ------ ------- ----- */ +#define SATSSPTYPE_NULL (SATSSPTYPE)0 +#define SATSSPTYPE_SYMKEY (SATSSPTYPE)1 +#define SATSSPTYPE_ASYMKEY (SATSSPTYPE)2 +/* Special marker for end of list. */ +#define SATSSPTYPE_LAST (SATSSPTYPE)3 + + +/* Asymmetric Ciphers */ +/* ---------- ------- */ +#define SATASYMTYPE_NULL (SATASYMTYPE)0U +#define SATASYMTYPE_DSA_SIGN (SATASYMTYPE)1U +#define SATASYMTYPE_DSA_VERIFY (SATASYMTYPE)2U +#define SATASYMTYPE_RSA_ENCRYPT (SATASYMTYPE)3U +#define SATASYMTYPE_RSA_DECRYPT (SATASYMTYPE)4U +#define SATASYMTYPE_DH (SATASYMTYPE)5U +#define SATASYMTYPE_ECDSA_SIGN (SATASYMTYPE)6U +#define SATASYMTYPE_ECDSA_VERIFY (SATASYMTYPE)7U +#define SATASYMTYPE_ECDH (SATASYMTYPE)8U +#define SATASYMTYPE_RSA_SIGN (SATASYMTYPE)9U +#define SATASYMTYPE_RSA_VERIFY (SATASYMTYPE)10U +/* Special marker for end of list. */ +#define SATASYMTYPE_LAST (SATASYMTYPE)11U + + +/* Encoding Types */ +/* -------- ----- */ +#define SATRSAENCTYPE_NULL (SATRSAENCTYPE)0U +#define SATRSAENCTYPE_PKCS (SATRSAENCTYPE)1U +#define SATRSAENCTYPE_ANSI (SATRSAENCTYPE)2U +#define SATRSAENCTYPE_PSS (SATRSAENCTYPE)3U +/* Special marker for end of list. */ +#define SATRSAENCTYPE_LAST (SATRSAENCTYPE)4U + + +/* Symmetric Ciphers */ +/* --------- ------- */ + +/* Cipher Type. */ +#define SATSYMTYPE_NULL (SATSYMTYPE)0U +#define SATSYMTYPE_AES128 (SATSYMTYPE)1U +#define SATSYMTYPE_AES192 (SATSYMTYPE)2U +#define SATSYMTYPE_AES256 (SATSYMTYPE)3U +#define SATSYMTYPE_AESKS128 (SATSYMTYPE)4U +#define SATSYMTYPE_AESKS192 (SATSYMTYPE)5U +#define SATSYMTYPE_AESKS256 (SATSYMTYPE)6U +/* Special marker for end of list. */ +#define SATSYMTYPE_LAST (SATSYMTYPE)7U + +/* Names for common cipher key lengths, in bits. */ +#define SATSYMKEYSIZE_AES128 (SATSYMKEYSIZE)128U +#define SATSYMKEYSIZE_AES192 (SATSYMKEYSIZE)192U +#define SATSYMKEYSIZE_AES256 (SATSYMKEYSIZE)256U +#define SATSYMKEYSIZE_AESKS128 (SATSYMKEYSIZE)256U +#define SATSYMKEYSIZE_AESKS192 (SATSYMKEYSIZE)384U +#define SATSYMKEYSIZE_AESKS256 (SATSYMKEYSIZE)512U + +/* Cipher Mode. */ +#define SATSYMMODE_NULL (SATSYMMODE)0U +#define SATSYMMODE_ECB (SATSYMMODE)1U +#define SATSYMMODE_CBC (SATSYMMODE)2U +#define SATSYMMODE_CFB (SATSYMMODE)3U +#define SATSYMMODE_OFB (SATSYMMODE)4U +#define SATSYMMODE_CTR (SATSYMMODE)5U +#define SATSYMMODE_GCM (SATSYMMODE)6U +#define SATSYMMODE_GHASH (SATSYMMODE)8U +/* Special marker for end of list. */ +#define SATSYMMODE_LAST (SATSYMMODE)9U + + +/* Hashes */ +/* ------ */ +#define SATHASHTYPE_NULL (SATHASHTYPE)0U +#define SATHASHTYPE_SHA1 (SATHASHTYPE)1U +#define SATHASHTYPE_SHA224 (SATHASHTYPE)2U +#define SATHASHTYPE_SHA256 (SATHASHTYPE)3U +#define SATHASHTYPE_SHA384 (SATHASHTYPE)4U +#define SATHASHTYPE_SHA512 (SATHASHTYPE)5U +#define SATHASHTYPE_SHA512_224 (SATHASHTYPE)6U +#define SATHASHTYPE_SHA512_256 (SATHASHTYPE)7U +/* Special marker for end of list. */ +#define SATHASHTYPE_LAST (SATHASHTYPE)8U + +/* Hash sizes defined in bits */ +#define SATHASHSIZE_NULL (SATHASHSIZE)0U +#define SATHASHSIZE_SHA1 (SATHASHSIZE)160U +#define SATHASHSIZE_SHA224 (SATHASHSIZE)224U +#define SATHASHSIZE_SHA256 (SATHASHSIZE)256U +#define SATHASHSIZE_SHA384 (SATHASHSIZE)384U +#define SATHASHSIZE_SHA512 (SATHASHSIZE)512U +#define SATHASHSIZE_SHA512_224 (SATHASHSIZE)224U +#define SATHASHSIZE_SHA512_256 (SATHASHSIZE)256U + +#define SATHASHSIZE_HASH160 (SATHASHSIZE)160U +#define SATHASHSIZE_HASH192 (SATHASHSIZE)192U +#define SATHASHSIZE_HASH224 (SATHASHSIZE)224U +#define SATHASHSIZE_HASH256 (SATHASHSIZE)256U +#define SATHASHSIZE_HASH320 (SATHASHSIZE)320U +#define SATHASHSIZE_HASH384 (SATHASHSIZE)384U +#define SATHASHSIZE_HASH512 (SATHASHSIZE)512U +#define SATHASHSIZE_HASH521 (SATHASHSIZE)521U + + +/* Message Authentication Codes */ +/* ------- -------------- ----- */ + +/* Message Authentication Types */ +#define SATMACTYPE_NULL (SATMACTYPE)0U +#define SATMACTYPE_SHA1 (SATMACTYPE)1U +#define SATMACTYPE_SHA224 (SATMACTYPE)2U +#define SATMACTYPE_SHA256 (SATMACTYPE)3U +#define SATMACTYPE_SHA384 (SATMACTYPE)4U +#define SATMACTYPE_SHA512 (SATMACTYPE)5U +#define SATMACTYPE_SHA512_224 (SATMACTYPE)6U +#define SATMACTYPE_SHA512_256 (SATMACTYPE)7U +#define SATMACTYPE_AESCMAC128 (SATMACTYPE)10U +#define SATMACTYPE_AESCMAC192 (SATMACTYPE)11U +#define SATMACTYPE_AESCMAC256 (SATMACTYPE)12U +#define SATMACTYPE_AESGMAC (SATMACTYPE)13U +/* Special marker for end of list. */ +#define SATMACTYPE_LAST (SATMACTYPE)14U + + +/* Message Authentication Flags */ +#define SATMACFLAG_OP (SATMACTYPEFLAG)0U +#define SATMACFLAG_FIRSTPASS (SATMACTYPEFLAG)1U +#define SATMACFLAG_FINALPASS (SATMACTYPEFLAG)2U +#define SATMACFLAG_IKEYFINAL (SATMACTYPEFLAG)4U +#define SATMACFLAG_OKEYFINAL (SATMACTYPEFLAG)8U + + +/* Non-deterministic Random Bit Generator */ +/* ------- -------------- ----- */ + +/* NRBG register write enables */ +#define SATNRBGCONFIG_NONE 0x0 +#define SATNRBGCONFIG_RNG_CSR 0x1 +#define SATNRBGCONFIG_RNG_CNTLIM 0x2 +#define SATNRBGCONFIG_RNG_VOTIMER 0X4 +#define SATNRBGCONFIG_RNG_FMSK 0X8 + +/* RNG_CSR access defines */ +#define SATNRBGCONFIG_CSR_RODIS 0x0 +#define SATNRBGCONFIG_CSR_ROEN 0x1 +#define SATNRBGCONFIG_CSR_ROFATAL 0x2 +#define SATNRBGCONFIG_CSR_ROFATALCLR 0X4 + +/* RNG_FMSK mask values */ +#define SATNRBGCONFIG_FMSK_ROOSCF 0xFF +#define SATNRBGCONFIG_FMSK_MONOBITF 0x10000 +#define SATNRBGCONFIG_FMSK_POKERF 0x20000 +#define SATNRBGCONFIG_FMSK_RUNSF 0x40000 +#define SATNRBGCONFIG_FMSK_LRUNSF 0x80000 +#define SATNRBGCONFIG_FMSK_F1401 0xF0000 +#define SATNRBGCONFIG_FMSK_REPCNTF 0x100000 +#define SATNRBGCONFIG_FMSK_APROPF 0x200000 +#define SATNRBGCONFIG_FMSK_SP800 0x300000 + +/* RNG_ROHEALTH mask values */ +#define SATNRBGCONFIG_HLTH_ROOSCF 0x3FC0 +#define SATNRBGCONFIG_HLTH_APROPF 0x20 +#define SATNRBGCONFIG_HLTH_REPCNTF 0x10 +#define SATNRBGCONFIG_HLTH_LRUNSF 0x8 +#define SATNRBGCONFIG_HLTH_RUNSF 0x4 +#define SATNRBGCONFIG_HLTH_POKERF 0x2 +#define SATNRBGCONFIG_HLTH_MONOBITF 0x1 + + +/* Return Codes */ +/* ------ ----- */ +#define SATR_SUCCESS (SATR)0U +#define SATR_FAIL (SATR)1U +#define SATR_BADPARAM (SATR)2U +#define SATR_VERIFYFAIL (SATR)3U +#define SATR_KEYSFULL (SATR)4U +#define SATR_BUSY (SATR)5U +#define SATR_ROFATAL (SATR)6U +#define SATR_PARITYFLUSH (SATR)7U +#define SATR_SIGNFAIL (SATR)8U +#define SATR_VALIDATEFAIL (SATR)9U +#define SATR_PAF (SATR)10U +#define SATR_VALPARMX (SATR)11U +#define SATR_VALPARMY (SATR)12U +#define SATR_VALPARMB (SATR)13U +#define SATR_DCMPPARMX (SATR)14U +#define SATR_DCMPPARMB (SATR)15U +#define SATR_DCMPPARMP (SATR)16U +#define SATR_SIGNPARMD (SATR)17U +#define SATR_SIGNPARMK (SATR)18U +#define SATR_VERPARMR (SATR)19U +#define SATR_VERPARMS (SATR)20U +#define SATR_MSBICV1 (SATR)21U +#define SATR_MSBICV2 (SATR)22U +#define SATR_PADLEN (SATR)23U +#define SATR_LSB0PAD (SATR)24U +#define SATR_BADLEN (SATR)25U +#define SATR_BADHASHTYPE (SATR)26U +#define SATR_BADTYPE (SATR)27U +#define SATR_BADMODE (SATR)28U +#define SATR_BADCONTEXT (SATR)29U +#define SATR_BADHASHLEN (SATR)30U +#define SATR_BADMACTYPE (SATR)31U +#define SATR_BADMACLEN (SATR)32U +#define SATR_BADHANDLE (SATR)33U +#define SATR_FNP (SATR)34U +#define SATR_HFAULT (SATR)35U +#define SATR_NOPEND (SATR)36U +#define SATR_BADRSAENC (SATR)37U +#define SATR_BADMOD (SATR)38U +/* Special marker for end of list. */ +#define SATR_LAST (SATR)39U + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* See caltypes.h for type definitions associated with defines above. */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALENUM_C +#ifdef __cplusplus +extern "C" { +#endif + +/* NOTE: this header file does not have an associated C file. */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/calini.h b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/calini.h new file mode 100644 index 0000000..62461d1 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/calini.h @@ -0,0 +1,69 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL initialization + ------------------------------------------------------------------- */ + +#ifndef CALINI_H +#define CALINI_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALINI_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALIni(void); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/calpolicy.h b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/calpolicy.h new file mode 100644 index 0000000..2a43445 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/calpolicy.h @@ -0,0 +1,183 @@ +/* ------------------------------------------------------------------- + $Rev: 1293 $ $Date: 2017-07-27 14:09:14 -0400 (Thu, 27 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file defining CAL policy for endianess, HW/SW, etc. + ------------------------------------------------------------------- */ + +#ifndef CALPOLICY_H +#define CALPOLICY_H + +/* -------- */ +/* Includes */ +/* -------- */ + +/* The following include provides a custom configuration header file when + CALCONFIGH is defined +*/ +#ifdef CALCONFIGH +# include CALCONFIGH +#else +# error "CALCONFIGH not defined. CAL requires a custom configuration header \ +defined by CALCONFIGH. Review CAL README." +#endif + +/* ------- */ +/* Defines */ +/* ------- */ + +/* Context switching */ +#ifndef MAXRESHANDLES +# define MAXRESHANDLES 1 +#endif + +/* Little Endian (default) / Big Endian */ +#ifndef SAT_LITTLE_ENDIAN +# define SAT_LITTLE_ENDIAN 1 +#endif + +/* PK SW Point Validate Checking */ +#ifndef PKSWCHKVALPT +# define PKSWCHKVALPT 1 +#endif + +/* DMA */ +#ifndef USE_X52EXEC_DMA +# define USE_X52EXEC_DMA 0 +#endif + +/* SHA */ +#define MAXHASHLEN 512 +#define MAXHMACKEYLEN 512 + +/* RNG */ +#define NRBGSIMNUMRO 16 +#define ENTROPYMEMBLOCKS 7 +#define BUFMEMBLOCKS 3 +#ifndef RNXBLKLEN +#define RNXBLKLEN 32 +#endif +#ifndef RNXBLKOUTLEN +#define RNXBLKOUTLEN 4 +#endif + +#ifndef USENRBGSW +# define USENRBGSW 0 +#endif + +/* PK */ +#ifndef PKX0_BASE +# define PKX0_BASE 0xE0000000u +#endif + +#if USEPKSW +# ifndef MAXMODSIZE +# define MAXMODSIZE 8192 +# endif +# ifndef PKSWBUFSIZE +# define PKSWBUFSIZE 15*(MAXMODSIZE/32) +# endif +#else +# define USEPKSW 0 +#endif + +/* Set default values for X52 configuration defines. */ +#ifndef X52_CFG_OPT +# define X52_CFG_OPT 0 +#endif +#ifndef X52_LIR_LEN +# define X52_LIR_LEN 0x800 +#endif +#ifndef X52_BER_LEN +# define X52_BER_LEN 0x400 +#endif +#ifndef X52_MMR_LEN +# define X52_MMR_LEN 0x400 +#endif +#ifndef X52_TSR_LEN +# define X52_TSR_LEN 0x400 +#endif +#ifndef X52_FPR_LEN +# define X52_FPR_LEN 0x400 +#endif +#if X52_LIR_ROM_LEN>0 && X52_LIR_LEN>X52_LIR_ROM_LEN +# define PKX_OFFSET 2048 +#else +# define PKX_OFFSET 0 +#endif + +/* X52 Configuration Options */ +#define AESPKX (X52_CFG_OPT&0x00000001u) +#define AESPKXGCM (X52_CFG_OPT&0x00000008u) +#define AESPKXFASTKEY (X52_CFG_OPT&0x01000000u) +#define SHAPKXOPT1 (X52_CFG_OPT&0x00000020u) +#define SHAPKXOPT224 (X52_CFG_OPT&0x00000040u) +#define SHAPKXOPT256 (X52_CFG_OPT&0x00000080u) +#define SHAPKXOPT384 (X52_CFG_OPT&0x00000100u) +#define SHAPKXOPT512 (X52_CFG_OPT&0x00000200u) +#define SHAPKXOPT5124 (X52_CFG_OPT&0x00400000u) +#define SHAPKXOPT5126 (X52_CFG_OPT&0x00800000u) + +/* Define the maximum number of return values that may be handled using + CAL*TrfRes() function(s). +*/ +#define CAL_MAXTRFS 4 + +/* Volatile pointer operations */ +/* These access macros are designed so that they may be redefined by a + user compiling CAL. +*/ +#ifndef CALREAD32 +# define CALREAD32(ptr) ( *(ptr) ) +#endif +#ifndef CALWRITE32 +# define CALWRITE32(ptr, val) ( *(ptr)=val ) +#endif +#ifndef CALPOLL32 +# define CALPOLL32(ptr, val, mask) while ((*(ptr) & (mask)) != (val)); +#endif + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +#ifndef CALPOLICY_C +#ifdef __cplusplus +extern "C" { +#endif + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +/* NOTE: this header file does not have an associated C file. */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/caltypes.h b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/caltypes.h new file mode 100644 index 0000000..3b2fe0b --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/caltypes.h @@ -0,0 +1,328 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + This file defines common types in the CAL. + + Since support for the C99 stdint.h integer types is not universal, + these are defined herein and may require customization from compiler + to compiler, or use of the stdint.h header, if present (recommended). + + C99 supports 64-bit types; however, support in older compilers is + spotty. For those that do not support it, the macro NO64BITINT may be + defined by the user to prevent defintion of 64-bit types. This is + generally safe with CAL-PK and CAL-SYM; however, this is incompatible + with CAL-SW. + + Most CAL types and constants are defined with the "SAT" prefix to + reduce the chance of name space collisions with other users. + ------------------------------------------------------------------- */ + +#ifndef CALTYPES_H +#define CALTYPES_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* Base Types */ +/* ---- ----- */ + +/* The user may compile using stdint.h instead of the definitions below + by defining the macro INC_STDINT_H. */ +#ifdef INC_STDINT_H +#include +#endif + +/* Integer type abstraction layer. */ +#ifndef INC_STDINT_H + +typedef unsigned char uint8_t; +typedef signed char int8_t; + +typedef unsigned short uint16_t; +typedef signed short int16_t; + +typedef unsigned int uint32_t; +typedef int int32_t; + +/* stdint.h is a C99 feature, and C99 supports 64-bit ints, so this is + immune to the macro used to disable 64-bit int support. +*/ +typedef unsigned long long uint64_t; +typedef long long int64_t; + +typedef long uintptr_t; + +#endif + +/* Boolean type. */ +typedef uint8_t SATBOOL; + +/* Unsigned integer type */ +typedef uint8_t SATUINT8_t; +typedef uint16_t SATUINT16_t; +typedef uint32_t SATUINT32_t; +#ifdef INC_STDINT_H +typedef uint64_t SATUINT64_t; +#else +#ifndef NO64BITINT +typedef uint64_t SATUINT64_t; +#endif +#endif + +/* Integer type */ +typedef int8_t SATINT8_t; +typedef int16_t SATINT16_t; +typedef int32_t SATINT32_t; +#ifdef INC_STDINT_H +typedef int64_t SATINT64_t; +#else +#ifndef NO64BITINT +typedef int64_t SATINT64_t; +#endif +#endif + +typedef uintptr_t SATUINTPTR_t; + +/* Major cipher key/SSP type. */ +/* ----- ------ ------- ----- */ +typedef uint8_t SATSSPTYPE; +typedef SATSSPTYPE * SATSSPTYPEPTR; + + +/* Asymmetric Ciphers */ +/* ---------- ------- */ + +/* Cipher type. */ +typedef uint8_t SATASYMTYPE; +typedef SATASYMTYPE * SATASYMTYPEPTR; + +/* Cipher size type. */ +typedef uint16_t SATASYMSIZE; +typedef SATASYMSIZE * SATASYMSIZEPTR; + +/* Cipher encoding */ +typedef uint8_t SATRSAENCTYPE; +typedef SATRSAENCTYPE * SATRSAENCTYPEPTR; + +/* DSA public/private key. */ +typedef struct { + uint16_t ui16PLen; /* Length of modulus p. */ + uint16_t ui16QLen; /* Length of prime divisor q. */ + uint32_t *pui32P; /* Prime modulus p. */ + uint32_t *pui32Q; /* Prime divisor q. */ + uint32_t *pui32G; /* Generator g, length==p. */ + uint32_t *pui32X; /* Private key x, length==p. */ + uint32_t *pui32Y; /* Private key y, length==q. */ +} SATASYMDSADOMAIN; +typedef SATASYMDSADOMAIN * SATASYMDSADOMAINPTR; + + +/* Symmetric Ciphers */ +/* --------- ------- */ + +/* Cipher type. */ +typedef uint8_t SATSYMTYPE; +typedef SATSYMTYPE * SATSYMTYPEPTR; + +/* Cipher key size type (in bits). */ +typedef uint16_t SATSYMKEYSIZE; +typedef SATSYMKEYSIZE * SATSYMKEYSIZEPTR; + +/* Cipher mode type. */ +typedef uint8_t SATSYMMODE; +typedef SATSYMMODE * SATSYMMODEPTR; + +/* Cipher key object. */ +/* Other fields are only valid when sstCipher!=SATSYMTYPE_NULL. */ +typedef struct { + SATSYMTYPE sstCipher; + SATSYMKEYSIZE ssksKeyLen; + uint32_t *pui32Key; +} SATSYMKEY; +typedef SATSYMKEY * SATSYMKEYPTR; + + +/* Hashes */ +/* ------ */ + +/* Hash type. */ +typedef uint8_t SATHASHTYPE; +typedef SATHASHTYPE * SATHASHTYPEPTR; + +/* Hash size type (in bits). */ +typedef uint16_t SATHASHSIZE; +typedef SATHASHSIZE * SATHASHSIZEPTR; + + +/* Context switching. */ +/* ----- ------ ------- ----- */ + +typedef uint32_t SATRESHANDLE; +typedef SATRESHANDLE * SATRESHANDLEPTR; + +typedef struct { + SATHASHTYPE sshashtype; + uint32_t uiRunLen; + uint32_t uiHash[MAXHASHLEN/32]; /* holds intermed hash */ +} SHACTX; + +typedef struct { + SATHASHTYPE sshashtype; + uint32_t uiRunLen; + uint32_t uiKeyLen; + uint32_t uiHash[MAXHASHLEN/32]; /* holds intermed hash */ + uint32_t uiKey[MAXHMACKEYLEN/32]; /* holds intermed key */ +} SHAHMACCTX; + +typedef struct { + uint8_t uiContextType; + union{ + SHACTX ctxSHA; + SHAHMACCTX ctxMAC; + }CTXUNION; +} SATRESCONTEXT; +typedef SATRESCONTEXT * SATRESCONTEXTPTR; + + +/* Message Authentication Codes */ +/* ------- -------------- ----- */ + +/* MAC type. */ +typedef uint8_t SATMACTYPE; +typedef SATMACTYPE * SATMACTYPEPTR; +typedef uint8_t SATMACTYPEFLAG; + + +/* Random Number Generator */ +/* ------ ------ --------- */ +typedef union { + uint32_t u32[4]; + uint8_t u8[16]; +} uint128_t; + +typedef struct { + uint128_t ui128V; + uint128_t ui128K[2]; + uint32_t uiReseedCnt; + uint32_t uiReseedLim; + uint32_t uiEntropyFactor; + SATSYMKEYSIZE eStrength; + SATBOOL bTesting; + +} DRBGCTX; + +typedef DRBGCTX * DRBGCTXPTR; + + +/* Function Return Code */ +/* -------- ------ ---- */ +typedef uint16_t SATR ; +typedef SATR * SATRPTR ; + + +/* Transfer Results */ +/* -------- ------- */ +typedef struct { + SATUINT32_t uiLen; + volatile SATUINT32_t* vpuiSrc; + void* pDest; +} SATDATATRF; + +typedef struct { + SATUINT32_t uiResType; + SATUINT32_t uiNumDataTrf; + SATDATATRF dtrfArray[CAL_MAXTRFS]; +} SATRESULT; + + +/* EC Ultra Structs */ +/* -- ----- ------- */ +typedef uint32_t SATECTYPE; + +typedef struct { + SATUINT32_t uiLen; + SATUINT32_t* puiX; + SATUINT32_t* puiY; +} SATECPOINT; + +typedef struct { + SATUINT32_t uiLen; + SATUINT32_t* puiMod; + SATUINT32_t* puiMontPrecompute; + SATUINT32_t* puiRSqd; +} SATECMONTMOD; + +typedef struct { + SATUINT32_t uiCurveSize; + SATECTYPE eCurveType; + SATECPOINT* pBasePoint; + SATECMONTMOD* pModP; + SATECMONTMOD* pModN; + SATUINT32_t* puiA; + SATUINT32_t* puiB; +} SATECCURVE; + +typedef struct { + SATUINT32_t uiLen; + SATUINT32_t* puiSigR; + SATUINT32_t* puiSigS; + SATUINT32_t* puiSigX; + SATUINT32_t* puiSigY; +} SATECDSASIG; + +typedef struct { + SATHASHSIZE sHashLen; + SATUINT32_t* puiHash; +} SATHASH; + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALTYPES_C +#ifdef __cplusplus +extern "C" { +#endif + +/* NOTE: this header file does not have an associated C file. */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/config_user.h b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/config_user.h new file mode 100644 index 0000000..3728565 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/config_user.h @@ -0,0 +1,44 @@ +/* ------------------------------------------------------------------- + $Rev: 727 $ $Date: 2017-10-20 16:50:53 -0400 (Fri, 20 Oct 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + + User configuration file to include/exclude CAL components. + ------------------------------------------------------------------- */ + +#ifndef CALCONFIG_F5200_H +#define CALCONFIG_F5200_H + +#include "x52cfg_user.h" +#include + +extern uint32_t g_user_crypto_base_addr; + +#define SAT_LITTLE_ENDIAN 1 +#define PKX0_BASE (g_user_crypto_base_addr) +#define USEPKX 1 +#define USEAESPKX 1 +#define USESHAPKX 1 +#define USEDRBGPKX 1 +#define USENRBGPKX 1 +#define USECALCTX 1 + +#endif diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/drbg.h b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/drbg.h new file mode 100644 index 0000000..dba16f7 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/drbg.h @@ -0,0 +1,91 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for DRBG functions for CAL + ------------------------------------------------------------------- */ + +#ifndef DRBG_H +#define DRBG_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ +#define CALDRBGENTROPYFACTOR 2 + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef DRBG_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALDRBGInstantiate(const SATUINT32_t *puiNonce, + SATUINT32_t uiNonceLen, const SATUINT32_t *puiPzStr, + SATUINT32_t uiPzStrLen, SATSYMKEYSIZE eStrength, + SATUINT32_t uiEntropyFactor, SATUINT32_t uiReseedLim, SATBOOL bTesting); + +extern SATR CALDRBGReseed(const SATUINT32_t *puiAddIn, SATUINT32_t uiAddInLen); + +extern SATR CALDRBGGenerate(const SATUINT32_t *puiAddIn, SATUINT32_t uiAddInLen, + SATBOOL bPredResist, SATUINT32_t *puiOut, SATUINT32_t uiOutBlocks); + +extern SATR CALDRBGUninstantiate(void); + +extern SATR CALDRBGGetCtx(DRBGCTXPTR drbgCtxExt); + +extern SATR CALDRBGLoadCtx(DRBGCTXPTR drbgCtxExt); + +extern SATR CALDRBGGetbInst(void); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +extern SATR CALDrbgTrfRes(SATBOOL bBlock); + +extern void CALDrbgIni(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/drbgf5200.h b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/drbgf5200.h new file mode 100644 index 0000000..d7f6c4c --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/drbgf5200.h @@ -0,0 +1,120 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for F5200 DRBG function hardware implementations + in CAL. + ------------------------------------------------------------------- */ + +#ifndef DRBGF5200_H +#define DRBGF5200_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ +#define RNXEFACTOR (X52BER+2) +#define RNXIRLEN (X52BER+2) +#define RNXKEYORD (X52BER+3) +#define RNXRESPRED (X52BER+4) +#define RNXTESTSEL (X52BER+5) +#define RNXBADDIN (X52BER+6) +#define RNXPPSTR (X52BER+7) +#define RNXPCTX (X52BER+8) +#define RNXPRENT (X52BER+13) +#define RNXITMP3 (X52BER+20) +#define RNXPCTX2 (X52BER+22) +/* These use same locs as tb generator, but can change */ +#define RNXRDATA (X52BER_ENDIAN+0x24) +#define RNXAIDATAOFF 0x0062 +#define RNXAIDATA (X52BER_ENDIAN+RNXAIDATAOFF) +#define RNXCTXOFF 0x0094 +#define RNXCTX (X52FPR+RNXCTXOFF) +#define RNXCTXV (X52FPR_ENDIAN+RNXCTXOFF+6) +#define RNXCTXVMMR (X52MMR_ENDIAN+RNXCTXOFF+6) +#define RNXTESTENT (X52TSR_ENDIAN+8) + +#define RNXCTXWORDS 18 +#define RNXBLENLOC (RNXCTX+RNXCTXWORDS) +#define RNXBOUTLENLOC (RNXCTX+RNXCTXWORDS+1) + +#define RNXMAXTESTENT32 512 +#define CALDRBGMAXADDINLEN X52_BER_LEN-RNXAIDATAOFF-4 +#define CALDRBGMAXPSNONCELEN X52_BER_LEN-RNXAIDATAOFF-4 + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef DRBGF5200_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATR drbgf5200Ini(void); + +extern SATR drbgf5200TrfRes(SATBOOL bBlock); + +extern SATR drbgf5200instantiate(const SATUINT32_t *puiNonce, + SATUINT32_t uiNonceLen, const SATUINT32_t *puiPzStr, SATUINT32_t uiPzStrLen, + SATSYMKEYSIZE eStrength, SATUINT32_t uiEntropyFactor, + SATUINT32_t uiReseedLim, SATBOOL bTesting); + +extern SATR drbgf5200reseed(const SATUINT32_t *puiAddIn, + SATUINT32_t uiAddInLen); + +extern SATR drbgf5200generate(const SATUINT32_t *puiAddIn, + SATUINT32_t uiAddInLen, SATBOOL bPredResist, SATUINT32_t uiReqLen, + SATUINT32_t *puiOut); + +extern SATR drbgf5200uninstantiate(void); + +extern SATR drbgf5200getctx(DRBGCTXPTR drbgCtxExt); + +extern SATR drbgf5200loadctx(DRBGCTXPTR drbgCtxExt); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/hash.h b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/hash.h new file mode 100644 index 0000000..f3fd6d4 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/hash.h @@ -0,0 +1,102 @@ +/* ------------------------------------------------------------------- + $Rev: 1293 $ $Date: 2017-07-27 14:09:14 -0400 (Thu, 27 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL hash functions. + ------------------------------------------------------------------- */ + +#ifndef HASH_H +#define HASH_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ +extern const SATHASHSIZE uiHashWordLen[SATHASHTYPE_LAST]; + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef HASH_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALHash(SATHASHTYPE eHashType, const void *pMsg, + SATUINT32_t uiMsgLen, void *pHash); + +extern SATR CALHashDMA(SATHASHTYPE eHashType, const void *pMsg, + SATUINT32_t uiMsgLen, void *pHash, SATUINT32_t uiDMAChConfig); + +extern SATR CALHashCtx(const SATRESHANDLE hResource, + const SATRESCONTEXTPTR pContext, const void *pMsg, SATUINT32_t uiMsgLen, + void *pHash, const SATBOOL bFinal); + +extern SATR CALHashCtxIni(const SATRESCONTEXTPTR pContext, + const SATHASHTYPE eHashType); + +extern SATR CALHashIni(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen); + +extern SATR CALHashWrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR CALHashRead(void *pHash); + +extern SATR CALKeyTree(SATBOOL bPathSizeSel, const SATUINT32_t* puiKey, + SATUINT8_t uiOpType, const SATUINT32_t* puiPath, SATUINT32_t* puiKeyOut); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATUINT32_t iGetHashLen(SATHASHTYPE eHashType); + +extern SATUINT32_t iGetBlockLen(SATHASHTYPE eHashType); + +extern SATR CALHashCtxLoad(const SATRESHANDLE hResource, + SATRESCONTEXTPTR const pContext, SATUINT32_t uiRunLen); + +extern SATUINT32_t iGetRunLen(SATRESCONTEXTPTR const pContext); + +extern SATR CALHashTypeIni(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/mac.h b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/mac.h new file mode 100644 index 0000000..acdc767 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/mac.h @@ -0,0 +1,95 @@ +/* ------------------------------------------------------------------- + $Rev: 1296 $ $Date: 2017-08-01 13:54:48 -0400 (Tue, 01 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL MAC functions. + ------------------------------------------------------------------- */ + +#ifndef MAC_H +#define MAC_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef MAC_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALMAC(SATMACTYPE eMACType, const SATUINT32_t *pKey, SATUINT32_t uiKeyLen, + const void *pMsg, SATUINT32_t uiMsgLen, void *pMAC); + +extern SATR CALMACDMA(SATMACTYPE eMACType, const SATUINT32_t *pKey, + SATUINT32_t uiKeyLen, const void *pMsg, SATUINT32_t uiMsgLen, + const void *pMAC, SATUINT32_t uiDMAChConfig); + +extern SATR CALMACIni(SATMACTYPE eMACType, const SATUINT32_t *pKey, + SATUINT32_t uiKeyLen, SATUINT32_t uiMsgLen); + +extern SATR CALMACCtx(const SATRESHANDLE hResource, + const SATRESCONTEXTPTR pContext, const void *pMsg, SATUINT32_t uiMsgLen, + void *pHash, const SATUINT8_t uiFlag); + +extern SATR CALMACCtxIni(const SATRESCONTEXTPTR pContext, const SATHASHTYPE eHashType, + const SATUINT32_t *pKey, SATUINT32_t uiKeyLen); + +extern SATR CALMACWrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR CALMACRead(void *pMAC); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATUINT32_t iGetMACKeyLen(SATMACTYPE eMACType); + +extern SATR CALMACCtxLoad(const SATRESHANDLE hResource, + SATRESCONTEXTPTR const pContext, SATUINT32_t uiRunLen); + +extern SATUINT32_t iGetMACRunLen(SATRESCONTEXTPTR const pContext); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/miv-rv32i-user-crypto-lib.a b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/miv-rv32i-user-crypto-lib.a new file mode 100644 index 0000000..5fda638 Binary files /dev/null and b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/miv-rv32i-user-crypto-lib.a differ diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/miv-rv32imc-user-crypto-lib.a b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/miv-rv32imc-user-crypto-lib.a new file mode 100644 index 0000000..ee7bcf4 Binary files /dev/null and b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/miv-rv32imc-user-crypto-lib.a differ diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/nrbg.h b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/nrbg.h new file mode 100644 index 0000000..d517065 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/nrbg.h @@ -0,0 +1,83 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for NRBG functions for CAL. + ------------------------------------------------------------------- */ + +#ifndef NRBG_H +#define NRBG_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef NRBG_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALNRBGSetTestEntropy(SATUINT32_t * puiEntropy, + SATUINT32_t uiEntLen32); + +extern SATR CALNRBGGetEntropy(SATUINT32_t * puiEntropy, SATUINT32_t uiEntLen32, + SATBOOL bTesting); + +extern SATR CALNRBGConfig(SATUINT32_t uiWriteEn, SATUINT32_t uiCSR, + SATUINT32_t uiCntLim, SATUINT32_t uiVoTimer, SATUINT32_t uiFMsk, + SATUINT32_t* puiStatus); + +extern SATUINT32_t CALNRBGHealthStatus(void); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATUINT32_t CALNRBGGetTestEntLen(void); + +extern SATR nrbgpkxgetentropy(SATUINT32_t * puiEntropy, + SATUINT32_t uiEntLen32); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/pk.h b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/pk.h new file mode 100644 index 0000000..5983d9a --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/pk.h @@ -0,0 +1,302 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for for CAL PK. + ------------------------------------------------------------------- */ + +#ifndef PK_H +#define PK_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef PK_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALPKTrfRes(SATBOOL bBlock); + +extern SATR CALDSASign(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALDSASignCM(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALDSASignHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, const SATUINT32_t* puiK, + const SATUINT32_t* puiX, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, SATUINT32_t uiN, + SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALDSASignHashCM(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, const SATUINT32_t* puiK, + const SATUINT32_t* puiX, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, SATUINT32_t uiN, + SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALDSAVerify(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiY, const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, + const SATUINT32_t* puiQMu, SATUINT32_t uiN, SATUINT32_t uiL); + +extern SATR CALDSAVerifyHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, const SATUINT32_t* puiY, + const SATUINT32_t* puiR, const SATUINT32_t* puiS, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALECDHC(const SATUINT32_t* puiS, const SATUINT32_t* puiWx, + const SATUINT32_t* puiWy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t* puiK, const SATUINT32_t* puiR, + const SATUINT32_t* puiRMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiZ); + +extern SATR CALECDSASign(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALECDSASignTwist(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALECDSASignCM(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALECDSASignTwistCM(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALECDSASignHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiK, const SATUINT32_t* puiD, const SATUINT32_t* puiB, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSASignHashCM(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiK, const SATUINT32_t* puiD, const SATUINT32_t* puiB, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSASignTwistHash(const SATUINT32_t* puiMsg, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSAVerify(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS,const + SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress); + +extern SATR CALECDSAVerifyTwist(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALECDSAVerifyHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSAVerifyTwistHash(const SATUINT32_t* puiMsg, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALECMult(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECMultCM(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t* puiN, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress, SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECMultTwist(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiLen, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECMultTwistCM(const SATUINT32_t* puiMul, + const SATUINT32_t* puiPx, const SATUINT32_t* puiPy, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiMod,const SATUINT32_t* puiMu, + const SATUINT32_t* puiN, SATUINT32_t uiLen, SATUINT32_t* puiRx, + SATUINT32_t* puiRy); + +extern SATR CALECMultAdd(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiB, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen, SATUINT32_t uiPtPCompress, SATUINT32_t uiPtQCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECPtValidate(const SATUINT32_t* puiPx, const SATUINT32_t* puiPy, + const SATUINT32_t* puiB, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen); + +extern SATR CALECKeyPairGen(const SATUINT32_t* puiC, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + const SATUINT32_t* puiNM1, const SATUINT32_t* puiNM1Mu, const SATUINT32_t* puiB, + SATUINT32_t* puiD, SATUINT32_t* puiQx, SATUINT32_t* puiQy, SATUINT32_t uiLen); + +extern SATR CALExpo(const SATUINT32_t* puiBase, const SATUINT32_t* puiExpo, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALExpoCM(const SATUINT32_t* puiBase, const SATUINT32_t* puiExpo, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALMMult(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALMMultAdd(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiC, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALModRed(const SATUINT32_t* puiA, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiALen, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPreCompute(const SATUINT32_t* puiMod, SATUINT32_t* puiMu, + SATUINT32_t uiModLen); + +extern SATR CALRSACRT(const SATUINT32_t* puiCipher, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ,const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiLen, SATUINT32_t* puiPlain); + +extern SATR CALRSACRTCM(const SATUINT32_t* puiCipher, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t * puiE, const SATUINT32_t* puiP, + const SATUINT32_t* puiQ, const SATUINT32_t * puiN, + const SATUINT32_t * puiNMu, SATUINT32_t uiLen, SATUINT32_t uiELen, + SATUINT32_t* puiPlain); + +extern SATR CALRSACRTSign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + const SATUINT32_t* puiN, SATUINT32_t uiLen, SATUINT32_t* puiSig); + +extern SATR CALRSACRTSignCM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, const SATUINT32_t* puiQ, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSig); + +extern SATR CALRSACRTSignHash(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ,const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + const SATUINT32_t* puiN, SATUINT32_t uiMsgLen, SATUINT32_t uiModLen, + SATUINT32_t* puiSig, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALRSACRTSignHashCM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, const SATUINT32_t* puiQ, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, SATUINT32_t* puiSig, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALRSASign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiD, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, SATUINT32_t* puiSig); + +extern SATR CALRSASignHash(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiD, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, SATUINT32_t uiModLen, + SATUINT32_t* puiSig, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALRSAVerify(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, + const SATUINT32_t* puiSig); + +extern SATR CALRSAVerifyHash(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiE, SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, const SATUINT32_t* puiSig, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPurge52(SATBOOL bVerify); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/pkx.h b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/pkx.h new file mode 100644 index 0000000..c23dda4 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/pkx.h @@ -0,0 +1,409 @@ +/* ------------------------------------------------------------------- + $Rev: 1298 $ $Date: 2017-08-04 13:04:19 -0400 (Fri, 04 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for for CAL PK. + ------------------------------------------------------------------- */ + +#ifndef PKX_H +#define PKX_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* X5200 Addressing */ +#define X52BER ((volatile SATUINT32_t *) (PKX0_BASE + 0x00000000u)) +#define X52MMR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00001000u)) +#define X52TSR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00002000u)) +#define X52FPR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00003000u)) +#define X52LIR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00004000u)) +#define X52CSR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00007F80u)) +#define X52CSRMERRS ((volatile SATUINT32_t *) (PKX0_BASE + 0x00007F8Cu)) +#define X52CSRMERRT0 ((volatile SATUINT32_t *) (PKX0_BASE + 0x00007F94u)) + +#if SAT_LITTLE_ENDIAN +#define X52BER_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00008000u)) +#define X52MMR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00009000u)) +#define X52TSR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x0000A000u)) +#define X52FPR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x0000B000u)) +#define X52DMACONFIG_ENDIAN 0x8 +#else +#define X52BER_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00000000u)) +#define X52MMR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00001000u)) +#define X52TSR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00002000u)) +#define X52FPR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00003000u)) +#define X52DMACONFIG_ENDIAN 0x0 +#endif + +/* X5200 Macros */ +#define X52GO(x) (0x10 | ((x)<<8)) + +/* Counter Measures */ +#define RANDLEN 4 + +/* X5200 CSRMAIN bit field masks. */ +#define X52CSRMAINRST 1 +#define X52CSRMAINCCMPLT 2 +#define X52CSRMAINCMPLT 4 +#define X52CSRMAINBUSY 8 +#define X52CSRMAINGO 0x10 +#define X52CSRMAINPURGE 0x20 +#define X52CSRMAINECDIS 0x40 +#define X52CSRMAINALARM 0x80 +#define X52CSRMAINLIRA ((0xFFF) << 8) +#define X52CSRMERRSSEC ((0x2) << 24) +#define X52CSRMERRSA 0x1FFF + +/* Address pointers for ROM'd P-curve moduli */ +#define P192_MOD (&uiROMMods[0]) +#define P224_MOD (&uiROMMods[1]) +#define P256_MOD (&uiROMMods[2]) +#define P384_MOD (&uiROMMods[3]) +#define P521_MOD (&uiROMMods[4]) + +/* X5200 Addressing Flags */ +#define X52BYTEREVERSE_FLAG 1 +#define X52WORDREVERSE_FLAG 2 +#define X52BYTEREVERSE 0x00002000 +#define X52WORDREVERSE 0x00004000 +#define X52ADDRESSRANGE 0x2000 + +/* X5200 DMA channel configuration constants. */ +#define X52CCR_DEFAULT 0 /* BSIZE=auto, ESWP=none, PROT=user, INC=inc */ +#define X52CCR_BSIZEAUTO 0 /* BSIZE=auto */ +#define X52CCR_BSIZEBYTE 0x10 /* BSIZE=byte */ +#define X52CCR_BSIZEHWORD 0x20 /* BSIZE=half word */ +#define X52CCR_BSIZEWORD 0x30 /* BSIZE=word */ +#define X52CCR_ESWPNONE 0 /* ESWP=none */ +#define X52CCR_ESWPWORD 0x8 /* ESWP=swap bytes in word [0123]->[3210] */ +#define X52CCR_PROTUSER 0 /* PROT=user */ +#define X52CCR_PROTPRIV 0x2 /* PROT=priv */ +#define X52CCR_INCADDR 0 /* INC=inc */ +#define X52CCR_NOINCADDR 0x1 /* INC=non-inc */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef PKX_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern void CALPKXIni(void); + +extern void CALPKMem32Load(volatile SATUINT32_t * puiDst, + const SATUINT32_t * puiSrc, SATUINT32_t uiNum ); + +extern SATR CALPKXTrfRes(SATBOOL bBlock); + +extern SATR CALPKXPreCompute(const SATUINT32_t* puiMod, SATUINT32_t* puiMu, + SATUINT32_t uiModLen); + +extern SATR CALPKXExpo(const SATUINT32_t* puiBase, const SATUINT32_t* puiExpo, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALPKXExpoCM(const SATUINT32_t* puiBase, + const SATUINT32_t* puiExpo, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPKXDSASign(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXDSASignCM(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXDSASHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATUINT32_t uiDMAChConfig, const SATBOOL bCM); + +extern SATR CALPKXDSAVerify(const SATUINT32_t *puiHash, + const SATUINT32_t *puiG, const SATUINT32_t *puiY, + const SATUINT32_t *puiSigR, const SATUINT32_t *puiSigS, + const SATUINT32_t *puiP, const SATUINT32_t *puiPMu, + const SATUINT32_t *puiQ, const SATUINT32_t *puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL); + +extern SATR CALPKXDSAVHDMA(const SATUINT32_t *puiExtInput, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t *puiG, const SATUINT32_t *puiY, + const SATUINT32_t *puiSigR, const SATUINT32_t *puiSigS, + const SATUINT32_t *puiP, const SATUINT32_t *puiPMu, const SATUINT32_t *puiQ, + const SATUINT32_t *puiQMu, SATUINT32_t uiN, SATUINT32_t uiL, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXModRed(const SATUINT32_t* puiA, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiALen, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPKXMMult(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPKXMMultAdd(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiC, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALPKXECMult(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECMultTwist(const SATUINT32_t* puiMul, + const SATUINT32_t* puiPx,const SATUINT32_t* puiPy, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen, SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECMultCM(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t * puiN, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress, SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECMultTwistCM(const SATUINT32_t* puiMul, + const SATUINT32_t* puiPx, const SATUINT32_t* puiPy, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + const SATUINT32_t * puiN, SATUINT32_t uiLen, SATUINT32_t* puiRx, + SATUINT32_t* puiRy); + +extern SATR CALPKXECMultAdd(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiB, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen, SATUINT32_t uiPtPCompress, SATUINT32_t uiPtQCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECDSASign(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASignTwist(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx,const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASignCM(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASignTwistCM(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASH(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + const SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASHCM(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + const SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, SATUINT32_t uiDMAChConfig, + const SATBOOL bCM); + +extern SATR CALPKXECDSASTwistH(const SATUINT32_t* puiHash, + const SATHASHTYPE eHashType, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiK, const SATUINT32_t* puiD, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, const SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASTwistHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECDSAVerify(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVerifyTwist(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVH(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB,const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + const SATUINT32_t uiLen, const SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB,const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECDSAVTwistH(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, const SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVTwistHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECDHC(const SATUINT32_t* puiS, const SATUINT32_t* puiWx, + const SATUINT32_t* puiWy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t* puiK, const SATUINT32_t* puiR, + const SATUINT32_t* puiRMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiZ); + +extern SATR CALPKXRSACRT(const SATUINT32_t* puiCipher, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, SATUINT32_t uiLen, + SATUINT32_t* puiPlain); + +extern SATR CALPKXRSACRTCM(const SATUINT32_t* puiCipher, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiE, + const SATUINT32_t* puiP, const SATUINT32_t* puiQ, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, const SATUINT32_t uiLen, const SATUINT32_t uiELen, + SATUINT32_t* puiPlain); + +extern SATR CALPKXRSACRTSign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiCipher, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, + const SATUINT32_t* puiQMu, const SATUINT32_t* puiN, SATUINT32_t uiLen, + SATUINT32_t* puiS); + +extern SATR CALPKXRSACRTSignCM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, + const SATUINT32_t* puiP, const SATUINT32_t* puiQ, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSig); + +extern SATR CALPKXRSACRTSHDMA(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + const SATUINT32_t* puiN, SATUINT32_t uiMsgLen, SATUINT32_t uiModLen, + SATUINT32_t* puiSig, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXRSACRTSHDMACM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, + const SATUINT32_t* puiP, const SATUINT32_t* puiQ, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, SATUINT32_t uiLen, + SATUINT32_t* puiSig, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXRSASign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiD, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, SATUINT32_t* puiSig); + +extern SATR CALPKXRSASHDMA(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiD, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, SATUINT32_t* puiSig, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXRSAVerify(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, + const SATUINT32_t* puiS); + +extern SATR CALPKXRSAVHDMA(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiE,SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, const SATUINT32_t* puiS, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECPtValidate(const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiLen); + +extern SATR CALPKXECKeyPairGen(const SATUINT32_t* puiC, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + const SATUINT32_t* puiNM1, const SATUINT32_t* puiNM1Mu, const SATUINT32_t* puiB, + SATUINT32_t* puiD, SATUINT32_t* puiQx, SATUINT32_t* puiQy, SATUINT32_t uiLen); + +extern SATR CALPKXPurge52(SATBOOL bVerify); + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ +extern SATRESULT SATResults; + +/* -------- ------ --------- */ +/* External Global Constants */ +/* -------- ------ --------- */ +extern const SATUINT32_t uiROMMods[]; + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/pkxlib.h b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/pkxlib.h new file mode 100644 index 0000000..fb4c0fc --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/pkxlib.h @@ -0,0 +1,95 @@ +/* ------------------------------------------------------------------- + $Rev: 1434 $ $Date: 2017-10-20 16:46:16 -0400 (Fri, 20 Oct 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for PKX-5200 Library. + ------------------------------------------------------------------- */ + +#ifndef PKXLIB_H +#define PKXLIB_H + +#include "caltypes.h" +#include "calpolicy.h" + +#define PKX_JMP_NONE (0xFFFFu + PKX_OFFSET) + +/* jump table entry points: starting PC value */ +#define PKX_JMP_RECIP_PRECOMPUTE (0x0000 + PKX_OFFSET) +#define PKX_JMP_MOD_EXP (0x0002 + PKX_OFFSET) +#define PKX_JMP_RSA_CRT (0x0004 + PKX_OFFSET) +#define PKX_JMP_EC_PTMUL (0x0006 + PKX_OFFSET) +#define PKX_JMP_EC_DSA_SIGN (0x0008 + PKX_OFFSET) +#define PKX_JMP_EC_DSA_VERIFY (0x000A + PKX_OFFSET) +#define PKX_JMP_DSA_SIGN (0x000C + PKX_OFFSET) +#define PKX_JMP_DSA_VERIFY (0x000E + PKX_OFFSET) +#define PKX_JMP_MOD_MULT (0x0010 + PKX_OFFSET) +#define PKX_JMP_MOD_RED (0x0012 + PKX_OFFSET) +#define PKX_JMP_EC_PTDECOMP (0x0014 + PKX_OFFSET) +#define PKX_JMP_EC_DHC (0x0016 + PKX_OFFSET) +#define PKX_JMP_MOD_MULT_ADD (0x0018 + PKX_OFFSET) +#define PKX_JMP_EC_PTMUL_ADD (0x001A + PKX_OFFSET) +#define PKX_JMP_EC_PTVALIDATE (0x001C + PKX_OFFSET) +#define PKX_JMP_F5200_SHA (0x001E + PKX_OFFSET) +#define PKX_JMP_F5200_AES (0x0020 + PKX_OFFSET) +#define PKX_JMP_F5200_AESK (0x0022 + PKX_OFFSET) +#define PKX_JMP_F5200_GCM (0x0024 + PKX_OFFSET) +#define PKX_JMP_F5200_GHA (0x0026 + PKX_OFFSET) +#define PKX_JMP_F5200_AESKW (0x0028 + PKX_OFFSET) +#define PKX_JMP_F5200_AESKWP (0x002A + PKX_OFFSET) +#define PKX_JMP_RNG_INSTANTIATE (0x002C + PKX_OFFSET) +#define PKX_JMP_RNG_RESEED (0x002E + PKX_OFFSET) +#define PKX_JMP_RNG_GENERATE (0x0030 + PKX_OFFSET) +#define PKX_JMP_RNG_UNINSTANTIATE (0x0032 + PKX_OFFSET) +#define PKX_JMP_RNG_GETENTROPY (0x0034 + PKX_OFFSET) +#define PKX_JMP_F5200_SHA_HMAC (0x0036 + PKX_OFFSET) +#define PKX_JMP_F5200_AES_DMA (0x0038 + PKX_OFFSET) +#define PKX_JMP_RNG_CTRLSTATUS (0x003A + PKX_OFFSET) +#define PKX_JMP_F5200_SHA_DMA (0x003C + PKX_OFFSET) +#define PKX_JMP_SHX_KEYTREE (0x003E + PKX_OFFSET) +#define PKX_JMP_PKX_DSA_DMA (0x0040 + PKX_OFFSET) +#define PKX_JMP_PKX_RSACRT_SIGN (0x0042 + PKX_OFFSET) +#define PKX_JMP_PKX_RSA_SIGN (0x0044 + PKX_OFFSET) +#define PKX_JMP_PKX_RSA_VERIFY (0x0046 + PKX_OFFSET) +#define PKX_JMP_PKX_EC_DSA_DMA (0x0048 + PKX_OFFSET) +#define PKX_JMP_F5200_AES_KEYROLL (0x004A + PKX_OFFSET) +#define PKX_JMP_EXPM (0x004C + PKX_OFFSET) +#define PKX_JMP_RSACRTM (0x004E + PKX_OFFSET) +#define PKX_JMP_EC_PTMULM (0x0050 + PKX_OFFSET) +#define PKX_JMP_DSA_SIGN_M (0x0052 + PKX_OFFSET) +#define PKX_JMP_EC_DSA_SIGN_M (0x0054 + PKX_OFFSET) +#define PKX_JMP_EC_KEYPAIRGEN (0x0056 + PKX_OFFSET) +#define PKX_JMP_RSACRTCM_SIGN (0x0058 + PKX_OFFSET) +#define PKX_JMP_F5200_GCM_NEW (0x005A + PKX_OFFSET) +/* PKX PKRev 2180 */ +/* PKX SHARev 2160 */ +/* PKX AESRev 2135 */ +/* Hex Checksum: 0xd0d79866 */ + +extern const SATUINT32_t uiPKX_Flags; +extern const SATUINT32_t uiPKX_BERWords; +extern const SATUINT32_t uiPKX_LIRWords; +extern const SATUINT32_t uiPKX_Rev; +extern const SATUINT32_t uiPKX_LibSize; +extern const SATUINT32_t uiPKX_LibChksum; +extern const SATUINT32_t uiPKX_Lib[]; +extern SATBOOL bMPF300TS_ES; + +#endif diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/shaf5200.h b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/shaf5200.h new file mode 100644 index 0000000..da598d1 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/shaf5200.h @@ -0,0 +1,101 @@ +/* ------------------------------------------------------------------- + $Rev: 1296 $ $Date: 2017-08-01 13:54:48 -0400 (Tue, 01 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for SHA function hardware implementation for CAL. + ------------------------------------------------------------------- */ + +#ifndef SHAF5200_H +#define SHAF5200_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef SHAF5200_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATR shapkxctx(SATRESCONTEXTPTR const pContext, const void *pBuffer, + SATUINT32_t uiBufLen,void *pHash, const SATBOOL bFinal); + +extern SATR shapkxhmacctx(SATRESCONTEXTPTR const pContext, const void *pBuffer, + SATUINT32_t uiBufLen, void *pHash, const SATUINT8_t uiFlag); + +extern SATR shapkxctxload(SATRESCONTEXTPTR const pContext); + +extern void shapkxctxunload(SATRESCONTEXTPTR const pContext); + +extern SATR shapkxini(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen); + +extern SATR shapkxhmacini(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, + const void *pKey, SATUINT32_t uiKeyLen); + +extern SATR shapkxwrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR shapkxhmacwrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR shapkxread(void *pHash, SATUINT32_t uiRevFlag); + +extern SATR shapkxkeytree(SATBOOL bPathSizeSel, const SATUINT32_t* puiKey, + SATUINT8_t uiOpType, const SATUINT32_t* puiPath, SATUINT32_t* puiKeyOut); + +extern SATR shapkxdma(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, + const void *pExtSrc, const void *pExtDest, SATUINT32_t uiDMAChConfig); + +extern SATR shapkxhmacdma(SATMACTYPE eMACType, const SATUINT32_t *pKey, + SATUINT32_t uiKeyLen, const void *pMsg, SATUINT32_t uiMsgLen, + const void *pMAC, SATUINT32_t uiDMAChConfig); + +extern SATR shapkxhashtypeini(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/sym.h b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/sym.h new file mode 100644 index 0000000..2e07faa --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/sym.h @@ -0,0 +1,129 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for Symmetric Key Cryptography in CAL. + ------------------------------------------------------------------- */ + +#ifndef SYM_H +#define SYM_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef SYM_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALSymTrfRes(SATBOOL bBlock); + +extern SATR CALSymEncrypt(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen); + +extern SATR CALSymDecrypt(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen); + +extern SATR CALSymEncryptDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymDecryptDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymEncryptKR(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF); + +extern SATR CALSymDecryptKR(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF); + +extern SATR CALSymEncryptKRDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymDecryptKRDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymEncAuth(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen); + +extern SATR CALSymDecVerify(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen); + +extern SATR CALSymKw(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR CALSymKwp(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR CALSymEncAuthDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymDecVerifyDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen, SATUINT32_t uiDMAChConfig); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/utils.h b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/utils.h new file mode 100644 index 0000000..91474f0 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/utils.h @@ -0,0 +1,93 @@ +/* ------------------------------------------------------------------- + $Rev: 1300 $ $Date: 2017-08-07 11:36:02 -0400 (Mon, 07 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL utility functions. + ------------------------------------------------------------------- */ + +#ifndef UTILS_H +#define UTILS_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef UTILS_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern void CALMemCopy(void *pDst, const void *pSrc, SATUINT32_t uiNum8); + +extern void CALMemClear( void * pLoc, SATUINT32_t uiNum ); + +extern void CALMemClear32( SATUINT32_t* puiLoc, SATUINT32_t uiLen32 ); + +extern SATBOOL CALMemCmp(const void *pA, const void *pB, SATUINT32_t uiNum); + +extern void CALVol32MemLoad(volatile SATUINT32_t * puiDst, const void * pSrc, + SATUINT32_t uiNum32); + +extern void CALVol32MemRead(void * pDst, volatile SATUINT32_t * puiSrc, + SATUINT32_t uiNum32); + +extern void CALByteReverse(SATUINT32_t* puiArray, SATINT32_t iNumberBytes); + +extern void CALByteReverseWord(SATUINT32_t* puiArray, SATINT32_t iNumberWords); + +extern void CALWordReverse(SATUINT32_t *puiArray, SATINT32_t iNumberWords); + +extern void vAppendNonzero(void *puiArray, SATUINT32_t uiLen, + SATUINT32_t uiBlockSize); + +extern void vAppendZero(void *puiArray, SATUINT32_t uiLen, + SATUINT32_t uiBlockSize); + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/x52cfg_user.h b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/x52cfg_user.h new file mode 100644 index 0000000..c8d8648 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/middleware/cal/x52cfg_user.h @@ -0,0 +1,72 @@ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ +/* X5200 configuration */ +/* $Date: 2015-07-23 14:30:19 -0400 (Thu, 23 Jul 2015) $ $Rev: 2093 $ */ +/* ------------------------------------------------------------------- + Options: + * LIR ROM size : 4096 + * LIR RAM size : 2048 + * BER size : 1024 + * MMR size : 1024 + * TSR size : 1024 + * FPR size : 1024 + * Single error correct, dual error detect (SECDED) memory parity + * DMA enabled + * FPGA multipliers disabled + * AES enabled + - Fast key schedule generation + - GCM/GHASH enabled + - AES countermeasures enabled + * RNG enabled + * External PRNG disabled + * SHA enabled + - Fast SHA enabled + - SHA-1 enabled + - SHA-224 enabled + - SHA-256 enabled + - SHA-384 enabled + - SHA-512 enabled + - SHA-512/224 enabled + - SHA-512/256 enabled + - SHA countermeasures enabled + * P-curves populated in FCR: + - P-192 populated + - P-224 populated + - P-256 populated + - P-384 populated + - P-521 populated + * Data memory scrambling enabled + + ------------------------------------------------------------------- */ + +#ifndef X52CFG_H +#define X52CFG_H + +#define X52_CFG_MODEL 0xf5200 +#define X52_CFG_DATE 0x15072720 +#define X52_CFG_REV 0x0000082e +#define X52_CFG_OPT 0x0fd87ff9 +#define X52_CFG_OPT2 0xc0000000 +#define X52_LIR_LEN 0x1800 +#define X52_LIR_ROM_LEN 0x1000 +#define X52_LIR_RAM_LEN 0x0800 +#define X52_BER_LEN 0x400 +#define X52_MMR_LEN 0x400 +#define X52_TSR_LEN 0x400 +#define X52_FPR_LEN 0x400 + +#endif diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/README.md b/applications/user-crypto/miv-rv32-key-agreement/src/platform/README.md new file mode 100644 index 0000000..f7f6030 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/README.md @@ -0,0 +1,27 @@ +# Mi-V soft processor platform source code + +## Repo organization + +``` + + | + |-- drivers + | |- fpga_ip + | | | CoreGPIO + | | | CoreSysServices_PF + | | | CoreUARTapb + | | + | |- off_chip + | | | . + | | | . + | | + |-- hal + | | + |-- miv_rv32_hal + + +``` + +The drivers published here are compatible with the improved SoftConsole project folder structure being used in the latest [example projects](https://github.com/Mi-V-Soft-RISC-V/miv-rv32-bare-metal-examples). +These drivers can also be used with the legacy folder structure (projects released via Firmware Catalog) by defining the **LEGACY_DIR_STRUCTURE** macro in the SoftConsole project settings. + diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c new file mode 100644 index 0000000..1a0073f --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c @@ -0,0 +1,533 @@ +/******************************************************************************* + * (c) Copyright 2008-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file core_gpio.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreGPIO bare metal driver implementation. + * + */ +#include "coregpio_regs.h" +#include "core_gpio.h" + +/*-------------------------------------------------------------------------*//** + * + */ +#define GPIO_INT_ENABLE_MASK (uint32_t)0x00000008UL +#define OUTPUT_BUFFER_ENABLE_MASK 0x00000004UL + + +#define NB_OF_GPIO 32 + +#define CLEAR_ALL_IRQ32 (uint32_t)0xFFFFFFFF +#define CLEAR_ALL_IRQ16 (uint16_t)0xFFFF +#define CLEAR_ALL_IRQ8 (uint8_t)0xFF + +/*-------------------------------------------------------------------------*//** + * GPIO_init() + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_init +( + gpio_instance_t * this_gpio, + addr_t base_addr, + gpio_apb_width_t bus_width +) +{ + uint8_t i = 0; + addr_t cfg_reg_addr = base_addr; + + this_gpio->base_addr = base_addr; + this_gpio->apb_bus_width = bus_width; + + /* Clear configuration. */ + for( i = 0, cfg_reg_addr = base_addr; i < NB_OF_GPIO; ++i ) + { + HW_set_8bit_reg( cfg_reg_addr, 0 ); + cfg_reg_addr += 4; + } + /* Clear any pending interrupts */ + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, CLEAR_ALL_IRQ32 ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, (uint16_t)CLEAR_ALL_IRQ16 ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, (uint16_t)CLEAR_ALL_IRQ16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, (uint8_t)CLEAR_ALL_IRQ8 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_config + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_config +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint32_t config +) +{ + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + uint32_t cfg_reg_addr = this_gpio->base_addr; + cfg_reg_addr += (port_id * 4); + HW_set_32bit_reg( cfg_reg_addr, config ); + + /* + * Verify that the configuration was correctly written. Failure to read + * back the expected value may indicate that the GPIO port was configured + * as part of the hardware flow and cannot be modified through software. + * It may also indicate that the base address passed as parameter to + * GPIO_init() was incorrect. + */ + HAL_ASSERT( HW_get_32bit_reg( cfg_reg_addr ) == config ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_set_outputs + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_set_outputs +( + gpio_instance_t * this_gpio, + uint32_t value +) +{ + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, GPIO_OUT, value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, GPIO_OUT0, (uint16_t)value ); + HAL_set_16bit_reg( this_gpio->base_addr, GPIO_OUT1, (uint16_t)(value >> 16) ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT0, (uint8_t)value ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT1, (uint8_t)(value >> 8) ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT2, (uint8_t)(value >> 16) ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT3, (uint8_t)(value >> 24) ); + break; + + default: + HAL_ASSERT(0); + break; + } + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( GPIO_get_outputs( this_gpio ) == value ); +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_inputs + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_inputs +( + gpio_instance_t * this_gpio +) +{ + uint32_t gpio_in = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + gpio_in = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_IN ); + break; + + case GPIO_APB_16_BITS_BUS: + gpio_in |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_IN0 ); + gpio_in |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_IN1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + gpio_in |= HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN0 ); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN1 ) << 8); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN2 ) << 16); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return gpio_in; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_outputs + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_outputs +( + gpio_instance_t * this_gpio +) +{ + uint32_t gpio_out = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + gpio_out = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ); + break; + + case GPIO_APB_16_BITS_BUS: + gpio_out |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT0 ); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + gpio_out |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT0 ); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT1 ) << 8); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT2 ) << 16); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return gpio_out; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_set_output + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_set_output +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint8_t value +) +{ + HAL_ASSERT( port_id < NB_OF_GPIO ); + + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + { + uint32_t outputs_state; + + outputs_state = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ); + if ( 0 == value ) + { + outputs_state &= ~(1 << port_id); + } + else + { + outputs_state |= 1 << port_id; + } + HAL_set_32bit_reg( this_gpio->base_addr, GPIO_OUT, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ) == outputs_state ); + } + break; + + case GPIO_APB_16_BITS_BUS: + { + uint16_t outputs_state; + uint32_t gpio_out_reg_addr = this_gpio->base_addr + GPIO_OUT_REG_OFFSET + ((port_id >> 4) * 4); + + outputs_state = HW_get_16bit_reg( gpio_out_reg_addr ); + if ( 0 == value ) + { + outputs_state &= ~(1 << (port_id & 0x0F)); + } + else + { + outputs_state |= 1 << (port_id & 0x0F); + } + HW_set_16bit_reg( gpio_out_reg_addr, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HW_get_16bit_reg( gpio_out_reg_addr ) == outputs_state ); + } + break; + + case GPIO_APB_8_BITS_BUS: + { + uint8_t outputs_state; + uint32_t gpio_out_reg_addr = this_gpio->base_addr + GPIO_OUT_REG_OFFSET + ((port_id >> 3) * 4); + + outputs_state = HW_get_8bit_reg( gpio_out_reg_addr ); + if ( 0 == value ) + { + outputs_state &= ~(1 << (port_id & 0x07)); + } + else + { + outputs_state |= 1 << (port_id & 0x07); + } + HW_set_8bit_reg( gpio_out_reg_addr, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HW_get_8bit_reg( gpio_out_reg_addr ) == outputs_state ); + } + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_drive_inout + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_drive_inout +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + gpio_inout_state_t inout_state +) +{ + uint32_t config; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + switch( inout_state ) + { + case GPIO_DRIVE_HIGH: + /* Set output high */ + GPIO_set_output( this_gpio, port_id, 1 ); + + /* Enable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config |= OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + case GPIO_DRIVE_LOW: + /* Set output low */ + GPIO_set_output( this_gpio, port_id, 0 ); + + /* Enable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config |= OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + case GPIO_HIGH_Z: + /* Disable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config &= ~OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_enable_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_enable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t cfg_value; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + cfg_reg_addr += (port_id * 4); + cfg_value = HW_get_8bit_reg( cfg_reg_addr ); + cfg_value |= GPIO_INT_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, cfg_value ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_disable_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_disable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t cfg_value; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + cfg_reg_addr += (port_id * 4); + cfg_value = HW_get_8bit_reg( cfg_reg_addr ); + cfg_value &= ~GPIO_INT_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, cfg_value ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_clear_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_clear_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t irq_clr_value = ((uint32_t)1) << ((uint32_t)port_id); + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, irq_clr_value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, irq_clr_value >> 16 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, irq_clr_value >> 24 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_irq_sources + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_irq_sources +( + gpio_instance_t * this_gpio +) +{ + uint32_t intr_src = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + intr_src = HAL_get_32bit_reg( this_gpio->base_addr, IRQ ); + break; + + case GPIO_APB_16_BITS_BUS: + intr_src |= HAL_get_16bit_reg( this_gpio->base_addr, IRQ0 ); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + intr_src |= HAL_get_16bit_reg( this_gpio->base_addr, IRQ0 ); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ1 ) << 8); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ2 ) << 16); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return intr_src; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_clear_all_irq_sources + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_clear_all_irq_sources +( + gpio_instance_t * this_gpio, + uint32_t bitmask +) +{ + uint32_t irq_clr_value = bitmask; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, irq_clr_value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, irq_clr_value >> 16 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, irq_clr_value >> 24 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h new file mode 100644 index 0000000..88ba178 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h @@ -0,0 +1,722 @@ +/******************************************************************************* + * (c) Copyright 2008-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file core_gpio.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreGPIO bare metal driver public API. + * + */ + +/*=========================================================================*//** + @mainpage CoreGPIO Bare Metal Driver. + + @section intro_sec Introduction + The CoreGPIO hardware IP includes up to 32 general-purpose input/output GPIOs. + This driver provides a set of functions for controlling the GPIOs as part of a + bare-metal system where no operating system is available. These drivers + can be adapted for use as part of an operating system, but the implementation + of the adaptation layer between this driver and the operating system's driver + model is outside the scope of this driver. + + @section driver_configuration Driver Configuration + The individual IOs of CoreGPIO can be configured either in the hardware flow + or as part of the software application through calls to the GPIO_config() + function. GPIOs configured as part of the hardware are fixed and cannot be + modified using a call to the GPI_config() function. + + @section theory_op Theory of Operation + The CoreGPIO driver uses the Actel Hardware Abstraction Layer (HAL) to access + hardware registers. You must ensure that the Actel HAL is included as part of + your software project. The Actel HAL is available through the Actel Firmware + Catalog. + + The CoreGPIO driver functions are logically grouped into the following groups: + - Initialization + - Configuration + - Reading and writing GPIO state + - Interrupt control + + The CoreGPIO driver is initialized through a call to the GPIO_init() function. + The GPIO_init() function must be called before any other GPIO driver functions + can be called. + + Each GPIO port is individually configured through a call to the + GPIO_config() function. Configuration includes deciding if a GPIO port is + going to be used as input, output, or both. GPIO ports configured as inputs + are further configured to generate interrupts based on the state of input. + Interrupts is either level- or edge-sensitive. + Note that a CoreGPIO hardware instance is generated as part of the hardware + flow with a fixed configuration for some or all of its IOs. + Attempting to modify the configuration of such a hardware-configured IO using + the GPIO_config() function has no effect. + + The state of the GPIO ports can be read and written using the following + functions: + - GPIO_get_inputs() + - GPIO_get_outputs() + - GPIO_set_outputs() + - GPIO_drive_inout() + + Interrupts generated by GPIO ports configured as inputs are controlled using + the following functions: + - GPIO_enable_irq() + - GPIO_disable_irq() + - GPIO_clear_irq() + - GPIO_get_irq_sources() + - GPIO_clear_all_irq_sources() + + *//*=========================================================================*/ +#ifndef CORE_GPIO_H_ +#define CORE_GPIO_H_ + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + The gpio_id_t enumeration is used to identify GPIOs as part of the + parameter to functions: + - GPIO_config(), + - GPIO_drive_inout(), + - GPIO_enable_int(), + - GPIO_disable_int(), + - GPIO_clear_int() + */ +typedef enum __gpio_id_t +{ + GPIO_0 = 0, + GPIO_1 = 1, + GPIO_2 = 2, + GPIO_3 = 3, + GPIO_4 = 4, + GPIO_5 = 5, + GPIO_6 = 6, + GPIO_7 = 7, + GPIO_8 = 8, + GPIO_9 = 9, + GPIO_10 = 10, + GPIO_11 = 11, + GPIO_12 = 12, + GPIO_13 = 13, + GPIO_14 = 14, + GPIO_15 = 15, + GPIO_16 = 16, + GPIO_17 = 17, + GPIO_18 = 18, + GPIO_19 = 19, + GPIO_20 = 20, + GPIO_21 = 21, + GPIO_22 = 22, + GPIO_23 = 23, + GPIO_24 = 24, + GPIO_25 = 25, + GPIO_26 = 26, + GPIO_27 = 27, + GPIO_28 = 28, + GPIO_29 = 29, + GPIO_30 = 30, + GPIO_31 = 31 +} gpio_id_t; + +/*-------------------------------------------------------------------------*//** + Possible width of the APB bus + */ +typedef enum __gpio_apb_width_t +{ + GPIO_APB_8_BITS_BUS = 0, + GPIO_APB_16_BITS_BUS = 1, + GPIO_APB_32_BITS_BUS = 2, + GPIO_APB_UNKNOWN_BUS_WIDTH = 3 +} gpio_apb_width_t; + +/*-------------------------------------------------------------------------*//** + Structure instance holding all data regarding the CoreGPIO + */ +typedef struct __gpio_instance_t +{ + addr_t base_addr; + gpio_apb_width_t apb_bus_width; +} gpio_instance_t; + +/*-------------------------------------------------------------------------*//** + GPIO ports definitions used to identify GPIOs as part of the parameter to + function GPIO_set_outputs(). + These definitions are also be used to identity GPIO through logical operations + on the return value of function GPIO_get_inputs(). + # GPIO_0_MASK + # GPIO_1_MASK + # GPIO_2_MASK + # GPIO_3_MASK + # GPIO_4_MASK + # GPIO_5_MASK + # GPIO_6_MASK + # GPIO_7_MASK + # GPIO_8_MASK + # GPIO_9_MASK + # GPIO_10_MASK + # GPIO_11_MASK + # GPIO_12_MASK + # GPIO_13_MASK + # GPIO_14_MASK + # GPIO_15_MASK + # GPIO_16_MASK + # GPIO_17_MASK + # GPIO_18_MASK + # GPIO_19_MASK + # GPIO_20_MASK + # GPIO_21_MASK + # GPIO_22_MASK + # GPIO_23_MASK + # GPIO_24_MASK + # GPIO_25_MASK + # GPIO_26_MASK + # GPIO_27_MASK + # GPIO_28_MASK + # GPIO_29_MASK + # GPIO_30_MASK + # GPIO_31_MASK + */ +#define GPIO_0_MASK 0x00000001UL +#define GPIO_1_MASK 0x00000002UL +#define GPIO_2_MASK 0x00000004UL +#define GPIO_3_MASK 0x00000008UL +#define GPIO_4_MASK 0x00000010UL +#define GPIO_5_MASK 0x00000020UL +#define GPIO_6_MASK 0x00000040UL +#define GPIO_7_MASK 0x00000080UL +#define GPIO_8_MASK 0x00000100UL +#define GPIO_9_MASK 0x00000200UL +#define GPIO_10_MASK 0x00000400UL +#define GPIO_11_MASK 0x00000800UL +#define GPIO_12_MASK 0x00001000UL +#define GPIO_13_MASK 0x00002000UL +#define GPIO_14_MASK 0x00004000UL +#define GPIO_15_MASK 0x00008000UL +#define GPIO_16_MASK 0x00010000UL +#define GPIO_17_MASK 0x00020000UL +#define GPIO_18_MASK 0x00040000UL +#define GPIO_19_MASK 0x00080000UL +#define GPIO_20_MASK 0x00100000UL +#define GPIO_21_MASK 0x00200000UL +#define GPIO_22_MASK 0x00400000UL +#define GPIO_23_MASK 0x00800000UL +#define GPIO_24_MASK 0x01000000UL +#define GPIO_25_MASK 0x02000000UL +#define GPIO_26_MASK 0x04000000UL +#define GPIO_27_MASK 0x08000000UL +#define GPIO_28_MASK 0x10000000UL +#define GPIO_29_MASK 0x20000000UL +#define GPIO_30_MASK 0x40000000UL +#define GPIO_31_MASK 0x80000000UL + +/*-------------------------------------------------------------------------*//** + * GPIO modes + * # GPIO_INPUT_MODE + * # GPIO_OUTPUT_MODE + * # GPIO_INOUT_MODE + */ +#define GPIO_INPUT_MODE 0x0000000002UL +#define GPIO_OUTPUT_MODE 0x0000000005UL +#define GPIO_INOUT_MODE 0x0000000003UL + +/*-------------------------------------------------------------------------*//** + * Possible GPIO inputs interrupt configurations. + * # GPIO_IRQ_LEVEL_HIGH + * # GPIO_IRQ_LEVEL_LOW + * # GPIO_IRQ_EDGE_POSITIVE + * # GPIO_IRQ_EDGE_NEGATIVE + * # GPIO_IRQ_EDGE_BOTH + */ +#define GPIO_IRQ_LEVEL_HIGH 0x0000000000UL +#define GPIO_IRQ_LEVEL_LOW 0x0000000020UL +#define GPIO_IRQ_EDGE_POSITIVE 0x0000000040UL +#define GPIO_IRQ_EDGE_NEGATIVE 0x0000000060UL +#define GPIO_IRQ_EDGE_BOTH 0x0000000080UL + +/*-------------------------------------------------------------------------*//** + * Possible states for GPIO configured as INOUT + */ +typedef enum gpio_inout_state +{ + GPIO_DRIVE_LOW = 0, + GPIO_DRIVE_HIGH, + GPIO_HIGH_Z +} gpio_inout_state_t; + +/*-------------------------------------------------------------------------*//** + The GPIO_init() function initializes a CoreGPIO hardware instance and the data + structure associated with the CoreGPIO hardware instance. + Note that a CoreGPIO hardware instance is generated with a fixed configuration + for some or all of its IOs as part of the hardware flow. + Attempting to modify the configuration of such a hardware-configured IO using + the GPIO_config() function has no effect. + + @param this_gpio + Pointer to the gpio_instance_t data structure instance holding all data + regarding the CoreGPIO hardware instance being initialized. A pointer to the + same data structure is used in subsequent calls to the CoreGPIO driver + functions in order to identify the CoreGPIO instance that must perform the + operation implemented by the called driver function. + + @param base_addr + The base_addr parameter is the base address in the memory map of the + processor for the registers of the GPIO instance being initialized. + + @param bus_width + The bus_width parameter informs the driver of the APB bus width selected + during the hardware flow configuration of the CoreGPIO hardware instance. It + indicates to the driver whether the CoreGPIO hardware registers are visible + as 8, 16, or 32-bits registers. Allowed values are: + - GPIO_APB_8_BITS_BUS + - GPIO_APB_16_BITS_BUS + - GPIO_APB_32_BITS_BUS + + @return + none. + + @example + @code + #define COREGPIO_BASE_ADDR 0xC2000000 + + gpio_instance_t g_gpio; + + void system_init( void ) + { + GPIO_init( &g_gpio, COREGPIO_BASE_ADDR, GPIO_APB_32_BITS_BUS ); + } + @endcode + */ +void GPIO_init +( + gpio_instance_t * this_gpio, + addr_t base_addr, + gpio_apb_width_t bus_width +); + +/*-------------------------------------------------------------------------*//** + The GPIO_config() function is used to configure an individual GPIO port. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO port to be configured. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @param config + The config parameter specifies the configuration to be applied to the GPIO + port identified by the first parameter. It is a logical OR of GPIO mode and + interrupt mode. The interrupt mode is only relevant if the GPIO is + configured as an input. + - Possible modes are: + - GPIO_INPUT_MODE, + - GPIO_OUTPUT_MODE, + - GPIO_INOUT_MODE. + - Possible interrupt modes are: + - GPIO_IRQ_LEVEL_HIGH, + - GPIO_IRQ_LEVEL_LOW, + - GPIO_IRQ_EDGE_POSITIVE, + - GPIO_IRQ_EDGE_NEGATIVE, + - GPIO_IRQ_EDGE_BOTH + + @return + none. + + @example + For example, the following call configures GPIO 4 as an input that generates + interrupts on a low-to-high transition of the input: + @code + GPIO_config( &g_gpio, GPIO_4, GPIO_INPUT_MODE | GPIO_IRQ_EDGE_POSITIVE ); + @endcode + */ +void GPIO_config +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint32_t config +); + +/*-------------------------------------------------------------------------*//** + The GPIO_set_outputs() function is used to set the state of the GPIO ports + configured as outputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param value + The value parameter specifies the state of the GPIO ports configured as + outputs. It is a bit mask of the form (GPIO_n_MASK | GPIO_m_MASK), where n + and m are numbers identifying GPIOs. + For example, (GPIO_0_MASK | GPIO_1_MASK | GPIO_2_MASK ) specifies that the + first, second, and third GPIO must be set high and all other outputs set + low. + + @return + none. + + @example + Set GPIO 0 and 8 outputs high and all other GPIO outputs low. + @code + GPIO_set_outputs( &g_gpio, GPIO_0_MASK | GPIO_8_MASK ); + @endcode + + @example + Set GPIO 2 and 4 outputs low without affecting the other GPIO outputs. + @code + uint32_t gpio_outputs; + gpio_outputs = GPIO_get_outputs( &g_gpio ); + gpio_outputs &= ~( GPIO_2_MASK | GPIO_4_MASK ); + GPIO_set_outputs( &g_gpio, gpio_outputs ); + @endcode + + @see GPIO_get_outputs() + */ +void GPIO_set_outputs +( + gpio_instance_t * this_gpio, + uint32_t value +); + +/*-------------------------------------------------------------------------*//** + The GPIO_set_output() function is used to set the state of a single GPIO port + configured as an output. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter specifies the GPIO port that has its output set by a + call to this function. + + @param value + The value parameter specifies the desired state for the GPIO output. A value + of 0 sets the output low, and a value of 1 sets the port high. + + @return + none. + */ +void GPIO_set_output +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint8_t value +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_inputs() function is used to read the state of all GPIOs + configured as inputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @return + This function returns a 32-bit unsigned integer, where each bit represents + the state of an input. The least significant bit represents the state of + GPIO 0, and the most significant bit represents the state of GPIO 31. + */ +uint32_t GPIO_get_inputs +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_outputs() function is used to read the current state of all + GPIO outputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @return + This function returns a 32-bit unsigned integer where each bit represents + the state of an output. The least significant bit represents the state + of GPIO 0, and the most significant bit represents the state of GPIO 31. + */ +uint32_t GPIO_get_outputs +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_drive_inout() function is used to set the output state of a + GPIO configured as INOUT. An INOUT GPIO is in one of three states: + - high + - low + - high impedance + + An INOUT output is typically be used where several devices drive the state of + a signal. The high and low states are equivalent to the high and low states of + a GPIO configured as an output. The high impedance state is used to prevent + the GPIO from driving the state of the output and therefore allow reading the + state of the GPIO as an input. + Note that the GPIO port you wish to use as INOUT through this function + must be configurable through software. Therefore, the GPIO ports used as INOUT + must not have a fixed configuration selected as part of the hardware flow. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO for which this function will + change the output state. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @param inout_state + The inout_state parameter specifies the state of the I/O identified by the + first parameter. Possible states are: + - GPIO_DRIVE_HIGH, + - GPIO_DRIVE_LOW, + - GPIO_HIGH_Z (high impedance) + + @return + none. + + @example + The call to GPIO_drive_inout() below will set the GPIO 7 output to + high impedance state. + @code + GPIO_drive_inout( &g_gpio, GPIO_7, GPIO_HIGH_Z ); + @endcode + */ +void GPIO_drive_inout +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + gpio_inout_state_t inout_state +); + +/*-------------------------------------------------------------------------*//** + The GPIO_enable_irq() function is used to enable an interrupt to be + generated based on the state of the input identified as a parameter. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO input that the call to + GPIO_enable_irq() enables to generate interrupts. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + @example + The call to GPIO_enable_irq() below allows GPIO 8 to generate interrupts. + + @code + GPIO_enable_irq( &g_gpio, GPIO_8 ); + @endcode + */ +void GPIO_enable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_disable_irq() function is used to disable interrupts from being + generated based on the state of the input specified as a parameter. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO input that the call to + GPIO_disable_irq() disables from generating interrupts. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + @example + The call to GPIO_disable_irq() below prevents GPIO 8 from generating + interrupts. + @code + GPIO_disable_irq( &g_gpio, GPIO_8 ); + @endcode + */ +void GPIO_disable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_clear_irq() function is used to clear the interrupt generated by + the GPIO specified as a parameter. The GPIO_clear_irq() function must be + called as part of a GPIO interrupt service routine (ISR) in order to prevent + the same interrupt event from re-triggering a call to the GPIO ISR. + Note that interrupts may also need to be cleared in the processor's + interrupt controller. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO input for which to clear the + interrupt. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + @example + The example below demonstrates the use of the GPIO_clear_irq() function as + part of the GPIO-9 interrupt service routine. + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + GPIO_clear_irq( &g_gpio, GPIO_9 ); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +void GPIO_clear_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_irq_sources() function is used to identify the source of the + interrupt. i.e. to That is the GPIO input line, whose state change triggered + the interrupt. The GPIO_get_irq_sources() function must be called as part of + a GPIO interrupt service routine (ISR) in order to determine the interrupt + source. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @return + This function returns a 32-bit unsigned integer, where each bit represents + the pin number of a GPIO. + + @example + The example below demonstrates the use of the GPIO_get_irq_sources() + function as part of the GPIO-9 interrupt service routine. + + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + GPIO_clear_all_irq_sources(g_p_mygpio, GPIO_get_irq_sources(g_p_mygpio)); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +uint32_t GPIO_get_irq_sources +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_clear_all_irq_sources() function is used to clear all the active + interrupts generated by the GPIO specified as a parameter. The + GPIO_clear_all_irq_sources() function must be called as part of a GPIO + interrupt service routine (ISR) in order to prevent the same interrupt event + from re-triggering a call to the GPIO ISR. + Note that interrupts may also need to be cleared in the processor's + interrupt controller. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param bitmask + This bitmask parameter is a 32-bit unsigned integer where each bit + represents the GPIO pin used to clear the interrupt bit register of the + corresponding GPIO bit. The least significant bit represents the status of + GPIO 0, and the most significant bit represents the status of GPIO 31. + + @return + none. + + @example + The example below demonstrates the use of the GPIO_clear_all_irq_sources() + function as part of the GPIO-9 interrupt service routine. + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + do_interrupt_processing(); + + GPIO_clear_all_irq_sources(g_p_mygpio, GPIO_get_irq_sources(g_p_mygpio)); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +void GPIO_clear_all_irq_sources +( + gpio_instance_t * this_gpio, + uint32_t bitmask +); + +#ifdef __cplusplus +} +#endif + +#endif /* CORE_GPIO_H_ */ diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h new file mode 100644 index 0000000..41f5b7c --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h @@ -0,0 +1,45 @@ +/******************************************************************************* + * (c) Copyright 2008-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file coregpio_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreGPIO register definitions + * + */ + +#ifndef __CORE_GPIO_REGISTERS_H +#define __CORE_GPIO_REGISTERS_H 1 + +/*------------------------------------------------------------------------------ + * + */ +#define IRQ_REG_OFFSET 0x80 + +#define IRQ0_REG_OFFSET 0x80 +#define IRQ1_REG_OFFSET 0x84 +#define IRQ2_REG_OFFSET 0x88 +#define IRQ3_REG_OFFSET 0x8C + +/*------------------------------------------------------------------------------ + * + */ +#define GPIO_IN_REG_OFFSET 0x90 + +#define GPIO_IN0_REG_OFFSET 0x90 +#define GPIO_IN1_REG_OFFSET 0x94 +#define GPIO_IN2_REG_OFFSET 0x98 +#define GPIO_IN3_REG_OFFSET 0x9C + +/*------------------------------------------------------------------------------ + * + */ +#define GPIO_OUT_REG_OFFSET 0xA0 + +#define GPIO_OUT0_REG_OFFSET 0xA0 +#define GPIO_OUT1_REG_OFFSET 0xA4 +#define GPIO_OUT2_REG_OFFSET 0xA8 +#define GPIO_OUT3_REG_OFFSET 0xAC + +#endif /* __CORE_GPIO_REGISTERS_H */ diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c new file mode 100644 index 0000000..1fd3dd6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c @@ -0,0 +1,1495 @@ +/******************************************************************************* + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * CoreI2C software driver implementation. + * + */ + +#include "core_smbus_regs.h" +#include "core_i2c.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * I2C transaction direction. + */ +#define WRITE_DIR 0u +#define READ_DIR 1u + +/* -- TRANSACTIONS TYPES -- */ +#define NO_TRANSACTION 0u +#define MASTER_WRITE_TRANSACTION 1u +#define MASTER_READ_TRANSACTION 2u +#define MASTER_RANDOM_READ_TRANSACTION 3u +#define WRITE_SLAVE_TRANSACTION 4u +#define READ_SLAVE_TRANSACTION 5u + +/* -- SMBUS H/W STATES -- */ +/* -- MASTER STATES -- */ +#define ST_BUS_ERROR 0x00u /* Bus error during MST or selected slave modes */ +#define ST_I2C_IDLE 0xF8u /* No activity and no interrupt either... */ +#define ST_START 0x08u /* start condition sent */ +#define ST_RESTART 0x10u /* repeated start */ +#define ST_SLAW_ACK 0x18u /* SLA+W sent, ack received */ +#define ST_SLAW_NACK 0x20u /* SLA+W sent, nack received */ +#define ST_TX_DATA_ACK 0x28u /* Data sent, ACK'ed */ +#define ST_TX_DATA_NACK 0x30u /* Data sent, NACK'ed */ +#define ST_LOST_ARB 0x38u /* Master lost arbitration */ +#define ST_SLAR_ACK 0x40u /* SLA+R sent, ACK'ed */ +#define ST_SLAR_NACK 0x48u /* SLA+R sent, NACK'ed */ +#define ST_RX_DATA_ACK 0x50u /* Data received, ACK sent */ +#define ST_RX_DATA_NACK 0x58u /* Data received, NACK sent */ +#define ST_RESET_ACTIVATED 0xD0u /* Master reset is activated */ +#define ST_STOP_TRANSMIT 0xE0u /* Stop has been transmitted */ + +/* -- SLAVE STATES -- */ +#define ST_SLAVE_SLAW 0x60u /* SLA+W received */ +#define ST_SLAVE_SLAR_ACK 0xA8u /* SLA+R received, ACK returned */ +#define ST_SLV_LA 0x68u /* Slave lost arbitration */ +#define ST_GCA 0x70u /* GCA received */ +#define ST_GCA_LA 0x78u /* GCA lost arbitration */ +#define ST_RDATA 0x80u /* Data received */ +#define ST_SLA_NACK 0x88u /* Slave addressed, NACK returned */ +#define ST_GCA_ACK 0x90u /* Previously addresses with GCA, data ACKed */ +#define ST_GCA_NACK 0x98u /* GCA addressed, NACK returned */ +#define ST_RSTOP 0xA0u /* Stop received */ +#define ST_SLARW_LA 0xB0u /* Arbitration lost */ +#define ST_RACK 0xB8u /* Byte sent, ACK received */ +#define ST_SLAVE_RNACK 0xC0u /* Byte sent, NACK received */ +#define ST_FINAL 0xC8u /* Final byte sent, ACK received */ +#define ST_SLV_RST 0xD8u /* Slave reset state */ + + +/* I2C Channel base offset */ +#define CHANNEL_BASE_SHIFT 5u +#define CHANNEL_MASK 0x1E0u + +/* + * Maximum address offset length in slave write-read transactions. + * A maximum of two bytes will be interpreted as address offset within the slave + * tx buffer. + */ +#define MAX_OFFSET_LENGTH 2u + +/*------------------------------------------------------------------------------ + * I2C interrupts control functions implemented "i2c_interrupt.c". + * the implementation of these functions depend on the underlying hardware + * design and how the CoreI2C interrupt line is connected to the system's + * interrupt controller. + */ +void I2C_enable_irq( i2c_instance_t * this_i2c ); +void I2C_disable_irq( i2c_instance_t * this_i2c ); +static void enable_slave_if_required(i2c_instance_t * this_i2c); + +/*------------------------------------------------------------------------------ + * I2C_init() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_init +( + i2c_instance_t * this_i2c, + addr_t base_address, + uint8_t ser_address, + i2c_clock_divider_t ser_clock_speed +) +{ + psr_t saved_psr; + uint_fast16_t clock_speed = (uint_fast16_t)ser_clock_speed; + + /* + * We need to disable ints while doing this as there is no guarantee we + * have not been called already and the ISR is active. + */ + saved_psr = HAL_disable_interrupts(); + + /* + * Initialize all items of the this_i2c data structure to zero. This + * initializes all state variables to their init value. It relies on + * the fact that NO_TRANSACTION, I2C_SUCCESS and I2C_RELEASE_BUS all + * have an actual value of zero. + */ + memset(this_i2c, 0, sizeof(i2c_instance_t)); + + /* + * Set base address of I2C hardware used by this instance. + */ + this_i2c->base_address = base_address; + + /* + * Update Serial address of the device + */ + this_i2c->ser_address = ((uint_fast8_t)ser_address << 1u); + + /* + * Configure hardware. + */ + HAL_set_8bit_reg_field(this_i2c->base_address, ENS1, 0x00); /* Reset I2C hardware. */ + HAL_set_8bit_reg_field(this_i2c->base_address, ENS1, 0x01); /* set enable bit */ + HAL_set_8bit_reg_field(this_i2c->base_address, CR2, ( (clock_speed >> 2) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c->base_address, CR1, ( (clock_speed >> 1) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c->base_address, CR0, ( clock_speed & 0x01) ); + + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS, this_i2c->ser_address); + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, this_i2c->ser_address); + + /* + * Finally safe to enable interrupts. + */ + HAL_restore_interrupts( saved_psr ); +} +/*------------------------------------------------------------------------------ + * I2C_channel_init() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_channel_init +( + i2c_instance_t * this_i2c_channel, + i2c_instance_t * this_i2c, + i2c_channel_number_t channel_number, + i2c_clock_divider_t ser_clock_speed +) +{ + psr_t saved_psr; + uint_fast16_t clock_speed = (uint_fast16_t)ser_clock_speed; + + HAL_ASSERT(channel_number < I2C_MAX_CHANNELS); + HAL_ASSERT(I2C_CHANNEL_0 != channel_number); + + /* + * Cannot allow channel 0 in this function as we will trash the hardware + * base address and slave address. + */ + if ((channel_number < I2C_MAX_CHANNELS) && + (I2C_CHANNEL_0 != channel_number)) + { + /* + * We need to disable ints while doing this as the hardware should already + * be active at this stage. + */ + saved_psr = HAL_disable_interrupts(); + + /* + * Initialize channel data. + */ + memset(this_i2c_channel, 0, sizeof(i2c_instance_t)); + + this_i2c_channel->base_address = + ((this_i2c->base_address) & ~((addr_t)CHANNEL_MASK)) + | (((addr_t)channel_number) << CHANNEL_BASE_SHIFT); + + this_i2c_channel->ser_address = this_i2c->ser_address; + + HAL_set_8bit_reg_field(this_i2c_channel->base_address, ENS1, 0x00); /* Reset I2C channel hardware. */ + HAL_set_8bit_reg_field(this_i2c_channel->base_address, ENS1, 0x01); /* set enable bit */ + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR2, ( (clock_speed >> 2) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR1, ( (clock_speed >> 1) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR0, ( clock_speed & 0x01) ); + /* + * Finally safe to enable interrupts. + */ + HAL_restore_interrupts( saved_psr ); + } +} + +/*------------------------------------------------------------------------------ + * I2C_write() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_write +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * write_buffer, + uint16_t write_size, + uint8_t options +) +{ + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + saved_psr = HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_WRITE_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_WRITE_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + this_i2c->dir = WRITE_DIR; + this_i2c->master_tx_buffer = write_buffer; + this_i2c->master_tx_size = write_size; + this_i2c->master_tx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_read() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +) +{ + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + saved_psr = HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_READ_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_READ_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + + this_i2c->dir = READ_DIR; + + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_write_read() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_write_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * addr_offset, + uint16_t offset_size, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +) +{ + HAL_ASSERT(offset_size > 0u); + HAL_ASSERT(addr_offset != (uint8_t *)0); + HAL_ASSERT(read_size > 0u); + HAL_ASSERT(read_buffer != (uint8_t *)0); + + this_i2c->master_status = I2C_FAILED; + + if((read_size > 0u) && (offset_size > 0u)) + { + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + saved_psr = HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_RANDOM_READ_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_RANDOM_READ_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + + this_i2c->dir = WRITE_DIR; + + this_i2c->master_tx_buffer = addr_offset; + this_i2c->master_tx_size = offset_size; + this_i2c->master_tx_idx = 0u; + + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + + HAL_restore_interrupts( saved_psr ); + } +} + +/*------------------------------------------------------------------------------ + * I2C_get_status() + * See "core_i2c.h" for details of how to use this function. + */ +i2c_status_t I2C_get_status +( + i2c_instance_t * this_i2c +) +{ + i2c_status_t i2c_status ; + + i2c_status = this_i2c->master_status ; + + return i2c_status; +} + +/*------------------------------------------------------------------------------ + * I2C_wait_complete() + * See "core_i2c.h" for details of how to use this function. + */ +i2c_status_t I2C_wait_complete +( + i2c_instance_t * this_i2c, + uint32_t timeout_ms +) +{ + i2c_status_t i2c_status; + psr_t saved_psr; + /* + * Because we have no idea of what CPU we are supposed to be running on + * we need to guard this write to the timeout value to avoid ISR/user code + * interaction issues. Checking the status below should be fine as only a + * single byte should change in that. + */ + saved_psr = HAL_disable_interrupts(); + this_i2c->master_timeout_ms = timeout_ms; + HAL_restore_interrupts( saved_psr ); + + /* Run the loop until state returns I2C_FAILED or I2C_SUCESS*/ + do { + i2c_status = this_i2c->master_status; + } while(I2C_IN_PROGRESS == i2c_status); + return i2c_status; +} + +/*------------------------------------------------------------------------------ + * I2C_system_tick() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_system_tick +( + i2c_instance_t * this_i2c, + uint32_t ms_since_last_tick +) +{ + if(this_i2c->master_timeout_ms != I2C_NO_TIMEOUT) + { + if(this_i2c->master_timeout_ms > ms_since_last_tick) + { + this_i2c->master_timeout_ms -= ms_since_last_tick; + } + else + { + psr_t saved_psr; + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + /* + * Mark current transaction as having timed out. + */ + this_i2c->master_status = I2C_TIMED_OUT; + this_i2c->transaction = NO_TRANSACTION; + this_i2c->is_transaction_pending = 0; + + HAL_restore_interrupts( saved_psr ); + + /* + * Make sure we do not incorrectly signal a timeout for subsequent + * transactions. + */ + this_i2c->master_timeout_ms = I2C_NO_TIMEOUT; + } + } +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_tx_buffer() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_tx_buffer +( + i2c_instance_t * this_i2c, + const uint8_t * tx_buffer, + uint16_t tx_size +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + this_i2c->slave_tx_buffer = tx_buffer; + this_i2c->slave_tx_size = tx_size; + this_i2c->slave_tx_idx = 0u; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_rx_buffer() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_rx_buffer +( + i2c_instance_t * this_i2c, + uint8_t * rx_buffer, + uint16_t rx_size +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + this_i2c->slave_rx_buffer = rx_buffer; + this_i2c->slave_rx_size = rx_size; + this_i2c->slave_rx_idx = 0u; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_mem_offset_length() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_mem_offset_length +( + i2c_instance_t * this_i2c, + uint8_t offset_length +) +{ + HAL_ASSERT(offset_length <= MAX_OFFSET_LENGTH); + + /* + * Single byte update, should be interrupt safe + */ + if(offset_length > MAX_OFFSET_LENGTH) + { + this_i2c->slave_mem_offset_length = MAX_OFFSET_LENGTH; + } + else + { + this_i2c->slave_mem_offset_length = offset_length; + } +} + +/*------------------------------------------------------------------------------ + * I2C_register_write_handler() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_register_write_handler +( + i2c_instance_t * this_i2c, + i2c_slave_wr_handler_t handler +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + this_i2c->slave_write_handler = handler; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_enable_slave() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_enable_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register and slave mode flag without the I2C ISR interrupting + * us. + */ + saved_psr = HAL_disable_interrupts(); + + /* Set the Assert Acknowledge bit. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + /* Enable slave mode */ + this_i2c->is_slave_enabled = 1u; + + HAL_restore_interrupts( saved_psr ); + + /* Enable I2C IRQ*/ + I2C_enable_irq( this_i2c ); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_slave() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_disable_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + /* Reset the assert acknowledge bit. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + + /* Disable slave mode with IRQ blocked to make whole change atomic */ + this_i2c->is_slave_enabled = 0u; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * + */ +static void enable_slave_if_required +( + i2c_instance_t * this_i2c +) +{ + /* + * This function is only called from within the ISR and so does not need + * guarding on the register access. + */ + if( 0 != this_i2c->is_slave_enabled ) + { + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x01u ); + } +} +/*------------------------------------------------------------------------------ + * I2C_set_slave_second_addr() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_slave_second_addr +( + i2c_instance_t * this_i2c, + uint8_t second_slave_addr +) +{ + uint8_t second_slave_address; + + /* + This function does not support CoreI2C hardware configured with a fixed + second slave address. The current implementation of the ADDR1[0] register + bit makes it difficult for the driver to support both programmable and + fixed second slave address, so we choose to support programmable only. + With the programmable configuration, ADDR1[0] and ADDR0[0] both control + enable/disable of GCA recognition, as an effective OR of the 2 bit fields. + Therefore we set ADDR1[0] to 0 here, so that only ADDR0[0] controls GCA. + */ + second_slave_address = (uint8_t)((second_slave_addr << 1u) & (~SLAVE1_EN_MASK)); + + /* + * Single byte register write, should be interrupt safe + */ + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, second_slave_address); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_slave_second_addr() + * See "i2c.h" for details of how to use this function. + */ +void I2C_disable_slave_second_addr +( + i2c_instance_t * this_i2c +) +{ + /* + We are disabling the second slave address by setting the value of the 2nd + slave address to the primary slave address. The reason for using this method + of disabling 2nd slave address is that ADDRESS1[0] has different meaning + depending on hardware configuration. Its use would likely interfere with + the intended GCA setting. + */ + /* + * Single byte register write, should be interrupt safe + */ + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, this_i2c->ser_address); +} + +/*------------------------------------------------------------------------------ + * i2C_set_gca() + * See "i2c.h" for details of how to use this function. + */ + +void I2C_set_gca +( + i2c_instance_t * this_i2c +) +{ + /* + * This read modify write access should be interrupt safe as the address + * register is not written to in the ISR. + */ + /* accept GC addressing. */ + HAL_set_8bit_reg_field(this_i2c->base_address, GC, 0x01u); +} + +/*------------------------------------------------------------------------------ + * I2C_clear_gca() + * See "i2c.h" for details of how to use this function. + */ +void I2C_clear_gca +( + i2c_instance_t * this_i2c +) +{ + /* + * This read modify write access should be interrupt safe as the address + * register is not written to in the ISR. + */ + /* Clear GC addressing. */ + HAL_set_8bit_reg_field(this_i2c->base_address, GC, 0x00u); +} + +/*------------------------------------------------------------------------------ + * I2C_isr() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_isr +( + i2c_instance_t * this_i2c +) +{ + volatile uint8_t status; + uint8_t data; + uint8_t hold_bus; + uint8_t clear_irq = 1u; + + status = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + + switch( status ) + { + /************** MASTER TRANSMITTER / RECEIVER *******************/ + + case ST_START: /* start has been xmt'd */ + case ST_RESTART: /* repeated start has been xmt'd */ + HAL_set_8bit_reg_field( this_i2c->base_address, STA, 0x00u); + HAL_set_8bit_reg( this_i2c->base_address, DATA, this_i2c->target_addr); /* write call address */ + HAL_set_8bit_reg_field( this_i2c->base_address, DIR, this_i2c->dir); /* set direction bit */ + if(this_i2c->dir == WRITE_DIR) + { + this_i2c->master_tx_idx = 0u; + } + else + { + this_i2c->master_rx_idx = 0u; + } + + /* + * Clear the pending transaction. This condition will be true if the slave + * has acquired the bus to carry out pending master transaction which + * it had received during its slave transmission or reception mode. + */ + if(this_i2c->is_transaction_pending) + { + this_i2c->is_transaction_pending = 0u; + } + + /* + * Make sure to update proper transaction after master START + * or RESTART + */ + if(this_i2c->transaction != this_i2c->pending_transaction) + { + this_i2c->transaction = this_i2c->pending_transaction; + } + break; + + case ST_LOST_ARB: + /* Set start bit. Let's keep trying! Don't give up! */ + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + break; + + case ST_STOP_TRANSMIT: + /* Stop has been transmitted. Do nothing */ + break; + + /******************* MASTER TRANSMITTER *************************/ + case ST_SLAW_NACK: + /* SLA+W has been transmitted; not ACK has been received - let's stop. */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_FAILED; + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + case ST_SLAW_ACK: + case ST_TX_DATA_ACK: + /* data byte has been xmt'd with ACK, time to send stop bit or repeated start. */ + if (this_i2c->master_tx_idx < this_i2c->master_tx_size) + { + HAL_set_8bit_reg(this_i2c->base_address, DATA, (uint_fast8_t)this_i2c->master_tx_buffer[this_i2c->master_tx_idx++]); + } + else if ( this_i2c->transaction == MASTER_RANDOM_READ_TRANSACTION ) + { + /* We are finished sending the address offset part of a random read transaction. + * It is is time to send a restart in order to change direction. */ + this_i2c->dir = READ_DIR; + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + else /* done sending. let's stop */ + { + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + hold_bus = this_i2c->options & I2C_HOLD_BUS; + + /* Store the information of current I2C bus status in the bus_status*/ + this_i2c->bus_status = hold_bus; + if ( hold_bus == 0u ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); /*xmt stop condition */ + enable_slave_if_required(this_i2c); + } + else + { + I2C_disable_irq( this_i2c ); + clear_irq = 0u; + } + this_i2c->master_status = I2C_SUCCESS; + } + break; + + case ST_TX_DATA_NACK: + /* data byte SENT, ACK to be received + * In fact, this means we've received a NACK (This may not be + * obvious, but if we've rec'd an ACK then we would be in state + * 0x28!) hence, let's send a stop bit + */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u);/* xmt stop condition */ + this_i2c->master_status = I2C_FAILED; + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + /********************* MASTER (or slave?) RECEIVER *************************/ + + /* STATUS codes 08H, 10H, 38H are all covered in MTX mode */ + case ST_SLAR_ACK: /* SLA+R tx'ed. */ + /* Let's make sure we ACK the first data byte received (set AA bit in CTRL) unless + * the next byte is the last byte of the read transaction. + */ + if(this_i2c->master_rx_size > 1u) + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + } + else if(1u == this_i2c->master_rx_size) + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + else /* this_i2c->master_rx_size == 0u */ + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_SUCCESS; + this_i2c->transaction = NO_TRANSACTION; + } + break; + + case ST_SLAR_NACK: /* SLA+R tx'ed; let's release the bus (send a stop condition) */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_FAILED; + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + case ST_RX_DATA_ACK: /* Data byte received, ACK returned */ + /* First, get the data */ + this_i2c->master_rx_buffer[this_i2c->master_rx_idx++] = HAL_get_8bit_reg(this_i2c->base_address, DATA); + if( this_i2c->master_rx_idx >= (this_i2c->master_rx_size - 1u)) + { + /* If we're at the second last byte, let's set AA to 0 so + * we return a NACK at the last byte. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + break; + + case ST_RX_DATA_NACK: /* Data byte received, NACK returned */ + /* Get the data, then send a stop condition */ + this_i2c->master_rx_buffer[this_i2c->master_rx_idx] = HAL_get_8bit_reg(this_i2c->base_address, DATA); + + hold_bus = this_i2c->options & I2C_HOLD_BUS; + + /* Store the information of current I2C bus status in the bus_status*/ + this_i2c->bus_status = hold_bus; + if ( hold_bus == 0u ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); /*xmt stop condition */ + + /* Bus is released, now we can start listening to bus, if it is slave */ + enable_slave_if_required(this_i2c); + } + else + { + I2C_disable_irq( this_i2c ); + clear_irq = 0u; + } + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + this_i2c->master_status = I2C_SUCCESS; + break; + + /******************** SLAVE RECEIVER **************************/ + case ST_GCA_NACK: /* NACK after, GCA addressing */ + case ST_SLA_NACK: /* Re-enable AA (assert ack) bit for future transmissions */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + this_i2c->transaction = NO_TRANSACTION; + this_i2c->slave_status = I2C_SUCCESS; + + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + break; + + case ST_GCA_LA: /* Arbitr. lost (GCA rec'd) */ + case ST_SLV_LA: /* Arbitr. lost (SLA rec'd) */ + /* + * We lost arbitration and either the GCE or our address was the + * one received so pend the master operation we were starting. + */ + this_i2c->is_transaction_pending = 1u; + /* Fall through to normal ST processing as we are now in slave mode */ + + case ST_GCA: /* General call address received, ACK returned */ + case ST_SLAVE_SLAW: /* SLA+W received, ACK returned */ + this_i2c->transaction = WRITE_SLAVE_TRANSACTION; + this_i2c->slave_rx_idx = 0u; + this_i2c->random_read_addr = 0u; + /* + * If Start Bit is set clear it, but store that information since it is because of + * pending transaction + */ + if(HAL_get_8bit_reg_field(this_i2c->base_address, STA)) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + this_i2c->is_transaction_pending = 1u; + } + this_i2c->slave_status = I2C_IN_PROGRESS; +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + /* Fall through to put address as first byte in payload buffer */ +#else + /* Only break from this case if the slave address must NOT be included at the + * beginning of the received write data. */ + break; +#endif + case ST_GCA_ACK: /* DATA received; ACK sent after GCA */ + case ST_RDATA: /* DATA received; must clear DATA register */ + if((this_i2c->slave_rx_buffer != (uint8_t *)0) + && (this_i2c->slave_rx_idx < this_i2c->slave_rx_size)) + { + data = HAL_get_8bit_reg(this_i2c->base_address, DATA); + this_i2c->slave_rx_buffer[this_i2c->slave_rx_idx++] = data; + +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + if((ST_RDATA == status) || (ST_GCA_ACK == status)) + { + /* Ignore the slave address byte in the random read address + computation in the case where INCLUDE_SLA_IN_RX_PAYLOAD + is defined. */ +#endif + this_i2c->random_read_addr = (this_i2c->random_read_addr << 8) + data; +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + } +#endif + } + + if(this_i2c->slave_rx_idx >= this_i2c->slave_rx_size) + { + /* Rx buffer is full. NACK next received byte. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + break; + + case ST_RSTOP: + /* STOP or repeated START occurred. */ + /* We cannot be sure if the transaction has actually completed as + * this hardware state reports that either a STOP or repeated START + * condition has occurred. We assume that this is a repeated START + * if the transaction was a write from the master to this point.*/ + if ( this_i2c->transaction == WRITE_SLAVE_TRANSACTION ) + { + if ( this_i2c->slave_rx_idx == this_i2c->slave_mem_offset_length ) + { + this_i2c->slave_tx_idx = this_i2c->random_read_addr; + } + /* Call the slave's write transaction handler if it exists. */ + if ( this_i2c->slave_write_handler != 0u ) + { + i2c_slave_handler_ret_t h_ret; + h_ret = this_i2c->slave_write_handler( this_i2c, this_i2c->slave_rx_buffer, (uint16_t)this_i2c->slave_rx_idx ); + if ( I2C_REENABLE_SLAVE_RX == h_ret ) + { + /* There is a small risk that the write handler could + * call I2C_disable_slave() but return + * I2C_REENABLE_SLAVE_RX in error so we only enable + * ACKs if still in slave mode. */ + enable_slave_if_required(this_i2c); + } + else + { + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x0u ); + /* Clear slave mode flag as well otherwise in mixed + * master/slave applications, the AA bit will get set by + * subsequent master operations. */ + this_i2c->is_slave_enabled = 0u; + } + } + else + { + /* Re-enable address acknowledge in case we were ready to nack the next received byte. */ + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x01u ); + } + } + else /* A stop or repeated start outside a write/read operation */ + { + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * See if we need to re-enable acknowledgement as some error conditions, such + * as a master prematurely ending a transfer, can see us get here with AA set + * to 0 which will disable slave operation if we are not careful. + */ + enable_slave_if_required(this_i2c); + } + + /* Mark any previous master write transaction as complete. */ + this_i2c->slave_status = I2C_SUCCESS; + + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + + break; + + case ST_SLV_RST: /* SMBUS ONLY: timeout state. must clear interrupt */ + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction. + */ + this_i2c->transaction = NO_TRANSACTION; + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * Clear status to I2C_FAILED only if there was an operation in progress. + */ + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->slave_status = I2C_FAILED; + } + + enable_slave_if_required(this_i2c); /* Make sure AA is set correctly */ + + break; + + /****************** SLAVE TRANSMITTER **************************/ + case ST_SLAVE_SLAR_ACK: /* SLA+R received, ACK returned */ + case ST_SLARW_LA: /* Arbitration lost, and: */ + case ST_RACK: /* Data tx'ed, ACK received */ + if ( status == ST_SLAVE_SLAR_ACK ) + { + this_i2c->transaction = READ_SLAVE_TRANSACTION; + this_i2c->random_read_addr = 0u; + this_i2c->slave_status = I2C_IN_PROGRESS; + /* If Start Bit is set clear it, but store that information since it is because of + * pending transaction + */ + if(HAL_get_8bit_reg_field(this_i2c->base_address, STA)) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + this_i2c->is_transaction_pending = 1u; + } + } + if (this_i2c->slave_tx_idx >= this_i2c->slave_tx_size) + { + /* Ensure 0xFF is returned to the master when the slave specifies + * an empty transmit buffer. */ + HAL_set_8bit_reg(this_i2c->base_address, DATA, 0xFFu); + } + else + { + /* Load the data the data byte to be sent to the master. */ + HAL_set_8bit_reg(this_i2c->base_address, DATA, (uint_fast8_t)this_i2c->slave_tx_buffer[this_i2c->slave_tx_idx++]); + } + /* Determine if this is the last data byte to send to the master. */ + if (this_i2c->slave_tx_idx >= this_i2c->slave_tx_size) /* last byte? */ + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + /* Next read transaction will result in slave's transmit buffer + * being sent from the first byte. */ + this_i2c->slave_tx_idx = 0u; + } + break; + + case ST_SLAVE_RNACK: /* Data byte has been transmitted; not-ACK has been received. */ + case ST_FINAL: /* Last Data byte tx'ed, ACK received */ + /* We assume that the transaction will be stopped by the master. + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. */ + this_i2c->slave_tx_idx = 0u; + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + /* Mark previous state as complete */ + this_i2c->slave_status = I2C_SUCCESS; + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + + break; + + /* Master Reset has been activated Wait 35 ms for interrupt to be set, + * clear interrupt and proceed to 0xF8 state. */ + case ST_RESET_ACTIVATED: + case ST_BUS_ERROR: /* Bus error during MST or selected slave modes */ + default: + /* Some undefined state has encountered. Clear Start bit to make + * sure, next good transaction happen */ + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction. + */ + this_i2c->transaction = NO_TRANSACTION; + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * Clear statuses to I2C_FAILED only if there was an operation in progress. + */ + if(I2C_IN_PROGRESS == this_i2c->master_status) + { + this_i2c->master_status = I2C_FAILED; + } + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->slave_status = I2C_FAILED; + } + + break; + } + + if ( clear_irq ) + { + /* clear interrupt. */ + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + /* Read the status register to ensure the last I2C registers write took place + * in a system built around a bus making use of posted writes. */ + status = HAL_get_8bit_reg( this_i2c->base_address, STATUS); +} + +/*------------------------------------------------------------------------------ + * I2C_smbus_init() + * See "i2c.h" for details of how to use this function. + */ + +/* + * SMBSUS_NO = 1 + * SMBALERT_NO = 1 + * SMBus enable = 1 + */ +#define INIT_AND_ENABLE_SMBUS 0x54u +void I2C_smbus_init +( + i2c_instance_t * this_i2c +) +{ + /* + * Single byte register write, should be interrupt safe + */ + /* Enable SMBUS */ + HAL_set_8bit_reg(this_i2c->base_address, SMBUS, INIT_AND_ENABLE_SMBUS); +} + +/*------------------------------------------------------------------------------ + * I2C_enable_smbus_irq() + * See "i2c.h" for details of how to use this function. + */ +void I2C_enable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + if ( irq_type & I2C_SMBALERT_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_IE, 0x01u); + } + if ( irq_type & I2C_SMBSUS_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_IE, 0x01u); + } + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_smbus_irq() + * See "i2c.h" for details of how to use this function. + */ +void I2C_disable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + if ( irq_type & I2C_SMBALERT_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_IE, 0x00u); + } + if (irq_type & I2C_SMBSUS_IRQ ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_IE, 0x00u); + } + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_suspend_smbus_slave() + * See "i2c.h" for details of how to use this function. + */ +void I2C_suspend_smbus_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_NO_CONTROL, 0x00u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_resume_smbus_slave() + * See "i2c.h" for details of how to use this function. + */ +void I2C_resume_smbus_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_NO_CONTROL, 0x01u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_reset_smbus() + * See "i2c.h" for details of how to use this function. + */ +void I2C_reset_smbus +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + HAL_set_8bit_reg_field(this_i2c->base_address, SMBUS_MST_RESET, 0x01u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_smbus_alert() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_smbus_alert +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_NO_CONTROL, 0x00u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_clear_smbus_alert() + * See "i2c.h" for details of how to use this function. + */ +void I2C_clear_smbus_alert +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_NO_CONTROL, 0x01u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_get_irq_status() + * See "i2c.h" for details of how to use this function. + */ +uint8_t I2C_get_irq_status +( + i2c_instance_t * this_i2c +) +{ + uint8_t status ; + uint8_t irq_type = I2C_NO_IRQ ; + + status = HAL_get_8bit_reg(this_i2c->base_address, SMBUS); + + if( status & (uint8_t)SMBALERT_NI_STATUS_MASK ) + { + irq_type |= I2C_SMBALERT_IRQ ; + } + + if( status & (uint8_t)SMBSUS_NI_STATUS_MASK ) + { + irq_type |= I2C_SMBSUS_IRQ ; + } + + status = HAL_get_8bit_reg(this_i2c->base_address, CONTROL); + + if( status & (uint8_t)SI_MASK ) + { + irq_type |= I2C_INTR_IRQ ; + } + return(irq_type); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_addr2() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_user_data +( + i2c_instance_t * this_i2c, + void * p_user_data +) +{ + this_i2c->p_user_data = p_user_data ; +} + +/*------------------------------------------------------------------------------ + * I2C_get_user_data() + * See "i2c.h" for details of how to use this function. + */ +void * I2C_get_user_data +( + i2c_instance_t * this_i2c +) +{ + return( this_i2c->p_user_data); +} + +#ifdef __cplusplus +} +#endif + diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h new file mode 100644 index 0000000..3891ce0 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h @@ -0,0 +1,2306 @@ +/***************************************************************************//** + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * CoreI2C software driver Application Programming Interface. + * This file contains defines and function declarations allowing to interface + * with the CoreI2C software driver. + * + */ +/*=========================================================================*//** + @mainpage CoreI2C Bare Metal Driver. + The CoreI2C bare metal software driver supports I2C master and slave + operations. + + ============================================================================== + Introduction + ============================================================================== + The CoreI2C driver provides a set of functions for controlling the Microchip + CoreI2C hardware IP. The driver supports up to 16 separate I2C channels per + CoreI2C instance, with common slave address settings shared between channels + on a device. + + Optional features of the CoreI2C allow it to operate with I2C based protocols + such as System Management Bus (SMBus), Power Management Bus (PMBus), and + Intelligent Platform Management Interface (IPMI). This driver provides support + for these features when enabled in the CoreI2C IP. + + The major features provided by CoreI2C driver: + - Provides support to configuring the I2C channels of each CoreI2C peripheral device. + - I2C master operations. + - I2C slave operations. + - SMBus related operations. + + This driver is used as part of a bare metal system where no operating + system is available. The driver gets adapted as a part of an operating system, + but the implementation of the adaptation layer between the driver and the operating + system's driver model is outside the scope of this driver. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + Your application software should configure the CoreI2C driver through + calls to the I2C_init() function for each CoreI2C instance in the + hardware design. The configuration parameters include the CoreI2C hardware + instance base address and other runtime parameters, such as the I2C serial + clock frequency and the I2C device address. + + Once channel 0 of a CoreI2C peripheral has been initialized by I2C_init(), + any additional channels present should be configured by calling + I2C_channel_init() for each of the remaining channels. + + Apart from the CoreI2C hardware instance base address, no CoreI2C hardware configuration + parameters are used by the driver. Hence, no additional configuration files are required + to use the driver. + + -------------------------------- + Interrupt Control + -------------------------------- + The CoreI2C driver has to enable and disable the generation of interrupts by + CoreI2C at various times when it is operating. This enabling and disabling of + interrupts must be done through the system’s interrupt controller. For that + reason, the method of controlling the CoreI2C interrupt is system specific + and it is necessary to customize the I2C_enable_irq() and I2C_disable_irq() + functions. These functions are available in the i2c_interrupt.c file. + The default implementation calls HAL_ASSERT(0) to indicate to the application + developer that a suitable implementations for these functions must be provided. + + The implementation of the I2C_enable_irq() function should permit interrupts + generated by a CoreI2C instance to interrupt the processor. The implementation + of the I2C_disable_irq() function should prevent interrupts generated by a + CoreI2C instance from interrupting the processor. See the provided example + projects for a working implementation of these functions. + + The I2C_register_write_handler() function registers a write handler + function with the CoreI2C driver that calls on completion of an I2C write + transaction by the CoreI2C slave. It is your responsibility to create and + register the implementation of this handler function that processes or + trigger the processing of the received data. + + The SMBSUS and SMBALERT interrupts are related to the SMBus interface and are + enabled and disabled through I2C_enable_smbus_irq() and + I2C_disable_smbus_irq() respectively. It is your responsibility to create + interrupt handler functions in your application to get the desired response + for the SMBus interrupts. + + Note: You must include the path to any application header files that are + included in the i2c_interrupt.c file, as an include path in your + project's compiler settings. The details of how to do this will depend + on your development software. + + -------------------------------- + SMBus Logic Options + -------------------------------- + SMBus related APIs does not have any effect if the "Generate SMBus Logic" + is not enabled in the CoreI2C hardware configuration. Following are API's + that does not give the desired results if SMBus Logic is disabled. + + - I2C_smbus_init() + - I2C_reset_smbus() + - I2C_enable_smbus_irq() + - I2C_disable_smbus_irq() + - I2C_suspend_smbus_slave() + - I2C_resume_smbus_slave() + - I2C_set_smsbus_alert() + - I2C_clear_smsbus_alert() + - I2C_get_irq_status() + + -------------------------------- + Fixed Baud Rate Values + -------------------------------- + The serial clock frequency parameter passed to the I2C_init() and + I2C_channel_init() functions may not have any effect if fixed values were + selected for Baud rate in the hardware configuration of CoreI2C. When fixed + values are selected for these baud rates, the driver cannot overwrite + the fixed values. + + ----------------------------------- + Fixed Slave Address Options Values + ----------------------------------- + The primary slave address parameter passed to the I2C_init() function and + secondary address value passed to the I2C_set_slave_second_addr() function, + may not have the desired effect if fixed values were selected for the slave 0 + address and slave 1 address respectively. Proper operation of this version of + the driver requires the slave addresses to be programmable. + + ============================================================================== + Theory of Operation + ============================================================================== + The CoreI2C software driver is designed to allow the control of multiple + instances of CoreI2C with one or more I2C channels. Each channel in an + instance of CoreI2C in the hardware design is associated with a single + instance of the i2c_instance_t structure in the software. You must allocate + memory for one unique i2c_instance_t structure instance for each channel of + each CoreI2C hardware instance. The contents of these data structures are + initialised by calling I2C_init() and if necessary I2C_channel_init(). + A pointer to the structure is passed to the subsequent driver functions in order + to identify the CoreI2C hardware instance and channel to perform the + requested operation. + + Note: Do not attempt to directly manipulate the contents of i2c_instance_t + structures. These structures are only intended to be modified by the driver + functions. + + The CoreI2C driver functions are grouped into the following categories: + - Initialization and configuration functions + - Interrupt control + - I2C slave addressing functions + - I2C master operations functions to handle write, read, and write-read + transactions + - I2C slave operations functions to handle write, read, and write-read + transactions + - Mixed master-slave operations + - SMBus interface configuration and control + + -------------------------------- + Initialization and Configuration + -------------------------------- + The CoreI2C device is first initialized by calling the I2C_init() + function. Since each CoreI2C peripheral supports up to 16 channels, an + additional function, I2C_channel_init(), is required to initialize the + remaining channels with their own data structures. + + I2C_init() function initializes channel 0 of a CoreI2C and the i2c_instance_t + for channel 0 acts as the basis for further channel initialization as the + hardware base address and I2C serial address are same across all the channels. + Ensure to call I2C_init() function before calling any other I2C driver function + calls. The I2C_init() call for each CoreI2C takes the I2C serial address assigned + to the I2C and the serial clock divider to generate its I2C clock as configuration + parameters. + + I2C_channel_init() function takes as input parameters a pointer to the CoreI2C + i2c_instance_t which has been initialized by calling the I2C_init() and a pointer + to a separate i2c_instance_t which represents this new channel. Another input + parameter which is required by this function is serial clock divider which generates + its I2C clock. + + -------------------------------- + Interrupt Control + -------------------------------- + The CoreI2C driver is interrupt driven and it uses each channels INT + interrupt to drive the state machine which is at the heart of the driver. + The application is responsible for providing the link between the interrupt + generating hardware and the CoreI2C interrupt handler and must ensure that + the I2C_isr() function is called with the correct i2c_instance_t structure + pointer for the CoreI2C channel initiating the interrupt. + + The driver enables and disables the generation of INT interrupts by CoreI2C + at various times when it is operating through the user supplied + I2C_enable_irq() and I2C_disable_irq() functions. + + The I2C_register_write_handler() function is used to register a write + handler function with the CoreI2C driver which is called on completion + of an I2C write transaction by the CoreI2C slave. It is the user + applications responsibility to create and register the implementation of + this handler function that processes or triggers the processing of the + received data. + + The other two interrupt sources in the CoreI2C are related to SMBus + operation and are enabled and disabled through I2C_enable_smbus_irq() and + I2C_disable_smbus_irq() respectively. Due to the application specific + nature of the response to SMBus interrupts, you must design interrupt + handler functions in the application to get the desired behaviour for + SMBus related interrupts. + + If enabled, the SMBA_INT signal from the CoreI2C is asserted if an + SMBALERT condition is signalled on the SMBALERT_NI input for the channel. + + If enabled, the SMBS_INT signal from the CoreI2C is asserted if an + SMBSUSPEND condition is signalled on the SMBSUS_NI input for the channel. + + ## I2C Slave Addressing Functions + A CoreI2C peripheral responds to the following three slave addresses: + - Slave address 0 - This is the primary slave address that accesses + a CoreI2C channel when it acts as a slave in + I2C transactions. You must configure the primary slave + address using I2C_init(). + + - Slave address 1 - This is the secondary slave address which might be + required in certain application specific scenarios. + The secondary slave address is configured by + I2C_set_slave_second_addr() and is disabled by + I2C_disable_slave_second_addr(). + + - General call address - A CoreI2C slave can be configured to respond to + a broadcast command by a master transmitting the + general call address of 0x00. Use the I2C_set_gca() + function to enable the slave to respond to the general + call address. If the CoreI2C slave is not required to + respond to the general call address, disable this + address by calling I2C_clear_gca(). + + Note: All channels on a CoreI2C instance share the same slave address logic. + This means that they cannot have separate slave addresses and rely on + the separate physical I2C bus connections to distinguish them. + + -------------------------------- + Transaction Types + -------------------------------- + The I2C driver is designed to handle three types of I2C transaction: + - Write transactions + - Read transactions + - Write-read transactions + + ## Write Transaction + The master I2C device initiates a write transaction by sending a START bit + as soon as the bus becomes free. The START bit is followed by the 7-bit + serial address of the target slave device followed by the read/write bit + indicating the direction of the transaction. The slave acknowledges the + receipt of it's address with an acknowledge bit. The master sends data one + byte at a time to the slave, which must acknowledge the receipt of each byte + for the next byte to be sent. The master sends a STOP bit to complete the + transaction. The slave can abort the transaction by replying with a + non-acknowledge bit instead of an acknowledge bit. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ## Read Transaction + The master I2C device initiates a read transaction by sending a START bit + as soon as the bus becomes free. The START bit is followed by the 7-bit + serial address of the target slave device followed by the read/write bit + indicating the direction of the transaction. The slave acknowledges the + receipt of it's slave address with an acknowledge bit. The slave sends + data one byte at a time to the master, which must acknowledge the receipt of + each byte for the next byte to be sent. The master sends a non-acknowledge + bit following the last byte it wishes to read followed by a STOP bit. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ## Write-Read Transaction + The write-read transaction is a combination of a write transaction + immediately followed by a read transaction. There is no STOP bit in between + the write and read phases of a write-read transaction. A repeated START + bit is sent between the write and read phases. + + Whilst the write handler is being executed, the slave holds the clock line + low to stretch the clock until the response is ready. + + The write-read transaction is typically used to send a command or offset + in the write transaction specifying the logical data to be transferred + during the read phase. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ## Master Operations + The application can use the I2C_write(), I2C_read(), and I2C_write_read() + functions to initiate an I2C bus transaction. The application can then wait + for the transaction to complete using the I2C_wait_complete() function + or poll the status of the I2C transaction using the I2C_get_status() + function until it returns a value different from I2C_IN_PROGRESS. The + I2C_system_tick() function is used to set a time base for the + I2C_wait_complete() function's time out delay. + + ## Slave Operations + To configure the I2C driver to operate as an I2C slave requires the use + of the following functions: + - I2C_set_slave_tx_buffer() + - I2C_set_slave_rx_buffer() + - I2C_set_slave_mem_offset_length() + - I2C_register_write_handler() + - I2C_enable_slave() + + Use of all functions is not required if the slave I2C does not need to support + all types of I2C read transactions. The subsequent sections list the functions + that must be used to support each transaction type. + + ## Responding to Read Transactions + The following functions are used to configure the CoreI2C driver to + respond to I2C read transactions: + • I2C_set_slave_tx_buffer() + • I2C_enable_slave() + + The I2C_set_slave_tx_buffer() function specifies the data buffer that + is transmitted when the I2C slave is the target of an I2C read + transaction. It is then up to the application to manage the content of + that buffer to control the data that will be transmitted to the I2C + master as a result of the read transaction. + + The I2C_enable_slave() function enables the I2C hardware instance + to respond to the I2C transactions. It must be called after the I2C driver + has been configured to respond to the required transaction types. + + ## Responding to Write Transactions + The following functions are used to configure the I2C driver to respond + to I2C write transactions: + • I2C_set_slave_rx_buffer() + • I2C_register_write_handler() + • I2C_enable_slave() + + The I2C_set_slave_rx_buffer() function specifies the data buffer that + stored the data received by the I2C slave when it targets an I2C write + transaction. + + The I2C_register_write_handler() function specifies the handler function + that must be called on completion of the I2C write transaction. It is this + handler function that processes or triggers the processing of the received + data. + + The I2C_enable_slave() function enables the I2C hardware instance + to respond to I2C transactions. It must be called after the I2C driver + has been configured to respond to the required transaction types. + + ## Responding to Write-Read Transactions + The following functions are used to configure the CoreI2C driver to + respond to write-read transactions: + - I2C_set_slave_mem_offset_length() + - I2C_set_slave_tx_buffer() + - I2C_set_slave_rx_buffer() + - I2C_register_write_handler() + - I2C_enable_slave() + + The I2C_set_slave_mem_offset_length() function specifies the number of + bytes expected by the I2C slave during the write phase of the write-read + transaction. + + The I2C_set_slave_tx_buffer() function specifies the data that is + transmitted to the I2C master during the read phase of the write-read + transaction. The value received by the I2C slave during the write phase of + the transaction will be used as an index into the transmit buffer + specified by this function. It decides which part of the transmit buffer + will be transmitted to the I2C master as part of the read phase of the + write-read transaction. + + The I2C_set_slave_rx_buffer() function specifies the data buffer that + stores the data received by the I2C slave during the write phase of + the write-read transaction. This buffer must be large enough to accommodate + the number of bytes specified through the I2C_set_slave_mem_offset_length() + function. + + The I2C_register_write_handler() function can optionally be used to + specify a handler function that is called on completion of the write phase + of the I2C write-read transaction. If a handler function is registered, it + is responsible for processing the received data in the slave receive + buffer and populating the slave transmit buffer with the data that will be + transmitted to the I2C master as part of the read phase of the write-read + transaction. + + The I2C_enable_slave() function enables the CoreI2C hardware instance to + respond to the I2C transactions. It must be called after configuring the + CoreI2C driver to respond to the required transaction types. + + ## Mixed Master-Slave Operations + The CoreI2C device supports mixed master and slave operations. If the + CoreI2C slave has a transaction in progress and your application attempts to + begin a master mode transaction, the CoreI2C driver queues the master mode + transaction until the bus is released and the CoreI2C can switch to master + mode and acquire the bus. The CoreI2C master then starts the previously + queued master transaction. + + ## SMBus Control + The CoreI2C driver enables the CoreI2C peripheral’s SMBus functionality + using the I2C_smbus_init() function. + + The I2C_suspend_smbus_slave() function is used with a master mode CoreI2C + to force slave devices on the SMBus to enter their Power-Down/Suspend mode. + The I2C_resume_smbus_slave() function is used to end the suspend operation + on the SMBus. + + The I2C_reset_smbus() function is used with a master mode CoreI2C to force + all devices on the SMBus to reset their SMBUs interface. + + The I2C_set_smsbus_alert() function is used by a slave mode CoreI2C to + force communication with the SMBus master. Once communications with the + master is initiated, the I2C_clear_smsbus_alert() function clears the alert + condition. + + The I2C_enable_smbus_irq() and I2C_disable_smbus_irq() functions are used to + enable and disable the SMBSUS and SMBALERT SMBus interrupts. + + *//*=========================================================================*/ + +#ifndef CORE_I2C_H_ +#define CORE_I2C_H_ + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#include "hal_assert.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + I2C_RELEASE_BUS + ======================================= + The I2C_RELEASE_BUS constant is used to specify the options parameter to + functions I2C_read(), I2C_write() and I2C_write_read() to indicate + that a STOP bit must be generated at the end of the I2C transaction to release + the bus. + */ +#define I2C_RELEASE_BUS 0x00u + +/*-------------------------------------------------------------------------*//** + I2C_HOLD_BUS + ======================================= + The I2C_HOLD_BUS constant specify the options parameter to functions I2C_read(), + I2C_write(), and I2C_write_read() to indicate that a STOP bit must not be + generated at the end of the I2C transaction in order to retain the bus ownership. + This causes the next transaction to begin with a repeated START bit and no STOP + bit between the transactions. + */ +#define I2C_HOLD_BUS 0x01u + +/*-------------------------------------------------------------------------*//** + Interrupt Identifier Number + ======================================= + The following constants specify the interrupt identifier number which is + solely used by the driver API. This has nothing to do with hardware interrupt + line. I2C_INTR_IRQ is the primary interrupt signal which drives the state machine + of the CoreI2C driver. The I2C_SMBALERT_IRQ and I2C_SMBSUS_IRQ are used by + SMBus interrupt enable and disable functions. These IRQ numbers are also used + by I2C_get_irq_status(). + + | Constant | Description | + |--------------------|--------------------------------------------------------| + | I2C_NO_IRQ | No interrupt | + | I2C_SMBALERT_IRQ | Used by SMBus interrupt enable functions | + | I2C_SMBSUS_IRQ | Used by SMBus interrupt disable functions | + | I2C_INTR_IRQ | Primary interrupt signal which drives the state machine| + + */ +#define I2C_NO_IRQ 0x00u +#define I2C_SMBALERT_IRQ 0x01u +#define I2C_SMBSUS_IRQ 0x02u +#define I2C_INTR_IRQ 0x04u + +/*-------------------------------------------------------------------------*//** + I2C_NO_TIMEOUT + ======================================= + The I2C_wait_complete() function uses I2C_NO_TIMEOUT constant as a parameter + to indicate that the wait for completion of the transaction should not time out. + */ +#define I2C_NO_TIMEOUT 0u + +/***************************************************************************//** + The i2c_channel_number_t type is used to specify the channel number of a + CoreI2C instance. + */ +typedef enum i2c_channel_number { + I2C_CHANNEL_0 = 0u, + I2C_CHANNEL_1, + I2C_CHANNEL_2, + I2C_CHANNEL_3, + I2C_CHANNEL_4, + I2C_CHANNEL_5, + I2C_CHANNEL_6, + I2C_CHANNEL_7, + I2C_CHANNEL_8, + I2C_CHANNEL_9, + I2C_CHANNEL_10, + I2C_CHANNEL_11, + I2C_CHANNEL_12, + I2C_CHANNEL_13, + I2C_CHANNEL_14, + I2C_CHANNEL_15, + I2C_MAX_CHANNELS = 16u +} i2c_channel_number_t; + +/***************************************************************************//** + The i2c_clock_divider_t type specifies the divider to be applied + to the I2C PCLK or BCLK signal in order to generate the I2C clock. + The I2C_BCLK_DIV_8 value selects a clock frequency based on division of BCLK, + all other values select a clock frequency based on division of PCLK. + */ +typedef enum i2c_clock_divider { + I2C_PCLK_DIV_256 = 0u, + I2C_PCLK_DIV_224, + I2C_PCLK_DIV_192, + I2C_PCLK_DIV_160, + I2C_PCLK_DIV_960, + I2C_PCLK_DIV_120, + I2C_PCLK_DIV_60, + I2C_BCLK_DIV_8 +} i2c_clock_divider_t; + +/***************************************************************************//** + The i2c_status_t type is used to report the status of I2C transactions. + */ +typedef enum i2c_status +{ + I2C_SUCCESS = 0u, + I2C_IN_PROGRESS, + I2C_FAILED, + I2C_TIMED_OUT +} i2c_status_t; + +/***************************************************************************//** + The i2c_slave_handler_ret_t type is used by slave write handler functions + to indicate whether or not the received data buffer should be released. + */ +typedef enum i2c_slave_handler_ret { + I2C_REENABLE_SLAVE_RX = 0u, + I2C_PAUSE_SLAVE_RX = 1u +} i2c_slave_handler_ret_t; + +/***************************************************************************//** + This structure identifies various CoreI2C hardware instances in the system + and the I2C channels within them. The application software should declare + one instance of this structure for each channel of each instance of CoreI2C + in your system. I2C_init() and I2C_channel_init() functions initialize this + structure depending on whether it is channel 0 or one of the additional + channels, respectively. A pointer to an initialized instance of the + structure should be passed as the first parameter to the CoreI2C driver + functions, to identify which CoreI2C hardware instance and channel should + perform the requested operation. + + The contents of this data structure should not be modified or used outside of + the CoreI2C driver. Software using the CoreI2C driver should only need to + create one single instance of this data structure for each channel of each + CoreI2C hardware instance in the system then pass a pointer to these data + structures with each call to the CoreI2C driver in order to identify which + CoreI2C hardware instance to use. + */ +typedef struct i2c_instance i2c_instance_t ; +/***************************************************************************//* + Slave write handler functions prototype +/***************************************************************************//** + This defines the function prototype that must be followed by I2C slave write + handler functions. These functions are registered with the CoreI2C driver + through the I2C_register_write_handler() function. + + Declaring and Implementing Slave Write Handler Functions: + + Slave write handler functions should follow the following prototype: + @code + i2c_slave_handler_ret_t write_handler + ( + i2c_instance_t *instance, uint8_t * data, uint16_t size + ); + @endcode + + The instance parameter is a pointer to the i2c_instance_t for which this + slave write handler has been declared. + + The data parameter is a pointer to a buffer (received data buffer) holding + the data written to the I2C slave. + + Define the INCLUDE_SLA_IN_RX_PAYLOAD macro for the driver to insert the + actual address used to access the slave as the first byte in the buffer. + This allows the applications to tailor their response based on the actual + address used to access the slave (primary address, secondary address, or GCA). + + The size parameter is the number of bytes held in the received data buffer. + Handler functions must return one of the following values: + - I2C_REENABLE_SLAVE_RX + - I2C_PAUSE_SLAVE_RX + + If the handler function returns I2C_REENABLE_SLAVE_RX, the driver releases + the received data buffer and allows further I2C write transactions to the + I2C slave. + + If the handler function returns I2C_PAUSE_SLAVE_RX, the I2C slave responds + to subsequent write requests with a non-acknowledge bit (NACK), until the + received data buffer content gets processed by some other part of the + software application. + + Call the I2C_enable_slave() after returning the I2C_PAUSE_SLAVE_RX to release + the received data buffer in order to store the data received by the subsequent + I2C write transactions. + */ +typedef i2c_slave_handler_ret_t (*i2c_slave_wr_handler_t)(i2c_instance_t *instance, uint8_t *, uint16_t ); + +/***************************************************************************//** + This structure is used to identify the various CoreI2C hardware instances in + your system and the I2C channels within them. Your application software should + declare one instance of this structure for each channel of each instance of + CoreI2C in your system. The functions I2C_init() and I2C_channel_init() + initialize this structure depending on whether it is channel 0 or one of the + additional channels respectively. A pointer to an initialized instance of the + structure should be passed as the first parameter to the CoreI2C driver + functions, to identify which CoreI2C hardware instance and channel should + perform the requested operation. + + The contents of this data structure should not be modified or used outside of + the CoreI2C driver. Software using the CoreI2C driver should only need to + create one single instance of this data structure for each channel of each + CoreI2C hardware instance in the system then pass a pointer to these data + structures with each call to the CoreI2C driver in order to identify the + CoreI2C hardware instance it wishes to use. + */ +struct i2c_instance +{ + addr_t base_address; + uint_fast8_t ser_address; + + /* Transmit related info:*/ + uint_fast8_t target_addr; + + /* Current transaction type (WRITE, READ, RANDOM_READ)*/ + uint8_t transaction; + + uint_fast16_t random_read_addr; + + uint8_t options; + + /* Master TX INFO: */ + const uint8_t * master_tx_buffer; + uint_fast16_t master_tx_size; + uint_fast16_t master_tx_idx; + uint_fast8_t dir; + + /* Master RX INFO: */ + uint8_t * master_rx_buffer; + uint_fast16_t master_rx_size; + uint_fast16_t master_rx_idx; + + /* Master Status */ + volatile i2c_status_t master_status; + uint32_t master_timeout_ms; + + /* Slave TX INFO */ + const uint8_t * slave_tx_buffer; + uint_fast16_t slave_tx_size; + uint_fast16_t slave_tx_idx; + + /* Slave RX INFO */ + uint8_t * slave_rx_buffer; + uint_fast16_t slave_rx_size; + uint_fast16_t slave_rx_idx; + /* Slave Status */ + volatile i2c_status_t slave_status; + + /* Slave data: */ + uint_fast8_t slave_mem_offset_length; + i2c_slave_wr_handler_t slave_write_handler; + uint8_t is_slave_enabled; + + /* user specific data */ + void *p_user_data ; + + /* I2C bus status */ + uint8_t bus_status; + + /* Is transaction pending flag */ + uint8_t is_transaction_pending; + + /* I2C Pending transaction */ + uint8_t pending_transaction; +}; + +/*------------------------Public Function-------------------------------------*/ + +/***************************************************************************//** + The I2C_init() function configures channel 0 of a CoreI2C instance. It sets + the base hardware address which is used to locate the CoreI2C instance + in memory and also used internally by I2C_channel_init() to calculate the + register addresses for any additional channels. The slave serial address set + is shared by all channels on a CoreI2C instance. + + If only one channel is configured in a CoreI2C, the address of the + i2c_instance_t used in I2C_Init() will also be used in subsequent calls to the + CoreI2C driver functions. If more than one channel is configured in the + CoreI2C, I2C_channel_init() will be called after I2C_init(), which initializes + the i2c_instance_t data structure for a specific channel. + + @param this_i2c + Pointer to the i2c_instance_t data structure that holds all the data + related to channel 0 of the CoreI2C instance is initialized. A pointer + to this structure is used in all subsequent calls to the CoreI2C driver + functions which operates on channel 0 of this CoreI2C instance. + + @param base_address + Base address in the processor's memory map of the registers of the CoreI2C + instance being initialized. + + @param ser_address + This parameter sets the primary I2C serial address (SLAVE0 address) for the + CoreI2C to initialize. It is the principal I2C bus address to which the + CoreI2C instance will respond. CoreI2C can operate in master mode or slave + mode and the serial address is significant only in the case of I2C slave + mode. In master mode, CoreI2C does not require a serial address and the + value of this parameter is not important. If you do not intend to use the + CoreI2C device in slave mode, then provide any dummy slave address value + to this parameter. However, in systems where the CoreI2C is expected to + switch from master mode to slave mode, it is advisable to initialize the + CoreI2C device with a valid serial slave address. Call the I2C_init() + function whenever it is required to change the primary slave address as + there is no separate function to set the primary slave address of the + I2C device. The serial address initialized through this function is + basically the primary slave address or slave address0. + I2C_set_slave_second_addr() is used to set the secondary slave address + or slave address 1. + Note : ser_address parameter does not have any affect if fixed slave + address is enabled in CoreI2C hardware design. CoreI2C will + be always addressed with the hardware configured fixed slave + address. + Note : ser_address parameter will not have any affect if the CoreI2C + instance is only used in master mode. + + @param ser_clock_speed + This parameter sets the I2C serial clock frequency. It selects the divider + that generates the serial clock from the APB PCLK or from the BCLK. + It can be one of the following: + - I2C_PCLK_DIV_256 + - I2C_PCLK_DIV_224 + - I2C_PCLK_DIV_192 + - I2C_PCLK_DIV_160 + - I2C_PCLK_DIV_960 + - I2C_PCLK_DIV_120 + - I2C_PCLK_DIV_60 + - I2C_BCLK_DIV_8 + Note: serial_clock_speed value does not have any affect if the fixed baud + rate is enabled in CoreI2C hardware instance configuration dialogue + window. The fixed baud rate divider value overrides the value passed + as parameter in this function. + Note: serial_clock_speed value is not critical for devices that only operate + as slaves and can be set to any of the above values. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void system_init( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + } + @endcode + */ +void I2C_init +( + i2c_instance_t * this_i2c, + addr_t base_address, + uint8_t ser_address, + i2c_clock_divider_t ser_clock_speed +); + +/***************************************************************************//** + The I2C_channel_init() function initializes and configures hardware and data + structures of one of the additional channels of a CoreI2C instance. + I2C_init() must be called before calling this function to set the CoreI2C + instance hardware base address and I2C serial address. I2C_channel_init() also + initializes I2C serial clock divider to set the serial clock baud rate. + The pointer to data structure i2c_instance_t used for a particular channel + is used as an input parameter to subsequent CoreI2C driver functions + which operate on this channel. + + @param this_i2c_channel + Pointer to the i2c_instance_t data structure that holds all data related to + the CoreI2C channel gets initialized. A pointer to the same data structure + is used in subsequent calls to the CoreI2C driver functions in order to + identify the CoreI2C channel instance that should perform the operation + implemented by the called driver function. + + @param this_i2c + This is a pointer to an i2c_instance_t structure, previously initialized by + I2C_init(). It holds information regarding the hardware base address and + I2C serial address for the CoreI2C containing the channel to be + initialized. This information is required by I2C_channel_init() to + initialize the i2c_instance_t structure pointed by this_i2c_channel as + all channels in a CoreI2C instance share the same base address and serial + address. It is very important that the i2c_instance_t structure pointed + by this_i2c must be previously initialized by calling I2C_init(). + + @param channel_number + This parameter of type i2c_channel_number_t identifies the channel to be + initialized. + + @param ser_clock_speed + This parameter sets the I2C serial clock frequency. It selects the divider + that is used to generate the serial clock from the APB PCLK or from + the BCLK. It can be one of the following: + - I2C_PCLK_DIV_256 + - I2C_PCLK_DIV_224 + - I2C_PCLK_DIV_192 + - I2C_PCLK_DIV_160 + - I2C_PCLK_DIV_960 + - I2C_PCLK_DIV_120 + - I2C_PCLK_DIV_60 + - I2C_BCLK_DIV_8 + Note: serial_clock_speed value does not have any affect if the fixed baud + rate is enabled in CoreI2C hardware instance configuration dialogue + window. The fixed baud rate divider value will supersede the value + passed as parameter in this function. + Note: ser_clock_speed value is not critical for devices that only operate + as slaves and can be set to any of the above values. + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_SER_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + i2c_instance_t g_i2c_channel_1_inst; + + uint8_t tx_buffer[DATA_LENGTH]; + uint8_t write_length = DATA_LENGTH; + + void system_init( void ) + { + uint8_t target_slave_addr = 0x12; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize CoreI2C channel 1 with different clock speed + I2C_channel_init( &g_i2c_channel_1_inst, &g_i2c_inst, I2C_CHANNEL_1, + I2C_PCLK_DIV_224 ); + + // Write data to Channel 1 of CoreI2C instance. + I2C_write( &g_i2c_channel_1_inst, target_slave_addr, tx_buffer, + write_length, I2C_RELEASE_BUS ); + } + @endcode + +*/ +void I2C_channel_init +( + i2c_instance_t * this_i2c_channel, + i2c_instance_t * this_i2c, + i2c_channel_number_t channel_number, + i2c_clock_divider_t ser_clock_speed +); + +/***************************************************************************//** + The I2C_isr function is the CoreI2C interrupt service routine. User must + call this function from their application level CoreI2C interrupt handler + function. This function runs the I2C state machine based on previous and + current status. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREINTERRUPT_BASE_ADDR 0xCC000000u + #define COREI2C_SER_ADDR 0x10u + #define I2C_IRQ_NB 2u + + i2c_instance_t g_i2c_inst; + + void core_i2c_isr( void ) + { + I2C_isr( &g_i2c_inst ); + } + + void main( void ) + { + CIC_init( COREINTERRUPT_BASE_ADDR ); + NVIC_init(); + CIC_set_irq_handler( I2C_IRQ_NB, core_i2c_isr ); + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + NVIC_enable_interrupt( NVIC_IRQ_0 ); + } + @endcode + */ +void I2C_isr +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//* + #Master Specific Functions + + The following functions are only used within an I2C master's implementation. +/***************************************************************************//** + This function initiates an I2C master write transaction. This function returns + immediately after initiating the transaction. The content of the write buffer + passed as parameter should not be modified until the write transaction + completes. It also means that the memory allocated for the write buffer should + not be freed or should not go out of scope before the write completes. You can + check for the write transaction completion using the I2C_status() function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr + This parameter specifies the serial address of the target I2C device. + + @param write_buffer + This parameter is a pointer to a buffer holding the data to be written to + the target I2C device. Do not to release the memory used by this buffer + before the write transaction completes. For example, it is not appropriate + to return from a function allocating this buffer as an auto array variable + before the write transaction completes as this would result in the buffer's + memory being de-allocated from the stack when the function returns. This + memory could then be subsequently reused and modified causing unexpected + data to be written to the target I2C device. + + @param write_size + Number of bytes held in the write_buffer to be written to the target I2C + device. + + @param options + The options parameter is used to indicate if the I2C bus should be released + on completion of the write transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the write transaction causing the bus to be released for other I2C + devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the write + transaction, preventing other I2C devices from initiating a bus transaction. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t tx_buffer[DATA_LENGTH]; + uint8_t write_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Write data to Channel 0 of CoreI2C instance. + I2C_write( &g_i2c_inst, target_slave_addr, tx_buffer, write_length, + I2C_RELEASE_BUS ); + + // Wait for completion and record the outcome + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_write +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * write_buffer, + uint16_t write_size, + uint8_t options +); + +/***************************************************************************//** + This function initiates an I2C master read transaction. This function returns + immediately after initiating the transaction. + The contents of the read buffer passed as parameter should not be modified + until the read transaction completes. It also means that the memory allocated + for the read buffer should not be freed or should not go out of scope before + the read completes. You can check for the read transaction completion using + the I2C_status() function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr + This parameter specifies the serial address of the target I2C device. + + @param read_buffer + This is a pointer to a buffer where the data received from the target device + gets stored. Do not to release the memory used by this buffer before the read + transaction completes. For example, it is not appropriate to return from a + function allocating this buffer as an auto array variable before the read + transaction completes as this would result in the buffer's memory being + de-allocated from the stack when the function returns. This memory could + then be subsequently reallocated resulting in the read transaction + corrupting the newly allocated memory. + + @param read_size + This parameter specifies the number of bytes to read from the target device. + This size must not exceed the size of the read_buffer buffer. + + @param options + The options parameter is used to indicate if the I2C bus should be released + on completion of the read transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the read transaction causing the bus to be released for other I2C + devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the read transaction, + preventing other I2C devices from initiating a bus transaction. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t rx_buffer[DATA_LENGTH]; + uint8_t read_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Read data from target slave Channel 0 of CoreI2C instance. + I2C_read( &g_i2c_inst, target_slave_addr, rx_buffer, read_length, + I2C_RELEASE_BUS ); + + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +); + +/***************************************************************************//** + This function initiates an I2C write-read transaction where data is first + written to the target device before issuing a restart condition and changing + the direction of the I2C transaction in order to read from the target device. + + The same warnings about buffer allocation in I2C_write() and I2C_read() + applies to this function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr + This parameter specifies the serial address of the target I2C device. + + @param addr_offset + This parameter is a pointer to the buffer containing the data that is sent + to the slave during the write phase of the write-read transaction. This + data is typically used to specify an address offset specifying to the I2C + slave device what data it must return during the read phase of the + write-read transaction. + + @param offset_size + This parameter specifies the number of offset bytes to be written during the + write phase of the write-read transaction. This is typically the size of the + buffer pointed by the addr_offset parameter. + + @param read_buffer + This parameter is a pointer to the buffer where the data read from the I2C + slave will be stored. + + @param read_size + This parameter specifies the number of bytes to read from the target I2C + slave device. This size must not exceed the size of the buffer pointed by + the read_buffer parameter. + + @param options + The options parameter is used to indicate if the I2C bus should be released + on completion of the write-read transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the write-read transaction causing the bus to be released for other + I2C devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the write-read + transaction, preventing other I2C devices from initiating a bus transaction. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define TX_LENGTH 16u + #define RX_LENGTH 8u + + i2c_instance_t g_i2c_inst; + uint8_t rx_buffer[RX_LENGTH]; + uint8_t read_length = RX_LENGTH; + uint8_t tx_buffer[TX_LENGTH]; + uint8_t write_length = TX_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + I2C_write_read( &g_i2c_inst, target_slave_addr, tx_buffer, write_length, + rx_buffer, read_length, I2C_RELEASE_BUS ); + + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_write_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * addr_offset, + uint16_t offset_size, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +); + +/***************************************************************************//** + This function indicates the current state of a CoreI2C channel. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + The return value indicates the current state of a CoreI2C channel or the + outcome of the previous transaction if no transaction is in progress. + Following are the return values are: + - I2C_SUCCESS + The last I2C transaction has completed successfully. + - I2C_IN_PROGRESS + There is an I2C transaction in progress. + - I2C_FAILED + The last I2C transaction failed. + - I2C_TIMED_OUT + The request has failed to complete in the allotted time. + + @example + @code + i2c_instance_t g_i2c_inst; + + while( I2C_IN_PROGRESS == I2C_get_status( &g_i2c_inst ) ) + { + // Do something useful while waiting for I2C operation to complete + our_i2c_busy_task(); + } + + if( I2C_SUCCESS != I2C_get_status( &g_i2c_inst ) ) + { + // Something went wrong... + our_i2c_error_recovery( &g_i2c_inst ); + } + @endcode + */ +i2c_status_t I2C_get_status +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + This function waits for the current I2C transaction to complete. The return + value indicates whether the last I2C transaction was successful or not. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + @param timeout_ms + The timeout_ms parameter specifies the delay within which the current I2C + transaction should complete. The time out delay is given in + milliseconds. I2C_wait_complete() will return I2C_TIMED_OUT if the current + transaction has not completed after the time out delay has expired. This + parameter can be set to I2C_NO_TIMEOUT to indicate that I2C_wait_complete() + must not time out. + + @return + The return value indicates the outcome of the last I2C transaction. It can + be one of the following: + - I2C_SUCCESS + The last I2C transaction has completed successfully. + - I2C_FAILED + The last I2C transaction failed. + - I2C_TIMED_OUT + The last transaction failed to complete within the time out delay given + as second parameter. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t rx_buffer[DATA_LENGTH]; + uint8_t read_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Read data from Channel 0 of CoreI2C instance. + I2C_read( &g_i2c_inst, target_slave_addr, rx_buffer, read_length, + I2C_RELEASE_BUS ); + + // Wait for completion and record the outcome + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +i2c_status_t I2C_wait_complete +( + i2c_instance_t * this_i2c, + uint32_t timeout_ms +); + +/***************************************************************************//** + This function is used to control the expiration of the time out delay + specified as a parameter to the I2C_wait_complete() function. It must be + called from the interrupt service routine of a periodic interrupt source such + as the SysTick timer interrupt. It takes the period of the interrupt + source as its ms_since_last_tick parameter and uses it as the time base for + the I2C_wait_complete() function's time out delay. + + Note: This function does not need to be called if the I2C_wait_complete() + function is called with a timeout_ms value of I2C_NO_TIMEOUT. + + Note: If this function is not called then the I2C_wait_complete() function + will behave as if its timeout_ms was specified as I2C_NO_TIMEOUT and it + will not time out. + + Note: If this function is being called from an interrupt handler (for example, + SysTick) it is important that the calling interrupt have a lower priority + than the CoreI2C interrupt(s) to ensure any updates to the shared data are + protected. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + @param ms_since_last_tick + The ms_since_last_tick parameter specifies the number of milliseconds that + elapsed since the last call to I2C_system_tick(). This parameter would + typically be a constant specifying the interrupt rate of a timer used to + generate system ticks. + + @return None. + + @example + The following example shows how the I2C_system_tick() function. I2C_system_tick() + is called for each I2C channel from the SysTick timer interrupt service routine. + The following example shows how the SysTick is configured to generate an interrupt + in every 10 milliseconds. + @code + #define SYSTICK_INTERVAL_MS 10 + + void SysTick_Handler(void) + { + I2C_system_tick(&g_core_i2c0, SYSTICK_INTERVAL_MS); + I2C_system_tick(&g_core_i2c2, SYSTICK_INTERVAL_MS); + } + @endcode + */ +void I2C_system_tick +( + i2c_instance_t * this_i2c, + uint32_t ms_since_last_tick +); + +/***************************************************************************//* + #Slave Specific Functions + + The following functions are only used within the implementation of an I2C slave device. + +/***************************************************************************//** + This function specifies the memory buffer holding the data that will be sent + to the I2C master when this CoreI2C channel is the target of an I2C read or + write-read transaction. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param tx_buffer + This parameter is a pointer to the memory buffer holding the data to be + returned to the I2C master when this CoreI2C channel is the target of an + I2C read or write-read transaction. + + @param tx_size + Size of the transmit buffer pointed by the tx_buffer parameter. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Specify the transmit buffer containing the data that will be + // returned to the master during read and write-read transactions. + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + } + @endcode + */ +void I2C_set_slave_tx_buffer +( + i2c_instance_t * this_i2c, + const uint8_t * tx_buffer, + uint16_t tx_size +); + +/***************************************************************************//** + This function specifies the memory buffer that is used by the CoreI2C channel + to receive data when it is a slave. This buffer is the memory where data gets + stored when the CoreI2C channel is the target of an I2C master write + transaction (that is, when it is the slave). + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param rx_buffer + This parameter is a pointer to the memory buffer allocated by the caller + software to be used as a slave receive buffer. + + @param rx_size + Size of the slave receive buffer. This is the amount of memory allocated + to the buffer pointed by rx_buffer. + Note: Indirectly, this buffer size specifies the maximum I2C write + transaction length this CoreI2C channel targets. This is because + this CoreI2C channel responds to further received bytes with + a non-acknowledge bit (NACK) as soon as its receive buffer is + full. This causes the write transaction to fail. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_RX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_rx_buffer[SLAVE_RX_BUFFER_SIZE]; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Specify the buffer used to store the data written by the I2C master. + I2C_set_slave_rx_buffer( &g_i2c_inst, g_slave_rx_buffer, + sizeof(g_slave_rx_buffer) ); + } + @endcode + */ +void I2C_set_slave_rx_buffer +( + i2c_instance_t * this_i2c, + uint8_t * rx_buffer, + uint16_t rx_size +); + +/***************************************************************************//** + This function is used as part of the configuration of a CoreI2C channel to + operate as a slave supporting write-read transactions. It specifies the + number of bytes expected as part of the write phase of a write-read + transaction. The bytes received during the write phase of a write-read + transaction will be interpreted as an offset into the slave's transmit buffer. + This allows random access into the I2C slave transmit buffer from a remote + I2C master. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param offset_length + The offset_length parameter configures the number of bytes to be interpreted + by the CoreI2C slave as a memory offset value during the write phase of + write-read transactions. The maximum value for the offset_length parameter + is two. The value of offset_length has the following effect on the + interpretation of the received data. + • If offset_length is 0, the offset into the transmit buffer is fixed at 0. + • If offset_length is 1, a single byte of received data is interpreted as an + unsigned 8-bit offset value in the range 0 to 255. + • If offset_length is 2, 2 bytes of received data are interpreted as an + unsigned 16-bit offset value in the range 0 to 65535. The first byte + received in this case provides the high order bits of the offset and + the second byte provides the low order bits. + If the number of bytes received does not match the non 0 value of + offset_length, the transmit buffer offset is set to 0. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + I2C_set_slave_mem_offset_length( &g_i2c_inst, 1 ); + } + @endcode + */ +void I2C_set_slave_mem_offset_length +( + i2c_instance_t * this_i2c, + uint8_t offset_length +); + +/***************************************************************************//** + Register the function that is called to process the data written to this + CoreI2C channel when it is the slave in an I2C write transaction. + + Note: If a write handler is registered, it is called on completion of the + write phase of a write-read transaction and responsible for processing + the received data in the slave receive buffer and populating the slave + transmit buffer with the data that is transmitted to the I2C master + as part of the read phase of the write-read transaction. If a write + handler is not registered, the write data of a write-read transaction is + interpreted as an offset into the slave’s transmit buffer and handled by + the driver. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param handler + Pointer to the function that processes the I2C write request. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + // local function prototype + void slave_write_handler + ( + i2c_instance_t * this_i2c, + uint8_t * p_rx_data, + uint16_t rx_size + ); + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + I2C_set_slave_mem_offset_length( &g_i2c_inst, 1 ); + I2C_register_write_handler( &g_i2c_inst, slave_write_handler ); + } + @endcode +*/ +void I2C_register_write_handler +( + i2c_instance_t * this_i2c, + i2c_slave_wr_handler_t handler +); + +/***************************************************************************//** + This function enables slave mode operation for a CoreI2C channel. It enables + the CoreI2C slave to receive data when it is the target of an I2C read, write, + or write-read transaction. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + // Enable I2C slave + I2C_enable_slave( &g_i2c_inst ); + @endcode + */ +void I2C_enable_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + This function disables the slave mode operation for a CoreI2C channel. It stops + the CoreI2C slave that acknowledges the I2C read, write, or write-read + transactions targeted at it. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + // Disable I2C slave + I2C_disable_slave( &g_i2c_inst ); + @endcode + */ +void I2C_disable_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_slave_second_addr() function sets the secondary slave address for + a CoreI2C slave device. This is an additional slave address required in certain + applications, for example, to enable fail-safe operation in a system. As the + CoreI2C device supports 7-bit addressing, the highest value assigned to second + slave address is 127 (0x7F). + + Note: This function does not support CoreI2C hardware configured with a fixed + second slave address. The current implementation of the ADDR1[0] register + bit makes it difficult for the driver to support both programmable and + fixed second slave address, so we choose to support programmable only. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param second_slave_addr + The second_slave_addr parameter is the secondary slave address of the I2C + device. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SECOND_SLAVE_ADDR 0x20u + + i2c_instance_t g_i2c_inst; + void main( void ) + { + // Initialize the CoreI2C driver with its base address, primary I2C + // serial address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_second_addr( &g_i2c_inst, SECOND_SLAVE_ADDR ); + } + @endcode + */ +void I2C_set_slave_second_addr +( + i2c_instance_t * this_i2c, + uint8_t second_slave_addr +); + +/***************************************************************************//** + The I2C_disable_slave_second_addr() function disables the secondary slave + address of the CoreI2C slave device. + + Note: This version of the driver only supports CoreI2C hardware configured + with a programmable second slave address. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + i2c_instance_t g_i2c_inst; + I2C_disable_slave_second_addr( &g_i2c_inst); + @endcode + */ +void I2C_disable_slave_second_addr +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_gca() function is used to set the general call acknowledgement bit + of a CoreI2C slave device. This allows all channels of the CoreI2C slave + device to respond to a general call or broadcast message from an I2C master. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + i2c_instance_t g_i2c_inst; + + // Enable recognition of the General Call Address + I2C_set_gca( &g_i2c_inst ); + @endcode + */ +void I2C_set_gca +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_clear_gca() function is used to clear the general call acknowledgement + bit of a CoreI2C slave device. This will stop all channels of the I2C slave + device responding to any general call or broadcast message from the master. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + i2c_instance_t g_i2c_inst; + + // Disable recognition of the General Call Address + I2C_clear_gca( &g_i2c_inst ); + @endcode + */ + +void I2C_clear_gca +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//* + #I2C SMBUS Specific APIs + +/***************************************************************************//** + The I2C_smbus_init() function enables SMBus timeouts and status logic for a + CoreI2C channel. + + Note: This and any of the other SMBus related functionality will only have an + effect if the CoreI2C was instantiated with the Generate SMBus Logic + option checked. + + Note: If the CoreI2C was instantiated with the Generate IPMI Logic option + checked this function then enables the IPMI 3mS SCL low timeout but + none of the other SMBus functions will have any effect. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void system_init( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst); + } + @endcode + */ +void I2C_smbus_init +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_enable_smbus_irq() function is used to enable the CoreI2C channel’s + SMBSUS and SMBALERT SMBus interrupts. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param irq_type + The irq_type specify the SMBUS interrupt(s) which will be enabled. + The two possible interrupts are: + - I2C_SMBALERT_IRQ + - I2C_SMBSUS_IRQ + To enable both interrupts in one call, use I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ. + + @return + None + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both I2C_SMBALERT_IRQ & I2C_SMBSUS_IRQ interrupts + I2C_enable_smbus_irq( &g_i2c_inst, + (uint8_t)(I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ) ); + } + @endcode + */ +void I2C_enable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +); + +/***************************************************************************//** + The I2C_disable_smbus_irq() function disable the CoreI2C channel’s SMBSUS and + SMBALERT SMBus interrupts. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param irq_type + The irq_type specifies the SMBUS interrupt(s) which are disabled. + The two possible interrupts are: + • I2C_SMBALERT_IRQ + • I2C_SMBSUS_IRQ + To disable both ints in one call, use I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both SMBALERT & SMBSUS interrupts + I2C_enable_smbus_irq( &g_i2c_inst, + (uint8_t)(I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ)); + + ... + + // Disable the SMBALERT interrupt + I2C_disable_smbus_irq( &g_i2c_inst, I2C_SMBALERT_IRQ ); + } + @endcode + */ +void I2C_disable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +); + +/***************************************************************************//** + The I2C_suspend_smbus_slave() function forces any SMBUS slave devices + connected to a CoreI2C channel into Power-Down or Suspend mode by asserting + the channel's SMBSUS signal. The CoreI2C channel is the SMBus master in this + case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // suspend SMBus slaves + I2C_suspend_smbus_slave( &g_i2c_inst ); + + ... + + // Re-enable SMBus slaves + I2C_resume_smbus_slave( &g_i2c_inst ); + } + @endcode + */ +void I2C_suspend_smbus_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_resume_smbus_slave() function de-asserts the CoreI2C channel's SMBSUS + signal to take any connected slave devices out of the Suspend mode. The CoreI2C + channel is the SMBus master in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // suspend SMBus slaves + I2C_suspend_smbus_slave( &g_i2c_inst ); + + ... + + // Re-enable SMBus slaves + I2C_resume_smbus_slave( &g_i2c_inst ); + } + @endcode + */ +void I2C_resume_smbus_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_reset_smbus() function resets the CoreI2C channel's SMBus connection + by forcing SCLK low for 35 mS. The reset that automatically cleares after 35 ms + gets elapsed. The CoreI2C channel is the SMBus master in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Make sure the SMBus channel is in a known state by resetting it + I2C_reset_smbus( &g_i2c_inst ); + } + @endcode + */ +void I2C_reset_smbus +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_smbus_alert() function is used to force master communication with + an I2C slave device by asserting the CoreI2C channel's SMBALERT signal. The + CoreI2C channel is the SMBus slave in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Get the SMBus masters attention + I2C_set_smbus_alert( &g_i2c_inst ); + + ... + + // Once we are happy, drop the alert + I2C_clear_smbus_alert( &g_i2c_inst ); + } + @endcode + */ +void I2C_set_smbus_alert +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_clear_smbus_alert() function is used to de-assert the CoreI2C channel's + SMBALERT signal once a slave device gets a response from the master. The + CoreI2C channel is the SMBus slave in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Get the SMBus masters attention + I2C_set_smbus_alert( &g_i2c_inst ); + + ... + + // Once we are happy, drop the alert + I2C_clear_smbus_alert( &g_i2c_inst ); + } + @endcode + */ +void I2C_clear_smbus_alert +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_get_irq_status function returns information about which interrupts are + currently pending in a CoreI2C channel. + The interrupts supported by CoreI2C are: + • SMBUSALERT + • SMBSUS + • INTR + + The macros I2C_NO_IRQ, I2C_SMBALERT_IRQ, I2C_SMBSUS_IRQ, and I2C_INTR_IRQ are + provided to use with this function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + This function returns the status of the CoreI2C channel's interrupts as a + single byte bitmap where a bit is set to indicate a pending interrupt. + The following are the bit positions associated with each interrupt type: + Bit 0 - SMBUS_ALERT_IRQ + Bit 1 - SMBSUS_IRQ + Bit 2 - INTR_IRQ + It returns 0, if there are no pending interrupts. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + uint8_t irq_to_enable = I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ; + uint8_t pending_irq = 0u; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both I2C_SMBALERT_IRQ & I2C_SMBSUS_IRQ irq + I2C_enable_smbus_irq( &g_i2c_inst, irq_to_enable ); + + // Get I2C IRQ type + pending_irq = I2C_get_irq_status( &g_i2c_inst ); + + // Let's assume, in system, INTR and SMBALERT IRQ is pending. + // So pending_irq will return status of both the IRQs + + if( pending_irq & I2C_SMBALERT_IRQ ) + { + // if true, it means SMBALERT_IRQ is there in pending IRQ list + } + if( pending_irq & I2C_INTR_IRQ ) + { + // if true, it means I2C_INTR_IRQ is there in pending IRQ list + } + } + @endcode + */ +uint8_t I2C_get_irq_status +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_user_data() function allows the association of a block of application + specific data with a CoreI2C channel. The composition of the data block is an + application matter and the driver simply provides the means for the application + to set and retrieve the pointer. For example, this is used to provide additional + channel specific information to the slave write handler. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param p_user_data + The p_user_data parameter is a pointer to the user specific data block for + this channel. It is defined as void * as the driver does not know the actual + type of data being pointed to and simply stores the pointer for later + retrieval by the application. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + app_data_t channel_xdata; + + void main( void ) + { + app_data_t *p_xdata; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Store location of user data in instance structure + I2C_set_user_data( &g_i2c_inst, (void *)&channel_xdata ); + + ... + + // Retrieve location of user data and do some work on it + p_xdata = (app_data_t *)I2C_get_user_data( &g_i2c_inst ); + if( NULL != p_xdata ) + { + p_xdata->foo = 123; + } + } + @endcode + */ +void I2C_set_user_data +( + i2c_instance_t * this_i2c, + void * p_user_data +); + +/***************************************************************************//** + The I2C_get_user_data() function is used to allows the retrieval of the address + of a block of application specific data associated with a CoreI2C channel. + The composition of the data block is an application matter and the driver + simply provides the means for the application to set and retrieve the pointer. + For example, this is used to provide additional channel specific information + to the slave write handler. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + This function returns a pointer to the user specific data block for this + channel. It is defined as void * as the driver does not know the actual type + of data being pointed. If no user data has been registered for this channel + a NULL pointer is returned. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + app_data_t channel_xdata; + + void main( void ) + { + app_data_t *p_xdata; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Store location of user data in instance structure + I2C_set_user_data( &g_i2c_inst, (void *)&channel_xdata ); + + ... + + // Retrieve location of user data and do some work on it + p_xdata = (app_data_t *)I2C_get_user_data( &g_i2c_inst ); + if( NULL != p_xdata ) + { + p_xdata->foo = 123; + } + } + @endcode + */ +void * I2C_get_user_data +( + i2c_instance_t * this_i2c +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h new file mode 100644 index 0000000..b1d872d --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h @@ -0,0 +1,190 @@ +/******************************************************************************* + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + */ + +#ifndef __CORE_SMBUS_REGISTERS +#define __CORE_SMBUS_REGISTERS 1 + +/*------------------------------------------------------------------------------ + * CONTROL register details + */ +#define CONTROL_REG_OFFSET 0x00u + +/* + * CR0 bits. + */ +#define CR0_OFFSET 0x00u +#define CR0_MASK 0x01u +#define CR0_SHIFT 0u + +/* + * CR1 bits. + */ +#define CR1_OFFSET 0x00u +#define CR1_MASK 0x02u +#define CR1_SHIFT 1u + +/* + * AA bits. + */ +#define AA_OFFSET 0x00u +#define AA_MASK 0x04u +#define AA_SHIFT 2u + +/* + * SI bits. + */ +#define SI_OFFSET 0x00u +#define SI_MASK 0x08u +#define SI_SHIFT 3u + +/* + * STO bits. + */ +#define STO_OFFSET 0x00u +#define STO_MASK 0x10u +#define STO_SHIFT 4u + +/* + * STA bits. + */ +#define STA_OFFSET 0x00u +#define STA_MASK 0x20u +#define STA_SHIFT 5u + +/* + * ENS1 bits. + */ +#define ENS1_OFFSET 0x00u +#define ENS1_MASK 0x40u +#define ENS1_SHIFT 6u + +/* + * CR2 bits. + */ +#define CR2_OFFSET 0x00u +#define CR2_MASK 0x80u +#define CR2_SHIFT 7u + +/*------------------------------------------------------------------------------ + * STATUS register details + */ +#define STATUS_REG_OFFSET 0x04u + +/*------------------------------------------------------------------------------ + * DATA register details + */ +#define DATA_REG_OFFSET 0x08u + +/* + * TARGET_ADDR bits. + */ +#define TARGET_ADDR_OFFSET 0x08u +#define TARGET_ADDR_MASK 0xFEu +#define TARGET_ADDR_SHIFT 1u + +/* + * DIR bit. + */ +#define DIR_OFFSET 0x08u +#define DIR_MASK 0x01u +#define DIR_SHIFT 0u + + +/*------------------------------------------------------------------------------ + * ADDRESS register details + */ +#define ADDRESS_REG_OFFSET 0x0Cu + +/* + * GC bits. + */ +#define GC_OFFSET 0x0Cu +#define GC_MASK 0x01u +#define GC_SHIFT 0u + +/* + * ADR bits. + */ +#define OWN_SLAVE_ADDR_OFFSET 0x0Cu +#define OWN_SLAVE_ADDR_MASK 0xFEu +#define OWN_SLAVE_ADDR_SHIFT 1u + +/*------------------------------------------------------------------------------ + * SMBUS register details + */ +#define SMBUS_REG_OFFSET 0x10u + +/* + * SMBALERT_IE bits. + */ +#define SMBALERT_IE_OFFSET 0x10u +#define SMBALERT_IE_MASK 0x01u +#define SMBALERT_IE_SHIFT 0u + +/* + * SMBSUS_IE bits. + */ +#define SMBSUS_IE_OFFSET 0x10u +#define SMBSUS_IE_MASK 0x02u +#define SMBSUS_IE_SHIFT 1u + +/* + * SMB_IPMI_EN bits. + */ +#define SMB_IPMI_EN_OFFSET 0x10u +#define SMB_IPMI_EN_MASK 0x04u +#define SMB_IPMI_EN_SHIFT 2u + +/* + * SMBALERT_NI_STATUS bits. + */ +#define SMBALERT_NI_STATUS_OFFSET 0x10u +#define SMBALERT_NI_STATUS_MASK 0x08u +#define SMBALERT_NI_STATUS_SHIFT 3u + +/* + * SMBALERT_NO_CONTROL bits. + */ +#define SMBALERT_NO_CONTROL_OFFSET 0x10u +#define SMBALERT_NO_CONTROL_MASK 0x10u +#define SMBALERT_NO_CONTROL_SHIFT 4u + +/* + * SMBSUS_NI_STATUS bits. + */ +#define SMBSUS_NI_STATUS_OFFSET 0x10u +#define SMBSUS_NI_STATUS_MASK 0x20u +#define SMBSUS_NI_STATUS_SHIFT 5u + +/* + * SMBSUS_NO_CONTROL bits. + */ +#define SMBSUS_NO_CONTROL_OFFSET 0x10u +#define SMBSUS_NO_CONTROL_MASK 0x40u +#define SMBSUS_NO_CONTROL_SHIFT 6u + +/* + * SMBUS_MST_RESET bits. + */ +#define SMBUS_MST_RESET_OFFSET 0x10u +#define SMBUS_MST_RESET_MASK 0x80u +#define SMBUS_MST_RESET_SHIFT 7u + +/*------------------------------------------------------------------------------ + * SLAVE ADDRESS 1 register details + */ + +#define ADDRESS1_REG_OFFSET 0x1Cu + +/* + * SLAVE1_EN bit of Slave Address 1 . + */ +#define SLAVE1_EN_OFFSET 0x1Cu +#define SLAVE1_EN_MASK 0x01u +#define SLAVE1_EN_SHIFT 0u + +#endif /* __CORE_SMBUS_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c new file mode 100644 index 0000000..12e352d --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * CoreI2C driver interrupt control. + * + */ +#include "core_i2c.h" + +/*------------------------------------------------------------------------------ + * This function must be modified to enable interrupts generated from the + * CoreI2C instance identified as parameter. + */ +void I2C_enable_irq( i2c_instance_t * this_i2c ) +{ + HAL_ASSERT(0) +} + +/*------------------------------------------------------------------------------ + * This function must be modified to disable interrupts generated from the + * CoreI2C instance identified as parameter. + */ +void I2C_disable_irq( i2c_instance_t * this_i2c ) +{ + HAL_ASSERT(0) +} diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreSPI/core_spi.c b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreSPI/core_spi.c new file mode 100644 index 0000000..2e11750 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreSPI/core_spi.c @@ -0,0 +1,1345 @@ +/***************************************************************************//** + * Copyright 2013-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * CoreSPI bare metal driver implementation for CoreSPI. + * + * This Core SPI driver provides functions for implementing SPI master or + * SPI slave operations with the CoreSPI version 4.2.xxx It is not compatible + * with CoreSPI version 3.0.xxx. + * + * @file core_spi.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreSPI software configuration + * + */ + +#include "core_spi.h" +#include "corespi_regs.h" +#include + +/******************************************************************************* + * Null parameters with appropriate type definitions + */ +#define NULL_ADDR ( ( addr_t ) 0u ) +#define NULL_INSTANCE ( ( spi_instance_t * ) 0u ) +#define NULL_BUFF ( ( uint8_t * ) 0u ) +#define NULL_FRAME_HANDLER ( ( spi_frame_rx_handler_t ) 0u ) +#define NULL_BLOCK_HANDLER ( ( spi_block_rx_handler_t ) 0u ) +#define NULL_SLAVE_TX_UPDATE_HANDLER ( ( spi_slave_frame_tx_handler_t ) 0u ) +#define NULL_SLAVE_CMD_HANDLER NULL_BLOCK_HANDLER + +#define SPI_ALL_INTS (0xFFu) /* For clearing all active interrupts */ + +/******************************************************************************* + * Possible states for different register bit fields + */ + +#define DISABLE 0u +#define ENABLE 1u + + +/******************************************************************************* + * Function return values + */ +enum { + FAILURE = 0u, + SUCCESS = 1u +}; + +/******************************************************************************* + * Local function declarations + */ +static void fill_slave_tx_fifo( spi_instance_t * this_spi ); +static void read_slave_rx_fifo( spi_instance_t * this_spi ); +static void recover_from_rx_overflow( const spi_instance_t * this_spi ); + +/******************************************************************************* + * SPI_init() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_init +( + spi_instance_t * this_spi, + addr_t base_addr, + uint16_t fifo_depth +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( NULL_ADDR != base_addr ); + HAL_ASSERT( SPI_MAX_FIFO_DEPTH >= fifo_depth ); + HAL_ASSERT( SPI_MIN_FIFO_DEPTH <= fifo_depth ); + + if( ( NULL_INSTANCE != this_spi ) && ( base_addr != NULL_ADDR ) ) + { + /* + * Initialize all transmit / receive buffers and handlers + * + * Relies on the fact that byte filling with 0x00 will equate + * to 0 for any non byte sized items too. + */ + + /* First fill struct with 0s */ + memset( this_spi, 0, sizeof(spi_instance_t) ); + + /* Configure CoreSPI instance attributes */ + this_spi->base_addr = (addr_t)base_addr; + + /* Store FIFO depth or fall back to minimum if out of range */ + if( ( SPI_MAX_FIFO_DEPTH >= fifo_depth ) && ( SPI_MIN_FIFO_DEPTH <= fifo_depth ) ) + { + this_spi->fifo_depth = fifo_depth; + } + else + { + this_spi->fifo_depth = SPI_MIN_FIFO_DEPTH; + } + /* Make sure the CoreSPI is disabled while we configure it */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Ensure all slaves are deselected */ + HAL_set_8bit_reg( this_spi->base_addr, SSEL, 0u ); + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Ensure RXAVAIL, TXRFM, SSEND and CMDINT are disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, 0u ); + /* + * Enable the CoreSPI in the reset default of master mode + * with TXUNDERRUN, RXOVFLOW and TXDONE interrupts disabled. + * The driver does not currently use interrupts in master mode. + */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL1, ENABLE | CTRL1_MASTER_MASK ); + } +} + +/***************************************************************************//** + * SPI_configure_slave_mode() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_configure_slave_mode +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Don't yet know what slave transfer mode will be used */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_NONE; + + /* Make sure the CoreSPI is disabled while we configure it */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Ensure RXAVAIL, TXRFM, SSEND and CMDINT are disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, 0u ); + /* + * Enable the CoreSPI in slave mode with TXUNDERRUN, RXOVFLOW and TXDONE + * interrupts disabled. The appropriate interrupts will be enabled later + * on when the transfer mode is configured. + */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL1, ENABLE ); + } +} + +/***************************************************************************//** + * SPI_configure_master_mode() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_configure_master_mode +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Disable the CoreSPI for a little while, while we configure the CoreSPI */ + HAL_set_8bit_reg_field(this_spi->base_addr, CTRL1_ENABLE, DISABLE); + + /* Reset slave transfer mode to unknown in case it has been set previously */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_NONE; + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Ensure RXAVAIL, TXRFM, SSEND and CMDINT are disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, 0u ); + + /* Enable the CoreSPI in master mode with TXUNDERRUN, RXOVFLOW and TXDONE interrupts disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL1, ENABLE | CTRL1_MASTER_MASK ); + } +} + +/***************************************************************************//** + * SPI_set_slave_select() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +) +{ + spi_slave_t temp = (spi_slave_t)(0x00u) ; + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( SPI_MAX_NB_OF_SLAVES > slave ); + + if( ( NULL_INSTANCE != this_spi ) && ( SPI_MAX_NB_OF_SLAVES > slave ) ) + { + /* This function is only intended to be used with an SPI master */ + if( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW ) ) + { + recover_from_rx_overflow( this_spi ); + } + /* Set the correct slave select bit */ + temp = (spi_slave_t)( HAL_get_8bit_reg( this_spi->base_addr, SSEL ) | ((uint32_t)1u << (uint32_t)slave) ); + HAL_set_8bit_reg( this_spi->base_addr, SSEL, (uint_fast8_t)temp ); + } + } +} + +/***************************************************************************//** + * SPI_clear_slave_select() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_clear_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +) +{ + spi_slave_t temp = (spi_slave_t) (0x00u) ; + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( SPI_MAX_NB_OF_SLAVES > slave ); + + if( ( NULL_INSTANCE != this_spi ) && ( SPI_MAX_NB_OF_SLAVES > slave ) ) + { + /* This function is only intended to be used with an SPI master. */ + if( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW) ) + { + recover_from_rx_overflow( this_spi ); + } + /* Clear the correct slave select bit */ + temp = (spi_slave_t)( HAL_get_8bit_reg( this_spi->base_addr, SSEL ) & ~((uint32_t)1u << (uint32_t)slave) ); + HAL_set_8bit_reg( this_spi->base_addr, SSEL, (uint_fast8_t)temp ) ; + } + } +} + +/***************************************************************************//** + * SPI_transfer_frame() + * See "core_spi.h" for details of how to use this function. + */ +uint32_t SPI_transfer_frame +( + spi_instance_t * this_spi, + uint32_t tx_bits +) +{ + volatile uint32_t rx_data = 0u; /* Ensure consistent return value if in slave mode */ + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI master. */ + if( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Flush the receive and transmit FIFOs by resetting both */ + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK); + + /* Send frame. */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, tx_bits ); + + /* Wait for frame Tx to complete. */ + while ( ENABLE != HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_DONE ) ) + { + ; + } + + /* Read received frame. */ + rx_data = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + } + } + + /* Finally, return the frame we received from the slave or 0 */ + return( rx_data ); +} + + +/***************************************************************************//** + * SPI_transfer_block() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_transfer_block +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_buffer, + uint16_t rx_byte_size +) +{ + uint32_t transfer_size = 0U; /* Total number of bytes to transfer. */ + uint16_t transfer_idx = 0U; /* Number of bytes transferred so far */ + uint16_t tx_idx = 0u; /* Number of valid data bytes sent */ + uint16_t rx_idx = 0u; /* Number of valid response bytes received */ + uint16_t transit = 0U; /* Number of bytes "in flight" to avoid FIFO errors */ + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI master. */ + if( ( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) && + /* Check for empty transfer as well */ + ( 0u != ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) ) ) + { + /* + * tansfer_size is one less than the real amount as we have to write + * the last frame separately to trigger the slave deselect in case + * the SPS option is in place. + */ + transfer_size = ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) - 1u; + /* Flush the receive and transmit FIFOs */ + HAL_set_8bit_reg(this_spi->base_addr, CMD, (uint32_t)(CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK )); + + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW) ) + { + recover_from_rx_overflow( this_spi ); + } + + /* Disable the Core SPI for a little bit, while we load the TX FIFO */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + while( ( tx_idx < transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out 0s to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + } + ++transit; + ++tx_idx; + } + + /* If room left to put last frame in before the off, then do it */ + if( ( tx_idx == transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data, not expecting any reply this time */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out last 0 to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + } + + ++transit; + ++tx_idx; + } + + /* FIFO is all loaded up so enable Core SPI to start transfer */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + + /* Perform the remainder of the transfer by sending a byte every time a byte + * has been received. This should ensure that no Rx overflow can happen in + * case of an interrupt occurring during this function. + * + * We break the transfer down into stages to minimise the processing in + * each loop as the SPI interface is very demanding at higher clock rates. + * This works well with FIFOs but might be less efficient if there is only + * a single frame buffer. + * + * First stage transfers remaining command bytes (if any). + * At this stage anything in the RX FIFO can be discarded as it is + * not part of a valid response. + */ + while( tx_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + /* Send another byte. */ + if( tx_idx == transfer_size ) /* Last frame is special... */ + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Read and discard. */ + HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now, we are writing dummy bytes to push through the response from + * the slave but we still have to keep discarding any read data that + * corresponds with one of our command bytes. + */ + while( transfer_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + if( tx_idx < transfer_size ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Read and discard. */ + HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now we are now only sending dummy data to push through the + * valid response data which we store in the response buffer. + */ + while( tx_idx < transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received byte. */ + rx_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* If we still need to send the last frame */ + while( tx_idx == transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received byte. */ + rx_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* + * Finally, we are now finished sending data and are only reading + * valid response data which we store in the response buffer. + */ + while( transfer_idx <= transfer_size ) + { + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received byte. */ + rx_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + } + } + } + } +} + +/***************************************************************************//** + * SPI_transfer_block_store_all_resp() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_transfer_block_store_all_resp +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_data_buffer, + uint16_t rx_byte_size, + uint8_t * cmd_response_buffer +) +{ + uint32_t transfer_size = 0U; /* Total number of bytes to transfer. */ + uint16_t transfer_idx = 0U; /* Number of bytes transferred so far */ + uint16_t tx_idx = 0u; /* Number of valid data bytes sent */ + uint16_t rx_idx = 0u; /* Number of valid response bytes received */ + uint16_t transit = 0U; /* Number of bytes "in flight" to avoid FIFO errors */ + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI master. */ + if( ( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) && + /* Check for empty transfer as well */ + ( 0u != ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) ) ) + { + /* + * tansfer_size is one less than the real amount as we have to write + * the last frame separately to trigger the slave deselect in case + * the SPS option is in place. + */ + transfer_size = ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) - 1u; + /* Flush the receive and transmit FIFOs */ + HAL_set_8bit_reg(this_spi->base_addr, CMD, (uint32_t)(CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK )); + + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW) ) + { + recover_from_rx_overflow( this_spi ); + } + + /* Disable the Core SPI for a little bit, while we load the TX FIFO */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + while( ( tx_idx < transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out 0s to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + } + ++transit; + ++tx_idx; + } + + /* If room left to put last frame in before the off, then do it */ + if( ( tx_idx == transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data, not expecting any reply this time */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out last 0 to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + } + + ++transit; + ++tx_idx; + } + + /* FIFO is all loaded up so enable Core SPI to start transfer */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + + /* Perform the remainder of the transfer by sending a byte every time a byte + * has been received. This should ensure that no Rx overflow can happen in + * case of an interrupt occurring during this function. + * + * We break the transfer down into stages to minimise the processing in + * each loop as the SPI interface is very demanding at higher clock rates. + * This works well with FIFOs but might be less efficient if there is only + * a single frame buffer. + * + * First stage transfers remaining command bytes (if any). + * At this stage anything in the RX FIFO can be discarded as it is + * not part of a valid response. + */ + while( tx_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + /* Send another byte. */ + if( tx_idx == transfer_size ) /* Last frame is special... */ + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received command byte. */ + cmd_response_buffer[transfer_idx] = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now, we are writing dummy bytes to push through the response from + * the slave, which we store in the command response buffer. + */ + while( transfer_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + if( tx_idx < transfer_size ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received command byte. */ + cmd_response_buffer[transfer_idx] = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now we are now only sending dummy data to push through the + * valid response data which we store in the data response buffer. + */ + while( tx_idx < transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received data byte. */ + rx_data_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* If we still need to send the last frame */ + while( tx_idx == transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received data byte. */ + rx_data_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* + * Finally, we are now finished sending data and are only reading + * valid response data which we store in the data response buffer. + */ + while( transfer_idx <= transfer_size ) + { + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received data byte. */ + rx_data_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + } + } + } + } +} +/***************************************************************************//** + * SPI_set_frame_rx_handler() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_frame_rx_handler +( + spi_instance_t * this_spi, + spi_frame_rx_handler_t rx_handler +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if(NULL_INSTANCE != this_spi) + { + /* This function is only intended to be used with an SPI slave. */ + if(DISABLE == HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER)) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Disable SSEND and CMD interrupts as we are not doing block transfers */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTSSEND, DISABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + + /* Disable block Rx handler as they are mutually exclusive. */ + this_spi->block_rx_handler = 0U; + + /* Keep a copy of the pointer to the Rx handler function. */ + this_spi->frame_rx_handler = rx_handler; + + if( SPI_SLAVE_XFER_FRAME != this_spi->slave_xfer_mode ) + { + /* + * Either just coming from init or were previously in block mode + * so no tx frame handler is set at this point in time... + * + * Don't allow TXDONE interrupts. + */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXDONE, DISABLE ); + } + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK); + + /* Enable Rx and FIFO error interrupts */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTRXOVFLOW, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXURUN, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTRXDATA, ENABLE ); + + /* Make sure correct mode is selected */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_FRAME; + + /* Finally re-enable the CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } + } +} + +/***************************************************************************//** + * SPI_set_slave_tx_frame() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_slave_tx_frame +( + spi_instance_t * this_spi, + uint32_t frame_value, + spi_slave_frame_tx_handler_t slave_tx_frame_handler +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI slave. */ + if( DISABLE == HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Disable SSEND and CMD interrupts as we are not doing block transfers */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTSSEND, DISABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + + if( SPI_SLAVE_XFER_FRAME != this_spi->slave_xfer_mode ) + { + /* + * Either just coming from init or were previously in block mode + * so no rx frame handler is set at this point in time... + * + * Don't allow RXDATA interrupts. + */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTRXDATA, DISABLE ); + } + + /* Disable slave block tx buffer as it is mutually exclusive with frame + * level handling. */ + this_spi->slave_tx_buffer = NULL_BUFF; + this_spi->slave_tx_size = 0U; + this_spi->slave_tx_idx = 0U; + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK); + + /* Assign the slave frame update handler - NULL_SLAVE_TX_UPDATE_HANDLER for none */ + this_spi->slave_tx_frame_handler = slave_tx_frame_handler; + + /* Keep a copy of the slave Tx frame value. */ + this_spi->slave_tx_frame = frame_value; + + /* Load one frame into Tx data register. */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, this_spi->slave_tx_frame ); + + /* Enable Tx Done interrupt in order to reload the slave Tx frame after each + * time it has been sent. */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXDONE, ENABLE ); + + /* Make sure correct mode is selected */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_FRAME; + + /* Ready to go so enable CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } + } +} + +/***************************************************************************//** + * SPI_set_slave_block_buffers() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_slave_block_buffers +( + spi_instance_t * this_spi, + const uint8_t * tx_buffer, + uint32_t tx_buff_size, + uint8_t * rx_buffer, + uint32_t rx_buff_size, + spi_block_rx_handler_t block_rx_handler +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI slave. */ + if( DISABLE == HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Make sure correct mode is selected */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_BLOCK; + /* + * No command handler should be setup at this stage so fake this + * to ensure 0 padding works. + */ + this_spi->cmd_done = 1u; + + /* Disable frame handlers as they are mutually exclusive with block Rx handler. */ + this_spi->frame_rx_handler = NULL_FRAME_HANDLER; + this_spi->slave_tx_frame_handler = NULL_SLAVE_TX_UPDATE_HANDLER; + + /* Keep a copy of the pointer to the block Rx handler function. */ + this_spi->block_rx_handler = block_rx_handler; + + /* Assign slave receive buffer */ + this_spi->slave_rx_buffer = rx_buffer; + this_spi->slave_rx_size = rx_buff_size; + this_spi->slave_rx_idx = 0U; + + /* Assign slave transmit buffer*/ + this_spi->slave_tx_buffer = tx_buffer; + this_spi->slave_tx_size = tx_buff_size; + this_spi->slave_tx_idx = 0U; + + /* Flush the receive and transmit FIFOs */ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Preload the transmit FIFO. */ + while( !(HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_TXFULL)) && + ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->slave_tx_buffer[this_spi->slave_tx_idx] ); + ++this_spi->slave_tx_idx; + } + /* + * Disable TXDATA interrupt as we will look after transmission in rx handling + * because we know that once we have read a frame it is safe to send another one. + */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTTXDATA, DISABLE ); + + /* Enable Rx, FIFO error and SSEND interrupts */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTRXOVFLOW, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXURUN, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTRXDATA, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTSSEND, ENABLE ); + + /* Disable command handler until it is set explicitly */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + + /* Now enable the CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } + } +} + +/***************************************************************************//** + * SPI_set_cmd_handler() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_cmd_handler +( + spi_instance_t * this_spi, + spi_block_rx_handler_t cmd_handler, + uint32_t cmd_size +) +{ + uint32_t ctrl2 = 0u; + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( NULL_SLAVE_CMD_HANDLER != cmd_handler ); + HAL_ASSERT( 0u < cmd_size ); + + if( ( NULL_INSTANCE != this_spi ) && ( 0u < cmd_size ) && + ( NULL_SLAVE_CMD_HANDLER != cmd_handler ) ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + /* + * Note we don't flush the FIFOs as this has been done already when + * block mode was configured. + * + * Clear this flag so zero padding is disabled until command response + * has been taken care of. + */ + this_spi->cmd_done = 0u; + + /* Assign user handler for Command received interrupt */ + this_spi->cmd_handler = cmd_handler; + + /* Configure the command size and Enable Command received interrupt */ + ctrl2 = HAL_get_8bit_reg( this_spi->base_addr, CTRL2 ); + + /* First clear the count field then insert count and int enables */ + ctrl2 &= ~(uint32_t)CTRL2_CMDSIZE_MASK; + ctrl2 |= (uint32_t)((cmd_size & CTRL2_CMDSIZE_MASK) | CTRL2_INTCMD_MASK | CTRL2_INTRXDATA_MASK); + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, ctrl2 ); + + /* Now enable the CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } +} + +/***************************************************************************//** + * SPI_set_cmd_response() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_cmd_response +( + spi_instance_t * this_spi, + const uint8_t * resp_tx_buffer, + uint32_t resp_buff_size +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( NULL_BUFF != resp_tx_buffer ); + HAL_ASSERT( 0u < resp_buff_size ); + + if( ( NULL_INSTANCE != this_spi ) && ( 0u < resp_buff_size ) && + ( NULL_BUFF != resp_tx_buffer ) ) + { + this_spi->resp_tx_buffer = resp_tx_buffer; + this_spi->resp_buff_size = resp_buff_size; + this_spi->resp_buff_tx_idx = 0u; + + fill_slave_tx_fifo(this_spi); + } +} + + +/***************************************************************************//** + * SPI_enable() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_enable +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } +} + + +/***************************************************************************//** + * SPI_disable() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_disable +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + } +} + + +/***************************************************************************//** + * SPI interrupt service routine. + */ +void SPI_isr +( + spi_instance_t * this_spi +) +{ + uint32_t rx_frame; + int32_t guard; + +/* + * The assert and the NULL check here can be commented out to reduce the interrupt + * latency once you are sure the interrupt vector code is correct. + */ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + if( NULL_INSTANCE != this_spi ) + { + /* Handle receive. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_RXDATA ) ) + { + /* + * Service receive data according to transfer mode in operation. + * + * We check block mode first as this is most likely to have back to back + * transfers with multiple bytes. + * + * Note the order of the checks here will effect interrupt latency and + * for critical timing the mode you are using most often should probably be + * be the first checked. + */ + if( SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode ) /* Block handling mode. */ + { + while( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Read irrespective to clear the RX IRQ */ + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + if( this_spi->slave_rx_idx < this_spi->slave_rx_size ) + { + this_spi->slave_rx_buffer[this_spi->slave_rx_idx] = (uint8_t)rx_frame; + } + ++this_spi->slave_rx_idx; + } + /* + * Now handle updating of tx FIFO to keep the data flowing. + * First see if there is anything in slave_tx_buffer to send. + */ + while( ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) + && ( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->slave_tx_buffer[this_spi->slave_tx_idx] ); + ++this_spi->slave_tx_idx; + } + /* + * Next see if there is anything in resp_tx_buffer to send. + */ + if( this_spi->slave_tx_idx >= this_spi->slave_tx_size ) + { + while( ( this_spi->resp_buff_tx_idx < this_spi->resp_buff_size ) + && ( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->resp_tx_buffer[this_spi->resp_buff_tx_idx] ); + ++this_spi->resp_buff_tx_idx; + } + } + /* + * Lastly, see if we are ready to pad with 0s . + */ + if( this_spi->cmd_done && ( this_spi->slave_tx_idx >= this_spi->slave_tx_size ) && + ( this_spi->resp_buff_tx_idx >= this_spi->resp_buff_size ) ) + { + guard = 1 + ((int32_t)this_spi->fifo_depth / 4); + while( ( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) + && ( 0 != guard ) ) + { + /* + * Pad TX FIFO with 0s for consistent behaviour if the master + * tries to transfer more than we expected. + */ + HAL_set_32bit_reg(this_spi->base_addr, TXDATA, 0x00u); + /* + * We use the guard count to cover the event that we are never + * seeing the TX FIFO full because the data is being pulled + * out as fast as we can stuff it in. In this case we never spend + * more than our allocated time spinning here. + */ + guard--; + } + } + } + else if( SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode ) /* Single frame handling mode. */ + { + while( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + if( NULL_FRAME_HANDLER != this_spi->frame_rx_handler ) + { + this_spi->frame_rx_handler( rx_frame ); + } + } + } + else /* Slave transfer mode not set up so discard anything in RX FIFO */ + { + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_RXFIFORST_MASK ); + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_RXDATA, ENABLE ); + } + + /* Handle transmit. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_TXDONE ) ) + { + /* + * Note, the driver only currently uses the txdone interrupt when + * in frame transmit mode. In block mode all TX handling is done by the + * receive interrupt handling code as we know that for every frame received + * a frame must be placed in the TX FIFO. + */ + if( SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode ) + { + /* Execute the user callback to update the slave_tx_frame */ + if( NULL_SLAVE_TX_UPDATE_HANDLER != this_spi->slave_tx_frame_handler ) + { + this_spi->slave_tx_frame_handler ( this_spi ); + } + + /* Reload slave tx frame into Tx data register. */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, this_spi->slave_tx_frame ); + } + else if( SPI_SLAVE_XFER_BLOCK != this_spi->slave_xfer_mode ) + { + /* Slave transfer mode not set up so discard anything in TX FIFO */ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK ); + } + else + { + /* Nothing to do, no slave mode configured */ + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_TXDONE, ENABLE ); + } + + + /* Handle receive overflow. */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, INTMASK_RXOVERFLOW)) + { + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_RXFIFORST_MASK); + HAL_set_8bit_reg_field(this_spi->base_addr, INTCLR_RXOVERFLOW, ENABLE); + } + + /* Handle transmit under run. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_TXUNDERRUN ) ) + { + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK ); + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_TXUNDERRUN, ENABLE ); + } + + /* Handle command interrupt. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_CMDINT ) ) + { + read_slave_rx_fifo( this_spi ); + + /* + * Call the command handler if one exists. + */ + if( NULL_SLAVE_CMD_HANDLER != this_spi->cmd_handler ) + { + this_spi->cmd_handler( this_spi->slave_rx_buffer, this_spi->slave_rx_idx ); + } + this_spi->cmd_done = 1u; + /* Disable command interrupt until slave select becomes de-asserted to avoid retriggering. */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_CMDINT, ENABLE ); + } + + /* Handle slave select becoming de-asserted. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_SSEND) ) + { + /* Only supposed to do all this if transferring blocks... */ + if(SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode) + { + uint32_t rx_size; + + /* Empty any remaining bytes in RX FIFO */ + read_slave_rx_fifo( this_spi ); + rx_size = this_spi->slave_rx_idx; + /* + * Re-enable command interrupt if required. + * Must be done before re loading FIFO to ensure stale response + * data is not pushed into the FIFO. + */ + if(NULL_SLAVE_CMD_HANDLER != this_spi->cmd_handler) + { + this_spi->cmd_done = 0u; + this_spi->resp_tx_buffer = 0u; + this_spi->resp_buff_size = 0u; + this_spi->resp_buff_tx_idx = 0u; + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_CMDINT, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, ENABLE ); + } + /* + * Reset the transmit index to 0 to restart transmit at the start of the + * transmit buffer in the next transaction. This also requires flushing + * the Tx FIFO and refilling it with the start of Tx data buffer. + */ + this_spi->slave_tx_idx = 0u; + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + fill_slave_tx_fifo( this_spi ); + + /* Prepare to receive next packet. */ + this_spi->slave_rx_idx = 0u; + /* + * Call the receive handler if one exists. + */ + if( NULL_BLOCK_HANDLER != this_spi->block_rx_handler ) + { + this_spi->block_rx_handler( this_spi->slave_rx_buffer, rx_size ); + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_RXDATA, ENABLE ); + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_SSEND, ENABLE ); + } + } +} + +/******************************************************************************* + * Local function definitions + */ + +/***************************************************************************//** + * Fill the transmit FIFO (used for slave block transfers). + */ +static void fill_slave_tx_fifo +( + spi_instance_t * this_spi +) +{ + /* First see if slave_tx_buffer needs transmitting */ + while( ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) && + !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->slave_tx_buffer[this_spi->slave_tx_idx] ); + ++this_spi->slave_tx_idx; + } + + /* Then see if it is safe to look at putting resp_tx_buffer in FIFO? */ + if( this_spi->slave_tx_idx >= this_spi->slave_tx_size ) + { + while( ( this_spi->resp_buff_tx_idx < this_spi->resp_buff_size ) && + !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->resp_tx_buffer[this_spi->resp_buff_tx_idx] ); + ++this_spi->resp_buff_tx_idx; + } + } +} + +/***************************************************************************//** + * + */ +static void read_slave_rx_fifo +( + spi_instance_t * this_spi +) +{ + uint32_t rx_frame; + + if( SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode ) /* Block handling mode. */ + { + while( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); /* Read irresepective to clear the RX IRQ */ + if( this_spi->slave_rx_idx < this_spi->slave_rx_size ) + { + this_spi->slave_rx_buffer[this_spi->slave_rx_idx] = (uint8_t)rx_frame; + } + ++this_spi->slave_rx_idx; + } + } + else if( SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode ) /* Frame handling mode */ + { + while( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Single frame handling mode. */ + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + if( NULL_FRAME_HANDLER != this_spi->frame_rx_handler ) + { + this_spi->frame_rx_handler( rx_frame ); + } + } + } + else /* Slave transfer mode not set up so discard anything in RX FIFO */ + { + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_RXFIFORST_MASK ); + } +} + +/***************************************************************************//** + * This function is to recover the CoreSPI from receiver overflow. + * It temporarily disables the CoreSPI from interacting with external world, flushes + * the transmit and receiver FIFOs, clears all interrupts and then re-enables + * the CoreSPI instance referred by this_spi parameter. + */ +static void recover_from_rx_overflow +( + const spi_instance_t * this_spi +) +{ + /* Disable CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Reset TX and RX FIFOs */ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Enable CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); +} + + diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreSPI/core_spi.h b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreSPI/core_spi.h new file mode 100644 index 0000000..c6873f7 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreSPI/core_spi.h @@ -0,0 +1,1324 @@ +/***************************************************************************//** + * Copyright 2013-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Core SPI bare metal software driver public API. + * + * This Core SPI driver provides functions for implementing SPI master or + * SPI slave operations with the CoreSPI version 4.2.xxx It is not compatible + * with CoreSPI version 3.0.xxx. + * + * The Core SPI driver supports two classes of data transfer operation: + * SPI frame operation or SPI block transfer operations. + * + * Frame operations allow transferring individual SPI frames from 4 to 32-bits + * in length. Block operations allow transferring blocks of data organized as + * 8-bit frames. + * + * @file core_spi.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreSPI prototypes + * + */ + +/*=========================================================================*//** + @mainpage Core SPI Bare Metal Driver. + + ============================================================================== + Introduction + ============================================================================== + CoreSPI is an IP component that implements a full-duplex, synchronous, and + configurable serial peripheral interface (SPI) with frame sizes from 4 to 32 + bits and bus interface sizes of 8-, 16-, or 32-bit. Each CoreSPI instance + communicates with up to eight slave devices. + + This driver provides a set of functions for controlling CoreSPI as part of + the bare metal system where no operating system is available. These drivers + can be adapted to be used as a part of an operating system, but the + implementation of the adaptation layer between driver and the operating + system's driver model is outside the scope of this User's Guide. + + ============================================================================== + Driver Configuration + ============================================================================== + Your application software should configure the CoreSPI driver through calls + to the SPI_init() function for each CoreSPI instance in the hardware design. + This function configures a default set of parameters that include a CoreSPI + hardware instance base address and the depth of the FIFOs for this instance. + + The CoreSPI instance is configured at the time of instantiation in hardware + design for APB width, frame size, FIFO depth, serial clock speed, serial + clock polarity, serial clock phase, and slave select state parameters. + + CoreSPI can communicate with up to eight different slave devices that match + the CoreSPI configuration at the time of hardware instantiation. + + The functions SPI_configure_slave_mode() and SPI_configure_master_mode() are + used to configure the CoreSPI instance as a master or slave as required by + the application. + + When CoreSPI wishes to communicate with a specific slave device, call + the SPI_set_slave_select() function with the slave number as an argument. + This function selects the slave device. A previously selected slave gets + unselected by calling the SPI_clear_slave_select() function. + + ============================================================================== + Theory of Operation + ============================================================================== + The CoreSPI driver functions are grouped into the following categories: + • Initialization + • Configuration for either master or slave operations + • SPI master frame transfer control + • SPI master block transfer control + • SPI slave frame transfer control + • SPI slave block transfer control + + Frame transfers allow CoreSPI to write or read up to 32-bits of data in a + single SPI transaction. For example, a frame transfer of 12-bits might be used + to read the result of an ADC conversion from a SPI analog to digital converter. + + Block transfers allow CoreSPI to write and/or read a number of bytes in a single + SPI transaction. With the driver as is, block transfer transactions allow data + transfers in multiples of 8-bits (8, 16, 24, 32, 40,...) and the CoreSPI instance + has to be configured for 8-bit frames. For other frame sizes, the + SPI_transfer_block() code can act as a template for developing a frame block + transfer function. + Block transfers are typically used with byte oriented devices like SPI + FLASH devices. + + Note: The CoreSPI instance in the hardware design must be configured for + the frame size required by the application; configuration by driver is + not possible. + + -------------------------------- + Initialization + -------------------------------- + The CoreSPI driver is initialized through a call to the SPI_init() function. + The SPI_init() function takes a pointer to the global CoreSPI instance data + structure of type spi_instance_t and the base address of the CoreSPI instance + as defined by the hardware design. The CoreSPI instance global data structure + is used by the driver to store state information for each CoreSPI instance. + A pointer to these data structures is also used as the first parameter to + any of the driver functions to identify which CoreSPI will be used by the + called function. It is the responsibility of the application programmer to + create and maintain these global CoreSPI instance data structures. Any call + to a CoreSPI driver function should be of the form SPI_function_name + ( &g_core_spi0, ... ). + The SPI_init() function resets the transmit and receives FIFOs of CoreSPI + instance being initialized. + The SPI_init() function must be called before any other CoreSPI driver + functions can be called. + + ---------------------------------------------------- + Configuration + ---------------------------------------------------- + A CoreSPI instance can operate either as a master or as a slave SPI device. + There are two distinct functions for configuring a CoreSPI instance for + master or slave operations. + + ## Master Configuration + The SPI_configure_master_mode() function configures the specified CoreSPI + block for operations as an SPI master. This function must be called once + before the CoreSPI block communicates with an SPI slave device. + + ## Slave Configuration + The SPI_configure_slave_mode() function configures the specified CoreSPI + block for operations as a SPI slave. This function must be called after + calling the SPI_init() to configure the CoreSPI instance referred by this_spi + parameter to operate in the slave mode. + + ------------------------------------- + SPI Master Frame Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI master frame transfers: + • SPI_set_slave_select() + • SPI_transfer_frame() + • SPI_clear_slave_select() + + The master must first select the target slave or slaves to be addressed by + calling the SPI_set_slave_select() function. This causes the relevant select + line(s) to become asserted while data is clocked out onto the SPI data line. + + A function call is then made to SPI_transfer_frame() specifying the value + of the data frame to be sent and returning the value read. + + After the transfer is complete, use the SPI_clear_slave_select() function + to prevent this slave select line from being asserted during subsequent SPI + transactions. A call to this function is required only if the master is + communicating with multiple slave devices. + + ------------------------------------- + SPI Master Block Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI master block transfers: + • SPI_set_slave_select() + • SPI_transfer_block() + • SPI_clear_slave_select() + + The master must first select the target slave or slaves by calling + SPI_set_slave_select(). This causes the relevant slave select line(s) to + become asserted while data is clocked out onto the SPI data line. + Alternatively, a general purpose input/output (GPIO) can be used to control + the state of the target slave device's chip select signal. + + A call is then made to the SPI_transfer_block() function. The parameters of + this function specify the following: + • The number of bytes to be transmitted + • A pointer to the buffer containing the data to be transmitted + • The number of bytes to be received + • A pointer to the buffer where the received data gets stored + + The number of bytes to be transmitted can be set to zero to indicate that the + transfer is purely a block read transfer. The number of bytes to be received + can be set to zero to specify that the transfer is purely a block write + transfer. + + Block mode transfers as implemented by the driver are effectively half duplex + as we do not store the values received from the slave device whilst we are + transmitting. If full duplex operation is required, the driver + SPI_transfer_block() function can serve as a starting point for implementing + full duplex block transfers. + + The SPI_clear_slave_select() function can be used after the transfer is + complete to prevent this slave select line from being asserted during + subsequent SPI transactions. A call to this function is only required if + the master is communicating with multiple slave devices. + + ------------------------------------- + SPI Slave Frame Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI slave frame transfers: + • SPI_set_frame_rx_handler() + • SPI_set_slave_tx_frame() + + The SPI_set_frame_rx_handler() function specifies the receive handler + function that is called when a frame of data has been received by the + SPI when it is configured as a slave. The receive handler function specified + through this call processes the frame data written over the SPI bus to the + SPI slave by the remote SPI master. The receive handler function must be + implemented as part of the application. It is only required if the SPI slave + is the target of SPI frame write transactions. + + The SPI_set_slave_tx_frame() function specifies the frame data that is + returned to the SPI master. The frame data specified through this function + is the value that will be read over the SPI bus by the remote SPI master, + when it initiates a transaction. Call the SPI_set_slave_tx_frame() function + only if the SPI slave is the target of SPI read transactions. That is, if + data is meant to be read over CoreSPI. + + If both frame handlers are required, call the SPI_set_frame_rx_handler() + first, otherwise the initial TX frame gets discarded when SPI_set_frame_rx_handler() + clears the FIFOs as part of its initialization. + + ------------------------------------- + SPI Slave Block Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI slave block transfers: + • SPI_set_slave_block_buffers() + • SPI_set_cmd_handler() + • SPI_set_cmd_response() + + The SPI_set_slave_block_buffers() function is used to configure an SPI slave + for block transfer operations. It specifies the following: + • The buffer containing the data that will be returned to the remote SPI + master + • The buffer where data received from the remote SPI master will be + stored + • The optional handler function that will be called after the receive + buffer is filled + + The SPI_set_cmd_handler() function specifies a command handler function that + is called by the driver once a specific number of frames have been + received after the SPI chip select signal becomes active. The number of + bytes making up the command part of the transaction is specified as part of + the parameters to the SPI_set_cmd_handler() function. The command handler + function is implemented as a part of the application making use of the SPI + driver and typically calls the SPI_set_cmd_response() function. + + The SPI_set_cmd_response() function specifies the data that gets returned + to the master. Typically, the SPI_set_slave_block_buffers() function is + called as a part of the system initialisation to specify the data sent to + the master while the command bytes are being received. The transmit buffer + specified through calling the SPI_set_slave_block_buffers() function would + also typically include one or more bytes allowing the turn around time + for the command handler function to execute and call the + SPI_set_cmd_response() function. + + *//*=========================================================================*/ +#ifndef CORE_SPI_H_ +#define CORE_SPI_H_ + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#include "hal_assert.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + SPI FIFO Depth + ======================================= + SPI_MAX_FIFO_DEPTH & SPI_MIN_FIFO_DEPTH constants define the maximum and minimum + FIFO depths allowed for the CoreSPI instance. User need to inform the driver of + the FIFO depth for each CoreSPI instance to ensure that the FIFOs are managed correctly. + + | Constant | Description | + |--------------------|----------------------------------------------------| + | SPI_MAX_FIFO_DEPTH | Maximum FIFO depth allowed for the CoreSPI instance| + | SPI_MIN_FIFO_DEPTH | Minimum FIFO depth allowed for the CoreSPI instance| + + */ +#define SPI_MAX_FIFO_DEPTH 32u +#define SPI_MIN_FIFO_DEPTH 1u + +/***************************************************************************//** + Instances of this structure are used to identify the specific CoreSPI hardware + instances. A pointer to an instance of the spi_instance_t structure is passed + as the first parameter to the CoreSPI driver functions to identify which SPI + performs the requested operation. + */ +typedef struct spi_instance spi_instance_t; + +/***************************************************************************//** + This function pointer type is to assign a callback function for TX interrupt + when slave wants to send the next updated frame. + + Declaring and Implementing Slave Frame Transmit Handler Functions: + Slave transmit frame update handler functions should follow the following + prototype: + void slave_tx_frame_update_handler ( spi_instance_t * this_spi ); + The actual name of the transmit handler is unimportant. You can use any name + of your choice for the frame update handler. + + A common handler function may be used when multiple CoreSPI instances are + configured as slave, as the particular slave device currently requiring + service is indicated by the function parameter. + */ +typedef void (*spi_slave_frame_tx_handler_t)( spi_instance_t * this_spi ); + +/***************************************************************************//** + This defines the function prototype that must be followed by the SPI slave + frame receive handler functions. These functions are registered with the SPI + driver through the SPI_set_frame_rx_handler() function. + + Declaring and Implementing the Slave Frame Receive Handler Functions: + The Slave frame receive handler functions should follow the following + prototype: + void slave_frame_receive_handler(uint32_t rx_frame); + The actual name of the receive handler is unimportant. You can use any name + of your choice for the receive frame handler. The rx_frame parameter contains + the value of the received frame. + + Separate handler functions are required for each slave instance as there is + no indication of the slave requiring service passed to the handler. + + */ +typedef void (*spi_frame_rx_handler_t)( uint32_t rx_frame ); + +/***************************************************************************//** + This defines the function prototype that must be followed by SPI slave + block receive handler functions. These functions are registered with the + SPI driver through the SPI_set_slave_block_buffers() function. + + Declaring and Implementing Slave Block Receive Handler Functions: + Slave block receive handler functions should follow the following prototype: + void spi_block_rx_handler ( uint8_t * rx_buff, uint16_t rx_size ); + The actual name of the receive handler is unimportant. You can use any name + of your choice for the receive frame handler. The rx_buff parameter contains + a pointer to the start of the received block. The rx_size parameter contains + the number of bytes of the received block. + + Separate handler functions are required for each slave instance as there is + no indication of the slave requiring service passed to the handler. + + */ +typedef void (*spi_block_rx_handler_t)( uint8_t * rx_buff, uint32_t rx_size ); + +/***************************************************************************//** + This enumeration is used to select a specific SPI slave device (0 to 7). It is + used as a parameter to the SPI_configure_master_mode(), SPI_set_slave_select(), + and SPI_clear_slave_select() functions. + */ +typedef enum __spi_slave_t +{ + SPI_SLAVE_0 = 0, + SPI_SLAVE_1 = 1, + SPI_SLAVE_2 = 2, + SPI_SLAVE_3 = 3, + SPI_SLAVE_4 = 4, + SPI_SLAVE_5 = 5, + SPI_SLAVE_6 = 6, + SPI_SLAVE_7 = 7, + SPI_MAX_NB_OF_SLAVES = 8 +} spi_slave_t; + +/***************************************************************************//** + This enumeration is used to indicate the current slave mode transfer type so + that we are not relying on buffer comparisons to dictate the logic of the driver. + */ +typedef enum __spi_sxfer_mode_t +{ + SPI_SLAVE_XFER_NONE = 0, /* Not configured yet */ + SPI_SLAVE_XFER_BLOCK = 1, /* Block transfers, with SSEND delimiting end of block */ + SPI_SLAVE_XFER_FRAME = 2 /* Single frame transfers */ +} spi_sxfer_mode_t; + +/***************************************************************************//** + There is one instance of this structure for each of the core SPIs. Instances + of this structure are used to identify a specific SPI. A pointer to an + instance of the spi_instance_t structure is passed as the first parameter to + SPI driver functions to identify which SPI should perform the requested operation. + */ +struct spi_instance{ + + /* Base address in the processor's memory map for the + registers of the CoreSPI instance being initialized */ + addr_t base_addr; /* Base address of SPI hardware instance */ + + uint32_t rx_frame; /* received data */ + + /* Internal transmit state: */ + const uint8_t * slave_tx_buffer; /* Pointer to slave transmit buffer */ + uint32_t slave_tx_size; /* Size of slave transmit buffer */ + uint32_t slave_tx_idx; /* Current index into slave transmit buffer */ + + /* Slave command response buffer: */ + const uint8_t * resp_tx_buffer; + uint32_t resp_buff_size; + uint32_t resp_buff_tx_idx; + spi_block_rx_handler_t cmd_handler; + uint32_t cmd_done; /* Flag which indicates response has been set up and + it is safe to pad with 0s once the response is sent */ + + /* Internal receive state: */ + uint8_t * slave_rx_buffer; /* Pointer to buffer where data received by a slave will be stored */ + uint32_t slave_rx_size; /* Slave receive buffer size */ + uint32_t slave_rx_idx; /* Current index into slave receive buffer */ + + /* Slave received frame handler: */ + spi_frame_rx_handler_t frame_rx_handler; /* Pointer to function that will be called when a frame + is received when the SPI block is configured as slave */ + /* Slave transmitted frame handler: */ + uint32_t slave_tx_frame; /* Value of the data frame that will be transmitted + when the SPI block is configured as slave */ + spi_slave_frame_tx_handler_t slave_tx_frame_handler; /* Callback function pointer to update slave_tx_frame */ + + /* Slave block rx handler: */ + spi_block_rx_handler_t block_rx_handler; /* Pointer to the function that will be called when a data block has been received */ + + /* Per instance specific hardware information that the driver needs to know */ + uint16_t fifo_depth; /* Depth of RX and TX FIFOs in frames */ + + /* How we are expecting to deal with slave transfers */ + spi_sxfer_mode_t slave_xfer_mode; /* Current slave mode transfer configuration */ +}; + +/*------------------------Public Function-------------------------------------*/ + +/***************************************************************************//** + The SPI_init() function initializes the hardware and data structures of a + CoreSPI instance referenced by this_spi parameter. This function must be + called for each CoreSPI instance with a unique this_spi and base_addr + parameter combination. The SPI_init() function must be called before any + other CoreSPI driver functions are called. + + After calling the SPI_init() the CoreSPI is configured as a master, + all interrupt sources will be masked and all the slaves are deselected. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to be initialized. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @param base_addr + The base_addr parameter is the base address in the processor's memory map for + the registers of the CoreSPI instance being initialized. It is assumed that + any non NULL value passed in here points to a valid instance of a CoreSPI as + the driver has no way of verifying this. Failure to pass in a valid address + can result in system instability. + + @param fifo_depth + The fifo_depth parameter specifies the number of frames in the receive + and transmit FIFOs of the CoreSPI instance being initialized. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + @endcode + */ +void SPI_init +( + spi_instance_t * this_spi, + addr_t base_addr, + uint16_t fifo_depth +); + +/***************************************************************************//** + The SPI_configure_slave_mode() function is used when a CoreSPI instance is + to be configured as a SPI slave. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to be configured. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + + int main(void) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_slave_mode ( &g _spi0 ); + } + @endcode + */ +void SPI_configure_slave_mode +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_configure_master_mode() function is used when a CoreSPI instance is + to be configured as a SPI master. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to be configured. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + + int main(void) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_master_mode ( &g _spi0 ); + } + @endcode + */ +void SPI_configure_master_mode +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_set_slave_select() function is used by a CoreSPI master to select a + specific slave. This function causes the relevant slave select signal to be + asserted while data is clocked out onto the SPI data line. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param slave + The slave parameter is one of the spi_slave_t enumerated constants + identifying a slave. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + const uint32_t master_tx_frame = 0x0100A0E1; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0 ); + SPI_transfer_frame( &g_spi0, master_tx_frame ); + SPI_clear_slave_select( &g_spi0, SPI_SLAVE_0 ); + + @endcode + */ +void SPI_set_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +); + +/***************************************************************************//** + The SPI_clear_slave_select() function is used by a CoreSPI master to + deselect a specific slave. This function causes the relevant slave select + signal to be de-asserted. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param slave + The slave parameter is one of the spi_slave_t enumerated constants + identifying a slave. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + const uint32_t master_tx_frame = 0x0100A0E1; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0 ); + SPI_transfer_frame( &g_spi0, master_tx_frame ); + SPI_clear_slave_select( &g_spi0, SPI_SLAVE_0 ); + @endcode + */ +void SPI_clear_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +); + +/***************************************************************************//** + The SPI_transfer_frame() function is used by a SPI master to transmit and + receive a single frame of the size that has been configured at the time of + CoreSPI hardware instantiation. This function is typically used for + transactions with a SPI slave where the number of transmit and receive bits + are not divisible by 8 or where full duplex exchange of frames is required. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param tx_bits + The tx_bits parameter is a 32-bit word containing the value that will be + transmitted. If the frame size configured for the CoreSPI is less than 32-bits, + the upper bits will be ignored. + Note: The bit length of the value to be transmitted to the slave is + set when the CoreSPI is instantiated in the hardware design. + + @return + This function returns a 32-bit word containing the value that is received + from the slave. If the frame size configured for the CoreSPI in question is + less that 32-bits, the upper bits will be 0. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + const uint32_t master_tx_frame = 0x0100A0E1; + uint32_t master_rx; + + SPI_init(&g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ); + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0 ); + master_rx = SPI_transfer_frame( &g_spi0, master_tx_frame ); + SPI_clear_slave_select( &g_spi0, SPI_SLAVE_0 ); + @endcode + */ +uint32_t SPI_transfer_frame +( + spi_instance_t * this_spi, + uint32_t tx_bits +); + +/***************************************************************************//** + The SPI_transfer_block() function is used by the SPI master to transmit and + receive blocks of data organized as a specified number of 8-bit frames. It + can be used for the following: + • Writing a data block to a slave + • Reading a data block from a slave + • Sending a command to a slave followed by reading the outcome of + the command in a single SPI transaction. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param cmd_buffer + The cmd_buffer parameter is a pointer to the buffer that contains the data + sent by the master from the beginning of the transfer. This pointer can be + null (0) if the master does not need to send a command before reading data. + + @param cmd_byte_size + The cmd_byte_size parameter specifies the number of bytes in cmd_buffer that + will be sent. A value ‘0’ indicates that no data needs to be sent to the slave. + + @param rx_buffer + The rx_buffer parameter is a pointer to the buffer that stores the data received + from the slave after sending the command. This pointer can be null (0) if the + master does not receive any data from the slave. + + @param rx_byte_size + The rx_byte_size parameter specifies the number of bytes received from + the slave and stored in the rx_buffer. A value ‘0’ indicates that no data is + to be read from the slave. + + @return + This function does not return any value. + + @example + @code + Polled write transfer example + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + + uint8_t master_tx_buffer[MASTER_TX_BUFFER] = + { + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A + }; + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0) ; + SPI_transfer_block + ( + &g_spi0, + master_tx_buffer, + sizeof(master_tx_buffer), + 0, + 0 + ); + SPI_clear_slave_select(&g_spi0, SPI_SLAVE_0 ); + @endcode + */ +void SPI_transfer_block +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_buffer, + uint16_t rx_byte_size +); + +/***************************************************************************//** + The SPI_transfer_block_store_all_resp() function is used by the SPI master + to transmit and receive blocks of data organized as a specified number + of 8-bit frames. It can be used for the following: + • Writing a data block to a slave + • Reading a data block from a slave + • Sending a command to a slave followed by reading the outcome of + the command in a single SPI transaction + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param cmd_buffer + The cmd_buffer parameter is a pointer to the buffer that contains the data sent by + the master from the beginning of the transfer. This pointer can be null (0) + if the master does not need to send a command before reading data. + + @param cmd_byte_size + The cmd_byte_size parameter specifies the number of bytes contained in + cmd_buffer that will be sent. A value ‘0’ indicates that no data needs + to be sent to the slave. + + @param rx_data_buffer + The rx_data_buffer parameter is a pointer to the buffer that stores the data received + from the slave after sending the command. This pointer can be null (0) if the + master does not receive any data from the slave. + + @param rx_byte_size + The rx_byte_size parameter specifies the number of bytes received from + the slave and stores in the rx_buffer. A value ‘0’ indicates that no data is + to be read from the slave. + + @param cmd_response_buffer + The cmd_response_buffer parameter is a pointer to the buffer which stores the + command response from the slave, while the master is transmitting the number + of bytes indicated by cmd_byte_size parameter. + + @return + This function does not return any value. + + @example + @code + Polled write transfer example + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + + uint8_t master_tx_buffer[MASTER_TX_BUFFER] = + { + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A + }; + + uint8_t cmd_rx_buffer[CMD_RX_BUFFER]={0}; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0) ; + SPI_transfer_block_store_all_resp + ( + &g_spi0, + master_tx_buffer, + sizeof(master_tx_buffer), + 0, + 0, + cmd_response_buffer + ); + SPI_clear_slave_select(&g_spi0, SPI_SLAVE_0 ); + @endcode + */ +void SPI_transfer_block_store_all_resp +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_data_buffer, + uint16_t rx_byte_size, + uint8_t * cmd_response_buffer +); + +/***************************************************************************//** + The SPI_set_frame_rx_handler() function is used by the SPI slaves to specify + the receive handler function that is called by the SPI driver interrupt + handler when a frame of data is received by the SPI slave. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param rx_handler + The rx_handler parameter is a pointer to the frame receive handler that must + be called when a frame is received by the CoreSPI slave. Passing in a NULL + pointer disables the receive handler but does enable the receive interrupt to + ensure the RX FIFO is empty each time a frame is received. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + uint32_t g_slave_rx_frame = 0; + spi_instance_t g_spi0; + + void slave_frame_handler(uint32_t rx_frame) + { + g_slave_rx_frame = rx_frame; + } + int setup_slave( void ) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_slave_mode( &g_spi0 ); + SPI_set_frame_rx_handler( &g_spi0, slave_frame_handler ); + } + @endcode + */ +void SPI_set_frame_rx_handler +( + spi_instance_t * this_spi, + spi_frame_rx_handler_t rx_handler +); + +/***************************************************************************//** + The SPI_set_slave_tx_frame() function is used by the SPI slaves to specify + the frame that gets transmitted when a transaction is initiated by the SPI + master. This function allows you to assign a slave_tx_frame_handler function, + which will be executed upon transmit interrupt when the SPI is in slave mode. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param frame_value + The frame_value parameter contains the value of the frame to be sent to the + master. + Note: The bit length of the value to be transmitted to the master is + set when the CoreSPI is instantiated in the hardware design. + + @param slave_tx_frame_handler + The slave_tx_frame_handler function pointer is executed upon occurrence of + transmit interrupt when CoreSPI is operating in slave mode. This parameter + is optional and if set to NULL it is assumed that the frame value is static or + updated asynchronously. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + const uint32_t slave_tx_frame[2] = { 0x0110F761, 0x0110F671 }; + uint32_t master_rx; + uint32_t slave_frame_idx = 0 ; + + slave_frame_update( spi_instance_t * this_spi ) + { + this_spi->slave_tx_frame = slave_tx_frame[slave_frame_idx++]; + if( slave_frame_idx > 2 ) + slave_frame_idx = 0; + } + main() + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ) ; + SPI_set_slave_tx_frame( &g_spi0, slave_tx_frame[slave_frame_idx++], + &slave_frame_update ); + } + @endcode + */ +void SPI_set_slave_tx_frame +( + spi_instance_t * this_spi, + uint32_t frame_value, + spi_slave_frame_tx_handler_t slave_tx_frame_handler +); + +/***************************************************************************//** + The SPI_set_slave_block_buffers() function is used to configure an SPI slave + for block transfer operations. It specifies one or more of the following: + • The data that is transmitted when accessed by a master. + • The buffer where the data received from a master is stored. + • The handler function that must be called after the receive buffer has + been filled. + • The number of bytes that must be received from the master before calling + the recieve handler function. + These parameters allow the following use cases: + • Slave performing an action after receiving a block of data from a + master containing a command. This action is performed by the + receive handler based on the content of the receive data buffer. + • Slave returning a block of data to the master. The type of information + is always the same but the actual values change over time. For example, + returning the voltage of a predefined set of analog inputs. + • Slave returning data based on a command contained in the first part of + the SPI transaction. For example, reading the voltage of the analog + input specified by the first data byte by the master. This is achieved + by using the SPI_set_slave_block_buffers() function in conjunction with + functions SPI_set_cmd_handler() and SPI_set_cmd_response(). + + See the SPI_set_cmd_handler() function description for details of + this use case. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param tx_buffer + The tx_buffer parameter is a pointer to a buffer containing the data that + will be sent to the master. This parameter can be set to ‘0’ if the SPI + slave is not intended to be the target of SPI read transactions. + + @param tx_buff_size + The tx_buff_size parameter specifies the number of bytes that are + transmitted by the SPI slave. It is the number of bytes contained in the + tx_buffer. This parameter can be set to ‘0’ if the SPI slave is not + intended to be the target of SPI read transactions. The driver returns 0s + to the master if there is no buffer specified or the master reads beyond the + end of the buffer. + Note: If SPI_transfer_block() is used to read from this slave and there is + no command handler involved, the buffer size here must be at least the + combined length of the command and response specified by the master. + On receiving this data, the master discards the data bytes equal to + command length bytes from the start of the received buffer. + + @param rx_buffer + The rx_buffer parameter is a pointer to the buffer where data received + from the master is stored. This parameter can be set to ‘0’ if the + SPI slave is not intended to be the target of SPI write or write-read + transactions. + + @param rx_buff_size + The rx_buff_size parameter specifies the size of the receive buffer. It is + also the number of bytes that must be received before the receive handler + is called, if a receive handler is specified using the block_rx_handler + parameter. Any bytes received in excess of the size specified by the + rx_buff_size parameter are discarded. This parameter can be set to ‘0’ + if the SPI slave is not intended to be the target of SPI write or + write-read transactions. + + @param block_rx_handler + The block_rx_handler parameter is a pointer to a function that is called + when receive buffer has been filled or the slave select has been de-asserted. + This parameter can be set to ‘0’ if the SPI slave is not intended to be the + target of SPI write or write-read transactions. + + @return + This function does not return any value. + + @example + @code + Slave Performing Operation Based on Master Command: + In this example the SPI slave is configured to receive 10 bytes of data + or command from the SPI slave, and process the data received from the master. + + #define SPI0_BASE_ADDR 0xC2000000 + + uint32_t nb_of_rx_handler_calls = 0; + spi_instance_t g_spi0; + + void spi1_block_rx_handler_b + ( + uint8_t * rx_buff, + uint16_t rx_size + ) + { + ++nb_of_rx_handler_calls; + } + + void setup_slave( void ) + { + uint8_t slave_rx_buffer[10] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_slave_mode( &g_spi0 ); + + SPI_set_slave_block_buffers + ( + &g_spi0, + 0, + 0, + slave_rx_buffer, + sizeof( master_tx_buffer ), + spi1_block_rx_handler_b + ); + } + @endcode + */ +void SPI_set_slave_block_buffers +( + spi_instance_t * this_spi, + const uint8_t * tx_buffer, + uint32_t tx_buff_size, + uint8_t * rx_buffer, + uint32_t rx_buff_size, + spi_block_rx_handler_t block_rx_handler +); + +/***************************************************************************//** + The SPI_isr() function is the top level interrupt handler function for the + CoreSPI driver. You must call SPI_isr() from the system level + (CoreInterrupt and NVIC level) interrupt handler assigned to the interrupt + triggered by the CoreSPI SPIINT signal. Your system level interrupt handler + must also clear the system level interrupt triggered by the CoreSPI SPIINT + signal before returning, to prevent a re-assertion of the same interrupt. + + This function supports all types of interrupt triggered by CoreSPI. It is not + a complete interrupt handler by itself; rather, it is a top level wrapper that + abstracts CoreSPI command interrupt and slave mode transmit interrupt handling + by calling lower level handler functions specific to each type of CoreSPI + interrupt. You must create the lower level handler functions to suit your + application and register them with the driver through calling the + SPI_set_cmd_handler(), SPI_set_cmd_response(), and SPI_set_slave_tx_frame() + functions. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + + @example + @code + + Example of configuring a CoreInterrupt connected to the Fabric Interrupt on a + SmartFusion device to handle CoreSPI interrupt. + + #define #define SPI1_INT_IRQ_NB 0 + spi_instance_t g_spi0; + + Void CIC_irq1_handler(void) + { + SPI_isr( &g_spi0 ); + } + + void Fabric_IRQHandler( void ) + { + // Call the CoreInterrupt driver ISR to determine the source of the + // interrupt and call the relevant ISR registered to it. + CIC_irq_handler(); + + // Clear NVIC interrupt status to allow further interrupts + NVIC_ClearPendingIRQ( Fabric_IRQn ); + } + + main() + { + ... + + CIC_init( CIC_BASE_ADDR ); + + // Install handler for SPI IRQ + CIC_set_irq_handler( SPI0_INT_IRQ_NB, CIC_irq1_handler ); + + NVIC_ClearPendingIRQ( Fabric_IRQn ); + NVIC_EnableIRQ( Fabric_IRQn ); + + CIC_enable_irq( SPI1_INT_IRQ_NB ); + + ... + } + @endcode + */ +void SPI_isr +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_set_cmd_handler() function specifies a command handler function that + will be called when the number of bytes received reaches the command size + specified as cmd_size parameter. + + This function is used by the SPI slaves performing block transfers. Its + purpose is to allow an SPI slave to decide the data that will be returned to + the master while an SPI transaction is taking place. Typically, one or more + command bytes are sent by the master to request some specific data. The slave + interprets the command byte(s) while one or more turn-around bytes are + transmitted. The slave adjusts its transmit data buffer based on the command + during the turn around time. + + The following table provides an example of the use of this function where the + SPI slave returns data bytes D0 to D6 based on the value of a command. The + 3 bytes long command is made up of a command opcode byte followed by an + address byte followed by a size byte. The cmd_handler() function specified + through an earlier call to SPI_set_cmd_handler() is called by the CoreSPI + driver once the third byte is received. The cmd_handler() function + interprets the command bytes and calls SPI_set_cmd_response() to set the SPI + slave's response transmit buffer with the data to be transmitted after the + turnaround bytes (T0 to T3). The number of turnaround bytes must be + sufficient to give enough time for the cmd_handler() to execute. The number + of turnaround bytes is specified by the protocol used on top of the SPI + transport layer so that master and slave agree on the number of turn around + bytes. + +|Timestamp| SPI Transaction | Bytes | Comments | +|---------|-------------|----------------------|---------------| +| t0|COMMAND|C A S |C - command opcode byte, A - address byte, S - size byte| +|t1| TURN-AROUND|T0 T1 |cmd_handler() called here (T0 to T3 are TURN-AROUND bytes)| +|t2|TURN-AROUND|T2 T3|SPI_set_cmd_response() called here by implementation of cmd_handler() +|| | |to set the data that will be transmitted by the SPI slave.| +|t3| DATA | D0 D1 D2 D3 D4 D5 D6 |Data transmition (SPI slave return data bytes)| + + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure identifying + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @param cmd_handler + The cmd_handler parameter is a pointer to a function with the prototype: + void cmd_handler(uint8_t * rx_buff, uint32_t rx_size); + It specifies the function that will be called when the number of bytes + specified by the cmd_size parameter has been received. + + @param cmd_size + The cmd_size parameter specifies the number of bytes that must be received + before calling the command handler function specified by the cmd_handler. + The CoreSPI supports cmd_size values in the range 1 to 7. + + @return + This function does not return any value. + + @example + @code + The following example demonstrates how to configure CoreSPI to implement + the protocol given as an example above. The configure_slave() function + configures CoreSPI. It sets receive and transmit buffers. The transmit + buffer specified through the call to SPI_set_slave_block_buffers() function + specifies the data that will be returned to the master in bytes between + t0 and t3. These bytes will be sent to the master while the master transmits + the command and dummy bytes. The spi_slave_cmd_handler() function will be + called by the driver at time t1 after the 3 command bytes have been received. + The spi_block_rx_handler() function will be called by the driver at time t4, + when the transaction completes and the slave select signal becomes + de-asserted. + + #define SPI0_BASE_ADDR 0xC2000000 + #define COMMAND_SIZE 3 + #define NB_OF_DUMMY_BYTES 4 + #define MAX_TRANSACTION_SIZE 16 + + spi_instance_t g_spi0; + uint8_t slave_tx_buffer[COMMAND_SIZE + NB_OF_DUMMY_BYTES]; + uint8_t slave_rx_buffer[MAX_TRANSACTION_SIZE]; + + void configure_slave( void ) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_slave_mode( &g_spi0 ); + SPI_set_slave_block_buffers + ( + &g_spi0, + slave_tx_buffer, + COMMAND_SIZE + NB_OF_DUMMY_BYTES, + slave_rx_buffer, + sizeof(slave_rx_buffer), + spi_block_rx_handler + ); + + SPI_set_cmd_handler + ( + &g_spi0, + spi_slave_cmd_handler, + COMMAND_SIZE + ); + } + + void spi_slave_cmd_handler + ( + uint8_t * rx_buff, + uint32_t rx_size + ) + { + uint8_t command; + uint8_t address; + uint8_t size; + uint8_t * p_response; + uint32_t response_size; + + command = rx_buff[0]; + address = rx_buff[1]; + size = rx_buff[2]; + + p_response = get_response_data( command, address, size, &response_size ); + SPI_set_cmd_response( &g_spi0, p_response, response_size ); + } + + void spi_block_rx_handler + ( + uint8_t * rx_buff, + uint32_t rx_size + ) + { + process_rx_data( rx_buff, rx_size ); + } + @endcode + */ +void SPI_set_cmd_handler +( + spi_instance_t * this_spi, + spi_block_rx_handler_t cmd_handler, + uint32_t cmd_size +); + +/***************************************************************************//** + The SPI_set_cmd_response() function specifies the data that will be returned + to the master. See the description of SPI_set_cmd_handler() for details. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param resp_tx_buffer + The resp_tx_buffer parameter is a pointer to the buffer containing the data + that must be returned to the host in the data phase of an SPI transaction. + + @param resp_buff_size + The resp_buff_size parameter specifies the size of the buffer pointed by the + resp_tx_buffer parameter. + + @return + This function does not return any value. + */ +void SPI_set_cmd_response +( + spi_instance_t * this_spi, + const uint8_t * resp_tx_buffer, + uint32_t resp_buff_size +); + +/***************************************************************************//** + The SPI_enable() function enables the CoreSPI and allows it to respond to the external + signals. It is usually called to re-enable a CoreSPI instance which has been + disabled previously via by calling the SPI_disable() as the normal state of a CoreSPI + after enabling the initialization. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + */ +void SPI_enable +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_disable() function disables the CoreSPI and stops responding to the + external signals. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + */ +void SPI_disable +( + spi_instance_t * this_spi +); + +#ifdef __cplusplus +} +#endif + +#endif /* CORE_SPI_H_*/ diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreSPI/corespi_regs.h b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreSPI/corespi_regs.h new file mode 100644 index 0000000..a3e5b2a --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreSPI/corespi_regs.h @@ -0,0 +1,270 @@ +/***************************************************************************//** + * Copyright 2011-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file corespi_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreSPI memory map + * + */ + +#ifndef CORESPI_REGS_H_ +#define CORESPI_REGS_H_ + +/******************************************************************************* + * Control register 1: + *------------------------------------------------------------------------------ + */ +#define CTRL1_REG_OFFSET 0x00u + +#define CTRL1_ENABLE_OFFSET 0x00u +#define CTRL1_ENABLE_MASK 0x01u +#define CTRL1_ENABLE_SHIFT 0x00 + +#define CTRL1_MASTER_OFFSET 0x00u +#define CTRL1_MASTER_MASK 0x02u +#define CTRL1_MASTER_SHIFT 0x01 + +#define CTRL1_INTRXDATA_OFFSET 0x00u +#define CTRL1_INTRXDATA_MASK 0x04u +#define CTRL1_INTRXDATA_SHIFT 0x02 + +#define CTRL1_INTTXDONE_OFFSET 0x00u +#define CTRL1_INTTXDONE_MASK 0x08u +#define CTRL1_INTTXDONE_SHIFT 0x03 + +#define CTRL1_INTRXOVFLOW_OFFSET 0x00u +#define CTRL1_INTRXOVFLOW_MASK 0x10u +#define CTRL1_INTRXOVFLOW_SHIFT 0x04 + +#define CTRL1_INTTXURUN_OFFSET 0x00u +#define CTRL1_INTTXURUN_MASK 0x20u +#define CTRL1_INTTXURUN_SHIFT 0x05 + +#define CTRL1_FRAMEURUN_OFFSET 0x00u +#define CTRL1_FRAMEURUN_MASK 0x40u +#define CTRL1_FRAMEURUN_SHIFT 0x06 + +#define CTRL1_OENOFF_OFFSET 0x00u +#define CTRL1_OENOFF_MASK 0x80u +#define CTRL1_OENOFF_SHIFT 0x07 + +/******************************************************************************* + * Interrupt clear register: + *------------------------------------------------------------------------------ + */ +#define INTCLR_REG_OFFSET 0x04u + +#define INTCLR_TXDONE_OFFSET 0x04u +#define INTCLR_TXDONE_MASK 0x01u +#define INTCLR_TXDONE_SHIFT 0x00 + +#define INTCLR_RXDONE_OFFSET 0x04u +#define INTCLR_RXDONE_MASK 0x02u +#define INTCLR_RXDONE_SHIFT 0x01 + +#define INTCLR_RXOVERFLOW_OFFSET 0x04u +#define INTCLR_RXOVERFLOW_MASK 0x04u +#define INTCLR_RXOVERFLOW_SHIFT 0x02 + +#define INTCLR_TXUNDERRUN_OFFSET 0x04u +#define INTCLR_TXUNDERRUN_MASK 0x08u +#define INTCLR_TXUNDERRUN_SHIFT 0x03 + +#define INTCLR_CMDINT_OFFSET 0x04u +#define INTCLR_CMDINT_MASK 0x10u +#define INTCLR_CMDINT_SHIFT 0x04 + +#define INTCLR_SSEND_OFFSET 0x04u +#define INTCLR_SSEND_MASK 0x20u +#define INTCLR_SSEND_SHIFT 0x05 + +#define INTCLR_RXDATA_OFFSET 0x04u +#define INTCLR_RXDATA_MASK 0x40u +#define INTCLR_RXDATA_SHIFT 0x06 + +#define INTCLR_TXDATA_OFFSET 0x04u +#define INTCLR_TXDATA_MASK 0x80u +#define INTCLR_TXDATA_SHIFT 0x07 + +/******************************************************************************* + * Receive data register: + *------------------------------------------------------------------------------ + */ +#define RXDATA_REG_OFFSET 0x08u + +/******************************************************************************* + * Transmit data register: + *------------------------------------------------------------------------------ + */ +#define TXDATA_REG_OFFSET 0x0Cu + +/******************************************************************************* + * Masked interrupt status register: + *------------------------------------------------------------------------------ + */ +#define INTMASK_REG_OFFSET 0x10u + +#define INTMASK_TXDONE_OFFSET 0x10u +#define INTMASK_TXDONE_MASK 0x01u +#define INTMASK_TXDONE_SHIFT 0x00 + +#define INTMASK_RXDONE_OFFSET 0x10u +#define INTMASK_RXDONE_MASK 0x02u +#define INTMASK_RXDONE_SHIFT 0x01 + +#define INTMASK_RXOVERFLOW_OFFSET 0x10u +#define INTMASK_RXOVERFLOW_MASK 0x04u +#define INTMASK_RXOVERFLOW_SHIFT 0x02 + +#define INTMASK_TXUNDERRUN_OFFSET 0x10u +#define INTMASK_TXUNDERRUN_MASK 0x08u +#define INTMASK_TXUNDERRUN_SHIFT 0x03 + +#define INTMASK_CMDINT_OFFSET 0x10u +#define INTMASK_CMDINT_MASK 0x10u +#define INTMASK_CMDINT_SHIFT 0x04 + +#define INTMASK_SSEND_OFFSET 0x10u +#define INTMASK_SSEND_MASK 0x20u +#define INTMASK_SSEND_SHIFT 0x05 + +#define INTMASK_RXDATA_OFFSET 0x10u +#define INTMASK_RXDATA_MASK 0x40u +#define INTMASK_RXDATA_SHIFT 0x06 + +#define INTMASK_TXDATA_OFFSET 0x10u +#define INTMASK_TXDATA_MASK 0x80u +#define INTMASK_TXDATA_SHIFT 0x07 + +/******************************************************************************* + * Raw interrupt status register: + *------------------------------------------------------------------------------ + */ +#define INTRAW_REG_OFFSET 0x14u + +#define INTRAW_TXDONE_OFFSET 0x14u +#define INTRAW_TXDONE_MASK 0x01u +#define INTRAW_TXDONE_SHIFT 0x00 + +#define INTRAW_RXDONE_OFFSET 0x14u +#define INTRAW_RXDONE_MASK 0x02u +#define INTRAW_RXDONE_SHIFT 0x01 + +#define INTRAW_RXOVERFLOW_OFFSET 0x14u +#define INTRAW_RXOVERFLOW_MASK 0x04u +#define INTRAW_RXOVERFLOW_SHIFT 0x02 + +#define INTRAW_TXUNDERRUN_OFFSET 0x14u +#define INTRAW_TXUNDERRUN_MASK 0x08u +#define INTRAW_TXUNDERRUN_SHIFT 0x03 + +#define INTRAW_CMDINT_OFFSET 0x14u +#define INTRAW_CMDINT_MASK 0x10u +#define INTRAW_CMDINT_SHIFT 0x04 + +#define INTRAW_SSEND_OFFSET 0x14u +#define INTRAW_SSEND_MASK 0x20u +#define INTRAW_SSEND_SHIFT 0x05 + +#define INTRAW_RXDATA_OFFSET 0x14u +#define INTRAW_RXDATA_MASK 0x40u +#define INTRAW_RXDATA_SHIFT 0x06 + +#define INTRAW_TXDATA_OFFSET 0x14u +#define INTRAW_TXDATA_MASK 0x80u +#define INTRAW_TXDATA_SHIFT 0x07 + +/******************************************************************************* + * Control register 2: + *------------------------------------------------------------------------------ + */ +#define CTRL2_REG_OFFSET 0x18u + +#define CTRL2_CMDSIZE_OFFSET 0x18u +#define CTRL2_CMDSIZE_MASK 0x07u +#define CTRL2_CMDSIZE_SHIFT 0x00 + +#define CTRL2_INTCMD_OFFSET 0x18u +#define CTRL2_INTCMD_MASK 0x10u +#define CTRL2_INTCMD_SHIFT 0x04 + +#define CTRL2_INTSSEND_OFFSET 0x18u +#define CTRL2_INTSSEND_MASK 0x20u +#define CTRL2_INTSSEND_SHIFT 0x05 + +#define CTRL2_INTRXDATA_OFFSET 0x18u +#define CTRL2_INTRXDATA_MASK 0x40u +#define CTRL2_INTRXDATA_SHIFT 0x06 + +#define CTRL2_INTTXDATA_OFFSET 0x18u +#define CTRL2_INTTXDATA_MASK 0x80u +#define CTRL2_INTTXDATA_SHIFT 0x07 + +/******************************************************************************* + * Command register: + *------------------------------------------------------------------------------ + */ +#define CMD_REG_OFFSET 0x1Cu + +#define CMD_RXFIFORST_OFFSET 0x1Cu +#define CMD_RXFIFORST_MASK 0x01u +#define CMD_RXFIFORST_SHIFT 0x00 + +#define CMD_TXFIFORST_OFFSET 0x1Cu +#define CMD_TXFIFORST_MASK 0x02u +#define CMD_TXFIFORST_SHIFT 0x01 + +/******************************************************************************* + * Status register: + *------------------------------------------------------------------------------ + */ +#define STATUS_REG_OFFSET 0x20u + +#define STATUS_FIRSTFRAME_OFFSET 0x20u +#define STATUS_FIRSTFRAME_MASK 0x01u +#define STATUS_FIRSTFRAME_SHIFT 0x00 + +#define STATUS_DONE_OFFSET 0x20u +#define STATUS_DONE_MASK 0x02u +#define STATUS_DONE_SHIFT 0x01 + +#define STATUS_RXEMPTY_OFFSET 0x20u +#define STATUS_RXEMPTY_MASK 0x04u +#define STATUS_RXEMPTY_SHIFT 0x02 + +#define STATUS_TXFULL_OFFSET 0x20u +#define STATUS_TXFULL_MASK 0x08u +#define STATUS_TXFULL_SHIFT 0x03 + +#define STATUS_RXOVFLOW_OFFSET 0x20u +#define STATUS_RXOVFLOW_MASK 0x10u +#define STATUS_RXOVFLOW_SHIFT 0x04 + +#define STATUS_TXUNDERRUN_OFFSET 0x20u +#define STATUS_TXUNDERRUN_MASK 0x20u +#define STATUS_TXUNDERRUN_SHIFT 0x05 + +#define STATUS_SSEL_OFFSET 0x20u +#define STATUS_SSEL_MASK 0x40u +#define STATUS_SSEL_SHIFT 0x06 + +#define STATUS_ACTIVE_OFFSET 0x20u +#define STATUS_ACTIVE_MASK 0x80u +#define STATUS_ACTIVE_SHIFT 0x07 + +/******************************************************************************* + * Slave select register: + *------------------------------------------------------------------------------ + */ +#define SSEL_REG_OFFSET 0x24u + +/******************************************************************************* + * Transmit data last register: + *------------------------------------------------------------------------------ + */ +#define TXLAST_REG_OFFSET 0x28u + + +#endif /*CORESPI_REGS_H_*/ diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.c b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.c new file mode 100644 index 0000000..b8adaed --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.c @@ -0,0 +1,889 @@ +/******************************************************************************* + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * PF_System_Services driver implementation. See file "core_syservices_pf.h" for + * description of the functions implemented in this file. + * + */ + +#include "core_sysservices_pf.h" +#include "coresysservicespf_regs.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define NULL_BUFFER (( uint8_t* ) 0) + +static uint8_t execute_ss_command +( + uint8_t cmd_opcode, + const uint8_t* cmd_data, + uint16_t cmd_data_size, + const uint8_t* p_response, + uint16_t response_size, + uint16_t mb_offset, + uint16_t response_offset +); + +uint32_t g_css_pf_base_addr = 0u; + +/***************************************************************************//** + * SYS_init() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +void +SYS_init +( + uint32_t base_addr +) +{ + g_css_pf_base_addr = base_addr; +} + +/***************************************************************************//** + * SYS_get_serial_number() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_serial_number +( + const uint8_t * p_serial_number, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if (p_serial_number == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(SERIAL_NUMBER_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_serial_number, + SERIAL_NUMBER_RESP_LEN, + mb_offset, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_get_user_code() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_user_code +( + const uint8_t * p_user_code, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_user_code == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(USERCODE_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_user_code, + USERCODE_RESP_LEN, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_get_design_info() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_design_info +( + const uint8_t * p_design_info, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_design_info == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(DESIGN_INFO_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_design_info, + DESIGN_INFO_RESP_LEN, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_get_device_certificate() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_device_certificate +( + const uint8_t * p_device_certificate, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_device_certificate == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(DEVICE_CERTIFICATE_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_device_certificate, + DEVICE_CERTIFICATE_RESP_LEN, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_read_digest() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_read_digest +( + const uint8_t * p_digest, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_digest == NULL_BUFFER) + { + return status; + } + +#ifndef CORESYSSERVICES_MPFS + status = execute_ss_command(READ_DIGEST_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_digest, + READ_DIGEST_RESP_LEN, + mb_offset, + 0u); +#else + status = execute_ss_command(READ_DIGEST_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_digest, + READ_DIGEST_MPFS_RESP_LEN, + mb_offset, + 0u); +#endif + return status; + +} + +/***************************************************************************//** + * SYS_query_security() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_query_security +( + uint8_t * p_security_locks, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint8_t idx = 0u; + + if(p_security_locks == NULL_BUFFER) + { + return status; + } + +#ifndef CORESYSSERVICES_MPFS + uint8_t buf[12] = {0}; + /* Actual QUERY_SECURITY_RESP_LEN is 9 or 33 but PF_System_Services core + * needs number of words instead of number of bytes to be written to or read + * from MailBox */ + status = execute_ss_command(QUERY_SECURITY_REQUEST_CMD, + NULL_BUFFER, + 0u, + buf, + (QUERY_SECURITY_RESP_LEN + 3u), + mb_offset, + 0u); + + for (idx = 0u; idx < 9u; idx++) + { + *(p_security_locks+idx) = buf[idx]; + } + +#else + uint8_t buf[36] = {0}; + + status = execute_ss_command(QUERY_SECURITY_REQUEST_CMD, + NULL_BUFFER, + 0u, + buf, + (QUERY_SECURITY_MPFS_RESP_LEN + 3u), + mb_offset, + 0u); + + for (idx = 0u; idx < 33u; idx++) + { + *(p_security_locks+idx) = buf[idx]; + } + +#endif + + return status; +} + +/***************************************************************************//** + * SYS_read_debug_info() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_read_debug_info +( + const uint8_t * p_debug_info, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_debug_info == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(READ_DEBUG_INFO_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_debug_info, + READ_DEBUG_INFO_RESP_LEN, + mb_offset, + 0u); + return status; +} + +#ifdef CORESYSSERVICES_MPFS +/***************************************************************************//** + * SYS_read_envm_parameter() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_read_envm_parameter +( + uint8_t * p_envm_param, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_envm_param == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(READ_ENVM_PARAM_REQUEST_CMD, + NULL_BUFFER, + 0, + p_envm_param, + READ_ENVM_PARAM_RESP_LEN, + mb_offset, + 0); + return status; +} + +#endif + +/***************************************************************************//** + * SYS_puf_emulation_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_puf_emulation_service +( + const uint8_t * p_challenge, + uint8_t op_type, + uint8_t* p_response, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint8_t mb_format[20] = {0x00}; + uint8_t index = 0u; + + if((p_response == NULL_BUFFER) || (p_challenge == NULL_BUFFER)) + { + return status; + } + + /* Frame the data required for mailbox */ + mb_format[index] = op_type; + + for (index = 4u; index < 20u; index++) + { + mb_format[index] = p_challenge[index - 4u]; + } + + status = execute_ss_command(PUF_EMULATION_SERVICE_REQUEST_CMD, + mb_format, + PUF_EMULATION_SERVICE_CMD_LEN, + p_response, + PUF_EMULATION_SERVICE_RESP_LEN, + mb_offset, + 5u); /* mentioning offset to number of words instead of bytes */ + + return status; +} + +/***************************************************************************//** + * SYS_digital_signature_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_digital_signature_service +( + const uint8_t* p_hash, + uint8_t format, + uint8_t* p_response, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if((p_hash == NULL_BUFFER) || (p_response == NULL_BUFFER)) + { + return status; + } + + if (format == DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD) + { + status = execute_ss_command(DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD, + p_hash, + DIGITAL_SIGNATURE_HASH_LEN, + p_response, + DIGITAL_SIGNATURE_RAW_FORMAT_RESP_SIZE, + mb_offset, + 12u); /* mentioning offset to number of words instead of bytes */ + } + else + { + status = execute_ss_command(DIGITAL_SIGNATURE_DER_FORMAT_REQUEST_CMD, + p_hash, + DIGITAL_SIGNATURE_HASH_LEN, + p_response, + DIGITAL_SIGNATURE_DER_FORMAT_RESP_SIZE, + mb_offset, + 12u); /* mentioning offset to number of words instead of bytes */ + } + + return status; +} + +/***************************************************************************//** + * SYS_secure_nvm_write() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_secure_nvm_write +( + uint8_t format, + uint8_t snvm_module, + const uint8_t* p_data, + const uint8_t* p_user_key, + uint16_t mb_offset +) +{ + uint8_t frame[256] = {0x00}; + uint8_t* p_frame = &frame[0]; + uint16_t index = 0u; + uint8_t status = SYS_PARAM_ERR; + + HAL_ASSERT(!(NULL_BUFFER == p_data)); + HAL_ASSERT(!(snvm_module >= 221u)); + if (format != SNVM_NON_AUTHEN_TEXT_REQUEST_CMD) + { + HAL_ASSERT(!(NULL_BUFFER == p_user_key)); + } + + if ((p_data == NULL_BUFFER) || (snvm_module >= 221)) + { + return status; + } + + if ((format != SNVM_NON_AUTHEN_TEXT_REQUEST_CMD) + && (p_user_key == NULL_BUFFER)) + { + return status; + } + + if ((format != SNVM_NON_AUTHEN_TEXT_REQUEST_CMD) + && (format != SNVM_AUTHEN_TEXT_REQUEST_CMD) + && (format != SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD)) + { + return status; + } + + *p_frame = snvm_module; /* SNVMADDR - SNVM module */ + + p_frame += 4u; /* Next 3 bytes RESERVED - For alignment */ + + /* Copy user key and send the command/data to mailbox. */ + if ((format == SNVM_AUTHEN_TEXT_REQUEST_CMD) || + (format == SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD)) + { + /* Copy user data */ + for (index = 0u; index < (AUTHENTICATED_TEXT_DATA_LEN - USER_SECRET_KEY_LEN - 4u); index++) + { + *p_frame = p_data[index]; + p_frame++; + } + + /* Copy user key */ + for (index = 0u; index < USER_SECRET_KEY_LEN; index++) + { + *p_frame = p_user_key[index]; + p_frame++; + } + + status = execute_ss_command(format, + &frame[0], + AUTHENTICATED_TEXT_DATA_LEN, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + } + else + { + /* Copy user data */ + for (index = 0u; index < (NON_AUTHENTICATED_TEXT_DATA_LEN - 4u); index++) + { + *(p_frame+index) = p_data[index]; + } + + status = execute_ss_command(format, + &frame[0], + NON_AUTHENTICATED_TEXT_DATA_LEN, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + } + + return status; +} + +/***************************************************************************//** + * SYS_secure_nvm_read() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_secure_nvm_read +( + uint8_t snvm_module, + const uint8_t* p_user_key, + uint8_t* p_admin, + uint8_t* p_data, + uint16_t data_len, + uint16_t mb_offset +) +{ + /* Frame the message. */ + uint8_t frame[16] = {0x00u}; + uint8_t* p_frame = &frame[0u]; + uint8_t status = SYS_PARAM_ERR; + uint8_t response[256] = {0x00u}; + uint16_t index = 0u; + + HAL_ASSERT(!(NULL_BUFFER == p_data)); + HAL_ASSERT(!(NULL_BUFFER == p_admin)); + HAL_ASSERT(!(snvm_module > 221u)); + + HAL_ASSERT(data_len == 236u || data_len == 252u); + + if((p_data == NULL_BUFFER) || + (snvm_module >= 221) || + (p_admin == NULL_BUFFER)) + { + return status; + } + + *p_frame = snvm_module; /* SNVMADDR - SNVM module */ + + p_frame += 4u; /* RESERVED - For alignment */ + + /* Copy user key */ + if (236u == data_len) + { + HAL_ASSERT(p_user_key != NULL_BUFFER); + + if(p_user_key == NULL_BUFFER) + { + return status; + } + + for (index = 0u; index < 12u; index++) + { + *p_frame = p_user_key[index]; + p_frame++; + } + } + else + { + p_frame += 12u; + } + + status = execute_ss_command(SNVM_READ_REQUEST_CMD, + &frame[0], + 16u, + response, + (data_len + 4u), + mb_offset, + 4u); /* mentioning offset to number of words instead of bytes */ + + if (SYS_SUCCESS == status) + { + for (index = 0u; index < 4u; index++) + { + *(p_admin+index) = (uint32_t)response[index]; + } + + + /* Copy data into user buffer. */ + for (index = 4u; index < (data_len + 4u); index++) + { + *(p_data + (index - 4u)) = response[index]; + } + } + else + { + ; + } + + return status; +} + +/***************************************************************************//** + * SYS_nonce_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_nonce_service +( + const uint8_t * p_nonce, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if((p_nonce == NULL_BUFFER)) + { + return status; + } + + status = execute_ss_command(NONCE_SERVICE_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_nonce, + NONCE_SERVICE_RESP_LEN, + mb_offset, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_bitstream_authenticate_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_bitstream_authenticate_service +( + uint32_t spi_flash_address, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint32_t l_spi_flash_address = spi_flash_address; + status = execute_ss_command(BITSTREAM_AUTHENTICATE_CMD, + (uint8_t* )&l_spi_flash_address, + 4u, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_IAP_image_authenticate_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_IAP_image_authenticate_service +( + uint8_t spi_idx +) +{ + uint8_t status = SYS_PARAM_ERR; + + HAL_ASSERT(!(spi_idx == 1u)); + + if (spi_idx == 1u) + { + return status; + } + + status = execute_ss_command(IAP_BITSTREAM_AUTHENTICATE_CMD, + NULL_BUFFER, + 0u, + NULL_BUFFER, + 0u, + spi_idx, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_digest_check_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_digest_check_service +( + uint32_t options, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint32_t l_options = options; + + status = execute_ss_command(DIGEST_CHECK_CMD, + (uint8_t* )&l_options, + 4u, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_iap_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_iap_service +( + uint8_t iap_cmd, + uint32_t spiaddr, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint16_t l_mb_offset = 0u; + uint16_t cmd_data_size = 0u; + uint8_t* cmd_data = NULL_BUFFER; + bool invalid_param = false; + + if (((IAP_PROGRAM_BY_SPIIDX_CMD == iap_cmd) + || (IAP_VERIFY_BY_SPIIDX_CMD == iap_cmd)) + && (1u == spiaddr)) + { + invalid_param = true; + HAL_ASSERT(!invalid_param); + } + + if (!invalid_param) + { + switch(iap_cmd) + { + case IAP_PROGRAM_BY_SPIIDX_CMD: + case IAP_VERIFY_BY_SPIIDX_CMD: + /*In SPI_IDX based program and verify commands, + * Mailbox is not Required. Instead of mailbox offset + * SPI_IDX is passed as parameter.*/ + l_mb_offset = (uint16_t)(0xFFu & spiaddr); + break; + + case IAP_PROGRAM_BY_SPIADDR_CMD: + case IAP_VERIFY_BY_SPIADDR_CMD: + /*In SPI_ADDR based program and verify commands, + * Mailbox is Required*/ + l_mb_offset = mb_offset; + /*command data size is four bytes holding the + * SPI Address in it.*/ + cmd_data_size = 4u; + cmd_data = (uint8_t*)&spiaddr; + break; + + case IAP_AUTOUPDATE_CMD: + /*In auto update command Mailbox is not Required*/ + l_mb_offset = 0u; + break; + + default: + l_mb_offset = 0u; + + } + + status = execute_ss_command( + (uint8_t)iap_cmd, + cmd_data, + cmd_data_size, + NULL_BUFFER, + 0, + (uint16_t)l_mb_offset, + 0); + } + + return status; +} + +/***************************************************************************//** + Internal functions. +*/ +/* +This function executes the SS command. If Mailbox input data is required by the +it will first load it from cmd_data into the Mailbox. If the service requires +the response data to be read from mailbox, it will do so and store it in p_response. +*/ +static uint8_t execute_ss_command +( + uint8_t cmd_opcode, + const uint8_t* cmd_data, + uint16_t cmd_data_size, + const uint8_t* p_response, + uint16_t response_size, + uint16_t mb_offset, + uint16_t response_offset +) +{ + /* Pointer used during Writing to Mailbox memory. */ + uint32_t status = 0u; + uint16_t idx = 0u; + uint16_t ss_command = 0u; + uint32_t* word_buf; + uint16_t timeout_count = SS_TIMEOUT_COUNT; + + /* making sure that the system controller is not executing any service i.e. + SS_USER_BUSY is gone 0 */ + + while (1u == HAL_get_32bit_reg_field(g_css_pf_base_addr, SS_USER_BUSY)) + { + --timeout_count; + + if (timeout_count == 0) + { + return SS_USER_BUSY_TIMEOUT; + } + } + + /* Form the SS command: bit 0to6 is the opcode, bit 7to15 is the Mailbox offset + For some services this field has another meaning + (e.g. for IAP bitstream auth. it means spi_idx) */ + ss_command = ((mb_offset << 7u) | (cmd_opcode & 0x7Fu)); + + /* Load the command register with the SS request command code*/ + HAL_set_32bit_reg(g_css_pf_base_addr, SS_CMD, ss_command); + + if (cmd_data_size > 0u) + { + HAL_ASSERT(!(NULL_BUFFER == cmd_data)); + HAL_ASSERT(!(cmd_data_size % 4u)); + + /* Load the MBX_WCNT register with number of words */ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_WCNT, (cmd_data_size/4u)); + + /* Load the MBX_WADDR register with offset of input data (write to Mailbox) + For all the services this offset remains either 0 or Not applicable + for the services in which no Mailbox write is required.*/ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_WADDR, (0x00u + mb_offset)); + + } + + if (response_size > 0u) + { + HAL_ASSERT(!(NULL_BUFFER == p_response)); + HAL_ASSERT(!(response_size % 4u)); + + /* + Load the MBX_RWCNT register with number of words to be read from Mailbox + */ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_RCNT, (response_size/4u)); + + /* + Load the MBX_RADRDESC register with offset address within the mailbox + format for that particular service. + It will be 0 for the services where there is no output data from G5CONTROL + is expected. + This function assumes that this value is pre-calculated by service specific + functions as this value is fixed for each service. + */ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_RADDR, (response_offset + mb_offset)); + } + + /*Set the request bit in SYS_SERV_REQ register to start the service*/ + HAL_set_32bit_reg_field(g_css_pf_base_addr, SS_REQ_REQ, 0x01u); + + if (cmd_data_size > 0u) + { + word_buf = (uint32_t*)cmd_data; + + /* Write the user data into mail box. */ + for (idx = 0u; idx < (cmd_data_size/4u); idx++) + { + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_WDATA, word_buf[idx]); + } + } + + timeout_count = SS_TIMEOUT_COUNT; + if (response_size > 0u) + { + word_buf = (uint32_t*)p_response; + + for (idx = 0u; idx < (response_size/4u); idx++) + { + while (0u == HAL_get_32bit_reg_field(g_css_pf_base_addr, + SS_USER_RDVLD)) + { + --timeout_count; + + if (timeout_count == 0) + { + return SS_USER_RDVLD_TIMEOUT; + } + } + word_buf[idx] = HAL_get_32bit_reg(g_css_pf_base_addr, MBX_RDATA); + } + } + + timeout_count = SS_TIMEOUT_COUNT; + /* make sure that service is complete i.e. SS_USER_BUSY is gone 0 */ + while (1u == HAL_get_32bit_reg_field(g_css_pf_base_addr, SS_USER_BUSY)) + { + --timeout_count; + + if (timeout_count == 0) + { + return SS_USER_RDVLD_TIMEOUT; + } + } + + /* Read the status returned by System Controller */ + status = HAL_get_32bit_reg(g_css_pf_base_addr, SS_STAT); + + return (uint8_t)status; +} + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h new file mode 100644 index 0000000..8e0ebb6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h @@ -0,0 +1,1249 @@ +/******************************************************************************* + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the + * CoreSysServices_PF bare metal driver. + */ +/*=========================================================================*//** + @mainpage CoreSysServices_PF Bare Metal Driver. + + @section intro_sec Introduction + The PolarFire System Services (PF_SYSTEM_SERVICES) SgCore enables executing + the system services on the PolarFire and PolarFire SoC device. The system services + are the system controller actions initiated by the System Controller's System + Service Interface (SSI). The PolarFire System Services "SgCore" provides a + method to initiate these system services. The PF_SYSTEM_SERVICES interacts + with the system controller on SSI and Mailbox interface to initiate system + services, exchange data required for that services, and to know the successful + completion or error status. + + The PF_SYSTEM_SERVICES provides an APB interface for controlling the registers + functions for controlling the PF_SYSTEM_SERVICES as part of a bare metal system + register implemented within it. This software driver provides a set of where no + part of an operating system but the implementation of the adaptation layer + operating system is available. This driver is adapted for use in + between this driver and the operating system's driver model is outside the + scope of this driver. + + ## Features + The CoreSysServices_PF driver provides the following features: + - Executing device and design information services + - Executing design services + - Executing data security services + - Executing Fabric services + + The CoreSysServices_PF driver is provided as C source code. + + @section Driver Configuration + The application software should configure the CoreSysServices_PF driver through + calling the SYS_init() function. Only one instance of PF_SYSTEM_SERVICES SgCore is + supported. No additional configuration files are required to use the driver. + If using this driver on RT PolarFire device FPGA, define RT_DEVICE_FAMILY + macro in application. + + @section theory_op Theory of Operation + The CoreSysServices_PF driver provides access to the PolarFire system services. + These system services are grouped into the following categories: + + Device and Design Information Service + - Serial Number Service + - USERCODE Service + - Design Info Service + - Device Certificate Services + - Read Digests + - Query Security + - Read Debug Info + - Read eNVM param + + Design Services + - Bitstream authentication service + - IAP bitstream authentication service + + Data Security Services + - Digital Signature Service + - Secure NVM (SNVM) Functions + - PUF Emulation Service + - Nonce Service + + Fabric Services + - Digest Check Service + - In Application programming(IAP)/Auto-Update service + + Initialization and Configuration + + The CoreSysServices_PF driver is initialized by calling the SYS_init() + function. The SYS_init() function must be called before calling any other + CoreSysServices_PF driver functions. + + Device and Design Information Services + + The CoreSysServices_PF driver is used to read information about the device + and the design using the following functions: + - SYS_get_serial_number() + - SYS_get_user_code() + - SYS_get_design_info() + - SYS_get_device_certificate() + - SYS_read_digest() + - SYS_query_security() + - SYS_read_debug_info() + + Design Authentication Services + + The CoreSysServices_PF driver is used to execute design services using the + following functions: + - SYS_bitstream_authenticate_service() + - SYS_IAP_image_authenticate_service() + + Data Security Services + + The CoreSysServices_PF driver is used to execute data security services + using the following functions: + - SYS_digital_signature_service() + - SYS_secure_nvm_write() + - SYS_secure_nvm_read() + - SYS_puf_emulation_service () + - SYS_nonce_service () + + Executing Fabric Services + + The CoreSysServices_PF driver is used to execute fabric services using the + following functions: + - SYS_digest_check_service() + - SYS_iap_service() + + All the service execution functions return the 8-bit status, which is returned + by the system controller on executing the given service. A '0' value indicates + successful execution of that service. A non-zero value indicates error. + The error codes for each service are different. See individual function + description to know the exact meanings of the error codes for each service. + + The function descriptions in this file mainly focus on the details required + by the user to use the APIs provided by this driver to execute the services. + To know the complete details of the system services, see the + PolarFire FPGA and PolarFire SoC FPGA System Services [document](https://onlinedocs.microchip.com/pr/GUID-1409CF11-8EF9-4C24-A94E-70979A688632-en-US-3/index.html) + + *//*=========================================================================*/ +#ifndef __CORE_SYSSERV_PF_H +#define __CORE_SYSSERV_PF_H 1 + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#include "hal_assert.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** +* # Service Execution Success and Error Status Codes +* +* The following status codes are the return values from the system service functions. +* For any service, a return value '0' indicates that the service was executed +* successfully. A non-zero return value indicates that the service was not +* executed successfully. For all the services, the return value represents the +* status code returned by the system controller for the respective service, +* except the values SYS_PARAM_ERR, SS_USER_BUSY_TIMEOUT, and SS_USER_RDVLD_TIMEOUT. +* These three values indicate the error conditions detected by this driver and +* they do not overlap with the status code returned by the system controller for +* any of the system service. +* +* SYS_SUCCESS +* System service executed successfully +* +* SYS_PARAM_ERR +* System service cannot be executed as one or more parameters are not as +* expected by this driver. No read/write access is performed with the +* IP. +* +* SS_USER_BUSY_TIMEOUT +* The System service request is initiated and the driver timed-out while +* waiting for the system service to complete. The System Service +* completion is indicated by de-assertion of the SS_USER_BUSY bit by the +* IP. +* +* SS_USER_RDVLD_TIMEOUT +* The System service request is initiated and the driver timed-out while +* waiting for SS_USER_RDVLD bit, which indicates availability of data to +* be read from the mailbox, to become active. +*/ +#define SYS_SUCCESS 0u +#define SYS_PARAM_ERR 0xFFu +#define SS_USER_BUSY_TIMEOUT 0xFAu +#define SS_USER_RDVLD_TIMEOUT 0xFBu + +/** +* # System Service Timeout Count +* +* The SS_TIMEOUT_COUNT value is used by the driver as a timeout count +* while waiting for either the SS_USER_BUSY or SS_USER_RDVLD. This empirical +* value is sufficiently large so that the operations are falsely +* timeout in the normal circumstance. It is provided as a way to provide +* more debug information to the application in case there are some +* unforeseen issues. You may change this value for your need based on your +* system design. +*/ +#define SS_TIMEOUT_COUNT 40000u +/* + * SYS_DCF_DEVICE_MISMATCH + * Public key or FSN do not match device + * + * + * SYS_DCF_INVALID_SIGNATURE + * Certificate signature is invalid + * + * SYS_DCF_SYSTEM_ERROR + * PUF or storage failure + */ +#define SYS_DCF_DEVICE_MISMATCH 1u +#define SYS_DCF_INVALID_SIGNATURE 2u +#define SYS_DCF_SYSTEM_ERROR 3u + +/* + * SYS_NONCE_PUK_FETCH_ERROR + * Error fetching PUK + * + * SYS_NONCE_SEED_GEN_ERROR + * Error generating seed + */ +#define SYS_NONCE_PUK_FETCH_ERROR 1u +#define SYS_NONCE_SEED_GEN_ERROR 2u + +/** + * # Secure Nvm Write Error Codes + * + * SNVM_WRITE_INVALID_SNVMADDR + * Illegal page address + * + * SNVM_WRITE_FAILURE + * PNVM program/verify failed + * + * SNVM_WRITE_SYSTEM_ERROR + * PUF or storage failure + * + * SNVM_WRITE_NOT_PERMITTED + * Write is not permitted + */ +#define SNVM_WRITE_INVALID_SNVMADDR 1u +#define SNVM_WRITE_FAILURE 2u +#define SNVM_WRITE_SYSTEM_ERROR 3u +#define SNVM_WRITE_NOT_PERMITTED 4u + +/** + * # Secure Nvm Read Error Codes + * + * SNVM_READ_INVALID_SNVMADDR + * Illegal page address + * + * SNVM_READ_AUTHENTICATION_FAILURE + * Storage corrupt or incorrect USK + * + * SNVM_READ_SYSTEM_ERROR + * PUF or storage failure + * + */ +#define SNVM_READ_INVALID_SNVMADDR 1u +#define SNVM_READ_AUTHENTICATION_FAILURE 2u +#define SNVM_READ_SYSTEM_ERROR 3u + +/** + * # Digital Signature Service Error Codes + * + * DIGITAL_SIGNATURE_FEK_FAILURE_ERROR + * Error retrieving FEK + * + * DIGITAL_SIGNATURE_DRBG_ERROR + * Failed to generate nonce + * + * DIGITAL_SIGNATURE_ECDSA_ERROR + * ECDSA failed + */ +#define DIGITAL_SIGNATURE_FEK_FAILURE_ERROR 1u +#define DIGITAL_SIGNATURE_DRBG_ERROR 2u +#define DIGITAL_SIGNATURE_ECDSA_ERROR 3u + +/** + * # Digest Check Error Codes + * + * NOTE: When these error occur, the DIGEST tamper flag is triggered. + * + * DIGEST_CHECK_FABRICERR + * Fabric digest check error + * + * DIGEST_CHECK_CCERR + * UFS Fabric Configuration (CC) segment digest check error + * + * DIGEST_CHECK_SNVMERR + * ROM digest in SNVM segment digest check error + * + * DIGEST_CHECK_ULERR + * UFS UL segment digest check error + * + * DIGEST_CHECK_UK0ERR + * UKDIGEST0 in User Key segment digest check error + * + * DIGEST_CHECK_UK1ERR + * UKDIGEST1 in User Key segment digest check error + * + * DIGEST_CHECK_UK2ERR + * UKDIGEST2 in User Key segment (UPK1) digest check error + * + * DIGEST_CHECK_UK3ERR + * UKDIGEST3 in User Key segment (UK1) digest check error + * + * DIGEST_CHECK_UK4ERR + * UKDIGEST4 in User Key segment (DPK) digest check error + * + * DIGEST_CHECK_UK5ERR + * UKDIGEST5 in User Key segment (UPK2) digest check error + * + * DIGEST_CHECK_UK6ERR + * UKDIGEST6 in User Key segment (UK2) digest check error + * + * DIGEST_CHECK_UPERR + * UFS Permanent Lock (UPERM) segment digest check error + * + * DIGEST_CHECK_SYSERR + * M3 ROM, Factory and Factory Key Segments digest check error + * + */ +#define DIGEST_CHECK_FABRICERR 0x00u +#define DIGEST_CHECK_CCERR 0x01u +#define DIGEST_CHECK_SNVMERR 0x02u +#define DIGEST_CHECK_ULERR 0x03u +#define DIGEST_CHECK_UK0ERR 0x04u +#define DIGEST_CHECK_UK1ERR 0x05u +#define DIGEST_CHECK_UK2ERR 0x06u +#define DIGEST_CHECK_UK3ERR 0x07u +#define DIGEST_CHECK_UK4ERR 0x08u +#define DIGEST_CHECK_UK5ERR 0x09u +#define DIGEST_CHECK_UK6ERR 0x10u +#define DIGEST_CHECK_UPERR 0x11u +#define DIGEST_CHECK_SYSERR 0x12u + +/** + * # Bitstream Authentication and Iap Bitstream Authentication Return Status + * + * BSTREAM_AUTH_CHAINING_MISMATCH_ERR + * Validator or hash chaining mismatch. Incorrectly constructed bitstream or + * wrong key used. + * + * BSTREAM_AUTH_UNEXPECTED_DATA_ERR + * Unexpected data received. + * Additional data received after end of EOB component. + * + * BSTREAM_AUTH_INVALID_ENCRY_KEY_ERR + * Invalid/corrupt encryption key. + * The requested key mode is disabled or the key could not be read/reconstructed. + * + * BSTREAM_AUTH_INVALID_HEADER_ERR + * Invalid component header + * + * BSTREAM_AUTH_BACK_LEVEL_NOT_SATISFIED_ERR + * Back level not satisfied + * + * BSTREAM_AUTH_ILLEGAL_BITSTREAM_MODE_ERR + * Illegal bitstream mode. + * Requested bitstream mode is disabled by user security. + * + * BSTREAM_AUTH_DNS_BINDING_MISMATCH_ERR + * DSN binding mismatch + * + * BSTREAM_AUTH_ILLEGAL_COMPONENT_SEQUENCE_ERR + * Illegal component sequence + * + * BSTREAM_AUTH_INSUFF_DEVICE_CAPAB_ERR + * Insufficient device capabilities + * + * BSTREAM_AUTH_INCORRECT_DEVICEID_ERR + * Incorrect DEVICEID + * + * BSTREAM_AUTH_PROTOCOL_VERSION_ERR + * Unsupported bitstream protocol version (regeneration required) + * + * BSTREAM_AUTH_VERIFY_ERR + * Verify not permitted on this bitstream + * + * BSTREAM_AUTH_INVALID_DEV_CERT_ERR + * Invalid Device Certificate. + * Device SCAC is invalid or not present. + * + * BSTREAM_AUTH_INVALID_DIB_ERR + * Invalid DIB + * + * BSTREAM_AUTH_SPI_NOT_MASTER_ERR + * Device not in SPI Master Mode. + * Error may occur only when bitstream is executed through IAP mode. + * + * BSTREAM_AUTH_AUTOIAP_NO_VALID_IMAGE_ERR + * No valid images found. + * Error may occur when bitstream is executed through Auto Update mode. + * Occurs when no valid image pointers are found. + * + * BSTREAM_AUTH_INDEXIAP_NO_VALID_IMAGE_ERR + * No valid images found. + * Error may occur when bitstream is executed through IAP mode via Index Mode. + * Occurs when No valid image pointers are found. + * + * BSTREAM_AUTH_NEWER_DESIGN_VERSION_ERR + * Programmed design version is newer than AutoUpdate image found. + * Error may occur when bitstream is executed through Auto Update mode. + * + * BSTREAM_AUTH_INVALID_IMAGE_ERR + * Selected image was invalid and no recovery was performed due to valid design + * in device. + * Error may occur only when bitstream is executed through Auto Update or IAP mode + * (This error is here for completeness but only can be observed by running the + * READ_DEBUG_INFO instruction and looking at IAP Error code field). + * + * BSTREAM_AUTH_IMAGE_PROGRAM_FAILED_ERR + * Selected and Recovery image failed to program. + * Error may occur only when bitstream is executed through Auto Update or + * IAP mode + * (This error is here for completeness but only can be observed by running the + * READ_DEBUG_INFO instruction and looking at IAP Error code field). + * + * BSTREAM_AUTH_ABORT_ERR + * Abort. + * Non-bitstream instruction executed during bitstream loading. + * + * BSTREAM_AUTH_NVMVERIFY_ERR + * Fabric/UFS verification failed (min or weak limit) + * + * BSTREAM_AUTH_PROTECTED_ERR + * Device security prevented modification of non-volatile memory + * + * BSTREAM_AUTH_NOTENA + * Programming mode not enabled + * + * BSTREAM_AUTH_PNVMVERIFY + * pNVM verify operation failed + * + * BSTREAM_AUTH_SYSTEM + * System hardware error (PUF or DRBG) + * + * BSTREAM_AUTH_BADCOMPONENT + * An internal error was detected in a component payload + * + * BSTREAM_AUTH_HVPROGERR + * HV programming subsystem failure (pump failure) + * + * BSTREAM_AUTH_HVSTATE + * HV programming subsystem in unexpected state (internal error) + * + */ +#define BSTREAM_AUTH_CHAINING_MISMATCH_ERR 1 +#define BSTREAM_AUTH_UNEXPECTED_DATA_ERR 2 +#define BSTREAM_AUTH_INVALID_ENCRY_KEY_ERR 3 +#define BSTREAM_AUTH_INVALID_HEADER_ERR 4 +#define BSTREAM_AUTH_BACK_LEVEL_NOT_SATISFIED_ERR 5 +#define BSTREAM_AUTH_ILLEGAL_BITSTREAM_MODE_ERR 6 +#define BSTREAM_AUTH_DNS_BINDING_MISMATCH_ERR 7 +#define BSTREAM_AUTH_ILLEGAL_COMPONENT_SEQUENCE_ERR 8 +#define BSTREAM_AUTH_INSUFF_DEVICE_CAPAB_ERR 9 +#define BSTREAM_AUTH_INCORRECT_DEVICEID_ERR 10 +#define BSTREAM_AUTH_PROTOCOL_VERSION_ERR 11 +#define BSTREAM_AUTH_VERIFY_ERR 12 +#define BSTREAM_AUTH_INVALID_DEV_CERT_ERR 13 +#define BSTREAM_AUTH_INVALID_DIB_ERR 14 +#define BSTREAM_AUTH_SPI_NOT_MASTER_ERR 21 +#define BSTREAM_AUTH_AUTOIAP_NO_VALID_IMAGE_ERR 22 +#define BSTREAM_AUTH_INDEXIAP_NO_VALID_IMAGE_ERR 23 +#define BSTREAM_AUTH_NEWER_DESIGN_VERSION_ERR 24 +/* 25 Reserved */ +#define BSTREAM_AUTH_INVALID_IMAGE_ERR 26 +#define BSTREAM_AUTH_IMAGE_PROGRAM_FAILED_ERR 27 +#define BSTREAM_AUTH_ABORT_ERR 127 +#define BSTREAM_AUTH_NVMVERIFY_ERR 128 +#define BSTREAM_AUTH_PROTECTED_ERR 129 +#define BSTREAM_AUTH_NOTENA 130 +#define BSTREAM_AUTH_PNVMVERIFY 131 +#define BSTREAM_AUTH_SYSTEM 132 +#define BSTREAM_AUTH_BADCOMPONENT 133 +#define BSTREAM_AUTH_HVPROGERR 134 +#define BSTREAM_AUTH_HVSTATE 135 + +/***************************************************************************//** + * # Mailbox ECC Status + * Provides ECC status when the mailbox is read. The values are as follows: + * 00: No ECC errors detected, data is correct. + * 01: Exactly one bit error occurred and has been corrected. + * 10: Exactly two bits error occurred and no correction performed. + * 11: Reserved. + */ +#define SYS_MBOX_ECC_NO_ERROR_MASK 0x00u +#define SYS_MBOX_ONEBIT_ERROR_CORRECTED_MASK 0x40u +#define SYS_MBOX_TWOBIT_ERROR_MASK 0xC0u + +/***************************************************************************//** + * Service request command opcodes: +*/ +#define SERIAL_NUMBER_REQUEST_CMD 0x00u +#define USERCODE_REQUEST_CMD 0x01u +#define DESIGN_INFO_REQUEST_CMD 0x02u +#define DEVICE_CERTIFICATE_REQUEST_CMD 0x03u +#define READ_DIGEST_REQUEST_CMD 0x04u +#define QUERY_SECURITY_REQUEST_CMD 0x05u +#define READ_DEBUG_INFO_REQUEST_CMD 0x06u +#define READ_ENVM_PARAM_REQUEST_CMD 0x07u +#define SNVM_NON_AUTHEN_TEXT_REQUEST_CMD 0x10u +#define SNVM_AUTHEN_TEXT_REQUEST_CMD 0x11u +#define SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD 0x12u +#define SNVM_READ_REQUEST_CMD 0x18u +#define DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD 0x19u +#define PUF_EMULATION_SERVICE_REQUEST_CMD 0x20u +#define NONCE_SERVICE_REQUEST_CMD 0x21u +#define DIGITAL_SIGNATURE_DER_FORMAT_REQUEST_CMD 0x1Au + +#define BITSTREAM_AUTHENTICATE_CMD 0x23u +#define IAP_BITSTREAM_AUTHENTICATE_CMD 0x22u + +#define DIGEST_CHECK_CMD 0x47u + +#define IAP_PROGRAM_BY_SPIIDX_CMD 0x42u +#define IAP_VERIFY_BY_SPIIDX_CMD 0x44u +#define IAP_PROGRAM_BY_SPIADDR_CMD 0x43u +#define IAP_VERIFY_BY_SPIADDR_CMD 0x45u +#define IAP_AUTOUPDATE_CMD 0x46u + +/***************************************************************************//** + * Service request Mailbox return data length + */ +#define SERIAL_NUMBER_RESP_LEN 16u +#define USERCODE_RESP_LEN 4u +#define DESIGN_INFO_RESP_LEN 36u +#define DEVICE_CERTIFICATE_RESP_LEN 1024u +#define READ_DIGEST_RESP_LEN 416u +#define QUERY_SECURITY_RESP_LEN 9u +#define READ_DEBUG_INFO_RESP_LEN 76u +#define READ_ENVM_PARAM_RESP_LEN 256u +#define NONCE_SERVICE_RESP_LEN 32u + +#define PUF_EMULATION_SERVICE_CMD_LEN 20u +#define PUF_EMULATION_SERVICE_RESP_LEN 32u + +#define DIGITAL_SIGNATURE_HASH_LEN 48u +#define DIGITAL_SIGNATURE_RAW_FORMAT_RESP_SIZE 96u +#define DIGITAL_SIGNATURE_DER_FORMAT_RESP_SIZE 104u + +#define USER_SECRET_KEY_LEN 12u + +/* Same driver can be used on PolarFire SoC platform and the response length + * is different for PolarFire SoC. Constants defined below are used only when the + * PF System services driver is used with PolarFire SoC Platform. + */ +#define READ_DIGEST_MPFS_RESP_LEN 576u +#define QUERY_SECURITY_MPFS_RESP_LEN 33u + +/* SNVM Input data length from sNVM write. */ +#ifndef RT_DEVICE_FAMILY +/* SNVMADDR + RESERVED + PT + USK */ +#define NON_AUTHENTICATED_TEXT_DATA_LEN 256u + +/* SNVMADDR + RESERVED + PT */ +#define AUTHENTICATED_TEXT_DATA_LEN 252u +#else +/* SNVMADDR + RESERVED + PT + USK */ +#define NON_AUTHENTICATED_TEXT_DATA_LEN 224u + +/* SNVMADDR + RESERVED + PT */ +#define AUTHENTICATED_TEXT_DATA_LEN 220u +#endif + +/** + * # Digest Check Input Options + * + * DIGEST_CHECK_FABRIC + * Carry out digest check on Fabric + * + * DIGEST_CHECK_CC + * Carry out digest check on UFS Fabric Configuration (CC) segment + * + * DIGEST_CHECK_SNVM + * Carry out digest check on ROM digest in SNVM segment + * + * DIGEST_CHECK_UL + * Carry out digest check on UFS UL segment + * + * DIGEST_CHECK_UKDIGEST0 + * Carry out digest check on UKDIGEST0 in User Key segment + * + * DIGEST_CHECK_UKDIGEST1 + * Carry out digest check on UKDIGEST1 in User Key segment + * + * DIGEST_CHECK_UKDIGEST2 + * Carry out digest check on UKDIGEST2 in User Key segment (UPK1) + * + * DIGEST_CHECK_UKDIGEST3 + * Carry out digest check on UKDIGEST3 in User Key segment (UK1) + * + * DIGEST_CHECK_UKDIGEST4 + * Carry out digest check on UKDIGEST4 in User Key segment (DPK) + * + * DIGEST_CHECK_UKDIGEST5 + * Carry out digest check on UKDIGEST5 in User Key segment (UPK2) + * + * DIGEST_CHECK_UKDIGEST6 + * Carry out digest check on UKDIGEST6 in User Key segment (UK2) + * + * DIGEST_CHECK_UPERM + * Carry out digest check on UFS Permanent lock (UPERM) segment + * + * DIGEST_CHECK_SYS + * Carry out digest check on Factory and Factory Key Segments + * + */ +#define DIGEST_CHECK_FABRIC (0x01<<0x00u) /*Fabric digest*/ +#define DIGEST_CHECK_CC (0x01<<0x01u) /*UFS Fabric Configuration (CC) segment*/ +#define DIGEST_CHECK_SNVM (0x01<<0x02u) /*ROM digest in SNVM segment*/ +#define DIGEST_CHECK_UL (0x01<<0x03u) /*UFS UL segment*/ +#define DIGEST_CHECK_UKDIGEST0 (0x01<<0x04u) /*UKDIGEST0 in User Key segment*/ +#define DIGEST_CHECK_UKDIGEST1 (0x01<<0x05u) /*UKDIGEST1 in User Key segment*/ +#define DIGEST_CHECK_UKDIGEST2 (0x01<<0x06u) /*UKDIGEST2 in User Key segment (UPK1)*/ +#define DIGEST_CHECK_UKDIGEST3 (0x01<<0x07u) /*UKDIGEST3 in User Key segment (UK1)*/ +#define DIGEST_CHECK_UKDIGEST4 (0x01<<0x08u) /*UKDIGEST4 in User Key segment (DPK)*/ +#define DIGEST_CHECK_UKDIGEST5 (0x01<<0x09u) /*UKDIGEST5 in User Key segment (UPK2)*/ +#define DIGEST_CHECK_UKDIGEST6 (0x01<<0x0au) /*UKDIGEST6 in User Key segment (UK2)*/ +#define DIGEST_CHECK_UPERM (0x01<<0x0bu) /*UFS Permanent lock (UPERM) segment*/ +#define DIGEST_CHECK_SYS (0x01<<0x0cu) /*Factory and Factory Key Segments.*/ + +/***************************************************************************//** + * The function SYS_init() is used to initialize the internal data structures of + * this driver. Currently this function is empty. + * + * @param base_addr The base_addr parameter specifies the base address of the + * PF_System_services core. + * + * @return This function does not return a value. + */ +void +SYS_init +( + uint32_t base_addr +); + +/***************************************************************************//** + * The function SYS_get_serial_number() is used to execute "serial number" system + * service. + * + * @param p_serial_number The p_serial_number parameter is a pointer to a buffer + * in which the data returned by system controller + * is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t +SYS_get_serial_number +( + const uint8_t * p_serial_number, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_get_user_code() is used to execute "USERCODE" system + * service. + * @param p_user_code The p_user_code parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t +SYS_get_user_code +( + const uint8_t * p_user_code, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_get_design_info() is used to execute "Get Design Info" system + * service. + * + * @param p_design_info The p_design_info parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. Total size of debug information is 36 bytes. + * The data from the system controller includes the 256-bit + * user-defined design ID, 16-bit design version, and 16-bit + * design back level. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t +SYS_get_design_info +( + const uint8_t * p_design_info, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_get_device_certificate() is used to execute "Get Device + * Certificate" system service. + * + * @param p_device_certificate The p_device_certificate parameter is a pointer + * to a buffer in which the data returned by the + * system controller is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code means that + * the service was executed successfully. + * + */ +uint8_t +SYS_get_device_certificate +( + const uint8_t * p_device_certificate, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_read_digest() is used to execute "Read Digest" system service. + * + * @param p_digest The p_digest parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t SYS_read_digest +( + const uint8_t * p_digest, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_query_security() is used to execute "Query Security" system + * service. + * + * @param p_security_locks The p_security_locks parameter is a pointer to a buffer + * in which the data returned by system controller is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code means that + * the service was executed successfully. + */ +uint8_t SYS_query_security +( + uint8_t * p_security_locks, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_read_debug_info() is used to execute "Read Debug info" system + * service. + * + * @param p_debug_info The p_debug_info parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t SYS_read_debug_info +( + const uint8_t * p_debug_info, + uint16_t mb_offset +); + +#ifdef CORESYSSERVICES_PFSOC +/***************************************************************************//** + * The function SYS_read_envm_parameter() is used to retrieve all parameters needed + * for the eNVM operation and programming. + * + * NOTE: This service is available only on PolarFire SoC Platform. + * This service is not yet supported by PF_SYSTEM_SERVICES 3.0.100. + * + * @param p_envm_param The p_envm_param parameter is a pointer to a buffer + * in which the data returned by system controller is copied. + * This buffer stores all the eNVM parameters. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_read_envm_parameter service will return zero if the + * service executed successfully, otherwise, it will return + * one indicating error. + */ +uint8_t SYS_read_envm_parameter +( + uint8_t * p_envm_param, + uint16_t mb_offset +); +#endif +/***************************************************************************//** + * The function SYS_puf_emulation_service() is used to authenticate a device. + * + * The SYS_puf_emulation_service() function accept a challenge comprising a + * 8-bit optype and 128-bit challenge and return a 256-bit response unique to + * the given challenge and the device. + * + * @param p_challenge The p_challenge parameter specifies the 128-bit challenge + * to generate the 256-bits unique response. + * + * @param op_type The op_type parameter specifies the operational parameter + * to generate the 256-bits unique response. + * + * @param p_response The p_response parameter is a pointer to a buffer where + * the data returned which is the response by system controller + * is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_puf_emulation_service function will return zero + * if the service executed successfully, otherwise, it will + * return one indicating error. + */ +uint8_t SYS_puf_emulation_service +( + const uint8_t * p_challenge, + uint8_t op_type, + uint8_t* p_response, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_digital_signature_service() function is used to generate P-384 ECDSA + * signature based on SHA384 hash value. + * + * @param p_hash The p_hash parameter is a pointer to the buffer which + * contain the 48 bytes SHA384 Hash value (input value). + * + * @param format The format parameter specifies the output format of + * generated SIGNATURE field. The different types of output + * signature formats are as follow: + * - DIGITAL_SIGNATURE_RAW_FORMAT + * - DIGITAL_SIGNATURE_DER_FORMAT + * + * @param p_response The p_response parameter is a pointer to a buffer that + * contains the generated ECDSA signature. The field may be + * 96 bytes or 104 bytes depending upon the output format. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digital_signature_service function returns + * zero if the service executed successfully, otherwise, it + * returns non-zero values indicating error. + */ +uint8_t SYS_digital_signature_service +( + const uint8_t* p_hash, + uint8_t format, + uint8_t* p_response, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_secure_nvm_write() function writes data in the sNVM region. + * Data gets stored in the following format: + * - Non-authenticated plaintext + * - Authenticated plaintext + * - Authenticated ciphertext + * + * Note: If you are executing this function with Authenticated plaintext + * or Authenticated ciphertext on a device whose sNVM was never previously + * written to, then the service may fail. For it to work, you must first write + * Authenticated data to the sNVM using Libero along with USK client and + * custom security. This flow generates the SMK. See UG0753 PolarFire FPGA + * Security User Guide for further details. + + * @param format The format parameter specifies the format used to write + * data in sNVM region. The different type of text formats + * are as follow: + * - NON_AUTHENTICATED_PLAINTEXT_FORMAT + * - AUTHENTICATED_PLAINTEXT_FORMAT + * - AUTHENTICATED_CIPHERTEXT_FORMAT + * + * @param snvm_module The snvm_module parameter specifies the the sNVM module + * in which the data need to be written. + * + * @param p_data The p_data parameter is a pointer to a buffer which + * contains the data to be stored in sNVM region. The data + * length to be written is fixed depending on the format + * parameter. If NON_AUTHENTICATED_PLAINTEXT_FORMAT is + * selected, then you can write 252 bytes in the sNVM module. + * For other two formats the data length is 236 bytes. + * + * @param p_user_key The p_user_key parameter is a pointer to a buffer which + * contain the 96-bit key USK (user secret key). This user + * secret key will enhance the security when authentication + * is used. That is, when Authenticated plaintext and + * Authenticated ciphertext format is selected. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digital_signature_service function returns + * zero if the service executed successfully, otherwise, it + * returns non-zero values indicating error. + */ +uint8_t SYS_secure_nvm_write +( + uint8_t format, + uint8_t snvm_module, + const uint8_t* p_data, + const uint8_t* p_user_key, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_secure_nvm_read() function is used to read data present in sNVM region. + * User should provide USK key, if the data was programmed using authentication. + * If the data was written in the sNVM using the authenticated plaintext or the + * authenticated ciphertext service option then this service will return the + * valid data only when authentication is successful. For more details, see + * SYS_secure_nvm_write() function. If the data was written in + * the sNVM using the authenticated plaintext or the authenticated ciphertext + * service option then this service will return the valid data only when + * authentication is successful. For more details, see SYS_secure_nvm_write() + * function and its parameter description. + * + * @param snvm_module The snvm_module parameter specifies the sNVM module + * from which the data need to be read. + * + * @param p_user_key The p_user_key parameter is a pointer to a buffer which + * contain the 96-bit key USK (user secret key). User should + * provide same secret key which is previously used for + * authentication while writing data in sNVM region. + * + * @param p_admin The p_admin parameter is a pointer to the buffer where + * the output page admin data is stored. The page admin + * data is 4 bytes long. + * + * @param p_data The p_data parameter is a pointer to a buffer which + * contains the data read from sNVM region. User should + * provide the buffer large enough to store the read data. + * + * @param data_len The data_len parameter specifies the number of bytes to be + * read from sNVM. + * The application should know whether the data written in the + * chose sNVM module was previously stored using Authentication + * or not. + * The data_len should be 236 bytes, for authenticated data. + * For not authenticated data the data_len should be 252 bytes. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digital_signature_service function returns + * zero if the service executed successfully, otherwise, it + * returns non-zero values indicating error. + */ +uint8_t SYS_secure_nvm_read +( + uint8_t snvm_module, + const uint8_t* p_user_key, + uint8_t* p_admin, + uint8_t* p_data, + uint16_t data_len, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_nonce_service() is used to issue "Nonce Service" system + * service to the system controller. + * + * @param p_nonce The p_nonce parameter is a pointer to a buffer + * in which the data returned by system controller is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code means + * that the service was executed successfully and a non-zero + * value indicates error. See the document link + * provided in the theory of operation section to know more + * about the service and service response. + */ +uint8_t SYS_nonce_service +( + const uint8_t * p_nonce, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_bitstream_authenticate_service() function is used to authenticate + * the Bitstream which is located in SPI through a system service routine. Prior + * to using the IAP service, it may be required to first validate the new + * bitstream before committing the device to reprogramming, thus avoiding the + * need to invoke recovery procedures if the bitstream is invalid. + * + * This service is applicable to bitstreams stored in SPI Flash memory only. + * + * @param spi_flash_address + * The spi_flash_address parameter specifies the address within + * SPI Flash memory where the bit-stream is stored. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_bitstream_authenticate_service function will return + * zero if the service executed successfully and the non-zero + * response from system controller indicates error. See + * the document link provided in the theory of + * operation section to know more about the service and service + * response. + */ +uint8_t SYS_bitstream_authenticate_service +( + uint32_t spi_flash_address, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_IAP_image_authenticate_service() function is used to authenticate + * the IAP image which is located in SPI through a system service routine. The + * service checks the image descriptor and the referenced bitstream and optional + * initialization data. If the image is authenticated successfully, then the + * image is guaranteed to be valid when used by an IAP function. + * + * This service is applicable to bitstreams stored in SPI Flash memory only. + * + * @param spi_idx + * The spi_idx parameter specifies the index in the SPI directory to + * be used where the IAP bit-stream is stored. + * Note: To support recovery SPI_IDX=1 should be an empty slot and the recovery + * image should be located in SPI_IDX=0. Since SPI_IDX=1 should be an + * empty slot, it shouldn’t be passed into the system service. + * + * @return The SYS_IAP_image_authenticate_service function will return + * zero if the service executed successfully the non-zero + * response from system controller indicates error. Please + * refer to the document link provided in the theory of + * operation section to know more about the service and service + * response. + */ +uint8_t SYS_IAP_image_authenticate_service +( + uint8_t spi_idx +); + +/***************************************************************************//** + * The SYS_digest_check_service() function is used to Recalculates and compares + * digests of selected non-volatile memories. If the fabric digest is to be + * checked, then the user design must follow all prerequisite steps for the + * FlashFreeze service before invoking this service. + * This service is applicable to bitstreams stored in SPI Flash memory only. + * @param options + * The options parameter specifies the digest check options which + * indicate the area on which the digest check should be performed. + * Below is the list of options. You can OR these options to indicate + * to perform digest check on multiple segments. + * Note: The options parameter is of 2 bytes when used with PF + * device and 4 bytes when used with PolarFire SoC device. + * Options[i] | Description + * ---------------|---------------------------------- + * 0x01 | Fabric digest + * 0x02 | Fabric Configuration (CC) segment + * 0x04 | ROM digest in SNVM segment + * 0x08 | UL segment + * 0x10 | UKDIGEST0 in User Key segment + * 0x20 | UKDIGEST1 in User Key segment + * 0x40 | UKDIGEST2 in User Key segment (UPK1) + * 0x80 | UKDIGEST3 in User Key segment (UK1) + * 0x100 | UKDIGEST4 in User Key segment (DPK) + * 0x200 | UKDIGEST5 in User Key segment (UPK2) + * 0x400 | UKDIGEST6 in User Key segment (UK2) + * 0x800 | UFS Permanent lock (UPERM) segment + * 0x1000 | Factory and Factory Key Segments. + * 0x2000 | UKDIGEST7 in User Key segment (HWM) (PFSoC) + * 0x4000 | ENVMDIGEST (PFSoC only) + * 0x8000 | UKDIGEST8 for MSS Boot Info (PFSoC only) + * 0x10000 | SNVM_RW_ACCESS_MAP Digest (PFSoC only) + * 0x20000 | SBIC revocation digest (PFSoC only) + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digest_check_service function will return + * zero if the service executed successfully the non-zero + * response from system controller indicates error. Pleaes + * refer to the document link provided in the theory of + * operation section to know more about the service and service + * response. + */ +uint8_t SYS_digest_check_service +( + uint32_t options, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_iap_service() function is used to IAP service. The IAP service allows + * the user to reprogram the device without the need for an external master. The + * user design writes the bitstream to be programmed into a SPI Flash connected + * to the SPI port. When the service is invoked, the System Controller + * automatically reads the bitstream from the SPI flash and programs the device. + * The service allows the image to be executed in either VERIFY or PROGRAM modes. + * Another option for IAP is to perform the auto-update sequence. In this case + * the newest image of the first two images in the SPI directory is chosen to be + * programmed. + * + * @param iap_cmd + * The iap_cmd parameter specifies the specific IAP command which + * depends upon VERIFY or PROGRAM modes and the SPI address method. + * iap_cmd | Description + * -----------------------|------------ + * IAP_PROGRAM_BY_SPIIDX_CMD | IAP program. + * IAP_VERIFY_BY_SPIIDX_CMD | Fabric Configuration (CC) segment + * IAP_PROGRAM_BY_SPIADDR_CMD | ROM digest in SNVM segment + * IAP_VERIFY_BY_SPIADDR_CMD | UL segment + * IAP_AUTOUPDATE_CMD | UKDIGEST0 in User Key segment + * + * @param spiaddr + * The spiaddr parameter specifies either the index + * in the SPI directory or the SPI address in the SPI Flash memory. + * Below is the list of the possible meaning of spiaddr parameter + * in accordance with the iap_cmd parameter. + * iap_cmd | spiaddr + * ----------------------|----------------- + * IAP_PROGRAM_BY_SPIIDX_CMD | Index in the SPI directory. + * IAP_VERIFY_BY_SPIIDX_CMD | Index in the SPI directory. + * IAP_PROGRAM_BY_SPIADDR_CMD | SPI address in the SPI Flash memory + * IAP_VERIFY_BY_SPIADDR_CMD | SPI address in the SPI Flash memory + * IAP_AUTOUPDATE_CMD | spiaddr is ignored as No index/address required for this command. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * Note: For the IAP services with command IAP_PROGRAM_BY_SPIIDX_CMD and + * IAP_VERIFY_BY_SPIIDX_CMD To support recovery SPI_IDX=1 should be an + * empty slot and the recovery image should be located in SPI_IDX=0. + * Since SPI_IDX=1 should be an empty slot it shouldn’t be passed into + * the system service. + * + * @return The SYS_iap_service function will return zero if the service + * executed successfully and the non-zero response from system + * controller indicates error. Please refer to the document + * link provided in the theory of operation section to know + * more about the service and service response. + */ +uint8_t SYS_iap_service +( + uint8_t iap_cmd, + uint32_t spiaddr, + uint16_t mb_offset +); + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_SYSSERV_PF_H */ diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h new file mode 100644 index 0000000..8b14b7e --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h @@ -0,0 +1,149 @@ +/******************************************************************************* + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Register bit offsets and masks definitions for CoreSysServices_PF driver. + */ + +#ifndef __CORE_SYSSERV_PF_REGISTERS +#define __CORE_SYSSERV_PF_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * SYS_SERV_CMD (offset 0x04) register details + */ +#define SS_CMD_REG_OFFSET 0x04u + +#define SS_CMD_OFFSET 0x04 +#define SS_CMD_MASK 0x0000FFFFu +#define SS_CMD_SHIFT 0u + +/*------------------------------------------------------------------------------ + * SYS_SERV_STAT (offset 0x08) register details + */ +#define SS_STAT_REG_OFFSET 0x08u + +#define SS_STAT_OFFSET 0x08 +#define SS_STAT_MASK 0x0000FFFFu +#define SS_STAT_SHIFT 0u + +/*------------------------------------------------------------------------------ + * SYS_SERV_REQ (offset 0x0C) register details + */ +#define SS_REQ_REG_OFFSET 0x0Cu + + +#define SS_REQ_REQ_OFFSET 0x0Cu +#define SS_REQ_REQ_MASK 0x00000001UL +#define SS_REQ_REQ_SHIFT 0u + +#define SS_REQ_ABUSY_OFFSET 0x0Cu +#define SS_REQ_ABUSY_MASK 0x00000002UL +#define SS_REQ_ABUSY_SHIFT 1u + +#define SS_REQ_NABUSY_OFFSET 0x0Cu +#define SS_REQ_NABUSY_MASK 0x00000004UL +#define SS_REQ_NABUSY_SHIFT 2u + +#define SS_REQ_SSBUSY_OFFSET 0x0Cu +#define SS_REQ_SSBUSY_MASK 0x00000008UL +#define SS_REQ_SSBUSY_SHIFT 3u + +#define SS_REQ_AREQ_OFFSET 0x0Cu +#define SS_REQ_AREQ_MASK 0x00000010UL +#define SS_REQ_AREQ_SHIFT 4u + +#define SS_REQ_NAREQ_OFFSET 0x0Cu +#define SS_REQ_NAREQ_MASK 0x00000020UL +#define SS_REQ_NAREQ_SHIFT 5u +/*------------------------------------------------------------------------------ + * MBX_ECCSTATUS (offset 0x10) register details + */ +#define MBX_ECCSTATUS_REG_OFFSET 0x10u + +#define MBX_ECCSTATUS_OFFSET 0x10 +#define MBX_ECCSTATUS_MASK 0x03u +#define MBX_ECCSTATUS_SHIFT 0u + + +/*------------------------------------------------------------------------------ + * MBX_WCNT (offset 0x14) register details + */ +#define MBX_WCNT_REG_OFFSET 0x14u + +#define MBX_WCNT_OFFSET 0x14 +#define MBX_WCNT_MASK 0x000001FFu +#define MBX_WCNT_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_RWCNT (offset 0x18) register details + */ +#define MBX_RCNT_REG_OFFSET 0x18u + +#define MBX_RCNT_OFFSET 0x18 +#define MBX_RCNT_MASK 0x000001FFu +#define MBX_RCNT_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_WADRDESC (offset 0x1C) register details + */ +#define MBX_WADDR_REG_OFFSET 0x1Cu + +#define MBX_WADDR_OFFSET 0x1C +#define MBX_WADDR_MASK 0x000001FFu +#define MBX_WADDR_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_RADRDESC (offset 0x20) register details + */ +#define MBX_RADDR_REG_OFFSET 0x20u + +#define MBX_RADDR_OFFSET 0x20 +#define MBX_RADDR_MASK 0x000001FFu +#define MBX_RADDR_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_WDATA (offset 0x28) register details + */ +#define MBX_WDATA_REG_OFFSET 0x28u + +#define MBX_WDATA_OFFSET 0x28 +#define MBX_WDATA_MASK 0xFFFFFFFFu +#define MBX_WDATA_SHIFT 0u + + +/*------------------------------------------------------------------------------ + * MBX_RDATA (offset 0x2C) register details + */ +#define MBX_RDATA_REG_OFFSET 0x2Cu + +#define MBX_RDATA_OFFSET 0x2C +#define MBX_RDATA_MASK 0xFFFFFFFFu +#define MBX_RDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * SS_USER (offset 0x30) register details + */ +#define SS_USER_REG_OFFSET 0x30u + +#define SS_USER_BUSY_OFFSET 0x30 +#define SS_USER_BUSY_MASK 0x00000001u +#define SS_USER_BUSY_SHIFT 0u + +#define SS_USER_RDVLD_OFFSET 0x30 +#define SS_USER_RDVLD_MASK 0x00000002u +#define SS_USER_RDVLD_SHIFT 1u + +#define SS_USER_CMDERR_OFFSET 0x30 +#define SS_USER_CMDERR_MASK 0x00000004u +#define SS_USER_CMDERR_SHIFT 2u + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_SYSSERV_PF_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c new file mode 100644 index 0000000..0c0a866 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c @@ -0,0 +1,297 @@ +/******************************************************************************* + * (c) Copyright 2007-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file core_uart_apb.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreUARTapb driver implementation. See file "core_uart_apb.h" for + * description of the functions implemented in this file. + * + */ + +#include "coreuartapb_regs.h" +#include "core_uart_apb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define NULL_INSTANCE ( ( UART_instance_t* ) 0 ) +#define NULL_BUFFER ( ( uint8_t* ) 0 ) + +#define MAX_LINE_CONFIG ( ( uint8_t )( DATA_8_BITS | ODD_PARITY ) ) +#define MAX_BAUD_VALUE ( ( uint16_t )( 0x1FFF ) ) +#define STATUS_ERROR_MASK ( ( uint8_t )( STATUS_PARITYERR_MASK | \ + STATUS_OVERFLOW_MASK | \ + STATUS_FRAMERR_MASK ) ) +#define BAUDVALUE_LSB ( (uint16_t) (0x00FF) ) +#define BAUDVALUE_MSB ( (uint16_t) (0xFF00) ) +#define BAUDVALUE_SHIFT ( (uint8_t) (5) ) + +#define STATUS_ERROR_OFFSET STATUS_PARITYERR_SHIFT + +/***************************************************************************//** + * UART_init() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_init +( + UART_instance_t * this_uart, + addr_t base_addr, + uint16_t baud_value, + uint8_t line_config +) +{ + uint8_t rx_full; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( line_config <= MAX_LINE_CONFIG ) + HAL_ASSERT( baud_value <= MAX_BAUD_VALUE ) + + if( ( this_uart != NULL_INSTANCE ) && + ( line_config <= MAX_LINE_CONFIG ) && + ( baud_value <= MAX_BAUD_VALUE ) ) + { + /* + * Store lower 8-bits of baud value in CTRL1. + */ + HAL_set_8bit_reg( base_addr, CTRL1, (uint_fast8_t)(baud_value & + BAUDVALUE_LSB ) ); + + /* + * Extract higher 5-bits of baud value and store in higher 5-bits + * of CTRL2, along with line configuration in lower 3 three bits. + */ + HAL_set_8bit_reg( base_addr, CTRL2, (uint_fast8_t)line_config | + (uint_fast8_t)((baud_value & + BAUDVALUE_MSB) >> BAUDVALUE_SHIFT ) ); + + this_uart->base_address = base_addr; +#ifndef NDEBUG + { + uint8_t config; + uint8_t temp; + uint16_t baud_val; + baud_val = HAL_get_8bit_reg( this_uart->base_address, CTRL1 ); + config = HAL_get_8bit_reg( this_uart->base_address, CTRL2 ); + /* + * To resolve operator precedence between & and << + */ + temp = ( config & (uint8_t)(CTRL2_BAUDVALUE_MASK ) ); + baud_val |= (uint16_t)( (uint16_t)(temp) << BAUDVALUE_SHIFT ); + config &= (uint8_t)(~CTRL2_BAUDVALUE_MASK); + HAL_ASSERT( baud_val == baud_value ); + HAL_ASSERT( config == line_config ); + } +#endif + + /* + * Flush the receive FIFO of data that may have been received before the + * driver was initialized. + */ + rx_full = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_RXFULL_MASK; + while ( rx_full ) + { + HAL_get_8bit_reg( this_uart->base_address, RXDATA ); + rx_full = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_RXFULL_MASK; + } + + /* + * Clear status of the UART instance. + */ + this_uart->status = (uint8_t)0; + } +} + +/***************************************************************************//** + * UART_send() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_send +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +) +{ + size_t char_idx; + uint8_t tx_ready; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( tx_buffer != NULL_BUFFER ) + HAL_ASSERT( tx_size > 0 ) + + if( (this_uart != NULL_INSTANCE) && + (tx_buffer != NULL_BUFFER) && + (tx_size > (size_t)0) ) + { + for ( char_idx = (size_t)0; char_idx < tx_size; char_idx++ ) + { + /* Wait for UART to become ready to transmit. */ + do { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( !tx_ready ); + /* Send next character in the buffer. */ + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)tx_buffer[char_idx] ); + } + } +} + +/***************************************************************************//** + * UART_fill_tx_fifo() + * See "core_uart_apb.h" for details of how to use this function. + */ +size_t +UART_fill_tx_fifo +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +) +{ + uint8_t tx_ready; + size_t size_sent = 0u; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( tx_buffer != NULL_BUFFER ) + HAL_ASSERT( tx_size > 0 ) + + /* Fill the UART's Tx FIFO until the FIFO is full or the complete input + * buffer has been written. */ + if( (this_uart != NULL_INSTANCE) && + (tx_buffer != NULL_BUFFER) && + (tx_size > 0u) ) + { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + if ( tx_ready ) + { + do { + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)tx_buffer[size_sent] ); + size_sent++; + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( (tx_ready) && ( size_sent < tx_size ) ); + } + } + return size_sent; +} + +/***************************************************************************//** + * UART_get_rx() + * See "core_uart_apb.h" for details of how to use this function. + */ +size_t +UART_get_rx +( + UART_instance_t * this_uart, + uint8_t * rx_buffer, + size_t buff_size +) +{ + uint8_t new_status; + uint8_t rx_full; + size_t rx_idx = 0u; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( rx_buffer != NULL_BUFFER ) + HAL_ASSERT( buff_size > 0 ) + + if( (this_uart != NULL_INSTANCE) && + (rx_buffer != NULL_BUFFER) && + (buff_size > 0u) ) + { + rx_idx = 0u; + new_status = HAL_get_8bit_reg( this_uart->base_address, STATUS ); + this_uart->status |= new_status; + rx_full = new_status & STATUS_RXFULL_MASK; + while ( ( rx_full ) && ( rx_idx < buff_size ) ) + { + rx_buffer[rx_idx] = HAL_get_8bit_reg( this_uart->base_address, + RXDATA ); + rx_idx++; + new_status = HAL_get_8bit_reg( this_uart->base_address, STATUS ); + this_uart->status |= new_status; + rx_full = new_status & STATUS_RXFULL_MASK; + } + } + return rx_idx; +} + +/***************************************************************************//** + * UART_polled_tx_string() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_polled_tx_string +( + UART_instance_t * this_uart, + const uint8_t * p_sz_string +) +{ + uint32_t char_idx; + uint8_t tx_ready; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( p_sz_string != NULL_BUFFER ) + + if( ( this_uart != NULL_INSTANCE ) && ( p_sz_string != NULL_BUFFER ) ) + { + char_idx = 0U; + while( 0U != p_sz_string[char_idx] ) + { + /* Wait for UART to become ready to transmit. */ + do { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( !tx_ready ); + /* Send next character in the buffer. */ + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)p_sz_string[char_idx] ); + char_idx++; + } + } +} + +/***************************************************************************//** + * UART_get_rx_status() + * See "core_uart_apb.h" for details of how to use this function. + */ +uint8_t +UART_get_rx_status +( + UART_instance_t * this_uart +) +{ + uint8_t status = UART_APB_INVALID_PARAM; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + /* + * Extract UART error status and place in lower bits of "status". + * Bit 0 - Parity error status + * Bit 1 - Overflow error status + * Bit 2 - Frame error status + */ + if( this_uart != NULL_INSTANCE ) + { + status = ( ( this_uart->status & STATUS_ERROR_MASK ) >> + STATUS_ERROR_OFFSET ); + /* + * Clear the sticky status for this instance. + */ + this_uart->status = (uint8_t)0; + } + return status; +} + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h new file mode 100644 index 0000000..c016403 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h @@ -0,0 +1,451 @@ +/******************************************************************************* + * (c) Copyright 2007-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file core_uart_apb.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief This file contains the application programming interface for the + * CoreUARTapb bare metal driver. + * + */ +/*=========================================================================*//** + @mainpage CoreUARTapb Bare Metal Driver. + + @section intro_sec Introduction + CoreUARTapb is an implementation of the Universal Asynchronous + Receiver/Transmitter aimed at minimal FPGA tile usage within a Microchip FPGA. + The CoreUARTapb bare metal software driver is designed to be used in systems + with no operating system. + + The CoreUARTapb driver provides functions for basic polled transmitting and + receiving operations. It also provide functions that allow the use of the + CoreUARTapb in interrupt-driven mode but leaves the management of interrupts + to the calling application, as interrupt enabling and disabling are not + controlled through the CoreUARTapb registers. The CoreUARTapb driver is + provided as C source code. + + @section driver_configuration Driver Configuration + Your application software should configure the CoreUARTapb driver by calling + the UART_init() function for each CoreUARTapb instance in the hardware design. + The configuration parameters include the CoreUARTapb hardware instance base + address and other runtime parameters, such as baud rate, bit width, and + parity. No CoreUARTapb hardware configuration parameters are needed by the + driver, apart from the CoreUARTapb hardware instance base address. Hence, no + additional configuration files are required to use the driver. + + A CoreUARTapb hardware instance is generated with fixed baud rate, character + size, and parity configuration settings as part of the hardware flow. The + baud_value and line_config parameter values passed to the UART_init() function + have no effect if fixed values were selected for the baud rate, character + size, and parity in the hardware configuration of CoreUARTapb. When fixed + values are selected for these hardware configuration parameters, the driver is + unable to overwrite the fixed values in the CoreUARTapb control registers, + CTRL1 and CTRL2. + + @section theory_op Theory of Operation + The CoreUARTapb software driver is designed to allow the control of multiple + instances of CoreUARTapb. Each instance of CoreUARTapb in the hardware design + is associated with a single instance of the UART_instance_t structure in the + software. You need to allocate memory for one unique UART_instance_t structure + instance for each CoreUARTapb hardware instance. The contents of these data + structures are initialized while calling the UART_init() function. A pointer + to the structure is passed to the subsequent driver functions in order to + identify the CoreUARTapb hardware instance you wish to perform the requested + operation on. + + Note: Do not attempt to directly manipulate the content of UART_instance_t + structures. This structure is only intended to be modified by the driver + function. + + Once initialized, the driver transmits and receives data. Transmit is + performed using the UART_send() function. If this function blocks, then it + returns only when the data passed to it has been sent to the CoreUARTapb + hardware. Data received by the CoreUARTapb hardware is read by the user + application using the UART_get_rx() function. + + The UART_fill_tx_fifo() function is also provided as a part of the + interrupt-driven transmit. This function fills the CoreUARTapb hardware + transmit FIFO with the content of a data buffer passed as a parameter before + returning. The control of the interrupts must be implemented outside the + driver, as the CoreUARTapb hardware does not provide the ability to enable + or disable its interrupt sources. + + The UART_polled_tx_string() function is provided to transmit a NULL-terminated + string in polled mode. If this function blocks, then it returns only when the + data passed to it has been sent to the CoreUARTapb hardware. + + The UART_get_rx_status() function returns the error status of the CoreUARTapb + receiver. This is used by applications to take appropriate action in case of + receiver errors. +*//*=========================================================================*/ +#ifndef __CORE_UART_APB_H +#define __CORE_UART_APB_H 1 + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + Data Bits Length Defines + ======================== + These constants define the data length in a UART packet. + | Constant | Description | + |-------------|---------------------------------------| + | DATA_7_BITS | Data length is 7-bits | + | DATA_8_BITS | Data length is 8-bits | + */ +#define DATA_7_BITS 0x00u +#define DATA_8_BITS 0x01u + +/***************************************************************************//** + Parity Defines + ============== + These constants define parity check options. + | Constant | Description | + |-------------|---------------------------------------| + | NO_PARITY | No Parity bit | + | EVEN_PARITY | Even Parity bit | + | ODD_PARITY | ODD Parity bit | + */ +#define NO_PARITY 0x00u +#define EVEN_PARITY 0x02u +#define ODD_PARITY 0x06u + +/***************************************************************************//** + Error Status Definitions + ======================== + These constants define the different types of possible errors in UART + transmission of data. + | Constant | Description | + |-------------------------|---------------------------------------| + | UART_APB_PARITY_ERROR | Data parity error | + | UART_APB_OVERFLOW_ERROR | Data overflow error | + | UART_APB_FRAMING_ERROR | Data framing error | + | UART_APB_NO_ERROR | No error | + | UART_APB_INVALID_PARAM | Invalid parameter | + */ +#define UART_APB_PARITY_ERROR 0x01u +#define UART_APB_OVERFLOW_ERROR 0x02u +#define UART_APB_FRAMING_ERROR 0x04u +#define UART_APB_NO_ERROR 0x00u +#define UART_APB_INVALID_PARAM 0xFFu + +/***************************************************************************//** + * There should be one instance of this structure for each instance of + * CoreUARTapb in your system. This structure instance identifies various UARTs + * in a system and should be passed as first parameter to UART functions to + * identify which UART performs the requested operation. The 'status' element in + * the structure is used to provide sticky status information. + */ +typedef struct +{ + addr_t base_address; + uint8_t status; +} UART_instance_t; + +/***************************************************************************//** + * The UART_init() function initializes the UART with the configuration passed + * as parameters. The configuration parameters are the baud_value that generates + * the baud rate and the line configuration (bit length and parity). + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data regarding + * this instance of the CoreUARTapb. This pointer is used to + * identify the target CoreUARTapb hardware instance in + * subsequent calls to the CoreUARTapb functions. + * @param base_addr The base_address parameter is the base address in the + * processor's memory map for the registers of the + * CoreUARTapb instance being initialized. + * @param baud_value The baud_value parameter selects the baud rate for the + * UART. The baud value is calculated from the frequency of + * the system clock in hertz and the desired baud rate using + * the following equation: + * baud_value = (clock / (baud_rate * 16)) - 1. + * The baud_value parameter must be a value in the range 0 + * to 8191 (or 0x0000 to 0x1FFF). + * @param line_config This parameter is the line configuration, specifies the + * bit length and parity settings. This is the logical OR of: + * - DATA_7_BITS + * - DATA_8_BITS + * - NO_PARITY + * - EVEN_PARITY + * - ODD_PARITY + * For example, 8 bits even parity would be specified as + * (DATA_8_BITS | EVEN_PARITY). + * @return This function does not return a value. + * @example + * @code + * #define BAUD_VALUE_57600 25 + * + * #define COREUARTAPB0_BASE_ADDR 0xC3000000UL + * + * UART_instance_t g_uart; + * int main() + * { + * UART_init(&g_uart, COREUARTAPB0_BASE_ADDR, + BAUD_VALUE_57600, (DATA_8_BITS | EVEN_PARITY)); + * } + * @endcode + */ +void +UART_init +( + UART_instance_t * this_uart, + addr_t base_addr, + uint16_t baud_value, + uint8_t line_config +); + +/***************************************************************************//** + * The UART_send() function is used to transmit data. It transfers the content + * of the transmitter data buffer, passed as a function parameter, into the + * UART's hardware transmitter FIFO. It returns when the full content of the + * transmitter data buffer has been transferred to the UART's transmitter FIFO. + * + * Note: You should not assume that the data you are sending using this function + * has been received at the other end by the time this function returns. The + * actual transmission over the serial connection is still be taking place at + * the time of the function return. It is safe to release or reuse the memory + * used as the transmit buffer once this function returns. + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data + * regarding this instance of the CoreUARTapbUART. + * @param tx_buffer The tx_buffer parameter is a pointer to a buffer that + * contains the data to be transmitted. + * @param tx_size The tx_size parameter is the size in bytes of the + * transmitted data. + * + * @return This function does not return a value. + * + * @example + * @code + * uint8_t testmsg1[] = {"\n\r\n\r\n\rUART_send() test message 1"}; + * UART_send(&g_uart,(const uint8_t *)&testmsg1,sizeof(testmsg1)); + * @endcode + */ +void +UART_send +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +); + +/***************************************************************************//** + * The UART_fill_tx_fifo() function fills the UART's transmitter hardware FIFO + * with the data found in the transmitter buffer that is passed in as a + * function parameter. The function returns either when the FIFO is full or + * when the complete contents of the transmitter buffer have been copied into + * the FIFO. It returns the number of bytes copied into the UART's transmitter + * hardware FIFO. This function is intended to be used as part of + * interrupt-driven transmission. + * + * Note: You should not assume that the data you transmit using this function + * has been received at the other end by the time this function returns. The + * actual transmission over the serial connection is still be taking place at + * the time of the function return. + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data + * regarding this instance of the UART. + * @param tx_buffer The tx_buffer parameter is a pointer to a buffer that + * contains the data to be transmitted. + * @param tx_size The tx_size parameter is the size in bytes of the + * transmitted data. + * @return This function returns the number of bytes copied into + * the UART's transmitter hardware FIFO. + * + * @example + * @code + * void send_using_interrupt + * ( + * uint8_t * pbuff, + * size_t tx_size + * ) + * { + * size_t size_in_fifo; + * size_in_fifo = UART_fill_tx_fifo( &g_uart, pbuff, tx_size ); + * } + * @endcode + */ +size_t +UART_fill_tx_fifo +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +); + +/***************************************************************************//** + * The UART_get_rx() function reads the content of the UART's receiver hardware + * FIFO and stores it in the receiver buffer that is passed in as a function + * parameter. It copies either the full contents of the FIFO into the receiver + * buffer, or just enough data from the FIFO to fill the receiver buffer, + * depending on the size of the receiver buffer. The size of the receiver + * buffer is passed in as a function parameter. UART_get_rx() returns the number + * of bytes copied into the receiver buffer. If no data was received at the time + * the function is called, the function returns 0. + * + * Note: This function reads and accumulates the receiver status of the + * CoreUARTapb instance before reading each byte from the receiver's + * data register/FIFO. This allows the driver to maintain a sticky + * record of any receiver errors that occur as the UART receives each + * data byte; receiver errors would otherwise be lost after each read + * from the receiver's data register. A call to the UART_get_rx_status() + * function returns any receiver errors accumulated during the execution + * of the UART_get_rx() function. + * + * Note: When FIFO mode is disabled in the CoreUARTapb hardware configuration, + * the driver accumulates a sticky record of any parity errors, framing + * errors, or overflow errors. When FIFO mode is enabled, the driver + * accumulates a sticky record of overflow errors only; in this case, + * interrupts must be used to handle parity errors or framing errors. + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data + * regarding this instance of the UART. + * @param rx_buffer The rx_buffer parameter is a pointer to a buffer where + * the received data is copied. + * @param buff_size The buff_size parameter is the size of the receive + * buffer in bytes. + * @return This function returns the number of bytes copied into + * the receive buffer. + * + * @example + * @code + * #define MAX_RX_DATA_SIZE 256 + * + * uint8_t rx_data[MAX_RX_DATA_SIZE]; + * uint8_t rx_size = 0; + * + * rx_size = UART_get_rx( &g_uart, rx_data, sizeof(rx_data) ); + * @endcode + */ +size_t +UART_get_rx +( + UART_instance_t * this_uart, + uint8_t * rx_buffer, + size_t buff_size +); + +/***************************************************************************//** + * The UART_polled_tx_string() function is used to transmit a NULL ('\0') + * terminated string. Internally, it polls for the transmit ready status and + * transfers the text starting at the address pointed by p_sz_string into + * the UART's hardware transmitter FIFO. It is a blocking function and returns + * only when the complete string has been transferred to the UART's transmit + * FIFO. + * + * Note: You should not assume that the data you transmit using this function + * has been received at the other end by the time this function returns. The + * actual transmission over the serial connection is still be taking place at + * the time of the function return. + * + * @param this_uart The this_uart parameter is the pointer to a + * UART_instance_t structure, which holds all data + * regarding this instance of the UART. + * @param p_sz_string The p_sz_string parameter is a pointer to a buffer + * containing the NULL ('\0') terminated string to be + * transmitted. + * @return This function does not return a value. + * + * @example + * @code + * uint8_t testmsg1[] = {"\r\n\r\nUART_polled_tx_string() test message 1\0"}; + * UART_polled_tx_string(&g_uart,(const uint8_t *)&testmsg1); + * @endcode + */ +void +UART_polled_tx_string +( + UART_instance_t * this_uart, + const uint8_t * p_sz_string +); + +/***************************************************************************//** + * The UART_get_rx_status() function returns the receiver error status of the + * CoreUARTapb instance. It reads both the current error status of the receiver + * and the accumulated error status from preceding calls to the UART_get_rx() + * function and combines them using a bitwise OR. It returns the cumulative + * parity, framing, and overflow error status of the receiver, since the + * previous call to UART_get_rx_status() as an 8-bit encoded value. + * + * Note: The UART_get_rx() function reads and accumulates the receiver status + * of the CoreUARTapb instance before reading each byte from the receiver's data + * register/FIFO. The driver maintains a sticky record of the cumulative error + * status, which persists after the UART_get_rx() function returns. The + * UART_get_rx_status() function clears this accumulated record of receiver + * errors before returning. + * + * @param this_uart The this_uart parameter is a pointer to a + * UART_instance_t structure which holds all data regarding + * this instance of the UART. + * @return This function returns the UART receiver error status as + * an 8-bit encoded value. The return value is 0, if there + * are no receiver errors occurred. The driver provides a + * set of bit mask constants, which should be compared with + * and/or used to mask the returned value to determine the + * receiver error status. + * When the return value is compared to the following bit + * masks, a non-zero result indicates that the + * corresponding error occurred: + * UART_APB_PARITY_ERROR (bit mask = 0x01) + * UART_APB_OVERFLOW_ERROR (bit mask = 0x02) + * UART_APB_FRAMING_ERROR (bit mask = 0x04) + * When the return value is compared to the following bit + * mask, a non-zero result indicates that no error + * occurred: + * UART_APB_NO_ERROR (0x00) + * + * @example + * @code + * UART_instance_t g_uart; + * uint8_t rx_data[MAX_RX_DATA_SIZE]; + * uint8_t err_status; + * err_status = UART_get_err_status(&g_uart); + * + * if(UART_APB_NO_ERROR == err_status ) + * { + * rx_size = UART_get_rx( &g_uart, rx_data, MAX_RX_DATA_SIZE ); + * } + * @endcode + */ +uint8_t +UART_get_rx_status +( + UART_instance_t * this_uart +); + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_UART_APB_H */ diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h new file mode 100644 index 0000000..c123cc3 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h @@ -0,0 +1,133 @@ +/******************************************************************************* + * (c) Copyright 2007-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file coreuartapb_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreUARTapb register definitions + */ + +#ifndef __CORE_UART_APB_REGISTERS +#define __CORE_UART_APB_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * TxData register details + */ +#define TXDATA_REG_OFFSET 0x0u + +/* + * TxData bits. + */ +#define TXDATA_OFFSET 0x0u +#define TXDATA_MASK 0xFFu +#define TXDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * RxData register details + */ +#define RXDATA_REG_OFFSET 0x4u + +/* + * RxData bits. + */ +#define RXDATA_OFFSET 0x4u +#define RXDATA_MASK 0xFFu +#define RXDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * ControReg1 register details + */ +#define CTRL1_REG_OFFSET 0x8u + +/* + * Baud value (Lower 8-bits) + */ +#define CTRL1_BAUDVALUE_OFFSET 0x8u +#define CTRL1_BAUDVALUE_MASK 0xFFu +#define CTRL1_BAUDVALUE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * ControReg2 register details + */ +#define CTRL2_REG_OFFSET 0xCu + +/* + * Bit length + */ +#define CTRL2_BIT_LENGTH_OFFSET 0xCu +#define CTRL2_BIT_LENGTH_MASK 0x01u +#define CTRL2_BIT_LENGTH_SHIFT 0u + +/* + * Parity enable. + */ +#define CTRL2_PARITY_EN_OFFSET 0xCu +#define CTRL2_PARITY_EN_MASK 0x02u +#define CTRL2_PARITY_EN_SHIFT 1u + +/* + * Odd/even parity selection. + */ +#define CTRL2_ODD_EVEN_OFFSET 0xCu +#define CTRL2_ODD_EVEN_MASK 0x04u +#define CTRL2_ODD_EVEN_SHIFT 2u + +/* + * Baud value (Higher 5-bits) + */ +#define CTRL2_BAUDVALUE_OFFSET 0xCu +#define CTRL2_BAUDVALUE_MASK 0xF8u +#define CTRL2_BAUDVALUE_SHIFT 3u + +/*------------------------------------------------------------------------------ + * StatusReg register details + */ +#define StatusReg_REG_OFFSET 0x10u + +#define STATUS_REG_OFFSET 0x10u + +/* + * Transmit ready. + */ +#define STATUS_TXRDY_OFFSET 0x10u +#define STATUS_TXRDY_MASK 0x01u +#define STATUS_TXRDY_SHIFT 0u + +/* + * Receive full. + */ +#define STATUS_RXFULL_OFFSET 0x10u +#define STATUS_RXFULL_MASK 0x02u +#define STATUS_RXFULL_SHIFT 1u + +/* + * Parity error. + */ +#define STATUS_PARITYERR_OFFSET 0x10u +#define STATUS_PARITYERR_MASK 0x04u +#define STATUS_PARITYERR_SHIFT 2u + +/* + * Overflow. + */ +#define STATUS_OVERFLOW_OFFSET 0x10u +#define STATUS_OVERFLOW_MASK 0x08u +#define STATUS_OVERFLOW_SHIFT 3u + +/* + * Frame Error. + */ +#define STATUS_FRAMERR_OFFSET 0x10u +#define STATUS_FRAMERR_MASK 0x10u +#define STATUS_FRAMERR_SHIFT 4u + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_UART_APB_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.c b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.c new file mode 100644 index 0000000..a2f4911 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.c @@ -0,0 +1,765 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Mi-V I2C Soft IP bare-metal driver. This module is delivered as part of + * Extended Sub System(ESS) MIV_ESS. + * Please refer to miv_i2c.h file for more information. + */ + +#include "miv_i2c.h" + +#define MIV_I2C_ERROR 0xFFu + +/*------------------------------------------------------------------------------ + * MIV I2C transaction direction. + */ +#define MIV_I2C_WRITE_DIR 0u +#define MIV_I2C_READ_DIR 1u + +/* -- TRANSACTIONS TYPES -- */ +#define MIV_I2C_NO_TRANSACTION 0u +#define MIV_I2C_MASTER_WRITE_TRANSACTION 1u +#define MIV_I2C_MASTER_READ_TRANSACTION 2u +#define MIV_I2C_MASTER_SEQUENTIAL_READ_TRANSACTION 3u + +/*------------------------------------------------------------------------------ + * MIV I2C HW states + */ +#define MIV_I2C_IDLE 0x00u +#define MIV_I2C_TX_STA_CB 0x01u +#define MIV_I2C_TX_DATA 0x02u +#define MIV_I2C_RX_DATA 0x03u + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_disable_irq() disables the Mi-V I2C interrupt. + */ +void +MIV_I2C_disable_irq +( + void +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_enable_irq() enables the Mi-V I2C interrupt. + */ +void +MIV_I2C_enable_irq +( + void +); + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_init +( + miv_i2c_instance_t *this_i2c, + addr_t base_addr +) +{ + /* Assign the base address + * Clock Prescale value set + * MIV_I2C interrupt enabled + * I2C core enable + */ + psr_t processor_state; + + /* Disabling the interrupts */ + processor_state = HAL_disable_interrupts(); + + /* + * Initialize all items of the this_miv_i2c data structure to zero. This + * initializes all state variables to their init value. It relies on + * the fact that NO_TRANSACTION, MIV_I2C_SUCCESS and I2C_RELEASE_BUS all + * have an actual value of zero. + */ + memset(this_i2c, 0, sizeof(miv_i2c_instance_t)); + + this_i2c->base_addr = base_addr; + + HAL_restore_interrupts(processor_state); +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_config +( + miv_i2c_instance_t *this_i2c, + uint16_t clk_prescale +) +{ + /* Assign the base address + * Clock Prescale value set + * MIV_I2C interrupt enabled + * I2C core enable + */ + psr_t processor_state; + + /* Disabling the interrupts */ + processor_state = HAL_disable_interrupts(); + + /* Before writing to prescale reg, the core enable must be zero */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CTRL_CORE_EN, 0x00u); + + /* Set the prescale value */ + HAL_set_16bit_reg(this_i2c->base_addr, PRESCALE, clk_prescale); + + /* Enable the MIV I2C interrupts */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CTRL_IRQ_EN, 0x01u); + + /* Enable the MIV I2C core */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CTRL_CORE_EN, 0x01u); + + this_i2c->master_state = MIV_I2C_IDLE; + + HAL_restore_interrupts(processor_state); +} + +/* + * Please refer to miv_i2c.h for more info + */ +uint8_t +MIV_I2C_start +( + miv_i2c_instance_t *this_i2c +) +{ + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + /* Generate I2C start condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + HAL_restore_interrupts(processor_state); + + return 0u; +} + +/* + * Please refer to miv_i2c.h for more info + */ +uint8_t +MIV_I2C_stop +( + miv_i2c_instance_t *this_i2c +) +{ + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + /* Generate I2C stop condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + HAL_restore_interrupts(processor_state); + + return 0u; +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_write +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t bus_options, + uint8_t ack_polling_options +) +{ + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + /* I2C write flow + * + * Check I2C status for ongoing transaction + * Populate the structure with input data + * Generate start condition + * Set the write_direction and target address. + */ + + /* Update the transaction only when there is no ongoing I2C transaction */ + if (this_i2c->transaction == MIV_I2C_NO_TRANSACTION) + { + this_i2c->transaction = MIV_I2C_MASTER_WRITE_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MIV_I2C_MASTER_WRITE_TRANSACTION ; + + /* Populate the i2c instance structure */ + + /* Set the target addr */ + this_i2c->target_addr = i2c_target_addr; + this_i2c->dir = MIV_I2C_WRITE_DIR; + + /* Set up the tx buffer */ + this_i2c->master_tx_buffer = write_buffer; + this_i2c->master_tx_size = write_size; + this_i2c->master_tx_idx = 0u; + + /* Set the I2C status in progress and setup the options */ + this_i2c->bus_options = bus_options; + this_i2c->ack_polling_options = ack_polling_options; + this_i2c->master_status = MIV_I2C_IN_PROGRESS; + + + /* Generate I2C start condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* write target address and write bit */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, MIV_I2C_WRITE_DIR); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, i2c_target_addr); + + /* Set WR bit to transmit start condition and control byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + /* Set current master hw state -> transmitted start condition and + * control byte + */ + this_i2c->master_state = MIV_I2C_TX_STA_CB; + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( MIV_I2C_HOLD_BUS == this_i2c->bus_status ) + { + /* Must toggle IACK bit to clear the MIV_I2C IRQ*/ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00); + } + + MIV_I2C_enable_irq(); + + HAL_restore_interrupts(processor_state); + +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_read +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +) +{ + psr_t processor_state; + uint8_t status = MIV_I2C_SUCCESS; + + processor_state = HAL_disable_interrupts(); + + /* MIV I2C Read operation flow + * + * Check for ongoing transaction + * Populate the i2c instance structure + * Generate the start condition + * Set the READ_direction bit and target addr + */ + + uint8_t read_stat = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_TIP); + + /* Update the transaction only when there is no ongoing I2C transaction */ + if (this_i2c->transaction == MIV_I2C_NO_TRANSACTION) + { + this_i2c->transaction = MIV_I2C_MASTER_READ_TRANSACTION; + } + + this_i2c->pending_transaction = MIV_I2C_MASTER_READ_TRANSACTION; + + /* Populate the MIV I2C instance structure */ + + this_i2c->target_addr = i2c_target_addr; + this_i2c->dir = MIV_I2C_READ_DIR; + + /* Populate read buffer */ + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set the BUS and ACK polling options */ + this_i2c->bus_options = bus_options; + this_i2c->ack_polling_options = ack_polling_options; + + /* Generate the start condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* Set the DIR bit and target addr */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, MIV_I2C_READ_DIR); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, i2c_target_addr); + + /* Set the WR bit to transmit the start condition and command byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + /* Set the i2c master state and status transmitting STA and Command Byte */ + this_i2c->master_state = MIV_I2C_TX_STA_CB; + this_i2c->master_status = MIV_I2C_IN_PROGRESS; + + /* Toggle the IACK bit if required */ + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( MIV_I2C_HOLD_BUS == this_i2c->bus_status ) + { + /* Must toggle IACK bit to clear the MIV_I2C IRQ*/ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00); + } + /* Enable the I2C interrupt */ + MIV_I2C_enable_irq(); + + HAL_restore_interrupts(processor_state); +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_write_read +( + miv_i2c_instance_t *this_i2c, + uint8_t target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +) +{ + uint8_t status = MIV_I2C_SUCCESS; + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + uint8_t read_stat = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_TIP); + + /* I2C write read operation flow + * + * Used to read the data from set address offset + * + * Configure the i2c instance structure + * generate the start and configure the dir and target addr + * set wr bit to transmit the start and command byte + * + */ + + /* Update the transaction only when there is no ongoing I2C transaction */ + if (this_i2c->transaction == MIV_I2C_NO_TRANSACTION) + { + this_i2c->transaction = MIV_I2C_MASTER_READ_TRANSACTION; + } + + this_i2c->pending_transaction = MIV_I2C_MASTER_READ_TRANSACTION; + + /* Populate the I2C instance */ + + this_i2c->target_addr = target_addr; + + /* setup the i2c direction */ + this_i2c->dir = MIV_I2C_WRITE_DIR; + + /* set up transmit buffer */ + this_i2c->master_tx_buffer = write_buffer; + this_i2c->master_tx_size = write_size; + this_i2c->master_tx_idx = 0u; + + /* set up receive buffer */ + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set the bus and ack polling options */ + this_i2c->bus_options = bus_options; + this_i2c->ack_polling_options = ack_polling_options; + + /* Generate the start command */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* Set the DIR and target addr */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + /* Set the WR bit to transmit the start command and command byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + /* Set the i2c master state and status transmitting STA and Command Byte */ + this_i2c->master_state = MIV_I2C_TX_STA_CB; + this_i2c->master_status = MIV_I2C_IN_PROGRESS; + + /* + * Clear interrupt if required + */ + if ( MIV_I2C_HOLD_BUS == this_i2c->bus_status ) + { + /* Must toggle IACK bit to clear the MIV_I2C IRQ*/ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00u); + } + + /* Enable the I2C interrupt */ + MIV_I2C_enable_irq(); + + HAL_restore_interrupts(processor_state); +} + +/* MIV_I2C_isr() + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_isr +( + miv_i2c_instance_t *this_i2c +) +{ + uint8_t i2c_state; + uint8_t i2c_ack_status; + uint8_t i2c_al_status; + uint8_t hold_bus; + + /* Read the I2C master state */ + i2c_state = this_i2c->master_state; + + /* Read the ack and al status */ + i2c_ack_status = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_RXACK); + i2c_al_status = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_AL); + + switch (i2c_state) + { + /* I2C ISR State Machine + * + * Cases: + * - Transmit start condition and control byte + * - Received ACK and bus arbitration was not lost (Read or Write) + * - Received NACK + * - Bus arbitration lost + * + * - Transmit data + * - Received ACK and bus arbitration was not lost (Read or Write) + * - Received NACK + * - Bus arbitration lost + * + * - Receive data + * - Received ACK and bus arbitration was not lost (Read or Write) + * - Bus arbitration lost + */ + + case MIV_I2C_TX_STA_CB: + + /* Received ACK from target and I2C bus arbitration is not lost */ + if (i2c_ack_status == 0u && i2c_al_status == 0u) + { + /* If I2C master write operation */ + if (this_i2c->dir == MIV_I2C_WRITE_DIR) + { + /* write first byte of data and set the WR bit to transfer the data */ + HAL_set_8bit_reg(this_i2c->base_addr, TRANSMIT, + this_i2c->master_tx_buffer[this_i2c->master_tx_idx]); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + /* Increment the index */ + this_i2c->master_tx_idx++; + + /* Set the master state to TX data */ + this_i2c->master_state = MIV_I2C_TX_DATA; + } + /* Master read operation */ + else + { + if (this_i2c->master_rx_size == 1u) + { + /* Send the ACK if the rx size is 1, transmit NACK to slave + * after receiving 1 byte to indicate slave to stop sending + * the data + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_ACK, 0x01u); + } + + /* Send the RD command to slave */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_RD, 0x01u); + + /* Increment the index */ + this_i2c->master_rx_idx++; + + /* Change state to receive data */ + this_i2c->master_state = MIV_I2C_RX_DATA; + } + } + else if (i2c_ack_status == 1u) + { + if (this_i2c->ack_polling_options == MIV_I2C_ACK_POLLING_ENABLE) + { + /* Target responded with NACK and ACK polling option is enabled + * + * Re-send the start condition and control byte + * + * TO-DO: This might become infinite loop check for timeout + * options. + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + this_i2c->master_tx_idx = 0u; + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + else + { + /* Target responded with NACK and ACK polling is disabled + * Abort the transaction and move to IDLE state + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + + this_i2c->master_status = MIV_I2C_FAILED; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + + this_i2c->master_state = MIV_I2C_IDLE; + } + } + + else if (i2c_al_status == 1u) + { + /* Arbitration was lost on the BUS during the transmission of + * previous start condition and control byte. + * Re-send the STA and CB + */ + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + break; + + /* Transmit master data */ + case MIV_I2C_TX_DATA: + + /* ACK received and arbitration was not lost */ + if (i2c_ack_status == 0u && i2c_al_status == 0u) + { + uint8_t tx_buff[this_i2c->master_tx_size]; + if (this_i2c->master_tx_idx < this_i2c->master_tx_size) + { + HAL_set_8bit_reg(this_i2c->base_addr, TRANSMIT, + this_i2c->master_tx_buffer[this_i2c->master_tx_idx]); + + tx_buff[this_i2c->master_tx_idx] = this_i2c->master_tx_buffer[this_i2c->master_tx_idx]; + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + /* Increment the index */ + this_i2c->master_tx_idx++; + + /* Set the master state to TX data */ + this_i2c->master_state = MIV_I2C_TX_DATA; + } + + /* All the bytes are transmitted */ + else if (this_i2c->master_tx_idx == this_i2c->master_tx_size) + { + /* If this is a MASTER_READ_TRANSACTION, hold bus and start a + new transfer in read mode now that the read address has been + written to the slave */ + if(this_i2c->transaction == MIV_I2C_MASTER_READ_TRANSACTION) + + { + //Switch direction to READ + this_i2c->dir = MIV_I2C_READ_DIR; + + // Set the STA bit + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* Set the DIR bit and target addr */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, MIV_I2C_READ_DIR); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, this_i2c->target_addr); + + /* Set the WR bit to transmit the start condition and command byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + // Reset the buffer index + this_i2c->master_tx_idx = 0u; + this_i2c->master_rx_idx = 0u; + + /* Set the master state to RX data */ + this_i2c->master_state = MIV_I2C_RX_DATA; + } + + else + { + /* If releasing the bus, transmit the stop condition at the end + * of the transfer. + */ + hold_bus = this_i2c->bus_status & MIV_I2C_HOLD_BUS; + + if (hold_bus == 0) + { + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + } + else + { + MIV_I2C_disable_irq(); + } + this_i2c->master_status = MIV_I2C_SUCCESS; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + this_i2c->master_state = MIV_I2C_IDLE; + } + } + } + + else if (i2c_ack_status == 1u) + { + /* Received NACK from target device + * + * Release the bus and end the transfer + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + + this_i2c->master_status = MIV_I2C_FAILED; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + + this_i2c->master_state = MIV_I2C_IDLE; + } + + else if (i2c_al_status == 1u) + { + /* Arbitration was lost on the BUS during the transmission of + * previous start condition and control byte. + * Re-send the STA and CB + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, + this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + break; + + /* Receive target device data */ + case MIV_I2C_RX_DATA: + + if (i2c_al_status == 0u) + { + if (this_i2c->master_rx_idx < this_i2c->master_rx_size) + { + this_i2c->master_rx_buffer[this_i2c->master_rx_idx - 1u] = + HAL_get_8bit_reg(this_i2c->base_addr, RECEIVE); + + /* If next byte is last one + * Send NACK to target device to stop sending data + */ + if (this_i2c->master_rx_idx == (this_i2c->master_rx_size - 1u)) + { + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_ACK, 0x01u); + } + + else + { + /* Send ACK to receive next bytes */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_ACK, 0x00u); + } + + /* Set RD bit to receive next byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_RD, 0x01u); + + this_i2c->master_rx_idx++; + } + + /* Received all bytes */ + else //if (this_i2c->master_rx_idx == this_i2c->master_rx_size) + { + this_i2c->master_rx_buffer[this_i2c->master_rx_idx - 1] = + HAL_get_8bit_reg(this_i2c->base_addr, RECEIVE); + + hold_bus = this_i2c->bus_status & MIV_I2C_HOLD_BUS; + + if (hold_bus == 0) + { + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + } + else + { + MIV_I2C_disable_irq(); + } + this_i2c->master_status = MIV_I2C_SUCCESS; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + + this_i2c->master_state = MIV_I2C_IDLE; + } + } + + else if (i2c_al_status == 1u) + { + /* Arbitration was lost on the BUS during the transmission of + * previous start condition and control byte. + * Re-send the STA and CB + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, + this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + break; + } + + /* Toggle the IACK bit to clear interrupt */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00u); +} + +/* + * Please refer to miv_i2c.h for more info + */ +uint8_t +MIV_I2C_get_status +( + miv_i2c_instance_t *this_i2c +) +{ + uint8_t i2c_status; + + i2c_status = HAL_get_8bit_reg(this_i2c->base_addr, STATUS); + + return i2c_status; +} diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.h b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.h new file mode 100644 index 0000000..c5e704d --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.h @@ -0,0 +1,854 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * I2C module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(MIV_ESS). + */ + +/*=========================================================================*//** + @mainpage Mi-V I2C Bare Metal Driver + + ============================================================================== + Introduction + ============================================================================== + The Mi-V I2C driver provides a set of functions for controlling the Mi-V I2C + Soft-IP module. This module is delivered as a part of the Mi-V Extended + Sub System(MIV_ESS). The driver provides a minimal APB-driven I2C interface, + supporting initiator read and write access to peripheral I2C devices. + + The major features provided by the Mi-V I2C driver are: + - Support for configuring the I2C instance. + - I2C master operations. + - I2C ISR. + + This driver can be used as part of a bare metal system where no operating + system is available. The driver can be adapted for use as part of an + operating system, but the implementation of the adaptation layer between the + driver and the operating system's driver model is outside the scope of this + driver. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + The application software should initialize and configure the Mi-V I2C through + the call to the MIV_I2C_init() and MIV_I2C_config() function for Mi-V I2C + instance in the design. The configuration parameter include base address and + Prescaler value. + + ------------------------------ + Interrupt Control + ------------------------------ + The Mi-V I2C driver has to enable and disable the generation of interrupts by + Mi-V I2C at various times while operating. This enabling and disabling of the + interrupts must be done through the Mi-V RV32 HAL provided interrupt handlers. + For that reason, the method controlling the Mi-V I2C interrupts is system + specific and it is necessary to customize the MIV_I2C_enable_irq() and + MIV_I2C_disable_irq() functions as per requirement. + + The implementation of MIV_I2C_enable_irq() should permit the interrupts + generated by the Mi-V I2C to the processor through a call to respective miv-hal + interrupt handler. The implementation of MIV_I2C_disable_irq() should prevent + the interrupts generated by a Mi-V I2C from interrupting the processor. + Please refer to the miv_i2c_interrupt.c for more information about the + implementation. + + No MIV_I2C hardware configuration parameters are used by the driver, apart + from the MIV_I2C base address. Hence, no additional configuration files + are required to use the driver. + + ============================================================================== + Theory of Operation + ============================================================================== + The Mi-V I2C software driver is designed to allow the control of multiple + instances of Mi-V I2C. Each instance of Mi-V I2C in the hardware design is + associated with a single instance of the miv_i2c_instance_t structure in the + software. User must allocate memory for one unique miv_i2c_instance_t + structure for each instance of Mi-V I2C in the hardware. + A pointer to the structure is passed to the subsequent driver functions in + order to identify the MIV_I2C hardware instance and to perform requested + operation. + + Note: Do not attempt to directly manipulate the contents of the + miv_i2c_instance_t structure. These structures are only intended to be modified + by the driver functions. + + The Mi-V I2C driver functions are grouped into following categories: + - Initialization and configuration + - I2C master operation functions to handle write, read and write_read + operations. + - Interrupt control + + -------------------------------- + Initialization and configuration + -------------------------------- + The Mi-V I2C device is first initialized by the call to MIV_I2C_init(). This + function initializes the instance of Mi-V I2C with the base address. + MIV_I2C_init() function must be called before any other Mi-V I2C driver API. + + The configuration of the Mi-V I2C instance is done via call to the + MIV_I2C_config() function. This function will set the prescale value which is + used to set the frequency of the I2C clock(SCLK) generated by I2C module. + + --------------------------------- + Transaction types + --------------------------------- + The driver is designed to handle three types of transactions: + - Write transactions + - Read transactions + - Write-Read transaction + + ### Write Transaction + The write transaction begins with master sending a start condition, followed + by device address byte with the R/W bit set to logic '0', and then by the + word address bytes. The slave acknowledges the receipt of its address with + acknowledge bit. The master sends one byte at a time to the slave, which must + acknowledge the receipt of each byte for the next byte to be sent. The master + sends STOP condition to complete the transaction. The slave can abort the + transaction by replying with negative acknowledge. + + The application programmer can choose not to send the STOP bit at the end of + the transaction causing repetitive start conditions. + + ### Read Transaction + The master I2C device initiates a read transaction by sending a START bit + as soon as the bus becomes free. The start condition is followed by the + control byte which contains 7-bit slave address followed by R/W bit set to + logic '1'. The slave sends data one byte at a time to the master, which must + acknowledge receipt of each byte for the next byte to be sent. The master + sends a non-acknowledge bit following the last byte it wishes to read + followed by a STOP bit. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ### Write-Read Transaction + The write read transaction is a combination of a write transaction + immediately followed by a read transaction. There is no STOP condition sent + between the write and read phase of write-read transaction. A repeated START + condition is sent between the write and read phases. + + Whilst the write handler is being executed, the slave holds the clock line + low to stretch the clock until the response is ready. + + The write-read transaction is typically used to send an memory/register + address in the write transaction specifying the start address of the data to + be transferred during the read phase. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ------------------------------------- + Interrupt Control + ------------------------------------- + The Mi-V I2C driver is interrupt driven and it uses the MIV_I2C_irq() function + to drive the ISR state machine which is at the heart of the driver. The + application is responsible for providing the link between the interrupt + generating hardware and the Mi-V I2C interrupt handler and must ensure that + the MIV_I2C_isr() function is called with the correct miv_i2c_instance_t + structure pointer for the Mi-V I2C instance initiating the interrupt. + +*//*=========================================================================*/ +#ifndef MIV_I2C_H_ +#define MIV_I2C_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "miv_i2c_regs.h" +#include + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#else +#include "hal.h" +#endif + +/*-------------------------------------------------------------------------*//** + The miv_i2c_status_t type is used to report the status of I2C transactions. + */ +typedef enum miv_i2c_status +{ + MIV_I2C_SUCCESS = 0u, + MIV_I2C_IN_PROGRESS, + MIV_I2C_FAILED, + MIV_I2C_TIMED_OUT +}miv_i2c_status_t; + +/*-------------------------------------------------------------------------*//** + This structure is used to identify the MIV_I2C hardware instances in a system. + Your application software should declare one instance of this structure for + each instance of the MIV_I2C in your system. The function MIV_I2C_init() + Initializes this structure. A pointer to an initialised instance of the structure + should be passed as the first parameter to the MIV_I2C driver functions, to + identify which MIV_I2C hardware instance should perform the requested operation. + + The contents of this data structure should not be modified or used outside of + the MIV_I2C driver. Software using the MIV_I2C driver should only need to + create one single instance of this data structure for each MIV_I2C hardware + instance in the system, then pass a pointer to these data structures with each + call to the MIV_I2C driver in order to identify the MIV_I2C hardware instance + it wishes to use. +*/ + +typedef struct miv_i2c_instance +{ + addr_t base_addr; + + /* Transmit related info:*/ + uint_fast8_t target_addr; + + /* Current transaction type */ + uint8_t transaction; + + uint8_t bus_options; + + uint8_t ack_polling_options; + + /* Current State of the I2C master */ + uint8_t master_state; + + /* Master TX INFO: */ + const uint8_t * master_tx_buffer; + uint_fast16_t master_tx_size; + uint_fast16_t master_tx_idx; + uint_fast8_t dir; + + /* Master RX INFO: */ + uint8_t * master_rx_buffer; + uint_fast16_t master_rx_size; + uint_fast16_t master_rx_idx; + + /* Master Status */ + volatile miv_i2c_status_t master_status; + uint32_t master_timeout_ms; + + /* user specific data */ + void *p_user_data ; + + /* I2C bus status */ + uint8_t bus_status; + + /* Is transaction pending flag */ + uint8_t is_transaction_pending; + + /* I2C Pending transaction */ + uint8_t pending_transaction; + +}miv_i2c_instance_t; + + +/*-------------------------------------------------------------------------*//** + MIV_I2C_RELEASE_BUS + ===================== + The MIV_I2C_RELEASE_BUS constant is used to specify the bus_options parameter + for MIV_I2C_read(), MIV_I2C_write() and MIV_I2C_write_read() to indicate + that a STOP bit must be generated at the end of the I2C transaction to release + the bus. + */ +#define MIV_I2C_RELEASE_BUS 0x00u + + +/*-------------------------------------------------------------------------*//** + MIV_I2C_HOLD_BUS + ===================== + The MIV_I2C_HOLD_BUS constant is used to specify the bus_optionsparameter + for MIV_I2C_read(), MIV_I2C_write() and MIV_I2C_write_read() to indicate + that a STOP bit must not be generated at the end of the I2C transaction in + order to retain the bus ownership. This causes the next transaction to + begin with a repeated START bit and no STOP bit between the transactions. + */ +#define MIV_I2C_HOLD_BUS 0x01u + +/*-------------------------------------------------------------------------*//** + MIV_I2C_ACK_POLLING_DISABLE + ===================== + The MIV_I2C_ACK_POLLING_DISABLE constant is used to specify the + ack_polling_options parameter to functions MIV_I2C_write(), + MIV_I2C_write_read() and MIV_I2C_read(). Acknowledgment polling is used when + working with I2C memory devices such as EEPROM, which feature an internal + write cycle. + + With acknowledgment polling disabled, if the target slave device responds to the + control byte with a NACK, the MIV_I2C will abort the transfer. + */ +#define MIV_I2C_ACK_POLLING_DISABLE 0x00u + +/*-------------------------------------------------------------------------*//** + MIV_I2C_ACK_POLLING_ENABLE + ===================== + The MIV_I2C_ACK_POLLING_ENABLE constant is used to specify the + ack_polling_options parameter to functions MIV_I2C_write(), + MIV_I2C_write_read() and MIV_I2C_read(). acknowledgment polling is used when + working with I2C memory devices such as EEPROM, which feature an internal + write cycle. + + With acknowledgment polling enabled, if the slave device responds to the + control byte with a NACK, the MIV_I2C will repeatedly transmit another control + byte until the slave device accepts the connection with an ACK, or the timeout + specified in the MIV_I2C_wait_complete() function is reached. Acknowledgment + polling allows for the next read/write operation to be started as soon as the + EEPROM has completed its internal write cycle. + */ +#define MIV_I2C_ACK_POLLING_ENABLE 0x01u + +/*--------------------------------Public APIs---------------------------------*/ + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_init() function is used to initialize the Mi-V I2C module instance + with the base address. + + Note: This function should be called before calling any other Mi-V I2C + functions. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + @param base_addr + Base address of the Mi-V I2C module instance in the MIV_ESS + soft IP. + + @return + This function does not return any value. + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + } + @endcode + */ +void +MIV_I2C_init +( + miv_i2c_instance_t *this_i2c, + addr_t base_addr +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_config() function is used to configure the Mi-V I2C module. This + function will set the prescale value which is used to set the frequency of + the I2C clock(SCLK) generated by I2C module and also enables the I2C core and + interrupts. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param clk_prescale + The value used to set the frequency of Mi-V I2C serial clock + (SCLK) generated by the Mi-V I2C module instance. The + prescaler value required to set particular frequency of + Mi-V I2C can be calculated using following formula: + + prescaler = (System Clock Frequency) / (5 * (Desired I2C Clock Frequency)) - 1 + + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + } + @endcode + */ +void +MIV_I2C_config +( + miv_i2c_instance_t *this_i2c, + uint16_t clk_prescale +); + + +uint8_t +MIV_I2C_start +( + miv_i2c_instance_t *this_i2c +); + + +uint8_t +MIV_I2C_stop +( + miv_i2c_instance_t *this_i2c +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_write() is used to set up and start the Mi-V I2C master write + transaction. This function is used for all Mi-V master write operation. + + For more information about the operation, please refer to the 'theory of + operations' section at the start of this document. + + This function returns immediately after initiating the transaction. The content + of the write buffer passed as parameter should not be modified until the write + transaction completes. It also means that the memory allocated for the write + buffer should not be freed or should not go out of scope before the write + completes. + You can check for the write transaction completion by polling the master_status + from miv_i2c_instance_t structure as shown in the sample code. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param i2c_target_addr + This parameter specifies the serial address for the slave + device. + + @param write_buffer + This parameter is a pointer to the buffer holding data to be + written to target I2C device. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param write_size + Number of bytes held in the write_buffer to be written to the + I2C device. + @param bus_options: + The bus_options parameter is used to indicate if the I2C bus + should be released on completion of the write transaction. + Using the MIV_I2C_RELEASE_BUS constant for the bus_options + parameter causes a STOP bit to be generated at the end of the + write transaction causing the bus to be released for other I2C + devices to use. Using the MIV_I2C_HOLD_BUS constant as + bus_options parameter prevents a STOP bit from being generated + at the end of the write transaction, preventing other I2C + devices from initiating a bus transaction. + + @param ack_polling_options: + The ack_polling_options parameter is used to indicate how the + MIV_I2C will respond if the slave device transmits a NACK to + the I2C control byte. Using the MIV_I2C_ACK_POLLING_DISABLE + constant for the ack_polling_options parameter causes the + MIV_I2C to abort the transfer if the slave device responds to + the I2C control byte with a NACK. Using the + MIV_I2C_ACK_POLLING_ENABLE constant for the ack_polling_options + parameter causes the MIV_I2C to repeatedly transmit a control + byte to the slave device until the slave device responds with + an ACK. + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + + MIV_I2C_write (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_tx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + } + @endcode + */ +void +MIV_I2C_write +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t bus_options, + uint8_t ack_polling_options +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_read() is used to set up and start the Mi-V I2C master read + transaction. This function is used for all MIV_I2C master read operation. + + For more information about the operation, please refer to the 'theory of + operations' section at the start of this document. + + This function returns immediately after initiating the transaction. The content + of the read buffer passed as parameter should not be modified until the write + transaction completes. It also means that the memory allocated for the read + buffer should not be freed or should not go out of scope before the read + completes. + You can check for the write transaction completion by polling the master_status + from miv_i2c_instance_t structure as shown in the sample code. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param i2c_target_addr + This parameter specifies the serial address for the slave + device. + + @param read_buffer + This parameter is a pointer to the buffer where the data + received from the I2C slave device is stored. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param read_size + Number of bytes held in the write_buffer to be read from the + I2C device. + + @param bus_options: + The bus_options parameter is used to indicate if the I2C bus + should be released on completion of the write transaction. + Using the MIV_I2C_RELEASE_BUS constant for the bus_options + parameter causes a STOP bit to be generated at the end of the + write transaction causing the bus to be released for other I2C + devices to use. Using the MIV_I2C_HOLD_BUS constant as + bus_options parameter prevents a STOP bit from being generated + at the end of the write transaction, preventing other I2C + devices from initiating a bus transaction. + + @param ack_polling_options: + The ack_polling_options parameter is used to indicate how the + MIV_I2C will respond if the slave device transmits a NACK to + the I2C control byte. Using the MIV_I2C_ACK_POLLING_DISABLE + constant for the ack_polling_options parameter causes the + MIV_I2C to abort the transfer if the slave device responds to + the I2C control byte with a NACK. Using the + MIV_I2C_ACK_POLLING_ENABLE constant for the ack_polling_options + parameter causes the MIV_I2C to repeatedly transmit a control + byte to the slave device until the slave device responds with + an ACK. + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + + MIV_I2C_write (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_tx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + + // reset miv_i2c_status variable + miv_i2c_status = 0u; + + MIV_I2C_read (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_rx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + } + @endcode + */ +void +MIV_I2C_read +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_write_read() is used to set up and start the Mi-V I2C master + write_read transaction. This function is used for all MIV_I2C master write_read + operation. + + This function is used in cases where data is being requested from a specific + address offset inside the target I2C slave device. + In this type of I2C operation, the I2C master starts by initiating a write + operation. During this write operation, the specific address offset is written + to the I2C slave. Once the address offset has been written to the I2C slave, + the I2C master transmits a repeated start, and initiates a read operation to + read data from the set address. + + For more information about the operation, please refer to the 'theory of + operations' section at the start of this document. + + This function returns immediately after initiating the transaction. The content + of the write and read buffer passed as parameter should not be modified until + the write transaction completes. It also means that the memory allocated for + the write and read buffer should not be freed or should not go out of scope + before the operation completes. + You can check for the write_read transaction completion by polling the + master_status from miv_i2c_instance_t structure. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param i2c_target_addr + This parameter specifies the serial address for the slave + device. + + @param write_buffer + This parameter is a pointer to the buffer holding data to be + written to target I2C device. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param write_size + Number of bytes held in the write_buffer to be written to the + I2C device. + + @param read_buffer + This parameter is a pointer to the buffer where the data + received from the I2C slave device is stored. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param read_size + Number of bytes held in the write_buffer to be read from the + I2C device. + + @param bus_options: + The bus_options parameter is used to indicate if the I2C bus + should be released on completion of the write transaction. + Using the MIV_I2C_RELEASE_BUS constant for the bus_options + parameter causes a STOP bit to be generated at the end of the + write transaction causing the bus to be released for other I2C + devices to use. Using the MIV_I2C_HOLD_BUS constant as + bus_options parameter prevents a STOP bit from being generated + at the end of the write transaction, preventing other I2C + devices from initiating a bus transaction. + + @param ack_polling_options: + The ack_polling_options parameter is used to indicate how the + MIV_I2C will respond if the slave device transmits a NACK to + the I2C control byte. Using the MIV_I2C_ACK_POLLING_DISABLE + constant for the ack_polling_options parameter causes the + MIV_I2C to abort the transfer if the slave device responds to + the I2C control byte with a NACK. Using the + MIV_I2C_ACK_POLLING_ENABLE constant for the ack_polling_options + parameter causes the MIV_I2C to repeatedly transmit a control + byte to the slave device until the slave device responds with + an ACK or the timeout specified in the MIV_I2C_wait_complete() + function is reached. + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + + MIV_I2C_write (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_tx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + + // reset miv_i2c_status variable + miv_i2c_status = 0u; + + uint8_t addr_offset[2] = {0x00, 0x00}; + MIV_I2C_write_read(&miv_i2c, + DUALEE_SLAVEADDRESS_1, + addr_offset, + sizeof(addr_offset), + i2c_rx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + } + @endcode + */ +void +MIV_I2C_write_read +( + miv_i2c_instance_t *this_i2c, + uint8_t target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_isr() function contains the MIV_I2C's interrupt service routine. + This ISR is at the heart of the MIV_I2C driver, and is used to control the + interrupt-driven, byte-by-byte I2C read and write operations. + + The ISR operates as a Finite State Machine (FSM), which uses the previously + completed I2C operation and its result to determine which I2C operation will + be performed next. + + The ISR operation is divided into following categories: + - MIV_I2C_IDLE + - MIV_I2C_TX_STA_CB + - MIV_I2C_TX_DATA + - MIV_I2C_RX_DATA + + ##### MIV_I2C_IDLE + The MIV_I2C_IDLE is entered on reset, or when an I2C master operation has been + completed or aborted. + Upon entering, the FSM will remain in this state until a write, read, or + write-read operation is requested + + ##### MIV_I2C_STA_CB + The MIV_I2C_TX_STA_CB operation is performed when the start condition and + control byte(i2c target address(7-bit) and direction of transaction(1-bit)) is + transmitted by the Mi-V I2C master device to the slave. + If the target I2C slave device responded to the previous START Condition + + Control Byte with an ACK, the MIV_I2C will start the requested I2C + read/write operation. + If the target slave I2C slave device responds with NACK, the MIV_I2C will + remain in this state or return to the idle state based on ack_polling + configuration. + + ##### MIV_I2C_TX_DATA + The MIV_I2C_TX_DATA state is entered after the target slave device accepts a + write request with an ACK. + This state is used to handle the byte-by-byte MIV_I2C write operations. + The FSM will remain in this state until either all data bytes have been + written to the target slave device, or an error occurs during the write + operation. + + ##### MIV_I2C_RX_DATA + The MIV_I2C_RX_DATA state is entered after the target slave device accepts a + read request with an ACK. + This state is used to handle the byte-by-byte MIV_I2C read operations. + The FSM will remain in this state until either all data bytes have been + received from the target slave device, or an error occurs. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + */ +void +MIV_I2C_isr +( + miv_i2c_instance_t *this_i2c +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_get_status() returns the 8-bit Mi-V I2C status register value. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + @return + This function returns 8-bit Mi-V I2C status register value. + */ +uint8_t +MIV_I2C_get_status +( + miv_i2c_instance_t *this_i2c +); + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_I2C_H_ */ diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_interrupt.c b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_interrupt.c new file mode 100644 index 0000000..871eafe --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_interrupt.c @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains functions used for MIV_I2C driver interrupt control. + * User should enable and disable the interrupts according to their design. + * Please refer to miv_i2c.h file for more information. + */ + +#include "miv_rv32_hal/miv_rv32_hal.h" + +void MIV_I2C_disable_irq(void) +{ +/* Disable I2C interrupt */ + MRV_disable_local_irq(MRV32_MSYS_EIE2_IRQn); +} + +void MIV_I2C_enable_irq(void) +{ +/* Enable I2C interrupt */ + MRV_enable_local_irq(MRV32_MSYS_EIE2_IRQn); +} + + diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_regs.h b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_regs.h new file mode 100644 index 0000000..9a4bfbf --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_regs.h @@ -0,0 +1,158 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP I2C module driver. This module is delivered as a part of Mi-V extended + * Sub-System(MIV_ESS). + */ + +#ifndef MIV_I2C_APB_REGISTERS +#define MIV_I2C_APB_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * Prescale register details + */ +#define PRESCALE_REG_OFFSET 0x00u + +/* Prescale register bits */ +#define PRESCALE_OFFSET 0x00u +#define PRESCALE_MASK 0xFFFFu +#define PRESCALE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Control register details + */ +#define CONTROL_REG_OFFSET 0x04u + +/* Control register bits */ +#define CONTROL_OFFSET 0x04u +#define CONTROL_MASK 0xC0u +#define CONTROL_SHIFT 0u + +/* Control register Core Enable Bit */ +#define CTRL_CORE_EN_OFFSET 0x04u +#define CTRL_CORE_EN_MASK 0x80u +#define CTRL_CORE_EN_SHIFT 7u + +/* Control register IRQ Enable bit */ +#define CTRL_IRQ_EN_OFFSET 0x04u +#define CTRL_IRQ_EN_MASK 0x40u +#define CTRL_IRQ_EN_SHIFT 6u + +/*------------------------------------------------------------------------------ + * Transmit register details + */ +#define TRANSMIT_REG_OFFSET 0x08u + +/* Transmit register bits */ +#define TRANSMIT_OFFSET 0x08u +#define TRANSMIT_MASK 0xFFu +#define TRANSMIT_SHIFT 0u + +/* Transmit register DIR bit */ +#define TX_DIR_OFFSET 0x08u +#define TX_DIR_MASK 0x01u +#define TX_DIR_SHIFT 0u + +/* Transmit register TARGET_ADDR bit */ +#define TX_TARGET_ADDR_OFFSET 0x08u +#define TX_TARGET_ADDR_MASK 0xFEu +#define TX_TARGET_ADDR_SHIFT 1u + +/*------------------------------------------------------------------------------ + * Receive register details + */ +#define RECEIVE_REG_OFFSET 0x0Cu + +/* Receive register bits */ +#define RECEIVE_OFFSET 0x0Cu +#define RECEIVE_MASK 0xFFu +#define RECEIVE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Command register details + */ +#define COMMAND_REG_OFFSET 0x10u + +/* Command register bits */ +#define COMMAND_OFFSET 0x10u +#define COMMAND_MASK 0xF9u +#define COMMAND_SHIFT 0u + +/* Command register IACK bit */ +#define CMD_IACK_OFFSET 0x10u +#define CMD_IACK_MASK 0x01u +#define CMD_IACK_SHIFT 0u + +/* Command register ACK bit */ +#define CMD_ACK_OFFSET 0x10u +#define CMD_ACK_MASK 0x08u +#define CMD_ACK_SHIFT 3u + +/* Command register WR bit */ +#define CMD_WR_OFFSET 0x10u +#define CMD_WR_MASK 0x10u +#define CMD_WR_SHIFT 4u + +/* Command register RD bit */ +#define CMD_RD_OFFSET 0x10u +#define CMD_RD_MASK 0x20u +#define CMD_RD_SHIFT 5u + +/* Command register STO bit */ +#define CMD_STO_OFFSET 0x10u +#define CMD_STO_MASK 0x40u +#define CMD_STO_SHIFT 6u + +/* Command register STA bit */ +#define CMD_STA_OFFSET 0x10u +#define CMD_STA_MASK 0x80u +#define CMD_STA_SHIFT 7u + +/*------------------------------------------------------------------------------ + * Status register details + */ +#define STATUS_REG_OFFSET 0x14u + +/* Command register bits */ +#define STATUS_OFFSET 0x14u +#define STATUS_MASK 0xFFu +#define STATUS_SHIFT 0u + +/* Status register Interrupt Flag(IF) bit */ +#define STAT_IF_OFFSET 0x14u +#define STAT_IF_MASK 0x01u +#define STAT_IF_SHIFT 0u + +/* Status register Transfer in Progress(TIP) bit */ +#define STAT_TIP_OFFSET 0x14u +#define STAT_TIP_MASK 0x02u +#define STAT_TIP_SHIFT 1u + +/* Status register Arbitration Lost(AL) bit */ +#define STAT_AL_OFFSET 0x14u +#define STAT_AL_MASK 0x20u +#define STAT_AL_SHIFT 5u + +/* Status register Busy(BUSY) bit */ +#define STAT_BUSY_OFFSET 0x14u +#define STAT_BUSY_MASK 0x40u +#define STAT_BUSY_SHIFT 6u + +/* Status register Ack received(RXACK) bit */ +#define STAT_RXACK_OFFSET 0x14u +#define STAT_RXACK_MASK 0x80u +#define STAT_RXACK_SHIFT 7u + + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_I2C_APB_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_plic/miv_plic.c b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_plic/miv_plic.c new file mode 100644 index 0000000..903f029 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_plic/miv_plic.c @@ -0,0 +1,283 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * MI-V Soft IP fabric bare-metal driver for Mi-V PLIC module. This module is + * delivered as a part of Mi-V Extended Sub System(MIV_ESS). + * Please refer to miv_plic.h file for more information. + */ + +#include "miv_plic.h" + +/***************************************************************************//** + * Mi-V PLIC interrupt handler function declaration. + * These functions are called by the external interrupt handler of the MIV_RV32 + * core base on the PLIC source causing the interrupt. + */ +uint8_t Invalid_IRQHandler(void); +uint8_t MIV_PLIC_EXT0_IRQHandler(void); +uint8_t MIV_PLIC_EXT1_IRQHandler(void); +uint8_t MIV_PLIC_EXT2_IRQHandler(void); +uint8_t MIV_PLIC_EXT3_IRQHandler(void); +uint8_t MIV_PLIC_EXT4_IRQHandler(void); +uint8_t MIV_PLIC_EXT5_IRQHandler(void); +uint8_t MIV_PLIC_EXT6_IRQHandler(void); +uint8_t MIV_PLIC_EXT7_IRQHandler(void); +uint8_t MIV_PLIC_EXT8_IRQHandler(void); +uint8_t MIV_PLIC_EXT9_IRQHandler(void); +uint8_t MIV_PLIC_EXT10_IRQHandler(void); +uint8_t MIV_PLIC_EXT11_IRQHandler(void); +uint8_t MIV_PLIC_EXT12_IRQHandler(void); +uint8_t MIV_PLIC_EXT13_IRQHandler(void); +uint8_t MIV_PLIC_EXT14_IRQHandler(void); +uint8_t MIV_PLIC_EXT15_IRQHandler(void); +uint8_t MIV_PLIC_EXT16_IRQHandler(void); +uint8_t MIV_PLIC_EXT17_IRQHandler(void); +uint8_t MIV_PLIC_EXT18_IRQHandler(void); +uint8_t MIV_PLIC_EXT19_IRQHandler(void); +uint8_t MIV_PLIC_EXT20_IRQHandler(void); +uint8_t MIV_PLIC_EXT21_IRQHandler(void); +uint8_t MIV_PLIC_EXT22_IRQHandler(void); +uint8_t MIV_PLIC_EXT23_IRQHandler(void); +uint8_t MIV_PLIC_EXT24_IRQHandler(void); +uint8_t MIV_PLIC_EXT25_IRQHandler(void); +uint8_t MIV_PLIC_EXT26_IRQHandler(void); +uint8_t MIV_PLIC_EXT27_IRQHandler(void); +uint8_t MIV_PLIC_EXT28_IRQHandler(void); +uint8_t MIV_PLIC_EXT29_IRQHandler(void); +uint8_t MIV_PLIC_EXT30_IRQHandler(void); + +/***************************************************************************//** + * MIV_PLIC interrupt handler for external interrupts. + * The array of the function pointers pointing to the weak handler of the Mi-V + * PLIC interrupt handlers. + * These functions are called by the external interrupt handler of the MIV_RV32 + * core base on the PLIC source causing the interrupt. + */ +uint8_t (* const ext_irq_handler_table[32]) (void) = +{ + Invalid_IRQHandler, + MIV_PLIC_EXT0_IRQHandler, + MIV_PLIC_EXT1_IRQHandler, + MIV_PLIC_EXT2_IRQHandler, + MIV_PLIC_EXT3_IRQHandler, + MIV_PLIC_EXT4_IRQHandler, + MIV_PLIC_EXT5_IRQHandler, + MIV_PLIC_EXT6_IRQHandler, + MIV_PLIC_EXT7_IRQHandler, + MIV_PLIC_EXT8_IRQHandler, + MIV_PLIC_EXT9_IRQHandler, + MIV_PLIC_EXT10_IRQHandler, + MIV_PLIC_EXT11_IRQHandler, + MIV_PLIC_EXT12_IRQHandler, + MIV_PLIC_EXT13_IRQHandler, + MIV_PLIC_EXT14_IRQHandler, + MIV_PLIC_EXT15_IRQHandler, + MIV_PLIC_EXT16_IRQHandler, + MIV_PLIC_EXT17_IRQHandler, + MIV_PLIC_EXT18_IRQHandler, + MIV_PLIC_EXT19_IRQHandler, + MIV_PLIC_EXT20_IRQHandler, + MIV_PLIC_EXT21_IRQHandler, + MIV_PLIC_EXT22_IRQHandler, + MIV_PLIC_EXT23_IRQHandler, + MIV_PLIC_EXT24_IRQHandler, + MIV_PLIC_EXT25_IRQHandler, + MIV_PLIC_EXT26_IRQHandler, + MIV_PLIC_EXT27_IRQHandler, + MIV_PLIC_EXT28_IRQHandler, + MIV_PLIC_EXT29_IRQHandler, + MIV_PLIC_EXT30_IRQHandler +}; + +/* Mi-V PLIC interrupt weak handlers */ +__attribute__((weak)) uint8_t Invalid_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT0_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT1_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT2_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT3_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT4_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT5_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT6_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT7_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT8_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT9_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT10_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT11_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT12_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT13_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT14_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT15_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT16_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT17_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT18_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT19_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT20_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT21_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT22_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT23_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT24_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT25_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT26_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT27_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT28_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT29_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT30_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +/*-------------------------------------------------------------------------*//** + * Please refer to miv_plic.h for more information about this function. +*/ +void +MIV_PLIC_isr +( + miv_plic_instance_t *this_plic +) +{ + unsigned long hart_id = read_csr(mhartid); + + /* claim the interrupt from PLIC controller */ + + uint32_t int_num = HAL_get_32bit_reg(this_plic->base_addr + + (0x1000 * hart_id), INT_CLAIM_COMPLETE); + + uint8_t disable = EXT_IRQ_KEEP_ENABLED; + disable = ext_irq_handler_table[int_num](); + + /* Indicate the PLIC controller that the interrupt is processed and claim is + * complete. */ + HAL_set_32bit_reg(this_plic->base_addr + + (0x1000 * hart_id), INT_CLAIM_COMPLETE, int_num); + + if (EXT_IRQ_DISABLE == disable) + { + MIV_PLIC_disable_irq(this_plic, (miv_plic_irq_num_t)int_num); + } +} diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_plic/miv_plic.h b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_plic/miv_plic.h new file mode 100644 index 0000000..f5d64cd --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_plic/miv_plic.h @@ -0,0 +1,425 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * PLIC module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(ESS). + */ + /*=========================================================================*//** + @mainpage Mi-V PLIC Bare Metal Driver + + ============================================================================== + Introduction + ============================================================================== + The Mi-V driver provides a set of functions for controlling the Mi-V PLIC + (platform level interrupt controller) soft-IP module. This module is delivered + as a part of the MIV_ESS. The PLIC multiplexes external interrupt signals into + a single interrupt signal that is connected to an external interrupt of the + processor. + + The major features provided by the driver are: + - Support for configuring the PLIC instances. + - Enabling and Disabling interrupts + - Interrupt Handling + + This driver can be used as part of a bare metal system where no operating + system is available. The driver can be adapted for use as part of an + operating system, but the implementation of the adaptation layer between the + driver and the operating system's driver model is outside the scope of this + driver. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + The application software should initialize the Mi-V PLIC through the call to + the MIV_PLIC_init() function for Mi-V PLIC instance in the design. + + No Mi-V PLIC hardware configuration parameters are used by the driver, apart + from the Mi-V PLIC base address. Hence, no additional configuration files + are required to use the driver. + + ============================================================================== + Theory of Operation + ============================================================================== + The operation of Mi-V PLIC driver is divided into following steps: + - Initialization + - Enabling and Disabling interrupts + - Interrupt control + + -------------------------------------------- + Initialization + -------------------------------------------- + The Mi-V PLIC module is first initialized by the call to MIV_PLIC_init(). This + function takes a pointer to the Mi-V PLIC instance data structure and the base + address of the Mi-V PLIC instance is defined by the hardware design. The + instance data structure is used to store the base address of the Mi-V PLIC + module and a pointer to the Mi-V PLIC register data structure. The Mi-V PLIC + register data structure maps the address of the Mi-V PLIC registers. + + --------------------------------------------- + Enabling and Disabling interrupts + --------------------------------------------- + The MIV_PLIC_enable_irq() function enables the specific interrupt provided by + user. A call to this function will allow the enabling of each of the global + interrupts corresponding to the bit in the interrupt enable register of Mi-V + PLIC. + The MIV_PLIC_disable_irq() function disables the specific interrupt provided + by the user. This function can be used to disable the interrupts from outside + of the external interrupt handler. + + ---------------------------------------- + Interrupt Control + ---------------------------------------- + When an interrupt occurs on an enabled interrupt, the PLIC gateway captures + the interrupt and asserts the corresponding interrupt pending bit. Once + the enable bit and pending bit are asserted, then the PLIC_IRQ signal asserts + until the interrupt is claimed by the driver interrupt handler MIV_PLIC_irq() + function. + When multiple interrupts assert then the lowest interrupt number will be + serviced first, for example, if interrupt 1 and 6 assert at the same time, + interrupt 1 will be serviced first, followed by interrupt 6. + +*/ + +#ifndef MIV_PLIC_H_ +#define MIV_PLIC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "miv_plic_regs.h" + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#include "miv_rv32_hal/miv_rv32_hal.h" +#else +#include "hal.h" +#include "miv_rv32_hal.h" +#endif + +/*-------------------------------------------------------------------------*//** + This enumeration is used to select a specific Mi-V PLIC interrupt. It is + used as a parameter to enable or disable the interrupt. +*/ +typedef enum miv_plic_irq_num +{ + NoInterrupt_IRQn = 0, + MIV_PLIC_EXT0_IRQn = 1, + MIV_PLIC_EXT1_IRQn = 2, + MIV_PLIC_EXT2_IRQn = 3, + MIV_PLIC_EXT3_IRQn = 4, + MIV_PLIC_EXT4_IRQn = 5, + MIV_PLIC_EXT5_IRQn = 6, + MIV_PLIC_EXT6_IRQn = 7, + MIV_PLIC_EXT7_IRQn = 8, + MIV_PLIC_EXT8_IRQn = 9, + MIV_PLIC_EXT9_IRQn = 10, + MIV_PLIC_EXT10_IRQn = 11, + MIV_PLIC_EXT11_IRQn = 12, + MIV_PLIC_EXT12_IRQn = 13, + MIV_PLIC_EXT13_IRQn = 14, + MIV_PLIC_EXT14_IRQn = 15, + MIV_PLIC_EXT15_IRQn = 16, + MIV_PLIC_EXT16_IRQn = 17, + MIV_PLIC_EXT17_IRQn = 18, + MIV_PLIC_EXT18_IRQn = 19, + MIV_PLIC_EXT19_IRQn = 20, + MIV_PLIC_EXT20_IRQn = 21, + MIV_PLIC_EXT21_IRQn = 22, + MIV_PLIC_EXT22_IRQn = 23, + MIV_PLIC_EXT23_IRQn = 24, + MIV_PLIC_EXT24_IRQn = 25, + MIV_PLIC_EXT25_IRQn = 26, + MIV_PLIC_EXT26_IRQn = 27, + MIV_PLIC_EXT27_IRQn = 28, + MIV_PLIC_EXT28_IRQn = 29, + MIV_PLIC_EXT29_IRQn = 30, + MIV_PLIC_EXT30_IRQn = 31 +} miv_plic_irq_num_t; + +/*--------------------------------------------------------------------------*//* + * This structure maps the priority threshold and claim complete register in + * the memory. + */ +typedef struct +{ + volatile uint32_t PRIORITY_THRESHOLD; + volatile uint32_t CLAIM_COMPLETE; + volatile uint32_t reserved[1022]; +} IRQ_Target_Type; + +/*--------------------------------------------------------------------------*//* + * This structure maps the Interrupt enable sources from 0 - 1023 for one + * context. + */ +typedef struct +{ + volatile uint32_t ENABLES[32]; +} Target_Enables_Type; + +/*-------------------------------------------------------------------------*//** + This structure holds the base address of the Mi-V PLIC module. This structure + is used by all the functions to access the Mi-V PLIC registers. +*/ +typedef struct miv_plic_instance +{ + addr_t base_addr; +} miv_plic_instance_t; + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_isr is the top level interrupt handler function for the Mi-V PLIC + * driver. You must call the MIV_PLIC_isr() from the system level interrupt + * handler(External_IRQHandler). + * This function must be called from the external interrupt handler function + * provided by the processor hardware abstraction layer. In case of MIV_RV32 + * soft processor, it must be called from External_IRQHandler() function + * provided by MIV_RV32 HAL. + * + * The MIV_PLIC_isr() function claims the interrupt number + * that triggered the interrupt and then invokes the appropriate PLIC interrupt + * handler. + * After handling the PLIC interrupt, this function will complete the interrupt + * by clearing the claim complete bit for the particular interrupt source. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * + * @return + * This function does not return any value. + * + * Example: + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * uint8_t MIV_PLIC_EXT0_IRQHandler(void) + * { + * *** ISR operation *** + * + * return(EXT_IRQ_KEEP_ENABLED); + * } + * + * void External_IRQHandler(void) + * { + * uint32_t reg_val = read_csr(mip); + * MIV_PLIC_isr(&g_plic); + * } + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * } + * @endcode + */ +void MIV_PLIC_isr(miv_plic_instance_t *this_plic); + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_init() function initializes the Mi-V PLIC instance with base + * address. This function resets the PLIC controller by disabling all the PLIC + * interrupts. + * + * Note: This function must be called before calling any other Mi-V PLIC driver + * function. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * + * @param base_addr + * Base address of the Mi-V PLIC instance in the MIV_ESS soft-IP. + * + * @param ext_intr_sources + * Number of interrupts initialized in the design. + * + * @return + * This function does not return any value. + * + * Example + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * } + * @endcode + */ +static inline void +MIV_PLIC_init +( + miv_plic_instance_t *this_plic, + addr_t base_addr, + uint8_t ext_intr_sources +) +{ + uint32_t inc; + unsigned long hart_id = read_csr(mhartid); + + this_plic->base_addr = base_addr; + + /* Disable all interrupts for the current hart. + * The PLIC_EXT_INTR_SOURCES should be defined in the hw_platform.h. This + * macro holds the number of PLIC interrupts enabled in the design. + */ + for(inc = 0; inc < ((ext_intr_sources + 32u) / 32u); ++inc) + { + HAL_set_32bit_reg( + (this_plic->base_addr + inc + (hart_id * 128)), INT_ENABLE , 0x0u); + } +} + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_enable_irq() function enables the PLIC interrupt provided with + * IRQn parameter. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * @param IRQn + * Number of PLIC interrupt to enable. + * + * @return + * This function does not return any value. + * + * Example + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * } + * @endcode + */ +static inline void +MIV_PLIC_enable_irq +( + miv_plic_instance_t *this_plic, + miv_plic_irq_num_t IRQn +) +{ + unsigned long hart_id = read_csr(mhartid); + + uint32_t current = HAL_get_32bit_reg( + (this_plic->base_addr + (IRQn/32) + (hart_id * 128)) , INT_ENABLE); + + current |= (uint32_t)1 << (IRQn % 32); + + HAL_set_32bit_reg( + (this_plic->base_addr + (IRQn/32) + (hart_id * 128)), INT_ENABLE, current); + +} + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_disable_irq() function disables the PLIC interrupt provided with + * IRQn parameter. + * + * NOTE: + * This function can be used to disable the PLIC interrupt from outside the + * external interrupt handler functions. + * If you wish to disable the PLIC interrupt from the external interrupt handler, + * you should use the return value of EXT_IRQ_DISABLE. This will disable the + * selected PLIC interrupt from the Mi-V PLIC driver interrupt handler. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * @param IRQn + * Number of PLIC interrupt to disable. + * + * @return + * This function does not return any value. + * + * Example + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * } + * @endcode + */ +static inline void +MIV_PLIC_disable_irq +( + miv_plic_instance_t *this_plic, + miv_plic_irq_num_t IRQn +) +{ + unsigned long hart_id = read_csr(mhartid); + + uint32_t current = HAL_get_32bit_reg((this_plic->base_addr + (IRQn/32) + (hart_id * 128)) , INT_ENABLE); + + current &= ~((uint32_t)1 << (IRQn % 32)); + + HAL_set_32bit_reg((this_plic->base_addr + (IRQn/32) + (hart_id * 128)), INT_ENABLE, current); + +} + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_PLIC_H_ */ diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_plic/miv_plic_regs.h b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_plic/miv_plic_regs.h new file mode 100644 index 0000000..76cbc0b --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_plic/miv_plic_regs.h @@ -0,0 +1,31 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP PLIC module driver. This module is delivered as a part of Mi-V extended + * Sub-System(MIV_ESS). + */ + +#ifndef MIV_PLIC_REGISTERS +#define MIV_PLIC_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Interrupt pending register offset */ +#define INT_PENDING_REG_OFFSET 0x1000u + +/* Interrupt enable register */ +#define INT_ENABLE_REG_OFFSET 0x2000u + +/* Interrupt claim complete register */ +#define INT_CLAIM_COMPLETE_REG_OFFSET 0x200004u + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_PLIC_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_timer/miv_timer.h b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_timer/miv_timer.h new file mode 100644 index 0000000..5f00889 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_timer/miv_timer.h @@ -0,0 +1,329 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Mi-V Timer Soft IP bare-metal driver. This module is delivered as part of + * the Mi-V Extended Sub System(ESS) MIV_ESS. + */ + +/*=========================================================================*//** + @mainpage Mi-V Timer Bare Metal Driver. + The Mi-V Timer bare metal software driver supports the timer module which + serves as a system timer for the Mi-V Extended Sub System(ESS). + + @section intro_sec Introduction + The MI-V Timer driver supports set of functions for controlling the Mi-V + Timer module. + The Mi-V Timer can generate a timer interrupt signal for the system based on + special system clock intervals specified by the parameters that can be passed + in by the user. + + The major features provided by Mi-V Timer driver are: + - Support for Mi-V Timer instance for each Mi-V Timer peripheral. + - Read current time + - Write to the machine time compare register + + @section hw_dependencies Hardware Flow dependency + The application should configure the Mi-V Timer driver through calls to + MIV_TIMER_init() functions for each MIV_TIMER instance in the hardware + design. The configuration parameter include the MIV_TIMER hardware instance, + base address and number of ticks to generate timer interrupt. + + MIV_RV32 core offers flexibility in terms of generating the MTIME and MTIMECMP + registers internal to the core or using external time reference. + When MIV_ESS is interfaced with MIV_RV32 core, the timer module in the MIV_ESS + can be configured as follows: + - Internal MTIME External MTIME IRQ + Generate the MTIME internally(MIV_RV32) and have a timer interrupt input + to the core as external pin(from MIV_ESS). + + - External MTIME Internal MTIME IRQ + Generate the time value externally(from MIV_ESS), in this case a 64-bit + port will open in the MIV_RV32 core as input and MIV_ESS will output the + 64-bit TIME_COUNT value. The generation of mtimecmp and interrupt is + done internally(MIV_RV32). + + - External MTIME External MTIME IRQ + Generate both the time and timer interrupt externally. + In this case 64-bit port will be available on the Mi-V RV32 core as input + and a 1 pin port will be available for timer interrupt. + + The design must be configured accordingly to use these combinations in the + firmware. + + No MIV_TIMER hardware configuration parameters are used by the driver, apart + from MIV_TIMER base address. Hence, no additional configuration files are + required to use the driver. + + @section theory_op Theory of Operation + + The MIV_TIMER module is a simple systick timer which can generate a timer + interrupt signal for the system at specific intervals specified by the + parameters that can be passed by the user. + These interrupt signal are then fed to the MIV_RV32 core via timer interrupt. + + The operation of MIV_TIMER is divided into following steps: + - Initialization + - Configuration + - Read/Write TIME + + ## Initialization + The MIV_TIMER is first initialized by a call to MIV_TIMER_init(). This + function initializes the instance of Mi-V TIMER with the base address. + The MIV_TIMER_init() function must be called before any other Mi-V Timer driver + function. + + ## Configuration + The Mi-V TIMER configuration includes writing the mtimecmp register with the + initial time value at which timer interrupt should be generated. + When the mtime register value becomes greater than or equal to mtimecmp value, + a timer interrupt signal(TIMER_IRQ) is generated. + + ## Read/Write TIME + The time value can be read by reading the mtime register via call to the + MIV_TIMER_read_mtime(). This function reads the MTIME register which contains + the 64-bit value of the timer count. The count increments by 1 every time the + prescale ticks. This function returns 64-bit MTIME_COUNT value which is the + current value of timer count. + + The time value read in the MIV_TIMER_read_mtime() function can be written to + the mtimecmp register by calling MIV_TIMER_write_mtimecmp() to generate + periodic interrupts. + The writing of the mtimecmp register should be done in the systick_handler() + function. + */ + +#ifndef MIV_TIMER_H_ +#define MIV_TIMER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#endif +/*-------------------------------------------------------------------------*//** +MIV_TIMER_SUCCESS +===================== + +The MIV_TIMER_SUCCESS constant indicates successful configuration of +Mi-V Timer module. +*/ +#define MIV_TIMER_SUCCESS 0u + +/*-------------------------------------------------------------------------*//** +MIV_TIMER_ERROR +===================== + +The MIV_TIMER_ERROR constant indicates that there is an error with +configuring the Mi-V Timer module. +*/ +#define MIV_TIMER_ERROR 1u + +/*-------------------------------------------------------------------------*//* +MIV_TIMER_MASK_32BIT +===================== + +32-bit mask constant used in calculation of 64-bit register value. +*/ +#define MIV_TIMER_MASK_32BIT 0xFFFFFFFFu + +/*-------------------------------------------------------------------------*//* +Mi-V Timer register offsets +===================== +The MTIMECMP is the 64-bit timer compare register, it pre-sets the threshold +which needs to be reached by the timer count register. +This 64-bit register is accessed with 2 32-bit address offset, lower 32-bits +and higher 32-bits. + - MIV_TIMER_MTIMECMP_L_REG_OFFSET + - MIV_TIMER_MTIMECMP_H_REG_OFFSET + +The MTIME is the 64-bit register that contains the 64-bit timer count. The +count increments by 1 every time the prescaler ticks. +This 64-bit register is accessed with 2 32-bit address offset, lower 32-bits +and higher 32-bits. + - MIV_TIMER_MTIME_L_REG_OFFSET + - MIV_TIMER_MTIME_H_REG_OFFSET + +The PRESCALE register is used to determine the amount of clock cycles the +selected clock needs to go through, for MTIME register to increment count. + - MIV_TIMER_PRESCALAR_REG_OFFSET +*/ + +/// @cond private +#define MIV_TIMER_MTIMECMP_L_REG_OFFSET 0x4000u +#define MIV_TIMER_MTIMECMP_H_REG_OFFSET 0x4004u + +#define MIV_TIMER_MTIME_L_REG_OFFSET 0xBFF8u +#define MIV_TIMER_MTIME_H_REG_OFFSET 0xBFFCu + +#define MIV_TIMER_PRESCALAR_REG_OFFSET 0x5000u +/// @endcond + +/*-------------------------------------------------------------------------*//** + This structure holds the base address of the Mi-V Timer module and instance + of the Mi-V Timer register structure. +*/ +typedef struct miv_timer_instance +{ + addr_t base_addr; +} miv_timer_instance_t; + +/** The MIV_TIMER_init() is used to initialize the Mi-V Timer module. This + function will assign the base addresses of the Mi-V Timer module. + User should call this function before calling any of the Mi-V Timer driver + APIs. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @param base_address + Base address of the Mi-V Timer module. + + @return + This function does not return any value. + */ +static inline void +MIV_TIMER_init +( + miv_timer_instance_t* this_timer, + addr_t base_addr +) +{ + this_timer->base_addr = base_addr; +} + +/** MIV_TIMER_read_current_time() is used to read the mtimecmp register values. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @return + This function returns 64-bit mtimecmp register value. + */ +static inline uint64_t +MIV_TIMER_read_current_time +( + miv_timer_instance_t* this_timer +) +{ + volatile uint64_t read_data = 0u; + volatile uint32_t mtime_hi = 0u; + volatile uint32_t mtime_lo = 0u; + + /* when mtime lower word is 0xFFFFFFFF, there will be rollover and + * returned value could be wrong. */ + do { + mtime_hi = HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIME_H); + mtime_lo = HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIME_L); + + } while(mtime_hi != HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIME_H)); + + read_data = mtime_hi; + + return(((read_data) << 32u) | mtime_lo); +} + +/** MIV_TIMER_write_compare_time() is used to write to the MTIMECMP register in + the event of interrupt. User must use this function in the interrupt handler + to de-assert the MIV_TIMER interrupt. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @param write_value + Value to write into the mtimecmp register. + + @return + This function does not return any value. + */ +static inline void +MIV_TIMER_write_compare_time +( + miv_timer_instance_t* this_timer, + uint64_t compare_reg_value +) +{ + HAL_set_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIMECMP_H, MIV_TIMER_MASK_32BIT); + + HAL_set_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIMECMP_L, + (compare_reg_value & MIV_TIMER_MASK_32BIT)); + + HAL_set_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIMECMP_H, + ((compare_reg_value >> 32u) & MIV_TIMER_MASK_32BIT)); +} + +/** The MIV_TIMER_config() is used to configure the MIV_ESS Timer module. The + prescale value serves to divide the count of clock cycles for the timer and + provides control over what point in time, the timer interrupt gets + asserted. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @param ticks + Number of ticks after which interrupt will be generated. + + @return + This function returns Mi-V Timer configuration status. + */ +static inline uint32_t +MIV_TIMER_config +( + miv_timer_instance_t* this_timer, + uint64_t ticks +) +{ + uint32_t ret_val = MIV_TIMER_ERROR; + uint64_t mtime_val = 0u; + uint32_t prescalar = 0u; + uint64_t miv_timer_increment = 0U; + + prescalar = HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_PRESCALAR); + + miv_timer_increment = (uint64_t)(ticks) / prescalar; + + if (miv_timer_increment > 0U) + { + mtime_val = MIV_TIMER_read_current_time(this_timer); + + MIV_TIMER_write_compare_time(this_timer ,(mtime_val + miv_timer_increment)); + + ret_val = MIV_TIMER_SUCCESS; + } + + return ret_val; +} + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_TIMER_H */ diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c new file mode 100644 index 0000000..cbd9652 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c @@ -0,0 +1,109 @@ +/******************************************************************************* + * (c) Copyright 2022-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Mi-V uDMA Soft IP bare-metal driver. This module is delivered as part of + * Mi-V Extended Sub System(MIV_ESS) + */ + +#include "miv_udma_regs.h" +#include "miv_udma.h" + +/***************************************************************************//** + * MIV_uDMA_init() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_init +( + miv_udma_instance_t* this_udma, + addr_t base_addr +) +{ + /* Assign the Mi-V uDMA base address to the uDMA instance structure */ + this_udma->base_address = base_addr; +} + +/***************************************************************************//** + * MIV_uDMA_config() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_config +( + miv_udma_instance_t* this_udma, + addr_t src_addr, + addr_t dest_addr, + uint32_t transfer_size, + uint32_t irq_config +) +{ + /* Source memory start address */ + HAL_set_32bit_reg(this_udma->base_address, SRC_START_ADDR, src_addr); + + /* Destination memory start address */ + HAL_set_32bit_reg(this_udma->base_address, DEST_START_ADDR, dest_addr); + + /* Data transfer size */ + HAL_set_32bit_reg(this_udma->base_address, BLK_SIZE, transfer_size); + + /* Configure the uDMA IRQ */ + HAL_set_32bit_reg(this_udma->base_address, IRQ_CFG, irq_config); +} + +/***************************************************************************//** + * MIV_uDMA_start() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_start +( + miv_udma_instance_t* this_udma +) +{ + /* Start the uDMA transfer */ + HAL_set_32bit_reg(this_udma->base_address, CONTROL_SR, CTRL_START_TX_MASK); +} + +/***************************************************************************//** + * MIV_uDMA_reset() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_reset +( + miv_udma_instance_t* this_udma +) +{ + /* Toggle the uDMA_reset bit to reset the uDMA. + * Resetting the uDMA will clear all the configuration made by + * MIV_uDMA_config(). + * + * This function should be called from the interrupt handler to clear the + * IRQ. + */ + HAL_set_32bit_reg_field(this_udma->base_address, CTRL_RESET_TX, 0x1u); + HAL_set_32bit_reg_field(this_udma->base_address, CTRL_RESET_TX, 0x0u); +} + +/***************************************************************************//** + * MIV_uDMA_read_status() + * See "miv_udma.h" for details of how to use this function. + */ +uint32_t +MIV_uDMA_read_status +( + miv_udma_instance_t* this_udma +) +{ + uint32_t status = 0u; + + /* Read the status of the uDMA transfer. + * The transfer status register can be Error or Busy depending on the + * current uDMA transfer. + */ + status = HAL_get_32bit_reg(this_udma->base_address, TX_STATUS); + + return status; +} diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h new file mode 100644 index 0000000..efa8731 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h @@ -0,0 +1,290 @@ +/******************************************************************************* + * Copyright 2022-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * uDMA module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(MIV_ESS). + */ + +/*=========================================================================*//** + @mainpage Mi-V uDMA Bare Metal Driver. + The Mi-V uDMA bare metal software driver. + + @section intro_sec Introduction + The Mi-V uDMA driver provides a set of functions to control the Mi-V uDMA + module in the Mi-V Extended Subsystem (MIV_ESS) soft-IP. The Mi-V uDMA module + allows peripherals with AHB interfaces to transfer data independently of the + MIV_RV32 RISC-V processor. + + Following are the major features provided by the Mi-V uDMA driver: + - Initialization and configuration + - Start and reset the transaction + + This driver can be used as part of a bare metal system where no operating + system is available. The driver can be adapted for use as part of an + operating system, but the implementation of the adaptation layer between the + driver and the operating system's driver model is outside the scope of this + driver. + + @section hw_dependencies Hardware Flow Dependency + The application software should initialize and configure the Mi-V uDMA through + calling the MIV_uDMA_init() and MIV_uDMA_config() functions for each Mi-V + uDMA instance in the design. + + The uDMA can operate in two possible transfer configurations: + + - AHBL Read -> AHBL Write: + In this configuration, the uDMA reads data from the source memory over an + AHBL (mirrored main/initiator) read interface and writes data to the + destination memory over an AHBL (mirrored main/initiator) write interface. + + - AHBL Read -> TAS Write: + In this configuration, the uDMA reads data from the source memory over an + AHBL (mirrored main/initiator) read interface and writes data to the + destination memory over the TAS (mirrored main/initiator) write interface. + + Note: The AHBL Read -> TAS Write configuration is out of scope for this + driver. + + @section theory_op Theory of Operation + The uDMA module in the Mi-V Extended Sub System (MIV_ESS) is a single-channel + uDMA module that allows peripherals to perform read-write operations between + source and destination memory. The Mi-V uDMA driver is used in + interrupt-driven mode and uses the Mi-V uDMA IRQ signal to drive the + interrupt service routine (ISR), which signifies a transfer has completed. + The status is checked in the ISR to ensure the transfer is completed + successfully. + The reset operation in the ISR resets the Mi-V uDMA controller. Once the Mi-V + uDMA transfer is complete, Mi-V uDMA retires. To initiate another + transaction, Mi-V uDMA needs to be configured again. + + The operation of the Mi-V uDMA driver is divided into the following + categories: + - Initialization + - Configuration + - Start and reset the transfer + + Initialization and configuration: + Mi-V uDMA is first initialized by calling MIV_uDMA_init() function. This + function initializes the instance of Mi-V uDMA with the base address. The + MIV_uDMA_init() function must be called before calling any other Mi-V uDMA + driver functions. + + The Mi-V uDMA is configured by calling MIV_uDMA_config() function. This + function configures the source_addr and dest_addr registers of the Mi-V + uDMA with source and destination addresses for Mi-V uDMA transfers. + This function also configures the transfer size and interrupt preference for + successful transfers using Mi-V uDMA. + + Start and reset the transfer: + Once the Mi-V uDMA is configured, initiate the transfers by calling the + MIV_uDMA_start() function. Once the Mi-V uDMA transfer is started, it cannot + be aborted, and the status of the transfer should be read from the ISR by + calling the MIV_uDMA_read_status() function. + + Reset the Mi-V uDMA to the default state by calling the MIV_uDMA_reset() + function. After performing the reset operation, reconfigure the Mi-V uDMA to + perform transfers as MIV_uDMA_reset() resets the Mi-V uDMA controller. + */ + +#ifndef MIV_uDMA_H_ +#define MIV_uDMA_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#include "hal/cpu_types.h" + +#else +#include "hal.h" +#include "cpu_types.h" +#endif + +/*-------------------------------------------------------------------------*//** + MIV_uDMA_CTRL_IRQ_CONFIG + ===================== + + The MIV_uDMA_CTRL_IRQ_CONFIG macro is used to assert the uDMA IRQ when an error + occurs during a uDMA transfer or on the completion of a uDMA transfer. + */ +#define MIV_uDMA_CTRL_IRQ_CONFIG 1u + +/*-------------------------------------------------------------------------*//** + MIV_uDMA_STATUS_BUSY + ===================== + + The MIV_uDMA_STATUS_BUSY macro is used to indicate that the uDMA transfer is + in progress. + */ +#define MIV_uDMA_STATUS_BUSY 1u + +/*-------------------------------------------------------------------------*//** + MIV_uDMA_STATUS_ERROR + ===================== + + The MIV_uDMA_STATUS_ERROR macro is used to indicate that the last uDMA + transfer has caused an error. + */ +#define MIV_uDMA_STATUS_ERROR 2u + +/***************************************************************************//** + * This structure holds the base of the Mi-V uDMA module, which is used in the + * other functions of the driver to access the uDMA registers. + */ +typedef struct miv_udma_instance +{ + addr_t base_address; +} miv_udma_instance_t; + +/***************************************************************************//** + * The MIV_uDMA_init() function assigns the base address of the Mi-V uDMA module + * to the uDMA instance structure. + * This address is used in a later part of the driver to access the uDMA + * registers. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure. + * + * @param base_addr + * Base address of the Mi-V uDMA module. + * + * @return + * This function does not return a value. + */ +void +MIV_uDMA_init +( + miv_udma_instance_t* this_udma, + addr_t base_addr +); + +/***************************************************************************//** + * The MIV_uDMA_config() function is used to configure the Mi-V uDMA controller. + * This function will set the source address, destination address, block size, + * and IRQ configuration register. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @param base_addr + * Base address of the Mi-V uDMA. + * + * @param src_addr + * Source address of memory from where the uDMA reads the data. + * + * @param dest_addr + * Destination address where the data is written from src_addr. + * + * @param transfer_size + * Number of 32-bit words to transfer. + * + * @param irq_config + * uDMA IRQ configuration + * - When set, the IRQ is asserted when an error occurs during a uDMA + * transfer or on the completion of the uDMA transfer. + * - When clear, the IRQ is only asserted when an error occurs during a + * uDMA transfer. + * + * @return + * This function does not return any value. + */ +void +MIV_uDMA_config +( + miv_udma_instance_t* this_udma, + addr_t src_addr, + addr_t dest_addr, + uint32_t transfer_size, + uint32_t irq_config +); + +/***************************************************************************//** + * The MIV_uDMA_start() function is used to start the uDMA transfer. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @return + * This function does not return any value. + */ +void +MIV_uDMA_start +( + miv_udma_instance_t* this_udma +); + +/***************************************************************************//** + * The MIV_uDMA_reset() function is used to clear the uDMA interrupt and reset + * the uDMA transfer. + * + * This function should be called from the interrupt handler to reset the values + * set during MIV_uDMA_config(). + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @return + * This function does not return any value. + */ +void +MIV_uDMA_reset +( + miv_udma_instance_t* this_udma +); + +/***************************************************************************//** + * The MIV_uDMA_read_status() function is used to read the status of the uDMA + * transfer. When interrupt is enabled, this function can be called from the + * interrupt handler to know the reason for a uDMA interrupt. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @return + * The return value indicates an error due to the busy status of the uDMA + * channel. + * + * |Bit Number| Name | Description | + * |----------|---------|------------------------------------------------------| + * | 0 | Busy | When set indicates that uDMA transfer is in progress| + * | 1 | Error | When set indicates that last uDMA transfer caused an| + * | | | error. | + */ +uint32_t +MIV_uDMA_read_status +( + miv_udma_instance_t* this_pdma +); + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_uDMA_H_ */ diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h new file mode 100644 index 0000000..14d0759 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h @@ -0,0 +1,94 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP uDMA module driver. This module is delivered as a part of Mi-V + * extended Sub-System(ESS) MIV_ESS. + */ + +#ifndef MIV_UDMA_APB_REGISTERS +#define MIV_UDMA_APB_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/**************************************************************************//** + * Control start/Reset register details + */ + +#define CONTROL_SR_REG_OFFSET 0x0u + +/* Control start/Reset register bits */ +#define CONTROL_SR_OFFSET 0x00u +#define CONTROL_SR_MASK 0x03u +#define CONTROL_SR_SHIFT 0u + +/* uDMA Control Start Transfer */ + +#define CTRL_START_TX_OFFSET 0x00u +#define CTRL_START_TX_MASK 0x01u +#define CTRL_START_TX_SHIFT 0u + +/* uDMA Control Reset Transfer */ +#define CTRL_RESET_TX_OFFSET 0x00u +#define CTRL_RESET_TX_MASK 0x02u +#define CTRL_RESET_TX_SHIFT 1u + +/**************************************************************************//** + * IRQ Configuration register details + */ +#define IRQ_CFG_REG_OFFSET 0x4u + +/* Control start/Reset register bits */ +#define IRQ_CFG_OFFSET 0x04u +#define IRQ_CFG_MASK 0x01u +#define IRQ_CFG_SHIFT 0u + +/***************************************************************************//** + * Transfer Status register details + */ +#define TX_STATUS_REG_OFFSET 0x08u + +/* Transfer status register bits */ +#define TX_STATUS_OFFSET 0x08u +#define TX_STATUS_MASK 0x03u +#define TX_STATUS_SHIFT 0u + +/***************************************************************************//** + * Source Memory Start Address Register + */ +#define SRC_START_ADDR_REG_OFFSET 0x0cu + +/* Source Memory Start Address Register bits */ +#define SRC_START_ADDR_OFFSET 0x0cu +#define SRC_START_ADDR_MASK 0xFFFFFFFFu +#define SRC_START_ADDR_SHIFT 0u + +/***************************************************************************//** + * Destination Memory Start Address register details + */ +#define DEST_START_ADDR_REG_OFFSET 0x10u + +/* Destination Memory Start Address register bits */ +#define DEST_START_ADDR_OFFSET 0x10u +#define DEST_START_ADDR_MASK 0xFFFFFFFFu +#define DEST_START_ADDR_SHIFT 0x0u + +/***************************************************************************//** + * Block Size register details + */ +#define BLK_SIZE_REG_OFFSET 0x14u + +/* Destination Memory Start Address register bits */ +#define BLK_SIZE_OFFSET 0x14u +#define BLK_SIZE_MASK 0xFFFFFFFFu +#define BLK_SIZE_SHIFT 0x0u + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_UDMA_APB_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c new file mode 100644 index 0000000..525928a --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Mi-V Watchdog Soft IP bare-metal driver. This module is delivered as part of + * Extended Sub System(ESS) MIV_ESS. + * Please refer to miv_watchdog.h file for more information. + */ + +#include "miv_watchdog.h" + +addr_t g_this_wdog; + +/***************************************************************************//* + * Please refer to miv_watchdog.h for more info about this function + */ +void +MIV_WDOG_init +( + addr_t base_addr +) +{ + /* Register the Mi-V Watchdog base address to the driver */ + g_this_wdog = base_addr; +} + +/***************************************************************************//* + * Please refer to miv_watchdog.h for more info about this function + */ +uint8_t MIV_WDOG_configure +( + const miv_wdog_config_t *config +) +{ + uint8_t error = 0u; + + /* check load value and trigger max value */ + if (config->timeout_val <= MIV_WDOG_TRIGGER_MAX) + { + HAL_set_32bit_reg(g_this_wdog, WDOGTRIG,(config->timeout_val)); + } + else + { + error = 1u; + } + + if (config->time_val <= MIV_WDOG_TIMER_MAX) + { + HAL_set_32bit_reg(g_this_wdog, WDOGMSVP,(config->mvrp_val)); + } + else + { + error = 1u; + } + + HAL_set_32bit_reg_field(g_this_wdog, WDOGCNTL_NEXT_ENFORBIDDEN, + config->forbidden_en); + + /* Reload watchdog with new load if it is not in forbidden window */ + if (!(WDOGSTAT_FORBIDDEN_MASK & (HAL_get_32bit_reg(g_this_wdog, WDOGSTAT)))) + { + HAL_set_32bit_reg(g_this_wdog, WDOGRFSH, MIV_WDOG_REFRESH_KEY); + } + else + { + error = 1u; + } + + return (error); +} + +/***************************************************************************//* + * Please refer to miv_watchdog.h for more info about this function + */ +void MIV_WDOG_get_config +( + miv_wdog_config_t *config +) +{ + if (0 != g_this_wdog) + { + + config->time_val = HAL_get_32bit_reg(g_this_wdog, WDOGTIME); + + config->timeout_val = HAL_get_32bit_reg(g_this_wdog, WDOGTRIG); + + config->mvrp_val = HAL_get_32bit_reg(g_this_wdog, WDOGMSVP); + + config->forbidden_en = HAL_get_32bit_reg_field(g_this_wdog, + WDOGCNTL_NEXT_ENFORBIDDEN); + } +} + diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h new file mode 100644 index 0000000..8877e55 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h @@ -0,0 +1,553 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * Watchdog module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(MIV_ESS). + */ +/*=========================================================================*//** + @mainpage MiV Watchdog Bare Metal Driver + + ============================================================================== + Introduction + ============================================================================== + The Mi-V Watchdog module in the MIV_ESS is used to generate a reset for the + system automatically if the software doesn't periodically update or refresh + the timer countdown register. This software driver provides set of functions + for controlling Mi-V Watchdog module as a part of bare metal system where no + operating system is available. The driver can be adapted for use as a part of + an operating system, but the implementation of the adaptation layer between + the driver and the operating system's driver model is outside the scope of the + driver. + + Mi-V Watchdog provides following features: + - Initializing the Mi-V Watchdog + - Reading current value and status of watchdog timer + - Refreshing the watchdog timer value + - Enabling, disabling and clearing timeout and Maximum Value up to which + Refresh is Permitted (MVRP) interrupts. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + The application software should initialize and configure the Mi-V Watchdog + module the the call to the MIV_WDOG_init() and MIV_WDOG_configure() functions. + + No MIV_WDOG hardware configuration parameter are used by the driver, apart + from the MIV_WDOG base address. Hence, no additional configuration files are + required to use the driver. + + ============================================================================== + Theory of Operation + ============================================================================== + The Mi-V Watchdog driver functions are grouped into the following categories: + - Initialization and configuration + - Reading the current value and status of the watchdog timer + - Refreshing the watchdog timer value + - Support for enabling, disabling and clearing time-out and MVRP interrupts. + + -------------------------------- + Initialization and Configuration + -------------------------------- + The MIV_WDOG_init() function stores the base of MIV_WDT module in the MIV_ESS. + This base address is used by rest of the functions to access the Mi-V Watchdog + registers. Please make call this function before calling any other function + from this driver. + Note: The Mi-V Watchdog driver supports only one instance of MIV_WDT in the + hardware. + The Mi-V Watchdog driver provides the MIV_WDOG_configure() function to + configure the MIV_WDOG module with desired configuration values. It also + provides the MIV_WDOG_get_config() to read back the current configuration of + the MIV_WDOG. You can use this function to retrieve the current configurations + and then overwrite them with the application specific values, such as initial + watchdog timer value, Maximum Value (up to which) Refresh (is) Permitted, + watchdog time-out value, enable/disable forbidden region, enable/disable + MVRP interrupt and interrupt type. + + -------------------------------------------- + Reading the Watchdog Timer Value and Status + -------------------------------------------- + Mi-V Watchdog is a down counter. A refresh forbidden window can be created by + configuring the watchdog Maximum Value up to which Refresh is Permitted (MVRP). + When the current value of the watchdog timer is greater than the MVRP value, + refreshing the watchdog is forbidden. Attempting to refresh the watchdog timer + in the forbidden window will assert a timeout interrupt. The + MIV_WDOG_forbidden_status() function can be used to know whether the watchdog + timer is in forbidden window or has crossed it. By default, the forbidden + window is disabled. It can be enabled by providing an appropriate value as + parameter to the MIV_WDOG_configure() function. When the forbidden window is + disabled, any attempt to refresh the watchdog timer is ignored and the counter + keeps on down counting. + + The current value of the watchdog timer can be read using the + MIV_WDOG_current_value() function. This function can be called at any time. + + -------------------------------------------- + Refreshing the Watchdog Timer Value + -------------------------------------------- + The watchdog timer value is refreshed using the MIV_WDOG_reload() function. + The value reloaded into the watchdog timer down-counter is specified at the + configuration time with an appropriate value as parameter to the + MIV_WDOG_get_config() function. + + -------------------------------------------- + Interrupt Control + -------------------------------------------- + The Mi-V Watchdog generates two interrupts, The MVRP interrupt and + the timeout interrupt. + The MVRP interrupt is generated when the watchdog down-counter crosses the + Maximum Value up to which Refresh is Permitted (MVRP). Following functions to + control MVRP interrupt: + - MIV_WDOG_enable_mvrp_irq + - MIV_WDOG_disable_mvrp_irq + - MIV_WDOG_clear_mvrp_irq + + The timeout interrupt is generated when the watchdog down-counter crosses the + watchdog timeout value. The timeout value is a non-zero value and it can be + set to a maximum of MIV_WDOG_TRIGGER_MAX. The non-maskable interrupt is + generated when the watchdog crosses this timeout value, the down counter + keeps on down counting and a reset signal is generated when reaches zero. + Following functions to control timeout interrupt: + - MIV_WDOG_enable_timeout_irq + - MIV_WDOG_disable_timeout_irq + - MIV_WDOG_clear_timeout_irq + +*//*=========================================================================*/ + +#ifndef MIV_WATCHDOG_H_ +#define MIV_WATCHDOG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "miv_watchdog_regs.h" + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#else +#include "hal.h" +#endif + +/****************************************************************************//* + * The following constants can be used to configure the Mi-V Watchdog where a + * zero or non-zero value such as enable or disable is to be provided as a input + * parameter as shown below: + */ +#define MIV_WDOG_ENABLE 1u +#define MIV_WDOG_DISABLE 0u + +/***************************************************************************//** + The miv_wdog_config_t type for the watchdog Configuration structure. This + type is used as a parameter for the MIV_WDOG_configure() and the + MIV_WDOG_get_config() functions. + + Following are the values as part of this structure +| Parameter | Description | +|------------------|-----------------------------------------------------------| +| time_val | The value from which the watchdog timer counts down | +| mvrp_val | The Watchdog MVRP value | +| timeout_val | The watchdog timeout value | +| forbidden_en | Enable/disable the forbidden window | +| | When set, if a refresh occurs in the forbidden window, | +| | the watchdog timeout interrupt will be generated. | + +Time calculation example: + + time_val = 0xFFFFF0u + mvrp_val = 0x989680u + timeout_val = 0x3e8u + + A prescaler = 256 is used. + Considering clock = 50Mhz + + The MVRP interrupt will happen after + (0xFFFFF0 - 0x989680) * ( 1/(50MHz/256)) + mvrp interrupt will happen after 34 sec. after system reset + + (0xFFFFF0 - 0x3e8) * ( 1/(50MHz/256)) + timeout interrupt will happen after 85 sec. after system reset + */ +typedef struct miv_wdog_config +{ + uint32_t time_val; + uint32_t mvrp_val; + uint32_t timeout_val; + uint32_t forbidden_en; + uint32_t intr_type; +}miv_wdog_config_t; + +extern addr_t g_this_wdog; + +/***************************************************************************//* + Internal constants and types +*******************************************************************************/ + +/// @cond private +#define MIV_WDOG_TRIGGER_MAX 4095u +#define MIV_WDOG_TIMER_MAX 16777200u +/// @endcond + +/*-------------------------------------------------------------------------*//* +MIV_WDOG_REFRESH_KEY +===================== + +The MIV_WDOG_REFRESH_KEY macro holds the magic value which will cause a +reload of the watchdog's down counter when written to the watchdog's +WDOGREFRESH register. +*/ +#define MIV_WDOG_REFRESH_KEY (uint32_t)0xDEADC0DEU + +/*-------------------------------------------------------------------------*//* +MIV_WDOG_FORCE_RESET_KEY +===================== +The MIV_WDOG_FORCE_RESET_KEY macro holds the magic value which will force a +reset if the watchdog is already timeout. Writing any other value or writing +TRIGGER register at other times will trigger the watchdog NMI sequence +(i.e raise a timeout interrupt) + */ +#define MIV_WDOG_FORCE_RESET_KEY (uint32_t)0xDEADU + +/***************************************************************************//** + * The MIV_WDOG_init() is used to register the Mi-V Watchdog module base + * address to the driver. + * + * Note: User should call this function before calling any other Mi-V watchdog + * driver function. + * + * @param base_addr + * The base address of the Mi-V watchdog module. This address is used by + * rest of the watchdog driver functions to access the registers. + * + * @return + * This function does not return any value. + */ +void +MIV_WDOG_init +( + addr_t base_addr +); + +/***************************************************************************//** + * The MIV_WDOG_get_config() function returns the current configurations of the + * Mi-V Watchdog. The Mi-V Watchdog is pre-initialized by the flash + * bits at the design time. When used for the first time before calling the + * MIV_WDOG_configure() function, this function will return the default + * configurations as configured at the design time. + * + * @param config + * The config parameter is used to store the current configuration of the Mi-V + * Watchdog. + * + * Please see the description of miv_wdog_config_t for details. + * + * @return + * This function does not return any value. + * + * Example: + */ +void +MIV_WDOG_get_config +( + miv_wdog_config_t* config +); + +/***************************************************************************//** + * The MIV_WDOG_configure() function configures the watchdog module. The + * Watchdog module is pre-initialized by the flash bits at the design time to the + * default values. You can reconfigure the Watchdog module using + * MIV_WDOG_configure() function. + * + * Note that the MIV_WDOG_configure() function can be used only once, as it + * writes into the TIME register. After a write into the TIME register, the TIME, + * TRIGGER and MSVP register values are frozen and can't be altered again unless + * a system reset happens. + * + * Note also that the Mi-V Watchdog is not enabled at reset, calling this function + * will start the watchdog, it cannot then be disabled and must be refreshed + * periodically. + * + * @param config + * The config parameter is the input parameter in which the configurations to + * be applied to the watchdog module are provided by the application. + * Please see the description of miv_wdog_config_t for details. + * + * @return + * This function returns a zero value when executed successfully. A non-zero + * value is returned when the configuration values are out of bound. + * + * Example: + */ +uint8_t +MIV_WDOG_configure +( + const miv_wdog_config_t * config +); + +/***************************************************************************//** + * The MIV_WDOG_reload() function causes the watchdog to reload its down-counter + * timer with the load value configured through interrupt handler. This function + * must be called regularly to avoid a system reset or a watchdog interrupt. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_reload +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg(g_this_wdog, WDOGRFSH, MIV_WDOG_REFRESH_KEY); + } +} + +/***************************************************************************//** + * The MIV_WDOG_current_value() function returns the current value of the + * watchdog's down-counter. + * + * @param + * Void + * + * @return + * This function returns the current value of the watchdog’s down-counter as + * a 32-bit unsigned integer. + */ +static inline uint32_t +MIV_WDOG_current_value +( + void +) +{ + return (HAL_get_32bit_reg(g_this_wdog, WDOGRFSH)); +} + +/***************************************************************************//** + * The MIV_WDOG_forbidden_status() function returns the refresh status of the + * Mi-V Watchdog. + * + * @param + * Void + * + * @return + * This function returns the refresh status of the watchdog. A value of 1 + * indicates that watchdog's down-counter is within the forbidden window and + * that a reload should not be done. A value of 0 indicates that the watchdog's + * down counter is within the permitted window and that a reload is allowed. + */ +static inline uint32_t +MIV_WDOG_forbidden_status +( + void +) +{ + return (HAL_get_32bit_reg_field(g_this_wdog, WDOGSTAT_FORBIDDEN)); +} + +/***************************************************************************//** + * The MIV_WDOG_enable_mvrp_irq() function enables the MVRP interrupt. + * This interrupt is asserted when the timer countdown register leaves the + * maximum value up to which refresh is permitted (MVRP) window. + * + * @param + * Void + * + * @return + * This function does not return a value. + * + * Example: + */ +static inline void +MIV_WDOG_enable_mvrp_irq +( + void +) +{ + + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGCNTL_NEXT_INTENT_MSVP, 0x01u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_disable_mvrp_irq() function disables the generation of the + * MVRP interrupt. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_disable_mvrp_irq +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGCNTL_NEXT_INTENT_MSVP, 0x0u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_clear_timeout_irq() function clears the watchdog’s timeout + * interrupt which is connected to the MIV-RV32 interrupt. Calling + * MIV_WDOG_clear_timeout_irq() results in clearing the MIV-RV32 interrupt. + * Note: You must call the MIV_WDOG_clear_timeout_irq() function as part of your + * implementation of the interrupt handler in order to prevent the same + * interrupt event re-triggering a call to the timeout ISR. + * + * @param + * Void + * + * @return + * This function does not return any value. + * + */ +static inline void +MIV_WDOG_clear_timeout_irq +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_WDOG_TRIPPED, 0x01u); + /* + * Perform a second write to ensure that the first write completed before + * returning from this function. This is to account for posted writes across + * the AHB matrix. The second write ensures that the first write has + * completed and that the interrupt line has been de-asserted by the time + * the function returns. Omitting the second write may result in a delay + * in the de-assertion of the interrupt line going to the RISC-V and a + * retriggering of the interrupt. + */ + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_WDOG_TRIPPED, 0x01u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_clear_mvrp_irq() function clears the mvrp interrupt. + * + * Note: You must call the MIV_WDOG_clear_mvrp_irq() function as part of your + * implementation of the interrupt service routine (ISR) in order to + * prevent the same interrupt event re-triggering a call to the mvrp ISR. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_clear_mvrp_irq +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_MSVP_TRIPPED, 0x01u); + /* + * Perform a second write to ensure that the first write completed before + * returning from this function. This is to account for posted writes across + * the AHB matrix. The second write ensures that the first write has + * completed and that the interrupt line has been de-asserted by the time + * the function returns. Omitting the second write may result in a delay + * in the de-assertion of the interrupt line going to the RISC-V and a + * re-triggering of the interrupt. + */ + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_MSVP_TRIPPED, 0x01u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_timeout_occured() function reports the occurrence of a timeout + * event. + * + * @param + * Void + * + * @return + * A zero value indicates no watchdog timeout event occurred. A value of 1 + * indicates that a timeout event occurred. + */ +static inline uint32_t +MIV_WDOG_timeout_occured +( + void +) +{ + return (HAL_get_32bit_reg_field(g_this_wdog, WDOGSTAT_TRIGGERED)); +} + +/***************************************************************************//** + * The MIV_WDOG_force_reset() function is used to force an immediate reset + * if the watchdog has already triggered. Writing any value in this condition + * will result in watchdog timeout. + * The time out interrupt WDOG_IRQ will be set to high and watchdog timer + * countdown register updated with watchdog trigger timeout register value. + * If the Watchdog has timed out, a special 16-bit value needs to be written + * to the register to force a reset on CPU_RESETN, 0xDEAD + * Then the Watchdog countdown is reset/updated with the top Watchdog Runtime + * register value. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_force_reset +( + void +) +{ + if (WDOGSTAT_TRIGGERED_MASK == + HAL_get_32bit_reg_field(g_this_wdog, WDOGSTAT_TRIGGERED)) + + { + HAL_set_32bit_reg(g_this_wdog, WDOGFORCE, MIV_WDOG_FORCE_RESET_KEY); + } + + else + { + HAL_set_32bit_reg(g_this_wdog, WDOGFORCE, 0x0u); + } +} + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_WATCHDOG_H_ */ diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h new file mode 100644 index 0000000..2fca983 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h @@ -0,0 +1,122 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP watchdog module driver. This module is delivered as a part of Mi-V + * extended Sub-System(ESS) MIV_ESS. + */ + +#ifndef MIV_WDOG_REGISTERS +#define MIV_WDOG_REGISTERS 1u + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * Refresh register details + */ +#define WDOGRFSH_REG_OFFSET 0x00u + +/* Refresh register bits */ +#define WDOGRFSH_OFFSET 0x00u +#define WDOGRFSH_MASK 0xFFFFFFFFu +#define WDOGRFSH_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Control register details + */ +#define WDOGCNTL_REG_OFFSET 0x04u + +/* Control register next intent msvp bit */ +#define WDOGCNTL_NEXT_INTENT_MSVP_OFFSET 0x04u +#define WDOGCNTL_NEXT_INTENT_MSVP_MASK 0x01u +#define WDOGCNTL_NEXT_INTENT_MSVP_SHIFT 0u + +/* Control register next intent wdog bit */ +#define WDOGCNTL_NEXT_INTENT_WDOG_OFFSET 0x04u +#define WDOGCNTL_NEXT_INTENT_WDOG_MASK 0x02u +#define WDOGCNTL_NEXT_INTENT_WDOG_SHIFT 1u + +/* Control register next enforbidden bit */ +#define WDOGCNTL_NEXT_ENFORBIDDEN_OFFSET 0x04u +#define WDOGCNTL_NEXT_ENFORBIDDEN_MASK 0x10u +#define WDOGCNTL_NEXT_ENFORBIDDEN_SHIFT 4u + +/*------------------------------------------------------------------------------ + * Watchdog status register + */ +#define WDOGSTAT_REG_OFFSET 0x08u + +/* msvp_tripped bit */ +#define WDOGSTAT_MSVP_TRIPPED_OFFSET 0x08u +#define WDOGSTAT_MSVP_TRIPPED_MASK 0x01u +#define WDOGSTAT_MSVP_TRIPPED_SHIFT 0u + +/* WDOG Tripped bit */ +#define WDOGSTAT_WDOG_TRIPPED_OFFSET 0x08u +#define WDOGSTAT_WDOG_TRIPPED_MASK 0x02u +#define WDOGSTAT_WDOG_TRIPPED_SHIFT 1u + +/* Forbidden bit */ +#define WDOGSTAT_FORBIDDEN_OFFSET 0x08u +#define WDOGSTAT_FORBIDDEN_MASK 0x04u +#define WDOGSTAT_FORBIDDEN_SHIFT 2u + +/* Triggered bit */ +#define WDOGSTAT_TRIGGERED_OFFSET 0x08u +#define WDOGSTAT_TRIGGERED_MASK 0x08u +#define WDOGSTAT_TRIGGERED_SHIFT 3u + +/* wdoglocked bit */ +#define WDOGSTAT_WDOGLOCKED_OFFSET 0x08u +#define WDOGSTAT_WDOGLOCKED_MASK 0x10u +#define WDOGSTAT_WDOGLOCKED_SHIFT 4u + +/*------------------------------------------------------------------------------ + * Watchdog runtime register + */ +#define WDOGTIME_REG_OFFSET 0x0Cu + +/* wdogmsvp bit */ +#define WDOGTIME_WDOGVALUE_OFFSET 0x0Cu +#define WDOGTIME_WDOGVALUE_MASK 0xFFFFFFu +#define WDOGTIME_WDOGVALUE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Watchdog MVRP register + */ +#define WDOGMSVP_REG_OFFSET 0x10u + +/* wdogmsvp bit */ +#define WDOGMSVP_OFFSET 0x10u +#define WDOGMSVP_MASK 0xFFFFFFu +#define WDOGMSVP_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Watchdog Trigger Timeout register + */ +#define WDOGTRIG_REG_OFFSET 0x14u + +/* wdogmsvp bit */ +#define WDOGTRIG_WDOGRST_OFFSET 0x14u +#define WDOGTRIG_WDOGRST_MASK 0xFFFFFFu +#define WDOGTRIG_WDOGRST_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Watchdog Force Reset register details + */ +#define WDOGFORCE_REG_OFFSET 0x18u + +/* Refresh register bits */ +#define WDOGFORCE_OFFSET 0x18u +#define WDOGFORCE_MASK 0xFFFFFFFFu +#define WDOGFORCE_SHIFT 0u + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_WATCHDOG_REGS_H_ */ diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/hal/cpu_types.h b/applications/user-crypto/miv-rv32-key-agreement/src/platform/hal/cpu_types.h new file mode 100644 index 0000000..ef8ab20 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/hal/cpu_types.h @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file cpu_types.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Type definitions which can be commonly used by the fabric-ip drivers. + * + */ +#ifndef __CPU_TYPES_H +#define __CPU_TYPES_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned int size_t; + +/*------------------------------------------------------------------------------ + * addr_t: address type. + * Used to specify the address of peripherals present in the processor's memory + * map. + */ +typedef unsigned int addr_t; + +/*------------------------------------------------------------------------------ + * psr_t: processor state register. + * Used by HAL_disable_interrupts() and HAL_restore_interrupts() to store the + * processor's state between disabling and restoring interrupts. + */ +typedef unsigned int psr_t; + +#ifdef __cplusplus +} +#endif + +#endif /* CPU_TYPES_H */ + diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/hal/hal.h b/applications/user-crypto/miv-rv32-key-agreement/src/platform/hal/hal.h new file mode 100644 index 0000000..7eec17a --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/hal/hal.h @@ -0,0 +1,235 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file hal.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware abstraction layer functions for peripheral register accesses. + * + */ +#ifndef __HAL_H +#define __HAL_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include "cpu_types.h" +#include "hw_reg_access.h" +#include "hal_assert.h" +/***************************************************************************//** + * Enable all interrupts at the processor level. + */ +void HAL_enable_interrupts( void ); + +/***************************************************************************//** + * Disable all interrupts at the processor core level. + * Return the interrupts enable state before disabling occurred so that it can + * later be restored. + */ +psr_t HAL_disable_interrupts( void ); + +/***************************************************************************//** + * Restore the interrupts enable state at the processor core level. + * This function is normally passed the value returned from a previous call to + * HAL_disable_interrupts(). + */ +void HAL_restore_interrupts( psr_t saved_psr ); + +/***************************************************************************//** + */ +#define FIELD_OFFSET(FIELD_NAME) (FIELD_NAME##_OFFSET) +#define FIELD_SHIFT(FIELD_NAME) (FIELD_NAME##_SHIFT) +#define FIELD_MASK(FIELD_NAME) (FIELD_NAME##_MASK) + +/***************************************************************************//** + * The macro HAL_set_32bit_reg() allows writing a 32 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint32_t containing the value to write. + */ +#define HAL_set_32bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_32bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_32bit_reg() is used to read the value of a 32 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint32_t value. + */ +#define HAL_get_32bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_32bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)) )) + +/***************************************************************************//** + * The macro HAL_set_32bit_reg_field() is used to write a field within a + * 32 bits wide register. The field written can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * VALUE: A variable of type uint32_t containing the field value to write. + */ +#define HAL_set_32bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_32bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_32bit_reg_field() is used to read a register field from + * within a 32 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint32_t value. + */ +#define HAL_get_32bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_32bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +/***************************************************************************//** + * The macro HAL_set_16bit_reg() allows writing a 16 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint_fast16_t containing the value to write. + */ +#define HAL_set_16bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_16bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_16bit_reg() is used to read the value of a 16 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint16_t value. + */ +#define HAL_get_16bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_16bit_reg( (BASE_ADDR) + (REG_NAME##_REG_OFFSET) )) + +/***************************************************************************//** + * The macro HAL_set_16bit_reg_field() is used to write a field within a + * 16 bits wide register. The field written can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * VALUE: A variable of type uint16_t containing the field value to write. + */ +#define HAL_set_16bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_16bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_16bit_reg_field() is used to read a register field from + * within a 8 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint16_t value. + */ +#define HAL_get_16bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_16bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +/***************************************************************************//** + * The macro HAL_set_8bit_reg() allows writing a 8 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint_fast8_t containing the value to write. + */ +#define HAL_set_8bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_8bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_8bit_reg() is used to read the value of a 8 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint8_t value. + */ +#define HAL_get_8bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_8bit_reg( (BASE_ADDR) + (REG_NAME##_REG_OFFSET) )) + +/***************************************************************************//** + */ +#define HAL_set_8bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_8bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_8bit_reg_field() is used to read a register field from + * within a 8 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint8_t value. + */ +#define HAL_get_8bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_8bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +#ifdef __cplusplus +} +#endif + +#endif /*HAL_H*/ + diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/hal/hal_assert.h b/applications/user-crypto/miv-rv32-key-agreement/src/platform/hal/hal_assert.h new file mode 100644 index 0000000..1e18b54 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/hal/hal_assert.h @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hal_assert.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief HAL assert functions + */ +#ifndef __HAL_ASSERT_HEADER +#define __HAL_ASSERT_HEADER 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Disable assertions if we do not recognize the compiler. */ +#if defined ( __GNUC__ ) +#if defined(NDEBUG) +/***************************************************************************//** + * HAL_ASSERT() is defined out when the NDEBUG symbol is used. + ******************************************************************************/ +#define HAL_ASSERT(CHECK) + +#else + +/***************************************************************************//** + * Default behavior for HAL_ASSERT() macro: + *------------------------------------------------------------------------------ + The behavior is toolchain specific and project setting specific. + ******************************************************************************/ +#define HAL_ASSERT(CHECK)\ + do { \ + if (!(CHECK)) \ + { \ + __asm__ volatile ("ebreak"); \ + }\ + } while(0); + +#endif /* NDEBUG */ +#endif /*__GNUC__*/ + +#ifdef __cplusplus +} +#endif +#endif /* __HAL_ASSERT_HEADER */ + diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/hal/hal_irq.c b/applications/user-crypto/miv-rv32-key-agreement/src/platform/hal/hal_irq.c new file mode 100644 index 0000000..95a0775 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/hal/hal_irq.c @@ -0,0 +1,45 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hal_irq.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Legacy interrupt control functions for the Microchip driver library + * hardware abstraction layer. + * + */ +#include "hal.h" +#include "miv_rv32_hal/miv_rv32_hal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * + */ +void HAL_enable_interrupts(void) { + MRV_enable_interrupts(); +} + +/*------------------------------------------------------------------------------ + * + */ +psr_t HAL_disable_interrupts(void) { + psr_t psr; + psr = read_csr(mstatus); + MRV_disable_interrupts(); + return(psr); +} + +/*------------------------------------------------------------------------------ + * + */ +void HAL_restore_interrupts(psr_t saved_psr) { + write_csr(mstatus, saved_psr); +} + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/hal/hw_macros.h b/applications/user-crypto/miv-rv32-key-agreement/src/platform/hal/hw_macros.h new file mode 100644 index 0000000..189609c --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/hal/hw_macros.h @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hw_macros.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware registers access macros. + * + * THE MACROS DEFINED IN THIS FILE ARE DEPRECATED. DO NOT USE FOR NEW + * DEVELOPMENT. + * + * These macros are used to access peripheral registers. They allow access to + * 8, 16 and 32 bit wide registers. All accesses to peripheral registers should + * be done through these macros in order to ease porting across different + * processors/bus architectures. + * + * Some of these macros also allow access to a specific register field. + * + */ +#ifndef __HW_REGISTER_MACROS_H +#define __HW_REGISTER_MACROS_H 1 +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * 32 bits registers access: + */ +#define HW_get_uint32_reg(BASE_ADDR, REG_OFFSET) (*((uint32_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint32_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint32_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint32_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint32_t) \ + ( \ + (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint32_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint32_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 32 bits memory access: + */ +#define HW_get_uint32(BASE_ADDR) (*((uint32_t volatile *)(BASE_ADDR))) + +#define HW_set_uint32(BASE_ADDR, VALUE) (*((uint32_t volatile *)(BASE_ADDR)) = (VALUE)) + +/*------------------------------------------------------------------------------ + * 16 bits registers access: + */ +#define HW_get_uint16_reg(BASE_ADDR, REG_OFFSET) (*((uint16_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint16_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint16_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint16_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint16_t) \ + ( \ + (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint16_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint16_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 8 bits registers access: + */ +#define HW_get_uint8_reg(BASE_ADDR, REG_OFFSET) (*((uint8_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint8_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint8_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint8_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint8_t) \ + ( \ + (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint8_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint8_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 8 bits memory access: + */ +#define HW_get_uint8(BASE_ADDR) (*((uint8_t volatile *)(BASE_ADDR))) + +#define HW_set_uint8(BASE_ADDR, VALUE) (*((uint8_t volatile *)(BASE_ADDR)) = (VALUE)) + +#ifdef __cplusplus +extern "C" { +#endif + +#endif /* __HW_REGISTER_MACROS_H */ + diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/hal/hw_reg_access.S b/applications/user-crypto/miv-rv32-key-agreement/src/platform/hal/hw_reg_access.S new file mode 100644 index 0000000..dd29223 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/hal/hw_reg_access.S @@ -0,0 +1,215 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hw_reg_access.S + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware registers access functions. + * The implementation of these function is platform and toolchain specific. + * The functions declared here are implemented using assembler as part of the + * processor/toolchain specific HAL. This implementation is for the combination + * of the 32 bit RISC-V processors and GNU tool chain. + * + */ + +.section .text + .globl HW_set_32bit_reg + .globl HW_get_32bit_reg + .globl HW_set_32bit_reg_field + .globl HW_get_32bit_reg_field + .globl HW_set_16bit_reg + .globl HW_get_16bit_reg + .globl HW_set_16bit_reg_field + .globl HW_get_16bit_reg_field + .globl HW_set_8bit_reg + .globl HW_get_8bit_reg + .globl HW_set_8bit_reg_field + .globl HW_get_8bit_reg_field + + +/***************************************************************************//** + * HW_set_32bit_reg is used to write the content of a 32 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint32_t value + */ +HW_set_32bit_reg: + sw a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_32bit_reg is used to read the content of a 32 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + + * @return 32 bits value read from the peripheral register. + */ +HW_get_32bit_reg: + lw a0, 0(a0) + ret + +/***************************************************************************//** + * HW_set_32bit_reg_field is used to set the content of a field in a 32 bits + * wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint32_t mask + * a3: uint32_t value + */ +HW_set_32bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lw t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sw t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_32bit_reg_field is used to read the content of a field out of a + * 32 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint32_t mask + * + * @return 32 bits value containing the register field value specified + * as parameter. + */ +HW_get_32bit_reg_field: + lw a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +/***************************************************************************//** + * HW_set_16bit_reg is used to write the content of a 16 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint_fast16_t value + */ +HW_set_16bit_reg: + sh a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_16bit_reg is used to read the content of a 16 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + + * @return 16 bits value read from the peripheral register. + */ +HW_get_16bit_reg: + lh a0, (a0) + ret + +/***************************************************************************//** + * HW_set_16bit_reg_field is used to set the content of a field in a 16 bits + * wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast16_t mask + * a3: uint_fast16_t value + * @param value Value to be written in the specified field. + */ +HW_set_16bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lh t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sh t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_16bit_reg_field is used to read the content of a field from a + * 16 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast16_t mask + * + * @return 16 bits value containing the register field value specified + * as parameter. + */ +HW_get_16bit_reg_field: + lh a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +/***************************************************************************//** + * HW_set_8bit_reg is used to write the content of a 8 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint_fast8_t value + */ +HW_set_8bit_reg: + sb a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_8bit_reg is used to read the content of a 8 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + + * @return 8 bits value read from the peripheral register. + */ +HW_get_8bit_reg: + lb a0, 0(a0) + ret + +/***************************************************************************//** + * HW_set_8bit_reg_field is used to set the content of a field in a 8 bits + * wide peripheral register. + * + * a0: addr_t reg_addr, + * a1: int_fast8_t shift + * a2: uint_fast8_t mask + * a3: uint_fast8_t value + */ +HW_set_8bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lb t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sb t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_8bit_reg_field is used to read the content of a field from a + * 8 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast8_t mask + * + * @return 8 bits value containing the register field value specified + * as parameter. + */ +HW_get_8bit_reg_field: + lb a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +.end diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/hal/hw_reg_access.h b/applications/user-crypto/miv-rv32-key-agreement/src/platform/hal/hw_reg_access.h new file mode 100644 index 0000000..1a24309 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/hal/hw_reg_access.h @@ -0,0 +1,239 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hw_reg_access.S + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware registers access functions. + * The implementation of these function is platform and tool-chain specific. + * The functions declared here are implemented using assembler as part of the + * processor/tool-chain specific HAL. This implementation is for the combination + * of the 32 bit RISC-V processors and GNU tool chain. + * + */ +#ifndef __HW_REG_ACCESS +#define __HW_REG_ACCESS +#ifdef __cplusplus +extern "C" { +#endif + +#include "cpu_types.h" +/***************************************************************************//** + * HW_set_32bit_reg is used to write the content of a 32 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_32bit_reg +( + addr_t reg_addr, + uint32_t value +); + +/***************************************************************************//** + * HW_get_32bit_reg is used to read the content of a 32 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 32 bits value read from the peripheral register. + */ +uint32_t +HW_get_32bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_32bit_reg_field is used to set the content of a field in a 32 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void +HW_set_32bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint32_t mask, + uint32_t value +); + +/***************************************************************************//** + * HW_get_32bit_reg_field is used to read the content of a field out of a + * 32 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 32 bits value containing the register field value specified + * as parameter. + */ +uint32_t +HW_get_32bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint32_t mask +); + +/***************************************************************************//** + * HW_set_16bit_reg is used to write the content of a 16 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_16bit_reg +( + addr_t reg_addr, + uint_fast16_t value +); + +/***************************************************************************//** + * HW_get_16bit_reg is used to read the content of a 16 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 16 bits value read from the peripheral register. + */ +uint16_t +HW_get_16bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_16bit_reg_field is used to set the content of a field in a 16 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void HW_set_16bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast16_t mask, + uint_fast16_t value +); + +/***************************************************************************//** + * HW_get_16bit_reg_field is used to read the content of a field from a + * 16 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 16 bits value containing the register field value specified + * as parameter. + */ +uint16_t HW_get_16bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast16_t mask +); + +/***************************************************************************//** + * HW_set_8bit_reg is used to write the content of a 8 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_8bit_reg +( + addr_t reg_addr, + uint_fast8_t value +); + +/***************************************************************************//** + * HW_get_8bit_reg is used to read the content of a 8 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 8 bits value read from the peripheral register. + */ +uint8_t +HW_get_8bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_8bit_reg_field is used to set the content of a field in a 8 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void HW_set_8bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast8_t mask, + uint_fast8_t value +); + +/***************************************************************************//** + * HW_get_8bit_reg_field is used to read the content of a field from a + * 8 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 8 bits value containing the register field value specified + * as parameter. + */ +uint8_t HW_get_8bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast8_t mask +); + +#ifdef __cplusplus +} +#endif + +#endif /* __HW_REG_ACCESS */ + diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld b/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld new file mode 100644 index 0000000..474eb43 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld @@ -0,0 +1,154 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-execute-in-place.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * image executing from a one address space whereas the data, sdata and stack + * sections are placed in another address space. This could be used in cases such + * as: + * 1) When using MIV_RV32, the reset vector points to the LSRAM at address + * 0x80000000 and the data, sdata, bss and stack sections are placed in the + * TCM region. + * + * 2) Executing from a Non Volatile memory. The actual memory will depend on + * the FPGA platform. For exameple, it could be the eNVM on SmartFusion2, + * Igloo2 or on-board non-volatile memory which supports code execution. + * + * NOTE: Modify the memory section addresses and the sizes according to your + * Libero design. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + + +MEMORY +{ + rom (rx) : ORIGIN = 0x80000000, LENGTH = 16k + ram (rwx) : ORIGIN = 0x80004000, LENGTH = 16k +} + +STACK_SIZE = 1k; /* needs to be calculated for your application */ +HEAP_SIZE = 1k; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > rom + + .text : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.text.entry))) + . = ALIGN(0x10); + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } >rom + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } >ram AT>rom + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } >ram AT>rom + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram +} + diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv-rv32-ram.ld b/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv-rv32-ram.ld new file mode 100644 index 0000000..53076a0 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv-rv32-ram.ld @@ -0,0 +1,150 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-ram.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * debug image executing in SRAM. + * + * This linker script assumes that a RAM is connected at on Mi-V soft processor + * memory space pointed by the reset vector address. + * + * NOTE : Modify the memory section address and the size according to your + * Libero design. + * For example: + * 1) If you want to download and step debug at a different RAM memory address in + * your design (For example TCM base address) than the one provided in this file. + * 2) The MIV_RV32, when used with MIV_ESS IP, provides ways to copy the executable + * HEX file from external Non-Volatile memory into the TCM at reset. In this + * case your executable must be linked to the TCM address. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +MEMORY +{ + ram (rwx) : ORIGIN = 0x80000000, LENGTH = 32k +} + +STACK_SIZE = 2k; /* needs to be calculated for your application */ +HEAP_SIZE = 1k; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > ram + + .text : ALIGN(0x10) + { + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } > ram + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } > ram + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } > ram + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram +} + diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv_rv32_assert.h b/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv_rv32_assert.h new file mode 100644 index 0000000..b3912ed --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv_rv32_assert.h @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * MIV_RV32 HAL Embedded Software + * + */ +#ifndef MIV_RV32_ASSERT_HEADER +#define MIV_RV32_ASSERT_HEADER + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + * ASSERT() implementation. + ******************************************************************************/ +/* Disable assertions if we do not recognize the compiler. */ +#if defined ( __GNUC__ ) +#if defined(NDEBUG) +#define ASSERT(CHECK) +#else +#define ASSERT(CHECK)\ + do { \ + if (!(CHECK)) \ + { \ + __asm__ volatile ("ebreak"); \ + }\ + } while(0); + +#endif /* NDEBUG check */ +#endif /* compiler check */ + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_RV32_ASSERT_HEADER */ + diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv_rv32_entry.S b/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv_rv32_entry.S new file mode 100644 index 0000000..0ea3172 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv_rv32_entry.S @@ -0,0 +1,590 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_entry.S + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor vectors, trap handling and startup code. + * + */ +#ifndef ENTRY_S +#define ENTRY_S + +#define A_EXTENSION_MASK 0x00000001u +#define MTVEC_MODE_BIT_MASK 0x00000003u +#define MTVEC_VECTORED_MODE_VAL 0x00000001u + +#define MTIMEH_ADDR 0x200BFFCu + + +#if __riscv_xlen == 64 +# define LREG ld +# define SREG sd +# define REGBYTES 8 +#else +# define LREG lw +# define SREG sw +# define REGBYTES 4 +#endif + +#if defined(MIV_FP_CONTEXT_SAVE) && defined(__riscv_flen) +#define SP_SHIFT_OFFSET 64 +#else +#define SP_SHIFT_OFFSET 32 +#endif + +.macro STORE_CONTEXT + addi sp, sp, -SP_SHIFT_OFFSET*REGBYTES + SREG x1, 0 * REGBYTES(sp) + SREG x1, 0 * REGBYTES(sp) + SREG x2, 1 * REGBYTES(sp) + SREG x3, 2 * REGBYTES(sp) + SREG x4, 3 * REGBYTES(sp) + SREG x5, 4 * REGBYTES(sp) + SREG x6, 5 * REGBYTES(sp) + SREG x7, 6 * REGBYTES(sp) + SREG x8, 7 * REGBYTES(sp) + SREG x9, 8 * REGBYTES(sp) + SREG x10, 9 * REGBYTES(sp) + SREG x11, 10 * REGBYTES(sp) + SREG x12, 11 * REGBYTES(sp) + SREG x13, 12 * REGBYTES(sp) + SREG x14, 13 * REGBYTES(sp) + SREG x15, 14 * REGBYTES(sp) + SREG x16, 15 * REGBYTES(sp) + SREG x17, 16 * REGBYTES(sp) + SREG x18, 17 * REGBYTES(sp) + SREG x19, 18 * REGBYTES(sp) + SREG x20, 19 * REGBYTES(sp) + SREG x21, 20 * REGBYTES(sp) + SREG x22, 21 * REGBYTES(sp) + SREG x23, 22 * REGBYTES(sp) + SREG x24, 23 * REGBYTES(sp) + SREG x25, 24 * REGBYTES(sp) + SREG x26, 25 * REGBYTES(sp) + SREG x27, 26 * REGBYTES(sp) + SREG x28, 27 * REGBYTES(sp) + SREG x29, 28 * REGBYTES(sp) + SREG x30, 29 * REGBYTES(sp) + SREG x31, 30 * REGBYTES(sp) + + #ifdef __riscv_flen + #ifdef MIV_FP_CONTEXT_SAVE + fsw f0, 31*REGBYTES(sp) + fsw f1, 32*REGBYTES(sp) + fsw f2, 33*REGBYTES(sp) + fsw f3, 34*REGBYTES(sp) + fsw f4, 35*REGBYTES(sp) + fsw f5, 36*REGBYTES(sp) + fsw f6, 37*REGBYTES(sp) + fsw f7, 38*REGBYTES(sp) + fsw f8, 39*REGBYTES(sp) + fsw f9, 40*REGBYTES(sp) + fsw f10, 41*REGBYTES(sp) + fsw f11, 42*REGBYTES(sp) + fsw f12, 43*REGBYTES(sp) + fsw f13, 44*REGBYTES(sp) + fsw f14, 45*REGBYTES(sp) + fsw f15, 46*REGBYTES(sp) + fsw f16, 47*REGBYTES(sp) + fsw f17, 48*REGBYTES(sp) + fsw f18, 49*REGBYTES(sp) + fsw f19, 50*REGBYTES(sp) + fsw f20, 51*REGBYTES(sp) + fsw f21, 52*REGBYTES(sp) + fsw f22, 53*REGBYTES(sp) + fsw f23, 54*REGBYTES(sp) + fsw f24, 55*REGBYTES(sp) + fsw f25, 56*REGBYTES(sp) + fsw f26, 57*REGBYTES(sp) + fsw f27, 58*REGBYTES(sp) + fsw f28, 59*REGBYTES(sp) + fsw f29, 60*REGBYTES(sp) + fsw f30, 61*REGBYTES(sp) + fsw f31, 62*REGBYTES(sp) + #endif /* __riscv_flen */ + #endif /* MIV_FP_CONTEXT_SAVE */ +.endm + + .section .entry, "ax" + .globl _start + +_start: + j handle_reset + +/* Some of the Mi-V soft IP cores support compressed 'C' extension. If the Mi-V + core in your design doesn't support 'C' extension and you enable 'C' extension + in firmware project compiler options, then it would result in a trap. For this + case, we are avoiding compressed instruction here so you can put a breakpoint + at the jump and you can at least look at mcause, mepc and get some hints + about the crash. */ +trap_entry: +.option push +.option norvc +j generic_trap_handler +.option pop + .word 0 + .word 0 + +sw_trap_entry: + j vector_sw_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + +tmr_trap_entry: + j vector_tmr_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + +ext_trap_entry: + j vector_ext_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + .word 0 + +#ifndef MIV_LEGACY_RV32 +MGEUI_trap_entry: + j vector_MGEUI_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MGECI_trap_entry: + j vector_MGECI_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + .word 0 + +#ifndef MIV_RV32_V3_0 +MSYS_MIE22_trap_entry: +#ifndef MIV_RV32_V3_0 + j vector_SUBSYSR_IRQHandler +#endif /*MIV_RV32_V3_0*/ +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE23_trap_entry: + j vector_SUBSYS_IRQHandler +#ifdef __riscv_compressed + .2byte 0 +#endif +#endif /*MIV_RV32_V3_0*/ + +MSYS_MIE24_trap_entry: + j vector_MSYS_EI0_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE25_trap_entry: + j vector_MSYS_EI1_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE26_trap_entry: + j vector_MSYS_EI2_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE27_trap_entry: + j vector_MSYS_EI3_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE28_trap_entry: + j vector_MSYS_EI4_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE29_trap_entry: + j vector_MSYS_EI5_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE30_trap_entry: +#ifndef MIV_RV32_V3_0 + j vector_MSYS_EI6_trap_handler +#else + j vector_SUBSYS_IRQHandler +#endif +#ifdef __riscv_compressed + .2byte 0 +#endif + +#ifndef MIV_RV32_V3_0 +MSYS_MIE31_trap_entry: + j vector_MSYS_EI7_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif +#endif /* MIV_RV32_V3_0 */ +#endif /* MIV_LEGACY_RV32 */ + +.align 4 +generic_trap_handler: + STORE_CONTEXT + csrr a0, mcause + csrr a1, mepc + jal handle_trap + j generic_restore + +vector_sw_trap_handler: + STORE_CONTEXT + jal handle_m_soft_interrupt + j generic_restore + +vector_tmr_trap_handler: + STORE_CONTEXT + jal handle_m_timer_interrupt + j generic_restore + +vector_ext_trap_handler: + STORE_CONTEXT +#ifdef MIV_LEGACY_RV32 + jal handle_m_ext_interrupt +#else + jal External_IRQHandler +#endif /* MIV_LEGACY_RV32 */ + j generic_restore + +#ifndef MIV_LEGACY_RV32 +vector_MGEUI_trap_handler: + STORE_CONTEXT + jal MGEUI_IRQHandler + j generic_restore + +vector_MGECI_trap_handler: + STORE_CONTEXT + jal MGECI_IRQHandler + j generic_restore + +vector_MSYS_EI0_trap_handler: + STORE_CONTEXT + jal MSYS_EI0_IRQHandler + j generic_restore + +vector_MSYS_EI1_trap_handler: + STORE_CONTEXT + jal MSYS_EI1_IRQHandler + j generic_restore + +vector_MSYS_EI2_trap_handler: + STORE_CONTEXT + jal MSYS_EI2_IRQHandler + j generic_restore + +vector_MSYS_EI3_trap_handler: + STORE_CONTEXT + jal MSYS_EI3_IRQHandler + j generic_restore + +vector_MSYS_EI4_trap_handler: + STORE_CONTEXT + jal MSYS_EI4_IRQHandler + j generic_restore + +vector_MSYS_EI5_trap_handler: + STORE_CONTEXT + jal MSYS_EI5_IRQHandler + j generic_restore + +vector_SUBSYS_IRQHandler: + STORE_CONTEXT + jal SUBSYS_IRQHandler + j generic_restore + +#ifndef MIV_RV32_V3_0 +vector_MSYS_EI6_trap_handler: + STORE_CONTEXT + jal MSYS_EI6_IRQHandler + j generic_restore + +vector_MSYS_EI7_trap_handler: + STORE_CONTEXT + jal MSYS_EI7_IRQHandler + j generic_restore + + +vector_SUBSYSR_IRQHandler: + STORE_CONTEXT + jal SUBSYSR_IRQHandler + j generic_restore + +#endif /*MIV_RV32_V3_0*/ +#endif /* MIV_LEGACY_RV32 */ + +generic_restore: + LREG x1, 0 * REGBYTES(sp) + LREG x2, 1 * REGBYTES(sp) + LREG x3, 2 * REGBYTES(sp) + LREG x4, 3 * REGBYTES(sp) + LREG x5, 4 * REGBYTES(sp) + LREG x6, 5 * REGBYTES(sp) + LREG x7, 6 * REGBYTES(sp) + LREG x8, 7 * REGBYTES(sp) + LREG x9, 8 * REGBYTES(sp) + LREG x10, 9 * REGBYTES(sp) + LREG x11, 10 * REGBYTES(sp) + LREG x12, 11 * REGBYTES(sp) + LREG x13, 12 * REGBYTES(sp) + LREG x14, 13 * REGBYTES(sp) + LREG x15, 14 * REGBYTES(sp) + LREG x16, 15 * REGBYTES(sp) + LREG x17, 16 * REGBYTES(sp) + LREG x18, 17 * REGBYTES(sp) + LREG x19, 18 * REGBYTES(sp) + LREG x20, 19 * REGBYTES(sp) + LREG x21, 20 * REGBYTES(sp) + LREG x22, 21 * REGBYTES(sp) + LREG x23, 22 * REGBYTES(sp) + LREG x24, 23 * REGBYTES(sp) + LREG x25, 24 * REGBYTES(sp) + LREG x26, 25 * REGBYTES(sp) + LREG x27, 26 * REGBYTES(sp) + LREG x28, 27 * REGBYTES(sp) + LREG x29, 28 * REGBYTES(sp) + LREG x30, 29 * REGBYTES(sp) + LREG x31, 30 * REGBYTES(sp) + + #ifdef __riscv_flen + #ifdef MIV_FP_CONTEXT_SAVE + flw f0, 0 * REGBYTES(sp) + flw f1, 1 * REGBYTES(sp) + flw f2, 2 * REGBYTES(sp) + flw f3, 3 * REGBYTES(sp) + flw f4, 4 * REGBYTES(sp) + flw f5, 5 * REGBYTES(sp) + flw f6, 6 * REGBYTES(sp) + flw f7, 7 * REGBYTES(sp) + flw f8, 8 * REGBYTES(sp) + flw f9, 9 * REGBYTES(sp) + flw f10, 10 * REGBYTES(sp) + flw f11, 11 * REGBYTES(sp) + flw f12, 12 * REGBYTES(sp) + flw f13, 13 * REGBYTES(sp) + flw f14, 14 * REGBYTES(sp) + flw f15, 15 * REGBYTES(sp) + flw f16, 16 * REGBYTES(sp) + flw f17, 17 * REGBYTES(sp) + flw f18, 18 * REGBYTES(sp) + flw f19, 19 * REGBYTES(sp) + flw f20, 20 * REGBYTES(sp) + flw f21, 21 * REGBYTES(sp) + flw f22, 22 * REGBYTES(sp) + flw f23, 23 * REGBYTES(sp) + flw f24, 24 * REGBYTES(sp) + flw f25, 25 * REGBYTES(sp) + flw f26, 26 * REGBYTES(sp) + flw f27, 27 * REGBYTES(sp) + flw f28, 28 * REGBYTES(sp) + flw f29, 29 * REGBYTES(sp) + flw f30, 30 * REGBYTES(sp) + flw f31, 31 * REGBYTES(sp) + #endif /* __riscv_flen */ + #endif /* MIV_FP_CONTEXT_SAVE */ + + addi sp, sp, SP_SHIFT_OFFSET*REGBYTES + mret + + .section .text, "ax" +handle_reset: +/* Ensure instructions are not relaxed, since gp is not yet set */ +.option push +.option norelax + +#ifndef MIV_RV32_V3_0 + csrwi mstatus, 0 + csrwi mie, 0 + la ra, _start + +/* Clearnig this to be on safer side as RTL doesnt seem to clear it on reset. */ +#ifndef MIV_LEGACY_RV32 + li t0, MTIMEH_ADDR + sw x0, 0(t0) +#endif + + csrr t0, misa + andi t0, t0, A_EXTENSION_MASK + bnez t0, ima_cores_setup /* Jump to IMA core handling */ + + +/* For MIV_RV32 cores the mtvec exception base address is fixed at Reset vector + address + 0x4. Check the mode bits. */ +/* In the MIV_RV32 v3.1, the MTVEC exception base address is WARL, and can be + configured by the user at runtime */ + + csrr t0, mtvec + andi t0, t0, MTVEC_MODE_BIT_MASK + li t1, MTVEC_VECTORED_MODE_VAL + bne t0, t1, ima_cores_setup /* Jump to IMA core handling */ + + /* When mode = 1 => this is vectored mode on MIV_RV32 core. + Verify that the trap_handler address matches the configuration in MTVEC */ + csrr t0, mtvec + andi t0, t0, 0xFFFFFFFC + la t1, trap_entry + bne t0, t1, vector_address_not_matching + j generic_reset_handling + +#else /* MIV_RV32_V3_0 */ + +/* Clearnig this to be on safer side as RTL doesnt seem to clear it on reset. */ +#ifndef MIV_LEGACY_RV32 + li t0, MTIMEH_ADDR + sw x0, 0(t0) +#endif + +/* In the MIV_RV32 v3.1, the MTVEC exception base address is WARL, and can be + configured by the user at runtime */ + csrr t0, mtvec + andi t0, t0, MTVEC_MODE_BIT_MASK + li t1, MTVEC_VECTORED_MODE_VAL + bne t0, t1, ima_cores_setup /* Jump to IMA core handling */ + +/* When mode = 1 => this is vectored mode on MIV_RV32 core. + Verify that the trap_handler address matches the configuration in MTVEC */ + csrr t0, mtvec + andi t0, t0, 0xFFFFFFFC + la t1, trap_entry + bne t0, t1, vector_address_not_matching + j generic_reset_handling +#endif /*MIV_RV32_V3_0*/ + +ima_cores_setup: + la t0, trap_entry + +#ifdef MIV_LEGACY_RV32_VECTORED_INTERRUPTS + addi t0, t0, 0x01 /* Set the mode bit for IMA cores. + For both MIV_RV32 v3.1 and v3.0 cores this is done by configurator. */ +#endif + csrw mtvec, t0 + +generic_reset_handling: +/* Copy sdata section first so that the gp is set and linker relaxation can be + used */ + la a4, __sdata_load + la a5, __sdata_start + la a6, __sdata_end + beq a4, a5, 1f /* Exit if source and dest are same */ + beq a5, a6, 1f /* Exit if section start and end addresses are same */ + call block_copy + +1: + /* initialize global pointer */ + la gp, __global_pointer$ + +.option pop + +/* Floating point support configuration */ +#ifdef __riscv_flen + csrr t0, mstatus + lui t1, 0xffffa + addi t1, t1, -1 + and t0, t0, t1 + lui t1, 0x4 + or t1, t0, t1 + csrw mstatus, t1 + + lui t0, 0x0 + fscsr t0 +#endif + call initializations + /* Initialize stack pointer */ + la sp, __stack_top + + /* Jump into C code */ + j _init + +/* Error: trap_entry is not at the expected address of reset_vector+mtvec offset + as configured in the MIV_RV32 core vectored mode */ +vector_address_not_matching: + ebreak + +initializations: +/* Initialize the .bss section */ + mv t0, ra /* Store ra for future use */ + la a5, __bss_start + la a6, __bss_end + beq a5, a6, 1f /* Section start and end address are the same */ + call zeroize_block + +1: +/* Initialize the .sbss section */ + la a5, __sbss_start + la a6, __sbss_end + beq a5, a6, 1f /* Section start and end address are the same */ + call zeroize_block + +/* Clear heap */ + la a5, __heap_start + la a6, __heap_end + beq a5, a6, 1f /* Section start and end address are the same */ + call zeroize_block + +1: +/* Copy data section */ + la a4, __data_load + la a5, __data_start + la a6, __data_end + beq a4, a5, 1f /* Exit early if source and dest are same */ + beq a5, a6, 1f /* Section start and end addresses are the same */ + call block_copy + +1: + mv ra, t0 /* Retrieve ra */ + ret + +zeroize_block: + bltu a6, a5, block_copy_error /* Error. End address is less than start */ + or a7, a6, a5 /* Check if start or end is unalined */ + andi a7, a7, 0x03u + bgtz a7, block_copy_error /* Unaligned addresses error*/ +zeroize_loop: + sw x0, 0(a5) + add a5, a5, __SIZEOF_POINTER__ + blt a5, a6, zeroize_loop + ret + +block_copy: + bltu a6, a5, block_copy_error /* Error. End address is less than start */ + or a7, a6, a5 /* Check if start or end is unalined */ + andi a7, a7, 0x03u + bgtz a7, block_copy_error /* Unaligned addresses error*/ +block_copy_loop: + lw a7, 0(a4) + sw a7, 0(a5) + addi a5, a5, 0x04 + addi a4, a4, 0x04 + blt a5, a6, block_copy_loop + j block_copy_exit + +block_copy_error: + j block_copy_error + +block_copy_exit: + ret + +#endif /*ENTRY_S*/ diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv_rv32_hal.c b/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv_rv32_hal.c new file mode 100644 index 0000000..a112821 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv_rv32_hal.c @@ -0,0 +1,410 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_hal.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Implementation of Hardware Abstraction Layer for Mi-V soft processors + * + */ +#include +#include "miv_rv32_hal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SUCCESS 0U +#define ERROR 1U +#define MASK_32BIT 0xFFFFFFFFu + +/*------------------------------------------------------------------------------ + * Write in a sequence recommended by privileged spec to avoid spurious + * interrupts + + # New comparand is in a1:a0. + li t0, -1 + sw t0, mtimecmp # No smaller than old value. + sw a1, mtimecmp+4 # No smaller than new value. + sw a0, mtimecmp # New value. + */ +#ifndef MIV_RV32_EXT_TIMECMP +#define WRITE_MTIMECMP(value) MTIMECMPH = MASK_32BIT; \ + MTIMECMP = value & MASK_32BIT;\ + MTIMECMPH = (value >> 32u) & MASK_32BIT; +#else +#define WRITE_MTIMECMP(value) +#endif + +#ifndef MIV_RV32_EXT_TIMER +#define WRITE_MTIME(value) MTIME = value & MASK_32BIT;\ + MTIMEH = (value >> 32u) & MASK_32BIT; +#else +#define WRITE_MTIME(value) +#endif + +extern void Software_IRQHandler(void); + +#ifdef MIV_LEGACY_RV32 +#define MTIME_PRESCALER 100UL +/*------------------------------------------------------------------------------ + * + */ +uint8_t Invalid_IRQHandler(void); +uint8_t External_1_IRQHandler(void); +uint8_t External_2_IRQHandler(void); +uint8_t External_3_IRQHandler(void); +uint8_t External_4_IRQHandler(void); +uint8_t External_5_IRQHandler(void); +uint8_t External_6_IRQHandler(void); +uint8_t External_7_IRQHandler(void); +uint8_t External_8_IRQHandler(void); +uint8_t External_9_IRQHandler(void); +uint8_t External_10_IRQHandler(void); +uint8_t External_11_IRQHandler(void); +uint8_t External_12_IRQHandler(void); +uint8_t External_13_IRQHandler(void); +uint8_t External_14_IRQHandler(void); +uint8_t External_15_IRQHandler(void); +uint8_t External_16_IRQHandler(void); +uint8_t External_17_IRQHandler(void); +uint8_t External_18_IRQHandler(void); +uint8_t External_19_IRQHandler(void); +uint8_t External_20_IRQHandler(void); +uint8_t External_21_IRQHandler(void); +uint8_t External_22_IRQHandler(void); +uint8_t External_23_IRQHandler(void); +uint8_t External_24_IRQHandler(void); +uint8_t External_25_IRQHandler(void); +uint8_t External_26_IRQHandler(void); +uint8_t External_27_IRQHandler(void); +uint8_t External_28_IRQHandler(void); +uint8_t External_29_IRQHandler(void); +uint8_t External_30_IRQHandler(void); +uint8_t External_31_IRQHandler(void); + + +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for external interrupts. + */ +uint8_t (* const mrv_ext_irq_handler_table[32])(void) = +{ + + Invalid_IRQHandler, + External_1_IRQHandler, + External_2_IRQHandler, + External_3_IRQHandler, + External_4_IRQHandler, + External_5_IRQHandler, + External_6_IRQHandler, + External_7_IRQHandler, + External_8_IRQHandler, + External_9_IRQHandler, + External_10_IRQHandler, + External_11_IRQHandler, + External_12_IRQHandler, + External_13_IRQHandler, + External_14_IRQHandler, + External_15_IRQHandler, + External_16_IRQHandler, + External_17_IRQHandler, + External_18_IRQHandler, + External_19_IRQHandler, + External_20_IRQHandler, + External_21_IRQHandler, + External_22_IRQHandler, + External_23_IRQHandler, + External_24_IRQHandler, + External_25_IRQHandler, + External_26_IRQHandler, + External_27_IRQHandler, + External_28_IRQHandler, + External_29_IRQHandler, + External_30_IRQHandler, + External_31_IRQHandler +}; + +#else +/*------------------------------------------------------------------------------ + * Interrupt handlers as mapped into the MIE register of the MIV_RV32 + */ +extern void Reserved_IRQHandler(void); +extern void External_IRQHandler(void); +extern void MGEUI_IRQHandler(void); +extern void MGECI_IRQHandler(void); +extern void MSYS_EI0_IRQHandler(void); +extern void MSYS_EI1_IRQHandler(void); +extern void MSYS_EI2_IRQHandler(void); +extern void MSYS_EI3_IRQHandler(void); +extern void MSYS_EI4_IRQHandler(void); +extern void MSYS_EI5_IRQHandler(void); +extern void SUBSYS_IRQHandler(void); + +#ifndef MIV_RV32_V3_0 /*For MIV_RV32 v3.1*/ +extern void MSYS_EI6_IRQHandler(void); +extern void MSYS_EI7_IRQHandler(void); +extern void SUBSYSR_IRQHandler(void); // @suppress("Unused function declaration") +#endif /*MIV_RV32_V3_0*/ + +#endif /* MIV_LEGACY_RV32 */ + +/*------------------------------------------------------------------------------ + * Increment value for the mtimecmp register in order to achieve a system tick + * interrupt as specified through the MRV_systick_config() function. + */ +static uint64_t g_systick_increment = 0U; +static uint64_t g_systick_cmp_value = 0U; + +/*------------------------------------------------------------------------------ + * Configure the machine timer to generate an interrupt. + */ +uint32_t MRV_systick_config(uint64_t ticks) +{ + uint32_t ret_val = ERROR; + uint64_t remainder = ticks; + g_systick_increment = 0U; + g_systick_cmp_value = 0U; + + while (remainder >= MTIME_PRESCALER) + { + remainder -= MTIME_PRESCALER; + g_systick_increment++; + } + + g_systick_cmp_value = g_systick_increment + MRV_read_mtime(); + + if (g_systick_increment > 0U) + { + WRITE_MTIMECMP(g_systick_cmp_value); + set_csr(mie, MIP_MTIP); + MRV_enable_interrupts(); + ret_val = SUCCESS; + } + + return ret_val; +} + +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for machine timer interrupts. + */ +void handle_m_timer_interrupt(void) +{ + clear_csr(mie, MIP_MTIP); + + uint64_t mtime_at_irq = MRV_read_mtime(); + +#ifndef NDEBUG + static volatile uint32_t d_tick = 0u; +#endif + + while(g_systick_cmp_value < (mtime_at_irq + MTIME_DELTA)) { + g_systick_cmp_value = g_systick_cmp_value + g_systick_increment; + +#ifndef NDEBUG + d_tick += 1; +#endif + } +/***************************************************************************//** + /* + * Note: If d_tick > 1 it means, that a system timer interrupt has been + * missed. + * Please ensure that interrupt handlers are as short as possible to prevent + * them stopping other interrupts from being handled. For example, if a + * system timer interrupt occurs during a software interrupt, the system + * timer interrupt will not be handled until the software interrupt handling + * is complete. If the software interrupt handling time is more than one + * systick interval, it will result in d_tick > 1. + * If you are running the program using the debugger and halt the CPU at a + * breakpoint, MTIME will continue to increment and interrupts will be + * missed; resulting in d_tick > 1. + */ + + WRITE_MTIMECMP(g_systick_cmp_value); + + SysTick_Handler(); + + set_csr(mie, MIP_MTIP); +} + +void handle_m_soft_interrupt(void) +{ + Software_IRQHandler(); + MRV_clear_soft_irq(); +} +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for software interrupts. + */ +#ifdef MIV_LEGACY_RV32 +void handle_m_ext_interrupt(void) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; + uint8_t disable = EXT_IRQ_KEEP_ENABLED; + + if (0u !=int_num) + { + disable = mrv_ext_irq_handler_table[int_num](); + + PLIC->TARGET[hart_id].CLAIM_COMPLETE = int_num; + + if(EXT_IRQ_DISABLE == disable) + { + MRV_PLIC_disable_irq((IRQn_Type)int_num); + } + } +} +#else + +/*------------------------------------------------------------------------------ + * MSYS local interrupts table + */ +void (* const local_irq_handler_table[16])(void) = +{ +#ifndef MIV_RV32_V3_0 + MGEUI_IRQHandler, + MGECI_IRQHandler, + SUBSYS_IRQHandler, + SUBSYSR_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + MSYS_EI0_IRQHandler, + MSYS_EI1_IRQHandler, + MSYS_EI2_IRQHandler, + MSYS_EI3_IRQHandler, + MSYS_EI4_IRQHandler, + MSYS_EI5_IRQHandler, + MSYS_EI6_IRQHandler, + MSYS_EI7_IRQHandler +#else + MGEUI_IRQHandler, + MGECI_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + MSYS_EI0_IRQHandler, + MSYS_EI1_IRQHandler, + MSYS_EI2_IRQHandler, + MSYS_EI3_IRQHandler, + MSYS_EI4_IRQHandler, + MSYS_EI5_IRQHandler, + SUBSYS_IRQHandler, + Reserved_IRQHandler, +#endif +}; + +/*------------------------------------------------------------------------------ + * Jump to interrupt table containing local interrupts + */ +void handle_local_ei_interrupts(uint8_t irq_no) +{ + uint64_t mhart_id = read_csr(mhartid); + ASSERT(irq_no <= MIV_LOCAL_IRQ_MAX) + ASSERT(irq_no >= MIV_LOCAL_IRQ_MIN) + + uint8_t ei_no = (uint8_t)(irq_no - MIV_LOCAL_IRQ_MIN); + (*local_irq_handler_table[ei_no])(); +} +#endif /* MIV_LEGACY_RV32 */ + + +/*------------------------------------------------------------------------------ + * Trap handler. This function is invoked in the non-vectored mode. + */ +void handle_trap(uintptr_t mcause, uintptr_t mepc) +{ + uint64_t is_interrupt = mcause & MCAUSE_INT; + + if (is_interrupt) + { +#ifndef MIV_LEGACY_RV32 + if (((mcause & MCAUSE_CAUSE) >= MIV_LOCAL_IRQ_MIN) && ((mcause & MCAUSE_CAUSE) <= MIV_LOCAL_IRQ_MAX)) + { + handle_local_ei_interrupts((uint8_t)(mcause & MCAUSE_CAUSE)); + } + else if ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT) +#else + if ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT) +#endif + { +#ifndef MIV_LEGACY_RV32 + External_IRQHandler(); +#else + handle_m_ext_interrupt(); +#endif + } + else if ((mcause & MCAUSE_CAUSE) == IRQ_M_SOFT) + { + handle_m_soft_interrupt(); + } + else if ((mcause & MCAUSE_CAUSE) == IRQ_M_TIMER) + { + handle_m_timer_interrupt(); + } + } + else + { +#ifndef NDEBUG + /* + Arguments supplied to this function are mcause, mepc (exception PC) and + stack pointer. + Based on privileged-isa specification mcause values and meanings are: + + 0 Instruction address misaligned (mtval/mtval is the address) + 1 Instruction access fault (mtval/mtval is the address) + 2 Illegal instruction (mtval/mtval contains the + offending instruction opcode) + 3 Breakpoint + 4 Load address misaligned (mtval/mtval is the address) + 5 Load address fault (mtval/mtval is the address) + 6 Store/AMO address fault (mtval/mtval is the address) + 7 Store/AMO access fault (mtval/mtval is the address) + 8 Environment call from U-mode + 9 Environment call from S-mode + A Environment call from M-mode + B Instruction page fault + C Load page fault (mtval/mtval is the address) + E Store page fault (mtval/mtval is the address) + + # Please note: mtval is the newer name for register mbadaddr + # If you get a compile failure here, use the older name. + # At this point, both are supported in latest compiler, older compiler + # versions only support mbadaddr. + # See: https://github.com/riscv/riscv-gcc/issues/133 + */ + + /* interrupt pending */ + uintptr_t mip = read_csr(mip); + + /* additional info and meaning depends on mcause */ + uintptr_t mtval = read_csr(mtval); + + /* trap vector */ + uintptr_t mtvec = read_csr(mtvec); + + /* temporary, sometimes might hold temporary value of a0 */ + uintptr_t mscratch = read_csr(mscratch); + + /* status contains many smaller fields: */ + uintptr_t mstatus = read_csr(mstatus); + + /* PC value when the exception was taken*/ + uintptr_t mmepc = read_csr(mepc); + + /* breakpoint */ + __asm__("ebreak"); +#else + _exit(1 + mcause); +#endif /* NDEBUG */ + } +} + +#ifdef __cplusplus +} +#endif + diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv_rv32_hal.h b/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv_rv32_hal.h new file mode 100644 index 0000000..9ce9ef6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv_rv32_hal.h @@ -0,0 +1,773 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_hal.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware Abstraction Layer functions for Mi-V soft processors + * + */ + +/*=========================================================================*//** + @mainpage MIV_RV32 Hardware Abstraction Layer + + ============================================================================== + Introduction + ============================================================================== + This document describes the Hardware Abstraction Layer (HAL) for the MIV_RV32 + Soft IP Core. This release of the HAL corresponds to the Soft IP core MIV_RV32 + v3.1 release. It also supports earlier versions of the MIV_RV32 as well as the + legacy RV32 IP cores. + The preprocessor macros provided with the MIV_RV32 HAL are used to customize + it to target the Soft Processor IP version being used in your project. + + The term "MIV_RV32" represents following two cores: + - MIV_RV32 v3.0 and later (the latest and greatest Mi-V soft processor) + - MIV_RV32IMC v2.1 (MIV_RV32 v3.0 is a drop in replacement for this core) + It is highly recommended to migrate your design to MIV_RV32 v3.1 + + The term, Legacy RV32 IP cores, represents following IP cores: + - MIV_RV32IMA_L1_AHB + - MIV_RV32IMA_L1_AXI + - MIV_RV32IMAF_L1_AHB + + These legacy RV32 IP cores are deprecated. It is highly recommended to migrate + your designs to MIV_RV32 v3.1 (and subsequent IP releases) for the latest + enhancements, bug fixes, and support. + + -------------------------------- + MIV_RV32 V3.1 + -------------------------------- + This is the latest release of the MIV_RV32 Soft IP core. For more details, + refer to the MIV_RV32 User [Guide](https://www.microchip.com/en-us/products/fpgas-and-plds/ip-core-tools/miv-rv32) + + The MIV_RV32 Core as well as this document use the terms defined below: + + -------------------------------- + - SUBSYS - Processor Subsystem for RISC-V + - OPSRV - Offload Processor Subsystem for RISC-V + - GPR - General Purpose Registers + - MGECIE - Machine GPR ECC Correctable Interrupt Enable + - MGEUIE - Machine GPR ECC Uncorrectable Interrupt Enable + - MTIE - Machine Timer Interrupt Enable + - MEIE - Machine External Interrupt Enable + - MSIE - Machine Software Interrupt Enable + - ISR - Interrupt Service Routine + + ============================================================================== + Customizing MIV_RV32 HAL + ============================================================================== + To use the HAL with older releases of MIV_RV32, preprocessor macros have been + provided. Using these macros, any of the IP version is targeted. + The HAL is used to target any of the mentioned platforms by adding the + following macros in the way : + Project Properties > C/C++ Build > Settings > Preprocessor in Assembler and + Compiler settings. + The table below shows the macros corresponding to the MIV Core being used in + your libero project. By default, the HAL targets v3.1 of the IP core and no + macros need to be set for this configutation. + + | Libero MI-V Soft IP Version | SoftConsole Macro | + |-----------------------------|-------------------| + | MIV_RV32 v3.1 | no macro required | + | MIV_RV32 v3.0 | MIV_CORE_V3_0 | + | Legacy RV32 Cores | MIV_LEGACY_RV32 | + + -------------------------------- + Interrupt Handling + -------------------------------- + The MIE Register is defined as a enum in the HAL, and the table below is used + as a reference when the vectored interrupts are enabled in the GUI core + configurator. + + The MIE register is a RISC-V Control and Status Register (CSR), which stands + for the Machine Interrupt Enable. This is used to enable the machine mode + interrupts in the MIV_RV32 hart. Refer to the RISC-V Priv spec for more details. + + The following table shows the trap entry addresses when an interrupt occurs and + the vectored interrupts are enabled in the GUI configurator. + + | MIE Register Bit | Interrupt Enable | Vector Address | + |-------------------|------------------|----------------| + | 31 | MSYS_IE7 | mtvec.BASE + 0x7C | + | 30 | MSYS_IE6 | mtvec.BASE + 0x78 | + | 29 | MSYS_IE5 | mtvec.BASE + 0x74 | + | 28 | MSYS_IE4 | mtvec.BASE + 0x70 | + | 27 | MSYS_IE3 | mtvec.BASE + 0x6C | + | 26 | MSYS_IE2 | mtvec.BASE + 0x68 | + | 25 | MSYS_IE1 | mtvec.BASE + 0x64 | + | 24 | MSYS_IE0 | mtvec.BASE + 0x60 | + | 23 | SUBSYS_EI | mtvec.BASE + 0x5C | + | 22 | SUBSYSR | mtvec.BASE + 0x58 | + | 17 | MGECIE | mtvec.BASE + 0x44 | + | 16 | MGEUIE | mtvec.BASE + 0x40 | + | 11 | MEIE | mtvec.BASE + 0x2C | + | 7 | MTIE | mtvec.BASE + 0x1C | + | 3 | MSIE | mtvec.BASE + 0x0C | + + + For changes in MIE register map, see the [MIE Register Map for MIV_RV32 v3.0] + (#mie-register-map-for-miv_rv32-v3.0) section. + + SUBSYSR is currently not being used by the core and is Reserved for future use. + + The mtvec.BASE field corresponds to the bits [31:2], where mtvec stands for + Machine Trap Vector, and all traps set the PC to the the value stored in the + mtvec.BASE field when in Non-Vectored mode. In this case, a generic trap + handler is as an interrupt service routine. + + When Vectored interrupts are enabled, use this formula to calculate the trap + address: (mtvec.BASE + 4*cause), where cause comes from the mcause CSR. The + mcause register is written with a code indicating the event that caused the trap. + For more details, see the RISC-V priv specification. + + The MIV_RV32 Soft IP core does not contain a Platfrom Level Interrup Controller + (PLIC). It is advised to use the PLIC contained within the MIV_ESS sub-system. + Connect the PLIC interrupt output of the MIV_ESS to the EXT_IRQ pin on the + MIV_RV32. + + The following table is the MIE register map for the MIV_RV32 Core V3.0. It only + highlights the differences between the V3.0 and V3.1 of the core. + + -------------------------------- + MIE Register Map for MIV_RV32 V3.0 + -------------------------------- + + | MIE Register Bit | Target Interrupt | Vector Address | + |-------------------|------------------|----------------| + | 31 | Not in use | top table | + | 30 | SUBSYS_EI | addr + 0x78 | + | 23 | Not in use | Not in use | + | 22 | Not in use | Not in use | + + Other interrupt bit postions like the MGEUIE and MSYS_IE5 to MSYS_IE0 remain + unchanged. + + -------------------------------- + Floating Point Interrupt Support + -------------------------------- + When an interrupt is taken and Floating Point instructions are used in the + ISR, the floating point register context must be saved to resume the application + correctly. To use this feature, enable the provided macro in the + Softconsole build settings. + This feature is turned off by default as it adds overhead which is not required + when the ISR does not used FP insturctions and saving the general purpose + register context is sufficient. + + | Macro Name | Definition | + |--------------------------|-------------------------------------------------| + | MIV_FP_CONTEXT_SAVE | Define to save the FP register file | + + + -------------------------------- + SUBSYS - SubSystem for RISC-V + -------------------------------- + SUBSYS stands for SubSystem for RISC-V. This was previously (MIV_RV32 v3.0) + known as OPSRV, which stands for "Offload Processor Subsystem + for RISC-V". See the earlier versions of the handbook for more details. + In the latest release of the MIV_RV32 IP core v3.1, OPSRV has been renamed to + SUBSYS. The MIV_RV32 HAL now uses SUBSYS instead of OPSRV. + + *//*=========================================================================*/ +#ifndef RISCV_HAL_H +#define RISCV_HAL_H + +#include "miv_rv32_regs.h" +#include "miv_rv32_plic.h" +#include "miv_rv32_assert.h" +#include "miv_rv32_subsys.h" + +#ifndef LEGACY_DIR_STRUCTURE +#include "fpga_design_config/fpga_design_config.h" +#else +#include "hw_platform.h" +#endif /*LEGACY_DIR_STRUCTURE*/ + +#ifdef __cplusplus +extern "C" { +#endif +/*-------------------------------------------------------------------------*//** + SUBSYS Backwards Compatibility + ======================================= + For application code using the older macro names and API functions, these macros + act as a compatibility layer and applications which use OPSRV API features work + due to these macro definitions. However, it is adviced to update your + application code to use the SUBSYS macros and API functions. + + | Macro Name | Now Called | + |-------------------------|--------------------------| + | OPSRV_TCM_ECC_CE_IRQ | SUBSYS_TCM_ECC_CE_IRQ | + | OPSRV_TCM_ECC_UCE_IRQ | SUBSYS_TCM_ECC_UCE_IRQ | + | OPSRV_AXI_WR_RESP_IRQ | SUBSYS_AXI_WR_RESP_IRQ | + | MRV32_MSYS_OPSRV_IRQn | MRV32_SUBSYS_IRQn | + | MRV32_opsrv_enable_irq | MRV32_subsys_enable_irq | + | MRV32_opsrv_disable_irq | MRV32_subsys_disable_irq | + | MRV32_opsrv_clear_irq | MRV32_subsys_clear_irq | + | OPSRV_IRQHandler | SUBSYS_IRQHandler | + */ + +/*-------------------------------------------------------------------------*//** + MTIME Timer Interrupt Constants + ======================================= + These values contain the register addresses for the registers used by the + machine timer interrupt + + MTIME_PRESCALER is not defined on the MIV_RV32IMC v2.0 and v2.1. By using this + definition the system crashes. For those core, use the following definition: + + #define MTIME_PRESCALER 100u + + MTIME and MTIMECMP + -------------------------------- + MIV_RV32 core offers flexibility in terms of generating MTIME and MTIMECMP + registers internal to the core or using external time reference. There four + possible combinations: + + - Internal MTIME and Internal MTIME IRQ enabled Generate the MTIME and MTIMECMP + registers internally. (The only combination available on legacy RV32 cores) + + - Internal MTIME enabled and Internal MTIME IRQ disabled Generate the MTIME + internally and have a timer interrupt input to the core as external pin. In + this case, 1 pin port will be available on MIV_RV32 for timer interrupt. + + - When the internal MTIME is disabled, and the Internal MTIME IRQ is enabled, the + system generates the time value externally and generates the mtimecmp and + interrupt internally (for example, a multiprocessor system with a shared time + between all cores). In this case, a 64-bit port is available on the MIV_RV32 + core as input. + + - Internal MTIME and Internal MTIME IRQ disabled Generate both the time and + timer interrupts externally. In this case a 64 bit port will be available on + the MIV_RV32 core as input, and a 1 pin port will be available for timer + interrupt. + + To handle all these combinations in the firmware, the following constants must + be defined in accordance with the configuration that you have made on your + MIV_RV32 core design. + + MIV_RV32_EXT_TIMER + -------------------------------- + When defined, it means that the MTIME register is not available internal to + the core. In this case, a 64 bit port will be available on the MIV_RV32 core as + input. When this macro is not defined, it means that the MTIME register is + available internally to the core. + + MIV_RV32_EXT_TIMECMP + -------------------------------- + When defined, it means the MTIMECMP register is not available internally to + the core and the Timer interrupt input to the core comes as an external pin. + When this macro is not defined it means the that MTIMECMP register exists + internal to the core and that the timer interrupt is generated internally. + +NOTE: All these macros must not be defined if you are using a MIV_RV32 core. + */ + +#define OPSRV_TCM_ECC_CE_IRQ SUBSYS_TCM_ECC_CE_IRQ +#define OPSRV_TCM_ECC_UCE_IRQ SUBSYS_TCM_ECC_UCE_IRQ +#define OPSRV_AXI_WR_RESP_IRQ SUBSYS_AXI_WR_RESP_IRQ +#define MRV32_MSYS_OPSRV_IRQn MRV32_SUBSYS_IRQn +#define MRV32_opsrv_enable_irq MRV32_subsys_enable_irq +#define MRV32_opsrv_disable_irq MRV32_subsys_disable_irq +#define MRV32_opsrv_clear_irq MRV32_subsys_clear_irq +#define OPSRV_IRQHandler SUBSYS_IRQHandler + +/*-------------------------------------------------------------------------*//** + External IRQ + ======================================= + Return value from External IRQ handler. This is used to disable the + External Interrupt. + + | Macro Name | Value | Description| + |-------------------|--------|----------------| + | EXT_IRQ_KEEP_ENABLED | 0 | Keep external interrupts enabled | + | EXT_IRQ_DISABLE | 1 | Disable external interrupts | + */ +#define EXT_IRQ_KEEP_ENABLED 0U +#define EXT_IRQ_DISABLE 1U + +#define MTIME_DELTA 5 +#ifdef MIV_LEGACY_RV32 +#define MSIP (*(uint32_t*)0x44000000UL) +#define MTIMECMP (*(uint32_t*)0x44004000UL) +#define MTIMECMPH (*(uint32_t*)0x44004004UL) +#define MTIME (*(uint32_t*)0x4400BFF8UL) +#define MTIMEH (*(uint32_t*)0x4400BFFCUL) + +/* To maintain backward compatibility with FreeRTOS config code */ +#define PRCI_BASE 0x44000000UL +#else /* MIV_LEGACY_RV32 */ + +/* To maintain backward compatibility with FreeRTOS config code */ +#define PRCI_BASE 0x02000000UL + +#ifndef MIV_RV32_EXT_TIMECMP +#define MTIMECMP (*(volatile uint32_t*)0x02004000UL) +#define MTIMECMPH (*(volatile uint32_t*)0x02004004UL) +#else +#define MTIMECMP (0u) +#define MTIMECMPH (0u) +#endif + +#define MTIME_PRESCALER (*(volatile uint32_t*)0x02005000UL) + +#ifndef MIV_RV32_EXT_TIMER +#define MTIME (*(volatile uint32_t*)0x0200BFF8UL) +#define MTIMEH (*(volatile uint32_t*)0x0200BFFCUL) + +/***************************************************************************//** + MIMPID Register + The MIMPID register is a RISC-V Control and Status Register In the v3.0 of + MIV_RV32, the value of `MIMPID = 0x000540AD`. In the v3.1 of MIV_RV32, the + value if `MIMPID = 0xE5010301` corresponding to (E)mbedded (5)ystem(01) core + version (03).(01) this terminology will be followed in the subsequent releases + of the core read the csr value and store it in a varible which may be used to + check the MIV_RV32 core version during runtime. + + Future releases of the core will increment the 03 and 01 as major and minor + releases respectively and the register can be read at runtime to find the + Soft IP core version. + + | Core Version | Register | Value | Notes | + |----------------|------------|---------|---------| + | MIV_RV32 V3.1 | mimpid | 0xE5010301 | implimentation ID | + | MIV_RV32 V3.0 | mimpid | 0x000540AD | implimentation ID | + */ +#define MIMPID read_csr(mimpid) + +/*Used as a mask to read and write to mte mtvec.BASE address*/ +#define MTVEC_BASE_ADDR_MASK 0xFFFFFFFC + +#else +#define MTIME (0u) +#define MTIMEH (0u) +#endif /*MIV_RV32_EXT_TIMER*/ + +/*-------------------------------------------------------------------------*//** + RISC-V Specification Interrupts + ======================================= + These definitions are provided for easy identification of the interrupt + in the MIE/MIP registers. + Apart from the standard software, timer, and external interrupts, the names + of the additional interrupts correspond to the names as used in the MIV_RV32 + handbook. Please refer the MIV_RV32 handbook for more details. + + All the interrups, provided by the MIV_RV32 core, follow the interrupt priority + order and register description as mentioned in the RISC-V spec. + + | Macro Name | Value | Description| + |-------------------|--------|----------------| + | MRV32_SOFT_IRQn | MIE_3_IRQn | Software interrupt enable | + | MRV32_TIMER_IRQn | MIE_7_IRQn | Timer interrupt enable | + | MRV32_EXT_IRQn | MIE_11_IRQn | External interrupt enable | + + */ +#define MRV32_SOFT_IRQn MIE_3_IRQn +#define MRV32_TIMER_IRQn MIE_7_IRQn +#define MRV32_EXT_IRQn MIE_11_IRQn + +/***************************************************************************//** + Interrupt numbers: + This enum represents the interrupt enable bits in the MIE register. + */ +enum +{ + MIE_0_IRQn = (0x01u), + MIE_1_IRQn = (0x01u<<1u), + MIE_2_IRQn = (0x01u<<2u), + MIE_3_IRQn = (0x01u<<3u), /*MSIE 0xC*/ + MIE_4_IRQn = (0x01u<<4u), + MIE_5_IRQn = (0x01u<<5u), + MIE_6_IRQn = (0x01u<<6u), + MIE_7_IRQn = (0x01u<<7u), /*MTIE 0x1C*/ + MIE_8_IRQn = (0x01u<<8u), + MIE_9_IRQn = (0x01u<<9u), + MIE_10_IRQn = (0x01u<<10u), + MIE_11_IRQn = (0x01u<<11u), /*MEIE 0x2C*/ + MIE_12_IRQn = (0x01u<<12u), + MIE_13_IRQn = (0x01u<<13u), + MIE_14_IRQn = (0x01u<<14u), + MIE_15_IRQn = (0x01u<<15u), + MIE_16_IRQn = (0x01u<<16u), /*MGEUIE ECC Uncorrectable 0x40*/ + MIE_17_IRQn = (0x01u<<17u), /*MGECIE ECC Correctable 0x44*/ + MIE_18_IRQn = (0x01u<<18u), + MIE_19_IRQn = (0x01u<<19u), + MIE_20_IRQn = (0x01u<<20u), + MIE_21_IRQn = (0x01u<<21u), + MIE_22_IRQn = (0x01u<<22u), /*SUBSYSR 0x58 (R)eserved*/ + MIE_23_IRQn = (0x01u<<23u), /*SUBSYS_IE 0x5C for MIV_RV32 v3.1*/ + MIE_24_IRQn = (0x01u<<24u), /*MSYS_IE0 0x60*/ + MIE_25_IRQn = (0x01u<<25u), /*MSYS_IE1 0x64*/ + MIE_26_IRQn = (0x01u<<26u), /*MSYS_IE2 0x68*/ + MIE_27_IRQn = (0x01u<<27u), /*MSYS_IE3 0x6C*/ + MIE_28_IRQn = (0x01u<<28u), /*MSYS_IE4 0x70*/ + MIE_29_IRQn = (0x01u<<29u), /*MSYS_IE5 0x74*/ + MIE_30_IRQn = (0x01u<<30u), /*MSYS_IE6 0x78, read comment below*/ + MIE_31_IRQn = (0x01u<<31u) /*MSYS_IE7 0x7C*/ +} MRV_LOCAL_IRQn_Type; + +#define MRV32_MGEUIE_IRQn MIE_16_IRQn +#define MRV32_MGECIE_IRQn MIE_17_IRQn +#define MRV32_MSYS_EIE0_IRQn MIE_24_IRQn +#define MRV32_MSYS_EIE1_IRQn MIE_25_IRQn +#define MRV32_MSYS_EIE2_IRQn MIE_26_IRQn +#define MRV32_MSYS_EIE3_IRQn MIE_27_IRQn +#define MRV32_MSYS_EIE4_IRQn MIE_28_IRQn +#define MRV32_MSYS_EIE5_IRQn MIE_29_IRQn +#ifndef MIV_RV32_V3_0 /*For MIV_RV32 v3.1*/ +#define MRV32_SUBSYSR_IRQn MIE_22_IRQn +#define MRV32_SUBSYS_IRQn MIE_23_IRQn +#define MRV32_MSYS_EIE6_IRQn MIE_30_IRQn +#define MRV32_MSYS_EIE7_IRQn MIE_31_IRQn +#else +#define MRV32_SUBSYS_IRQn MIE_30_IRQn +#endif /*MIV_RV32_V3_0*/ + +/*--------------------------------Public APIs---------------------------------*/ + +/***************************************************************************//** + The MRV32_clear_gpr_ecc_errors() function clears single bit ECC errors on the + GPRs. The ECC block does not write back corrected data to memory. Hence, when + ECC is enabled for the GPRs and if that data has a single bit error then the + data coming out of the ECC block is corrected and will not have the error, but + the data source will still have the error. Therefore, if data has a single bit + error, then the corrected data must be written back to prevent the single bit + error from becoming a double bit error. Clear the pending interrupt bit after + this using MRV32_mgeci_clear_irq() function to complete the ECC error handling. + + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline void MRV32_clear_gpr_ecc_errors(void) +{ + uint32_t temp; + + __asm__ __volatile__ ( + "sw x31, %0" + :"=m" (temp)); + + __asm__ volatile ( + "mv x31, x1;" + "mv x1, x31;" + + "mv x31, x2;" + "mv x2, x31;" + + "mv x31, x3;" + "mv x3, x31;" + + "mv x31, x4;" + "mv x4, x31;" + + "mv x31, x5;" + "mv x5, x31;" + + "mv x31, x6;" + "mv x6, x31;" + + "mv x31, x7;" + "mv x7, x31;" + + "mv x31, x8;" + "mv x8, x31;" + + "mv x31, x9;" + "mv x9, x31;" + + "mv x31, x10;" + "mv x10, x31;" + + "mv x31, x11;" + "mv x11, x31;" + + "mv x31, x12;" + "mv x12, x31;" + + "mv x31, x13;" + "mv x13, x31;" + + "mv x31, x14;" + "mv x14, x31;" + + "mv x31, x15;" + "mv x15, x31;" + + "mv x31, x16;" + "mv x16, x31;" + + "mv x31, x17;" + "mv x17, x31;" + + "mv x31, x18;" + "mv x18, x31;" + + "mv x31, x19;" + "mv x19, x31;" + + "mv x31, x20;" + "mv x20, x31;" + + "mv x31, x21;" + "mv x21, x31;" + + "mv x31, x22;" + "mv x22, x31;" + + "mv x31, x23;" + "mv x23, x31;" + + "mv x31, x24;" + "mv x24, x31;" + + "mv x31, x25;" + "mv x25, x31;" + + "mv x31, x26;" + "mv x26, x31;" + + "mv x31, x27;" + "mv x27, x31;" + + "mv x31, x28;" + "mv x28, x31;" + + "mv x31, x29;" + "mv x29, x31;" + + "mv x31, x30;" + "mv x30, x31;"); + + __asm__ __volatile__ ( + "lw x31, %0;" + : + :"m" (temp)); +} + + +/***************************************************************************//** + The MRV32_mgeui_clear_irq() function clears the GPR ECC Uncorrectable + Interrupt. MGEUI interrupt is available only when ECC is enabled in the MIV_RV32 + IP configurator. + + @return + This function does not return any value. + */ +static inline void MRV32_mgeui_clear_irq(void) +{ + clear_csr(mip, MRV32_MGEUIE_IRQn); +} + +/***************************************************************************//** + The MRV32_mgeci_clear_irq() function clears the GPR ECC Correctable Interrupt + MGECI interrupt is available only when ECC is enabled in the MIV_RV32 IP + configurator. + + @return + This function does not return any value. + */ +static inline void MRV32_mgeci_clear_irq(void) +{ + clear_csr(mip, MRV32_MGECIE_IRQn); +} + +/***************************************************************************//** + The MRV_enable_local_irq() function enables the local interrupts. It takes a + mask value as input. For each set bit in the mask value, the corresponding + interrupt bit in the MIE register is enabled. + + MRV_enable_local_irq( MRV32_SOFT_IRQn | MRV32_TIMER_IRQn | MRV32_EXT_IRQn | + MRV32_MSYS_EIE0_IRQn | + MRV32_MSYS_SUBSYS_IRQn); + */ +static inline void MRV_enable_local_irq(uint32_t mask) +{ + set_csr(mie, mask); +} + +/***************************************************************************//** + The MRV_disable_local_irq() function disables the local interrupts. It takes a + mask value as input. For each set bit in the mask value, the corresponding + interrupt bit in the MIE register is disabled. + + MRV_disable_local_irq( MRV32_SOFT_IRQn | MRV32_TIMER_IRQn | MRV32_EXT_IRQn | + MRV32_MSYS_EIE0_IRQn | + MRV32_MSYS_SUBSYS_IRQn); + */ +static inline void MRV_disable_local_irq(uint32_t mask) +{ + clear_csr(mie, mask); +} +#endif /* MIV_LEGACY_RV32 */ + +/***************************************************************************//** + The MRV_enable_interrupts() function enables all interrupts by setting the + machine mode interrupt enable bit in MSTATUS register. + + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline void MRV_enable_interrupts(void) +{ + set_csr(mstatus, MSTATUS_MIE); +} + +/***************************************************************************//** + The MRV_disable_interrupts() function disables all interrupts by clearing the + machine mode interrupt enable bit in MSTATUS register. + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline void MRV_disable_interrupts(void) +{ + clear_csr(mstatus, MSTATUS_MPIE); + clear_csr(mstatus, MSTATUS_MIE); +} + +/***************************************************************************//** + The MRV_read_mtvec_base() function reads the mtvec base value, which is the + addr used when an interrupt/trap occurs. In the mtvec register, [31:2] is the + BASE address. NOTE: The BASE address must be aligned on a 4B boundary. + + @param + The function does not take any parameters. + + @return + The function returns the value of the BASE field [31:2] as an unsigned 32-bit + value. + */ + +#ifndef MIV_LEGACY_RV32 +#ifndef MIV_RV32_v3_0 +static inline uint32_t MRV_read_mtvec_base (void) +{ + uint32_t mtvec_addr_base = read_csr(mtvec); + return mtvec_addr_base & MTVEC_BASE_ADDR_MASK; +} + +/***************************************************************************//** + The MRV_set_mtvec_base() function takes the mtvec_base address as a unsigned int + and writes the value into the BASE field [31:2] in the mtvec CSR, MODE[1:0] + is Read-only. BASE is 4B aligned, so the lowest 2 bits of mtvec_base are + ignored. + + @param mtvec_base + Any legal value is passed into the function, and it is used as the trap_entry + for interrupts. The PC jumps to this address provided when an interrupt occurs. + In case of vectored interrupts, the address value mentioned in the vector + table under the MIE Register Map is updated to the value passed to this + function parameter. + + @return + This function does not return any value. + */ +static inline void MRV_set_mtvec_base (uint32_t mtvec_base) +{ + mtvec_base = mtvec_base & MTVEC_BASE_ADDR_MASK; + write_csr(mtvec, mtvec_base); +} +#endif /*MIV_RV32_v3_0*/ +#endif /*MIV_LEGACY_RV32*/ + +/***************************************************************************//** + The MRV_read_mtime() function returns the current MTIME register value. + */ +static inline uint64_t MRV_read_mtime(void) +{ + volatile uint32_t hi = 0u; + volatile uint32_t lo = 0u; + + /* when mtime lower word is 0xFFFFFFFF, there will be rollover and + * returned value could be wrong. */ + do { + hi = MTIMEH; + lo = MTIME; + } while(hi != MTIMEH); + + return((((uint64_t)MTIMEH) << 32u) | lo); +} + +/***************************************************************************//** + The MRV_raise_soft_irq() function raises a synchronous software interrupt + by writing into the MSIP register. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV_raise_soft_irq(void) +{ + set_csr(mie, MIP_MSIP); /* Enable software interrupt bit */ + +#ifdef MIV_LEGACY_RV32 + /* You need to make sure that the global interrupt is enabled */ + MSIP = 0x01; /* raise soft interrupt */ +#else + /* Raise soft IRQ on MIV_RV32 processor */ + SUBSYS->soft_reg |= SUBSYS_SOFT_IRQ; +#endif +} + +/***************************************************************************//** + The MRV_clear_soft_irq() function clears a synchronous software interrupt + by clearing the MSIP register. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV_clear_soft_irq(void) +{ +#ifdef MIV_LEGACY_RV32 + MSIP = 0x00u; /* clear soft interrupt */ +#else + /* Clear soft IRQ on MIV_RV32 processor */ + SUBSYS->soft_reg &= ~SUBSYS_SOFT_IRQ; +#endif +} + +/***************************************************************************//** + System tick handler. This handler function gets called when the Machine + timer interrupt asserts. An implementation of this function must be provided + by the application to implement the application specific machine timer + interrupt handling. If application does not provide such implementation, the + weakly linked handler stub function implemented in riscv_hal_stubs.c gets + linked. + */ +void SysTick_Handler(void); + +/***************************************************************************//** + System timer tick configuration. + Configures the machine timer to generate a system tick interrupt at regular + intervals. Takes the number of system clock ticks between interrupts. + + Though this function can take any valid ticks value as parameter, we expect + that, for all practical purposes, a small tick value (to generate periodic + interrupts every few miliseconds) is passed. If you need to generate periodic + events in the range of seconds or more, you may use the SysTick_Handler() to + further count the number of interrupts and hence the larger time intervals. + + @param ticks + This is the number of ticks or clock cycles which are counted down from the + interrupt to be triggered. + + @return + Returns 0 if successful. + Returns 1 if the interrupt interval is not achieved. + */ +uint32_t MRV_systick_config(uint64_t ticks); + +#ifdef __cplusplus +} +#endif +#endif /* RISCV_HAL_H */ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv_rv32_hal_version.h b/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv_rv32_hal_version.h new file mode 100644 index 0000000..4922bf2 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv_rv32_hal_version.h @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_hal_version.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware Abstraction Layer functions for Mi-V soft processors + * + */ + +#ifndef MIV_RV32_HAL_VERSION_H +#define MIV_RV32_HAL_VERSION_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MIV_RV32_HAL_VERSION_MAJOR 4 +#define MIV_RV32_HAL_VERSION_MINOR 2 +#define MIV_RV32_HAL_VERSION_PATCH 100 + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv_rv32_init.c b/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv_rv32_init.c new file mode 100644 index 0000000..85f8aca --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv_rv32_init.c @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_init.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor memory section initializations and start-up code. + * + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern void main(void); + +void _init(void) +{ + /* This function is a placeholder for the case where some more hardware + * specific initializations are required before jumping into the application + * code. You can implement it here. */ + + /* Jump to the application code after all initializations are completed */ + main(); +} + +/* Function called after main() finishes */ +void +_fini(void) +{ +} + +#ifdef __cplusplus +} +#endif + diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv_rv32_plic.h b/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv_rv32_plic.h new file mode 100644 index 0000000..3fd4103 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv_rv32_plic.h @@ -0,0 +1,214 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_plic.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V legacy RV32 soft processor PLIC access data structures and + * functions. + * Legacy RV32 soft processors are DEPRICATED. + * Migrate to MIV_RV32 v3.0 or later. + * + */ +#ifndef RISCV_PLIC_H +#define RISCV_PLIC_H + +#include +#include "miv_rv32_regs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================== + * Interrupt numbers: + */ +#ifdef MIV_LEGACY_RV32 +typedef enum +{ + MRV_NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + External_3_IRQn = 3, + External_4_IRQn = 4, + External_5_IRQn = 5, + External_6_IRQn = 6, + External_7_IRQn = 7, + External_8_IRQn = 8, + External_9_IRQn = 9, + External_10_IRQn = 10, + External_11_IRQn = 11, + External_12_IRQn = 12, + External_13_IRQn = 13, + External_14_IRQn = 14, + External_15_IRQn = 15, + External_16_IRQn = 16, + External_17_IRQn = 17, + External_18_IRQn = 18, + External_19_IRQn = 19, + External_20_IRQn = 20, + External_21_IRQn = 21, + External_22_IRQn = 22, + External_23_IRQn = 23, + External_24_IRQn = 24, + External_25_IRQn = 25, + External_26_IRQn = 26, + External_27_IRQn = 27, + External_28_IRQn = 28, + External_29_IRQn = 29, + External_30_IRQn = 30, + External_31_IRQn = 31 +} IRQn_Type; + +#define EXT_INTR_SOURCES 31 + +/*============================================================================== + * PLIC: Platform Level Interrupt Controller + */ +#define PLIC_BASE_ADDR 0x40000000UL + +typedef struct +{ + volatile uint32_t PRIORITY_THRESHOLD; + volatile uint32_t CLAIM_COMPLETE; + volatile uint32_t reserved[1022]; +} MRV_IRQ_Target_Type; + +typedef struct +{ + volatile uint32_t ENABLES[32]; +} MRV_Target_Enables_Type; + +typedef struct +{ + /*-------------------- Source Priority --------------------*/ + volatile uint32_t SOURCE_PRIORITY[1024]; + + /*-------------------- Pending array --------------------*/ + volatile const uint32_t PENDING_ARRAY[32]; + volatile uint32_t RESERVED1[992]; + + /*-------------------- Target enables --------------------*/ + volatile MRV_Target_Enables_Type TARGET_ENABLES[15808]; + + volatile uint32_t RESERVED2[16384]; + + /*--- Target Priority threshold and claim/complete---------*/ + MRV_IRQ_Target_Type TARGET[15872]; + +} PLIC_Type; + +#define PLIC ((PLIC_Type *)PLIC_BASE_ADDR) + +/*============================================================================== + * The function MRV_PLIC_init() initializes the PLIC controller and enables + * the global external interrupt bit. + */ +static inline void MRV_PLIC_init(void) +{ + uint32_t inc; + unsigned long hart_id = read_csr(mhartid); + + /* Disable all interrupts for the current hart. */ + for(inc = 0; inc < ((EXT_INTR_SOURCES + 32u) / 32u); ++inc) + { + PLIC->TARGET_ENABLES[hart_id].ENABLES[inc] = 0; + } + + /* Set priorities to zero. */ + for(inc = 0; inc < EXT_INTR_SOURCES; ++inc) + { + PLIC->SOURCE_PRIORITY[inc] = 0; + } + + /* Set the threshold to zero. */ + PLIC->TARGET[hart_id].PRIORITY_THRESHOLD = 0; + + /* Enable machine external interrupts. */ + set_csr(mie, MIP_MEIP); +} + +/*============================================================================== + * The function MRV_PLIC_enable_irq() enables the external interrupt for the + * interrupt number indicated by the parameter IRQn. + */ +static inline void MRV_PLIC_enable_irq(IRQn_Type IRQn) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t current = PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32]; + current |= (uint32_t)1 << (IRQn % 32); + PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32] = current; +} + +/*============================================================================== + * The function MRV_PLIC_disable_irq() disables the external interrupt for + * the interrupt number indicated by the parameter IRQn. + + * NOTE: + * This function can be used to disable the external interrupt from outside + * external interrupt handler function. + * This function MUST NOT be used from within the External Interrupt handler. + * If you wish to disable the external interrupt while the interrupt handler + * for that external interrupt is executing then you must use the return value + * EXT_IRQ_DISABLE to return from the extern interrupt handler. + */ +static inline void MRV_PLIC_disable_irq(IRQn_Type IRQn) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t current = PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32]; + + current &= ~((uint32_t)1 << (IRQn % 32)); + + PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32] = current; +} + +/*============================================================================== + * The function MRV_PLIC_set_priority() sets the priority for the external + * interrupt for the interrupt number indicated by the parameter IRQn. + */ +static inline void MRV_PLIC_set_priority(IRQn_Type IRQn, uint32_t priority) +{ + PLIC->SOURCE_PRIORITY[IRQn] = priority; +} + +/*============================================================================== + * The function MRV_PLIC_get_priority() returns the priority for the external + * interrupt for the interrupt number indicated by the parameter IRQn. + */ +static inline uint32_t MRV_PLIC_get_priority(IRQn_Type IRQn) +{ + return PLIC->SOURCE_PRIORITY[IRQn]; +} + +/***************************************************************************//** + * MRV_PLIC_clear_pending_irq(void) + * This is only called by the startup hart and only once + * Clears any pending interrupts as PLIC can be in unknown state on startup + */ +static inline void MRV_PLIC_clear_pending_irq(void) +{ + unsigned long hart_id = read_csr(mhartid); + volatile uint32_t int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; + volatile int32_t wait_possible_int; + + while (MRV_NoInterrupt_IRQn != int_num) + { + PLIC->TARGET[hart_id].CLAIM_COMPLETE = int_num; + wait_possible_int = 0xFU; + while (wait_possible_int) + { + wait_possible_int--; + } + + int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; + } +} + +#endif /* MIV_LEGACY_RV32 */ + +#ifdef __cplusplus +} +#endif + +#endif /* RISCV_PLIC_H */ diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv_rv32_regs.h b/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv_rv32_regs.h new file mode 100644 index 0000000..07d58e7 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv_rv32_regs.h @@ -0,0 +1,520 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor register bit mask and shift constants encodings. + * + */ +#ifndef MIV_RV32_REGS_H +#define MIV_RV32_REGS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MSTATUS_UIE 0x00000001UL +#define MSTATUS_SIE 0x00000002UL +#define MSTATUS_HIE 0x00000004UL +#define MSTATUS_MIE 0x00000008UL +#define MSTATUS_UPIE 0x00000010UL +#define MSTATUS_SPIE 0x00000020UL +#define MSTATUS_HPIE 0x00000040UL +#define MSTATUS_MPIE 0x00000080UL +#define MSTATUS_SPP 0x00000100UL +#define MSTATUS_HPP 0x00000600UL +#define MSTATUS_MPP 0x00001800UL +#define MSTATUS_FS 0x00006000UL +#define MSTATUS_XS 0x00018000UL +#define MSTATUS_MPRV 0x00020000UL +#define MSTATUS_SUM 0x00040000UL +#define MSTATUS_MXR 0x00080000UL +#define MSTATUS_TVM 0x00100000UL +#define MSTATUS_TW 0x00200000UL +#define MSTATUS_TSR 0x00400000UL +#define MSTATUS_RES 0x7F800000UL +#define MSTATUS32_SD 0x80000000UL +#define MSTATUS64_SD 0x8000000000000000UL + +#define MCAUSE32_CAUSE 0x7FFFFFFFUL +#define MCAUSE64_CAUSE 0x7FFFFFFFFFFFFFFFUL +#define MCAUSE32_INT 0x80000000UL +#define MCAUSE64_INT 0x8000000000000000UL + +#define MIP_SSIP (1u << IRQ_S_SOFT) +#define MIP_HSIP (1u << IRQ_H_SOFT) +#define MIP_MSIP (1u << IRQ_M_SOFT) +#define MIP_STIP (1u << IRQ_S_TIMER) +#define MIP_HTIP (1u << IRQ_H_TIMER) +#define MIP_MTIP (1u << IRQ_M_TIMER) +#define MIP_SEIP (1u << IRQ_S_EXT) +#define MIP_HEIP (1u << IRQ_H_EXT) +#define MIP_MEIP (1u << IRQ_M_EXT) + +#define PRV_M 3U + +#define VM_MBARE 0U +#define VM_MBB 1U +#define VM_MBBID 2U +#define VM_SV32 8U +#define VM_SV39 9U +#define VM_SV48 10U + +#define IRQ_S_SOFT 1U +#define IRQ_H_SOFT 2U +#define IRQ_M_SOFT 3U +#define IRQ_S_TIMER 5U +#define IRQ_H_TIMER 6U +#define IRQ_M_TIMER 7U +#define IRQ_S_EXT 9U +#define IRQ_H_EXT 10U +#define IRQ_M_EXT 11U + +#define DEFAULT_RSTVEC 0x00001000 +#define DEFAULT_NMIVEC 0x00001004 +#define DEFAULT_MTVEC 0x00001010 +#define CONFIG_STRING_ADDR 0x0000100C +#define EXT_IO_BASE 0x40000000 +#define DRAM_BASE 0x80000000 + +#ifdef __riscv + +#if __riscv_xlen == 64 +# define MSTATUS_SD MSTATUS64_SD +# define SSTATUS_SD SSTATUS64_SD +# define MCAUSE_INT MCAUSE64_INT +# define MCAUSE_CAUSE MCAUSE64_CAUSE +# define RISCV_PGLEVEL_BITS 9 +#else +# define MSTATUS_SD MSTATUS32_SD +# define SSTATUS_SD SSTATUS32_SD +# define RISCV_PGLEVEL_BITS 10 +# define MCAUSE_INT MCAUSE32_INT +# define MCAUSE_CAUSE MCAUSE32_CAUSE +#endif + +#define RISCV_PGSHIFT 12U +#define RISCV_PGSIZE (1U << RISCV_PGSHIFT) + +#ifndef __ASSEMBLER__ + +#ifdef __GNUC__ + +#define read_csr(reg) ({ unsigned long __tmp; \ + __asm__ volatile ("csrr %0, " #reg : "=r"(__tmp)); \ + __tmp; }) + +#define write_csr(reg, val) ({ \ + __asm__ volatile ("csrw " #reg ", %0" :: "rK"(val)); }) + +#define swap_csr(reg, val) ({ unsigned long __tmp; \ + __asm__ volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "rK"(val)); \ + __tmp; }) + +#define set_csr(reg, bit) ({ unsigned long __tmp; \ + __asm__ volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ + __tmp; }) + +#define clear_csr(reg, bit) ({ unsigned long __tmp; \ + __asm__ volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ + __tmp; }) + +#ifdef __riscv_atomic + +#define MASK(nr) (1UL << nr) +#define MASK_NOT(nr) (~(1UL << nr)) + +/** + * atomic_read - read atomic variable + * @v: pointer of type int + * + * Atomically reads the value of @v. + */ +static inline int atomic_read(const int *v) +{ + return *((volatile int *)(v)); +} + +/** + * atomic_set - set atomic variable + * @v: pointer of type int + * @i: required value + * + * Atomically sets the value of @v to @i. + */ +static inline void atomic_set(int *v, int i) +{ + *v = i; +} + +/** + * atomic_add - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v. + */ +static inline void atomic_add(int i, int *v) +{ + __asm__ __volatile__ ( + "amoadd.w zero, %1, %0" + : "+A" (*v) + : "r" (i)); +} + +static inline int atomic_fetch_add(unsigned int mask, int *v) +{ + int out; + + __asm__ __volatile__ ( + "amoadd.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_sub - subtract integer from atomic variable + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v. + */ +static inline void atomic_sub(int i, int *v) +{ + atomic_add(-i, v); +} + +static inline int atomic_fetch_sub(unsigned int mask, int *v) +{ + int out; + + __asm__ __volatile__ ( + "amosub.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_add_return - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v and returns the result + */ +static inline int atomic_add_return(int i, int *v) +{ + register int c; + __asm__ __volatile__ ( + "amoadd.w %0, %2, %1" + : "=r" (c), "+A" (*v) + : "r" (i)); + return (c + i); +} + +/** + * atomic_sub_return - subtract integer from atomic variable + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v and returns the result + */ +static inline int atomic_sub_return(int i, int *v) +{ + return atomic_add_return(-i, v); +} + +/** + * atomic_inc - increment atomic variable + * @v: pointer of type int + * + * Atomically increments @v by 1. + */ +static inline void atomic_inc(int *v) +{ + atomic_add(1, v); +} + +/** + * atomic_dec - decrement atomic variable + * @v: pointer of type int + * + * Atomically decrements @v by 1. + */ +static inline void atomic_dec(int *v) +{ + atomic_add(-1, v); +} + +static inline int atomic_inc_return(int *v) +{ + return atomic_add_return(1, v); +} + +static inline int atomic_dec_return(int *v) +{ + return atomic_sub_return(1, v); +} + +/** + * atomic_sub_and_test - subtract value from variable and test result + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v and returns + * true if the result is zero, or false for all + * other cases. + */ +static inline int atomic_sub_and_test(int i, int *v) +{ + return (atomic_sub_return(i, v) == 0); +} + +/** + * atomic_inc_and_test - increment and test + * @v: pointer of type int + * + * Atomically increments @v by 1 + * and returns true if the result is zero, or false for all + * other cases. + */ +static inline int atomic_inc_and_test(int *v) +{ + return (atomic_inc_return(v) == 0); +} + +/** + * atomic_dec_and_test - decrement and test + * @v: pointer of type int + * + * Atomically decrements @v by 1 and + * returns true if the result is 0, or false for all other + * cases. + */ +static inline int atomic_dec_and_test(int *v) +{ + return (atomic_dec_return(v) == 0); +} + +/** + * atomic_add_negative - add and test if negative + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v and returns true + * if the result is negative, or false when + * result is greater than or equal to zero. + */ +static inline int atomic_add_negative(int i, int *v) +{ + return (atomic_add_return(i, v) < 0); +} + +static inline int atomic_xchg(int *v, int n) +{ + register int c; + __asm__ __volatile__ ( + "amoswap.w %0, %2, %1" + : "=r" (c), "+A" (*v) + : "r" (n)); + return c; +} + +/** + * atomic_and - Atomically clear bits in atomic variable + * @mask: Mask of the bits to be retained + * @v: pointer of type int + * + * Atomically retains the bits set in @mask from @v + */ +static inline void atomic_and(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoand.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_and(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoand.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_or - Atomically set bits in atomic variable + * @mask: Mask of the bits to be set + * @v: pointer of type int + * + * Atomically sets the bits set in @mask in @v + */ +static inline void atomic_or(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoor.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_or(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoor.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_xor - Atomically flips bits in atomic variable + * @mask: Mask of the bits to be flipped + * @v: pointer of type int + * + * Atomically flips the bits set in @mask in @v + */ +static inline void atomic_xor(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoxor.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_xor(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoxor.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * test_and_set_bit - Set a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_set_bit(int nr, volatile unsigned long *addr) +{ + unsigned long __res, __mask; + __mask = MASK(nr); + __asm__ __volatile__ ( \ + "amoor.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to clear + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_clear_bit(int nr, volatile unsigned long *addr) +{ + unsigned long __res, __mask; + __mask = MASK_NOT(nr); + __asm__ __volatile__ ( \ + "amoand.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * test_and_change_bit - Change a bit and return its old value + * @nr: Bit to change + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_change_bit(int nr, volatile unsigned long *addr) +{ + + unsigned long __res, __mask; + __mask = MASK(nr); + __asm__ __volatile__ ( \ + "amoxor.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * set_bit - Atomically set a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * This function is atomic and may not be reordered. + */ + +static inline void set_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOOR.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK(nr))); +} + +/** + * clear_bit - Clears a bit in memory + * @nr: Bit to clear + * @addr: Address to start counting from + * + * clear_bit() is atomic and may not be reordered. + */ +static inline void clear_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOAND.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK_NOT(nr))); +} + +/** + * change_bit - Toggle a bit in memory + * @nr: Bit to change + * @addr: Address to start counting from + * + * change_bit() is atomic and may not be reordered. + */ +static inline void change_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOXOR.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK(nr))); +} + +#endif /* __riscv_atomic */ + +#endif /* __GNUC__ */ + +#endif /* __ASSEMBLER__ */ + +#endif /* __riscv */ + +#ifdef __cplusplus +} +#endif + +#endif /* RISCV_REGS_H */ diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv_rv32_stubs.c b/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv_rv32_stubs.c new file mode 100644 index 0000000..e26ecfc --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv_rv32_stubs.c @@ -0,0 +1,243 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_stubs.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Stubs for the Mi-V soft processor Interrupt handler. + * + * The functions below will only be linked with the application code if the user + * does not provide an implementation for these functions. These functions are + * defined with weak linking so that they can be overridden by a function with + * same prototype in the user's application code. + * + */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +__attribute__((weak)) void Software_IRQHandler(void) +{ + _exit(10); +} + +__attribute__((weak)) void SysTick_Handler(void) +{ + /* Default handler */ +} + +#ifdef MIV_LEGACY_RV32 +__attribute__((weak)) uint8_t Invalid_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_1_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_2_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_3_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_4_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_5_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_6_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_7_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_8_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_9_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_10_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_11_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_12_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_13_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_14_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_15_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_16_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_17_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_18_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_19_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_20_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_21_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_22_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_23_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_24_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_25_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_26_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_27_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_28_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_29_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_30_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_31_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +#else +__attribute__((weak)) void External_IRQHandler(void) +{ +} +__attribute__((weak)) void MGECI_IRQHandler(void) +{ +} +__attribute__((weak)) void MGEUI_IRQHandler(void) +{ +} +__attribute__((weak)) void SUBSYS_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI0_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI1_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI2_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI3_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI4_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI5_IRQHandler(void) +{ +} +__attribute__((weak)) void Reserved_IRQHandler(void) +{ + _exit(10); +} +#ifndef MIV_RV32_V3_0 /* For MIV_RV32 v3.0 */ +__attribute__((weak)) void MSYS_EI6_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI7_IRQHandler(void) +{ +} +__attribute__((weak)) void SUBSYSR_IRQHandler(void) +{ +} +#endif /* MIV_RV32_V3_0 */ +#endif /* MIV_LEGACY_RV32 */ + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv_rv32_subsys.h b/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv_rv32_subsys.h new file mode 100644 index 0000000..509f13b --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv_rv32_subsys.h @@ -0,0 +1,293 @@ +/******************************************************************************* + * Copyright 2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_subsys.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor SUBSYS regsiter description and API fuctions. + * + */ +#ifndef MIV_RV32_SUBSYS_H +#define MIV_RV32_SUBSYS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef MIV_LEGACY_RV32 +#define MGEUI 16U +#define MGECI 17U +#define MSYS_EI0 24U +#define MSYS_EI1 25U +#define MSYS_EI2 26U +#define MSYS_EI3 27U +#define MSYS_EI4 28U +#define MSYS_EI5 29U + +#define MGEUI_MEIP (1u << MGEUI) +#define MGECI_MEIP (1u << MGECI) +#define MSYS_EI0IP (1u << MSYS_EI0) +#define MSYS_EI1IP (1u << MSYS_EI1) +#define MSYS_EI2IP (1u << MSYS_EI2) +#define MSYS_EI3IP (1u << MSYS_EI3) +#define MSYS_EI4IP (1u << MSYS_EI4) +#define MSYS_EI5IP (1u << MSYS_EI5) + +#define MIV_LOCAL_IRQ_MIN 16 +#ifndef MIV_RV32_V3_0 /*For MIV_RV32 v3.1*/ +#define SUBSYSR 22U +#define SUBSYS_EI 23U +#define MSYS_EI6 30U +#define MSYS_EI7 31U +#define MIV_SUBSYSR (1u << SUBSYSR) +#define MIV_SUBSYS (1u << SUBSYS_EI) +#define MSYS_EI6IP (1u << MSYS_EI6) +#define MSYS_EI7IP (1u << MSYS_EI7) +#define MIV_LOCAL_IRQ_MAX 31 + +#else /* MIV_RV32_V3_0 */ +#define MIV_LOCAL_IRQ_MAX 29 +#define SUBSYS_EI 30U +#define MIP_SUBSYS_REG (1u << SUBSYS_EI) + +#endif /* MIV_RV32_V3_0 */ +#endif /* MIV_LEGACY_RV32 */ + +#ifdef MIV_LEGACY_RV32 +#define MIV_LOCAL_IRQ_MAX 0U +#define MIV_LOCAL_IRQ_MIN 0U +#endif /* MIV_LEGACY_RV32 */ + +#ifdef __cplusplus +} +#endif + +/*-------------------------------------------------------------------------*//** + SUBSYS Register Configuration + ======================================= + For the SUBSYS registers configutation, the following definitions are used in + the SUBSUS API functions. For example, to raise soft interrupts, enable parity + checks, soft reset, and so on. + + | Configuration | Value | Description | + |--------------------------|-------|------------------------------------------------| + | SUBSYS_SOFT_REG_GRP_DED | 0x04 | Mask for the Core GPR DED Reset Register | + | SUBSYS_CFG_PARITY_CHECK | 0x01 | Use to set or clear the parity check on the TCM | + | SUBSYS_SOFT_RESET | 0x01 | Use the SUBSYS soft reset the MIV_RV32 IP core | + | SUBSYS_SOFT_IRQ | 0x02 | Use to raise a software interrupt through SUBSYS| + */ +/*Mask for the Core GPR DED Reset Register*/ +#define SUBSYS_SOFT_REG_GRP_DED 0x04U + +/*Use to set or clear the parity check on the TCM*/ +#define SUBSYS_CFG_PARITY_CHECK 0x01U + +/*Use the SUBSYS soft reset the MIV_RV32 IP core*/ +#define SUBSYS_SOFT_RESET 0x01U + +/*Use to raise a software interrupt through SUBSYS*/ +#define SUBSYS_SOFT_IRQ 0x02U + +/*-------------------------------------------------------------------------*//** + SUBSYS Interrupt Request Masks + ======================================= + The following values correspond to the bit value of the SUBSYS interrupt + enable and interrupt pending register. + + | Interrupt Mask | Value | Description | + |----------------------------|---------|-------------------------------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | TCM ECC controllable error irq enable | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | TCM ECC uncontrollable error irq enable | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | AXI write response error irq enable | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | Icache ECC Correctable error irq | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | Icache ECC Uncorrectable error irq | + | SUBSYS_BASE_ADDR | 0x6000u | Base address of the SUBSYS | + */ +/* TCM ECC correctable error irq enable mask value */ +#define SUBSYS_TCM_ECC_CE_IRQ 0x01u + +/* TCMECC uncorrectable error irq enable */ +#define SUBSYS_TCM_ECC_UCE_IRQ 0x02u + +/* AXI write response error irq enable */ +#define SUBSYS_AXI_WR_RESP_IRQ 0x10u + +/*Icache ECC Correctable error irq*/ +#define SUBSYS_ICACHE_ECC_CE_IRQ 0x40u + +/*Icache ECC Uncorrectable error irq*/ +#define SUBSYS_ICACHE_ECC_UCE_IRQ 0x80u + +/*Base address of the SUBSYS*/ +#define SUBSYS_BASE_ADDR 0x00006000UL + +/***************************************************************************//** + Subsys contains interrupt enable, interrupt pending and Subsys registers + which can be used to enable SUBSYS specific features such as ECC for vaious + memories. For more available features refer to the MIV_RV32 User Guide +*/ +typedef struct +{ + volatile uint32_t cfg; /*Parity is not supported by MIV_RV32 v3.1 and MIV_RV32 v3.0.100*/ + volatile uint32_t reserved0[3]; + volatile uint32_t irq_en; /*offset 0x10*/ + volatile uint32_t irq_pend; + volatile uint32_t reserved1[2]; + volatile uint32_t soft_reg; /*offset 0x20*/ +} SUBSYS_Type; + +#define SUBSYS ((SUBSYS_Type *)SUBSYS_BASE_ADDR) + +/***************************************************************************//** + The MRV32_subsys_enable_irq() function initializes the SUBSYS interrupts. It + takes the logical OR of the following defined IRQ masks as a parameter. + + @param irq_mask + | irq_mask | Value | + |------------------------|------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | + Use logical OR values of one or more interrupts to enable them in the SUBSYS + @return + This function does not return any value. + */ +static inline void MRV32_subsys_enable_irq(uint32_t irq_mask) +{ + SUBSYS->irq_en |= irq_mask; +} + +/***************************************************************************//** + The MRV32_subsys_disable_irq() function disables the SUBSYS interrupts. It + takes the logical OR of the following defined IRQ masks as a parameter. + + @param irq_mask + | irq_mask | Value | + |------------------------|------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | + Use logical OR values of one or more interrupts to disable them in the SUBSYS + @return + This function does not return any value. + */ +static inline void MRV32_subsys_disable_irq(uint32_t irq_mask) +{ + SUBSYS->irq_en &= ~irq_mask; +} + +/***************************************************************************//** + The MRV32_subsys_clear_irq() function clears the SUBSYS interrupts, which was + triggered. It takes the logical OR of the following defined IRQ masks as a + parameter. + @param irq_mask + | irq_mask | Value | + |------------------------|------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | + Use logical OR values of one or more interrupts to disable them in the SUBSYS + @return + This function does not return any value. + */ +static inline void MRV32_subsys_clear_irq(uint32_t irq_mask) +{ + SUBSYS->irq_pend |= irq_mask; +} + +/***************************************************************************//** + The MRV32_subsys_irq_cause() function returns the irq_pend register value which + is present in the SUBSYS. This is be used to check which irq_mask value + caused the SUBSYS interrupt to occur. + @param + This function does not take any parameters + + @return + This function returns the irq_pend regsiter value. +*/ +static inline uint32_t MRV32_subsys_irq_cause() +{ + return SUBSYS->irq_pend; +} + +/***************************************************************************//** + The MRV32_is_gpr_ded() function returns the core_gpr_ded_reset_reg bit value. + When ECC is enabled, the core_gpr_ded_reset_reg is set when the core was + reset due to GPR DED error. + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline uint32_t MRV32_is_gpr_ded(void) +{ + return((SUBSYS->soft_reg & SUBSYS_SOFT_REG_GRP_DED) >> 0x02u); +} + +/***************************************************************************//** + The MRV32_clear_gpr_ded() function must be used to clear the + core_gpr_ded_reset_reg bit. When ECC is enabled, the core_gpr_ded_reset_reg is + set when the core was previously reset due to GPR DED error. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV32_clear_gpr_ded(void) +{ + SUBSYS->soft_reg &= ~SUBSYS_SOFT_REG_GRP_DED; +} + +/***************************************************************************//** + The MRV32_enable_parity_check() function is used to enable parity check on + the TCM and it's interface transactions. This feature is not available on + MIV_RV32 v3.1 and MIV_RV32 v3.0.100 + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV32_enable_parity_check(void) +{ + SUBSYS->cfg |= SUBSYS_CFG_PARITY_CHECK; +} + +/***************************************************************************//** + The MRV32_disable_parity_check() function is used to disable parity check on + the TCM and it's interface transactions. + @param + This function does not take any parameters + + @return + This function does not return any value. + + */ +static inline void MRV32_disable_parity_check(void) +{ + SUBSYS->cfg &= ~SUBSYS_CFG_PARITY_CHECK; +} + +/***************************************************************************//** + The MRV32_cpu_soft_reset() function is used to cause a soft cpu reset on + the MIV_RV32 soft processor core. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV32_cpu_soft_reset(void) +{ + SUBSYS->soft_reg |= SUBSYS_SOFT_RESET; +} +#endif /* MIV_RV32_SUBSYS_H */ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv_rv32_syscall.c b/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv_rv32_syscall.c new file mode 100644 index 0000000..bd2f881 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/miv_rv32_syscall.c @@ -0,0 +1,364 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_syscall.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Stubs for system calls. + * + */ +#include +#include +#include +#include +#include "miv_rv32_hal.h" + +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +#include + +#ifndef LEGACY_DIR_STRUCTURE +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" +#else +#include "core_uart_apb.h" +#endif + +#endif /*MSCC_STDIO_THRU_CORE_UART_APB*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + +/*------------------------------------------------------------------------------ + * CoreUARTapb instance data for the CoreUARTapb instance used for standard + * output. + */ +static UART_instance_t g_stdio_uart; + +/*============================================================================== + * Flag used to indicate if the UART driver needs to be initialized. + */ +static int g_stdio_uart_init_done = 0; + +/* + * Disable semihosting apis + */ +#pragma import(__use_no_semihosting_swi) + +/*============================================================================== + * sendchar() + */ +int sendchar(int ch) +{ + /*-------------------------------------------------------------------------- + * Initialize the UART driver if it is the first time this function is + * called. + */ + if ( !g_stdio_uart_init_done ) + { + /****************************************************************************** + * Baud value: + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + UART_init( &g_stdio_uart, + MSCC_STDIO_UART_BASE_ADDR, + ((SYS_CLK_FREQ/(16 * MSCC_STDIO_BAUD_VALUE))-1), + (DATA_8_BITS | NO_PARITY)); + + g_stdio_uart_init_done = 1; + } + + /*-------------------------------------------------------------------------- + * Output text to the UART. + */ + UART_send( &g_stdio_uart, (uint8_t *)&ch, 1 ); + + return (ch); +} + +/*============================================================================== + * getachar() + */ +int getachar(void) +{ + uint8_t rx_size; + uint8_t rx_byte; + + if ( !g_stdio_uart_init_done ) + { + /****************************************************************************** + * Baud value: + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + UART_init( &g_stdio_uart, + MSCC_STDIO_UART_BASE_ADDR, + ((SYS_CLK_FREQ/(16 * MSCC_STDIO_BAUD_VALUE))-1), + (DATA_8_BITS | NO_PARITY)); + + g_stdio_uart_init_done = 1; + } + + do + { + rx_size = UART_get_rx(&g_stdio_uart, &rx_byte, 1); + } while(0u == rx_size); + + return rx_byte; +} + +#endif /*MSCC_STDIO_THRU_CORE_UART_APB*/ + +#undef errno +static int errno; + +static char *__env[1] = { 0 }; +char **environ = __env; + +void write_hex(int fd, uint32_t hex) +{ + char towrite; + + write( fd , "0x", 2U ); + + for (uint32_t ii = 8U ; ii > 0U; ii--) + { + uint32_t jj = ii-1U; + uint8_t digit = ((hex & (0xFU << (jj*4U))) >> (jj*4U)); + towrite = digit < 0xAU ? (0x48U + digit) : (0x65U + (digit - 0xAU)); + write( fd, &towrite, 1U); + } +} + + +#ifdef GDB_TESTING +void __attribute__((optimize("O0"))) _exit(int code) +#else +void _exit(int code) +#endif +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + const char * message = "\nProgam has exited with code:"; + + write(STDERR_FILENO, message, strlen(message)); + write_hex(STDERR_FILENO, code); +#endif + + while (1){}; +} + +void *_sbrk(ptrdiff_t incr) +{ + extern char _end; + extern char _heap_end; + extern char __heap_start; + extern char __heap_end; + static char *curbrk = &_end; + void * ret = NULL; + + /* + * Did we allocated memory for the heap in the linker script? + * You need to set HEAP_SIZE to a non-zero value in your linker script if + * the following assertion fires. + */ + ASSERT(&__heap_end > &__heap_start); + + if (((curbrk + incr) < &_end) || ((curbrk + incr) > &_heap_end)) + { + errno = ENOMEM; + ret = ((char *) - 1); + } + else + { + curbrk += incr; + ret = curbrk - incr; + } + + /* + * Did we run out of heap? + * You need to increase the heap size in the linker script if the following + * assertion fires. + * */ + ASSERT(curbrk <= &__heap_end); + + return(ret); +} + +int _isatty(int fd) +{ + int ret = 0; + + if (fd <= 2) /* one of stdin, stdout, stderr */ + { + ret = 1; + } + else + { + errno = EBADF; + ret = 0; + } + + return(ret); +} + +static int stub(int err) +{ + errno = err; + return -1; +} + +int _open(const char* name, int flags, int mode) +{ + return stub(ENOENT); +} + +int _openat(int dirfd, const char* name, int flags, int mode) +{ + return stub(ENOENT); +} + +int _close(int fd) +{ + return stub(EBADF); +} + +int _execve(const char* name, char* const argv[], char* const env[]) +{ + return stub(ENOMEM); +} + +int _fork(void) +{ + return stub(EAGAIN); +} + +int _fstat(int fd, struct stat *st) +{ + int ret = 0; + + if (isatty(fd)) + { + st->st_mode = S_IFCHR; + ret = 0; + } + else + { + ret = stub(EBADF); + } + + return ret; +} + +int _getpid(void) +{ + return 1; +} + +int _kill(int pid, int sig) +{ + return stub(EINVAL); +} + +int _link(const char *old_name, const char *new_name) +{ + return stub(EMLINK); +} + +off_t _lseek(int fd, off_t ptr, int dir) +{ + off_t ret = 0; + if (_isatty(fd)) + { + ret = 0; + } + else + { + ret = stub(EBADF); + } + + return ret; +} + +ssize_t _read(int fd, void* ptr, size_t len) +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + + char* ptr1 = (char*)ptr; + + if (_isatty(fd)) + { + int count; + + for (count = 0; count < len; count++) + { + ptr1[count] = getachar(); + sendchar(ptr1[count]); + + /* Return partial buffer if we get EOL */ + if (('\r' == ptr1[count])||('\n' == ptr1[count])) + { + ptr1[count] = '\n'; + return count; + } + } + + return count; /* Filled the buffer */ + } +#endif + + return stub(EBADF); +} + +int _stat(const char* file, struct stat* st) +{ + return stub(EACCES); +} + +clock_t _times(struct tms* buf) +{ + return stub(EACCES); +} + +int _unlink(const char* name) +{ + return stub(ENOENT); +} + +int _wait(int* status) +{ + return stub(ECHILD); +} + +ssize_t _write(int fd, const void* ptr, size_t len) +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + int count_out; + char* ptr1 = (char*)ptr; + + /*-------------------------------------------------------------------------- + * Output text to the UART. + */ + count_out = 0; + while(len--) + { + sendchar(ptr1[count_out]); + count_out++; + } + + errno = 0; + return count_out; + +#else /* MSCC_STDIO_THRU_CORE_UART_APB */ + + return stub(EBADF); + +#endif /* MSCC_STDIO_THRU_CORE_UART_APB */ + +} + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/sample_fpga_design_config.h b/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/sample_fpga_design_config.h new file mode 100644 index 0000000..a380d96 --- /dev/null +++ b/applications/user-crypto/miv-rv32-key-agreement/src/platform/miv_rv32_hal/sample_fpga_design_config.h @@ -0,0 +1,167 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file sample_fpga_design_config.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Sample design configuration settings + * + */ + /*========================================================================*//** + @mainpage + Example file detailing how the fpga_design_config.h should be constructed + for the SoftConsole project targeted for Mi-V processors. + + @section intro_sec Introduction + The SoftConsole project targeted for Mi-V processors now have an improved + folder structure. Detailed description of the folder structure is available + at https://github.com/Mi-V-Soft-RISC-V/miv-rv32-documentation. + + The fpga_design_config.h must be stored as shown below + /boards//fpga_design_config.h + + Currently this file must be hand crafted when using the Mi-V Soft Processor. + In future, all the design and soft IP configurations will be automatically + generated from the Libero design description data. + + You can use this sample file as an example. + Rename this file from sample_fpga_design_config.h to fpga_design_config.h + and then customize it per your hardware design. + + @section Project configuration Instructions + 1. Change SYS_CLK_FREQ define to frequency of Mi-V Soft processor clock + 2 Add all the soft IP core BASE addresses + 3. Add the peripheral Core Interrupts to Mi-V Soft processor IRQ number + mappings + 4. Define MSCC_STDIO_UART_BASE_ADDR if you want a CoreUARTapb mapped to + STDIO + + **NOTE** + In the legacy folder structures, the file hw_config.h as was used at the + root of the project folder. This file is now depricated. + +*//*=========================================================================*/ + +#ifndef FPGA_DESIGN_CONFIG_H_ +#define FPGA_DESIGN_CONFIG_H_ + +/***************************************************************************//** + * Soft-processor clock definition + * This is the only clock brought over from the Mi-V Libero design. + */ +#ifndef SYS_CLK_FREQ +#define SYS_CLK_FREQ 50000000UL +#endif + +/***************************************************************************//** + * Peripheral base addresses. + * Format of define is: + * __BASE_ADDR + * The field is optional if there is only one instance of the core + * in the design + * MIV_ESS is an extended peripheral subsystem IP core with peripherals + * connections as defined below. + * The system can be further extended by attaching APB peripherals to the + * empty APB slots. + */ +#define MIV_ESS_PLIC_BASE_ADDR 0x70000000UL +#define COREUARTAPB0_BASE_ADDR 0x71000000UL +#define MIV_MTIMER_BASE_ADDR 0x72000000UL +#define MIV_ESS_APBSLOT3_BASE_ADDR 0x73000000UL +#define MIV_ESS_APBSLOT4_BASE_ADDR 0x74000000UL +#define COREGPIO_OUT_BASE_ADDR 0x75000000UL +#define CORESPI_BASE_ADDR 0x76000000UL +#define MIV_ESS_uDMA_BASE_ADDR 0x78000000UL +#define MIV_ESS_WDOG_BASE_ADDR 0x79000000UL +#define MIV_ESS_I2C_BASE_ADDR 0x7A000000UL +#define MIV_ESS_APBSLOTB_BASE_ADDR 0x7B000000UL +#define MIV_ESS_APBSLOTC_BASE_ADDR 0x7C000000UL +#define MIV_ESS_APBSLOTD_BASE_ADDR 0x7D000000UL +#define MIV_ESS_APBSLOTE_BASE_ADDR 0x7E000000UL +#define MIV_ESS_APBSLOTF_BASE_ADDR 0x7F000000UL + +/***************************************************************************//** + * Peripheral Interrupts are mapped to the corresponding Mi-V Soft processor + * interrupt in the Libero design. + * + * On the legacy RV32 cores, there can be up to 31 external interrupts (IRQ[30:0] + * pins). The legacy RV32 Soft processor external interrupts are defined in the + miv_rv32_plic.h + * + * These are of the form + * typedef enum +{ + NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + . + . + . + External_31_IRQn = 31 +} IRQn_Type; + + On the legacy RV32 processors, the PLIC identifies the interrupt and passes it + on to the processor core. The interrupt 0 is not used. The pin IRQ[0] should + map to External_1_IRQn likewise IRQ[30] should map to External_31_IRQn + +e.g + +#define TIMER0_IRQn External_30_IRQn +#define TIMER1_IRQn External_31_IRQn + + The MIV_RV32 soft processor has up to six optional system interrupts, MSYS_EI[n] + in addition to one EXT_IRQ. + The MIV_RV32 does not have an inbuilt PLIC and all the interrupts are directly + delivered to the processor core, hence unlike legacy RV32 cores, no interrupt + number mapping is necessary on MIV_RV32 core. + */ + +/**************************************************************************** + * Baud value to achieve a 115200 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ +#define BAUD_VALUE_115200 ((SYS_CLK_FREQ / (16 * 115200)) - 1) + +/****************************************************************************** + * Baud value to achieve a 57600 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + #define BAUD_VALUE_57600 ((SYS_CLK_FREQ / (16 * 57600)) - 1) + +/***************************************************************************//** + * Define MSCC_STDIO_THRU_CORE_UART_APB in the project settings if you want the + * standard IOs to be redirected to a terminal via UART. + */ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +/* + * A base address mapping for the STDIO printf/scanf mapping to CortUARTapb + * must be provided if it is being used + * + * e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR + */ +#define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB0_BASE_ADDR + +#ifndef MSCC_STDIO_UART_BASE_ADDR +#error MSCC_STDIO_UART_BASE_ADDR not defined- e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR +#endif + +#ifndef MSCC_STDIO_BAUD_VALUE +/* + * The MSCC_STDIO_BAUD_VALUE define should be set in your project's settings to + * specify the baud value used by the standard output CoreUARTapb instance for + * generating the UART's baud rate if you want a different baud rate from the + * default of 115200 baud + */ +#define MSCC_STDIO_BAUD_VALUE 115200 +#endif /*MSCC_STDIO_BAUD_VALUE*/ + +#endif /* end of MSCC_STDIO_THRU_CORE_UART_APB */ +/******************************************************************************* + * End of user edit section + */ +#endif /* FPGA_DESIGN_CONFIG_H_ */ diff --git a/applications/user-crypto/miv-rv32-keytree-services/.cproject b/applications/user-crypto/miv-rv32-keytree-services/.cproject new file mode 100644 index 0000000..d523f8c --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/.cproject @@ -0,0 +1,333 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-keytree-services/.gitignore b/applications/user-crypto/miv-rv32-keytree-services/.gitignore new file mode 100644 index 0000000..f1b6b72 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/.gitignore @@ -0,0 +1,3 @@ +/.settings/ +/*miv-rv32-imc-debug*/ +/*miv-rv32-imc-release*/ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-keytree-services/.project b/applications/user-crypto/miv-rv32-keytree-services/.project new file mode 100644 index 0000000..774b513 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/.project @@ -0,0 +1,26 @@ + + + miv-rv32-keytree-services + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/applications/user-crypto/miv-rv32-keytree-services/README.md b/applications/user-crypto/miv-rv32-keytree-services/README.md new file mode 100644 index 0000000..9faa683 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/README.md @@ -0,0 +1,144 @@ +PolarFire User Crypto - Key Tree Services example +================================================================================ +This example project demonstrates the use of following the PolarFire User Crypto +Services functions: + + - CALKeyTree() + +There are two different build configurations provided with this project which +configure this SoftConsole project for RISC-V IMC instruction extension. +The following configurations are provided with the example: + + - miv-rv32-imc-debug + - miv-rv32-imc-release + +Mi-V Soft Processor +-------------------------------------------------------------------------------- +This example uses Mi-V SoftProcessor MiV_RV32.The design is built for debugging +MiV_RV32 through the PolarFire FPGA programming JTAG port using a FlashPro5. +To achieve this the CoreJTAGDebug IP is used to connect to the JTAG port of the +MiV_RV32. + +All the platform/design specific definitions such as peripheral base addresses, +system clock frequency etc. are included in fpga_design_config.h. The +fpga_design_config.h is located at the root folder of this project. + +The Mi-V Soft Processor MiV_RV32 firmware projects needs the miv_rv32_hal and +the hal firmware(RISC-V HAL). + +The RISC-V HAL is available at GitHub [Mi-V-Soft-RISC-V](https://mi-v-ecosystem.github.io/redirects/platform). + +How to use this example +-------------------------------------------------------------------------------- +This example project is targeted at a MIV_RV32 design running on a PolarFire-Eval-Kit +connected via a USB-UART serial cable to a host PC running a terminal emulator +such as TeraTerm or Putty configured as follows: + + - 115200 baud + - 8 data bits + - 1 stop bit + - no parity + - no flow control. + +Run the example project using a debugger. A greeting message will appear over the +UART terminal followed by a menu system and instructions. + +Key tree service is used to derive a secret key from a secret value or values. +This example project demonstrates the use of 256-bit production key, 128-bit +nonce, 8-bit optype to derive secret key. This example project reads the key, +nonce, and operation type from UART terminal and calls the **CALKeyTree()** +function. The **CALKeyTree()** function derive a session key using a 128-bit or +256-bit path nonce, size combined with a user-defined operation type. The output +of this service is a eight 32-bit word that is stored in a user buffer as well +displayed on the UART terminal. + +fpga_design_config (formerly known as hw_config.h) +-------------------------------------------------------------------------------- +The SoftConsole project targeted for Mi-V processors now use an improved +directory structure. The fpga_design_config.h must be stored as shown below + +` + /boards//fpga_design_config/fpga_design_config.h +` + +Currently, this file must be hand crafted when using the Mi-V Soft Processor. +In future, all the design and soft IP configurations will be automatically +generated from the Libero design description data. + +You can use the sample file provided with MIV_RV32 HAL as an example. Rename it +from sample_fpga_design_config.h to fpga_design_config.h and then customize it +per your hardware design such as SYS_CLK_FREQ, peripheral BASE addresses, +interrupt numbers, definition of MSCC_STDIO_UART_BASE_ADDR if you want a +CoreUARTapb mapped to STDIO, etc. + +### Configurations + +The CAL library needs a config_user.h containing the configuration data. +This application provides following settings as per CAL requirement + 1. A variable which provides the base address of the User Crypto hardware block + is defined in main.c + + `uint32_t g_user_crypto_base_addr = 0x62000000UL;` + + 2. A symbol INC_STDINT_H is defined in project preprocessor setting. + For more detail, please refer to caltypes.h file present in CAL folder. + +### Test script + +A test script is provided with this example which automatically enters the NIST +vectors and associated data to verify the functionality. You can use +miv-rv32-key-tree.ttl Tera Term Macro script present in project directory for +testing keytree services example project. + +**NOTE:** +1. Tera Term Macros dont work with Windows 10 build 14393.0. You should update + to Windows 10 build 14393.0.105 or [later.](https://osdn.net/ticket/browse.php?group_id=1412&tid=36526) +2. Before running Tera Term Macro script, set language as English + (Setup->General->Language). Also setup transmit delay in (Setup->Serial port) + to 5msec/char and 5msec/line. +3. By default, Tera Term log will be stored in Tera Term installation Directory. + +**NOTE**: + 1. If you try to enter data values other than 0 - 9, a - f, A - F, an error + message will be displayed on the serial port terminal. + 2. NIST vector is not available to test key Tree service so only return value + of CALKeyTree() function is check to determine key service is successful or + not. + +## Target hardware + +This project was tested on PolarFire-Eval-Kit with CFG4 configuration of the +MIV_RV32 design available [here](https://github.com/Mi-V-Soft-RISC-V/PolarFire-Eval-Kit/tree/main/Libero_Projects) + +All the design specific definitions such as peripheral base addresses, system +clock frequency etc. are included in fpga_design_config.h. + +The firmware projects needs the HAL and the MIV_RV32 HAL firmware components. + +This example project can be used with another design using a different hardware +configurations. This can be achieved by overwriting the content of this example +project's "fpga_design_config.h" file with the correct data per your Libero design. + +### Booting the system + +Currently the example project is configured to use FlashPro debugger to execute +from LSRAM in both Debug and Release mode. + +In the release mode build configuration, following setting is used +`--change-section-lma *-0x80000000` under +Tool Settings > Cross RISCV GNU Create Flash Image > General > Other flags. + +This will allow you to attach the release mode executable as the memory +initialization client in Libero when you want to execute it from non-volatile memory. + +## Silicon revision dependencies + +This example is tested on PolarFire MPF300TS device. + +### CAL library src + +To obtain the CAL source code and a SoftConsole project to generate the CAL +library archive file (*.a) refer [SoftConsole Documentation](https://mi-v-ecosystem.github.io/SoftConsole-Documentation/SoftConsole-v2021.3/using_softconsole/other.html#crypto-application-library). +The CAL source code is bound by license agreement and it will be available as +part of the SoftConsole installation if the CAL specific license was agreed +while installing it. \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-keytree-services/miv-rv32-key-tree.ttl b/applications/user-crypto/miv-rv32-keytree-services/miv-rv32-key-tree.ttl new file mode 100644 index 0000000..f7044de --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/miv-rv32-key-tree.ttl @@ -0,0 +1,73 @@ +; Tera Term Setting: +; 1. Before running Tera Term Macro script, you should set language as English +; and transmit delay in Serial port setup to 5msec/char and 5msec/line. +; 2. By default, Tera Term log will be stored in Tera Term installation Directory. + +changedir '.' +logopen "Cryptography.log" 0 0 0 1 + +settitle 'PolarFire User Crypto AES-128' + +setsync 1 + +;Clear screen +clearscreen 0 + +; Set baud rate to 115200 +setbaud 115200 + +; local echo off +setecho 0 + +;; Send Dummy +send $0 + +; --------------------------------------------------------------------------------------------------------------- +; KEY DERIVATION SERVICES +; --------------------------------------------------------------------------------------------------------------- +; --------------------------------------------------------------------------------------------------------------- + +; INPUT +; KEY = 2c82552b5e75eefbe716a1c377292232b2e281bd4d11060dfe3226218a0d4f8b +; NONCE = 46A85E18A798BE38010549CA17983E0D8B7DD1B55B953FB2321A1D66910EB3B0 +; OPTION = 1 +; OUTPUT +; SESSION_KEY = 8EA304523CD9E68D756451AE24A3B114 +; ␀ A75AEF0EA52483DC87AF2DAB422EA974 +; --------------------------------------------------------------------------------------------------------------- + +;key +send '2c82552b5e75eefbe716a1c377292232b2e281bd4d11060dfe3226218a0d4f8b' +pause 1 + +;user option +send '1' +pause 2 + +;select send path nonce +send '1' +pause 2 + +;enter nonce +send '46A85E18A798BE38010549CA17983E0D8B7DD1B55B953FB2321A1D66910EB3B0' +pause 10 + +;---------------------------------------------------------------------------------- +; USE AUTO GENERATED NONCE +;--------------------------------------------------------------------------------- + +;key +send '2c82552b5e75eefbe716a1c377292232b2e281bd4d11060dfe3226218a0d4f8b' +pause 1 + +;user option +send '1' +pause 2 + +;select send path nonce +send '2' +pause 2 + + + +logclose diff --git a/applications/user-crypto/miv-rv32-keytree-services/miv-rv32-keytree-services hw Debug.launch b/applications/user-crypto/miv-rv32-keytree-services/miv-rv32-keytree-services hw Debug.launch new file mode 100644 index 0000000..621dc90 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/miv-rv32-keytree-services hw Debug.launch @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/user-crypto/miv-rv32-keytree-services/miv-rv32-keytree-services hw attach.launch b/applications/user-crypto/miv-rv32-keytree-services/miv-rv32-keytree-services hw attach.launch new file mode 100644 index 0000000..f63546a --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/miv-rv32-keytree-services hw attach.launch @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/application/helper.c b/applications/user-crypto/miv-rv32-keytree-services/src/application/helper.c new file mode 100644 index 0000000..4a78569 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/application/helper.c @@ -0,0 +1,312 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file helper.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Helper function for PolarFire User Crypto- Cryptography service example. + * + */ +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" +#include "helper.h" + +extern UART_instance_t g_uart; + +static const uint8_t g_separator[] = +"\r\n\ +------------------------------------------------------------------------------"; + + +/*============================================================================== + Function to clear local variable and array. + */ +static void clear_variable(uint8_t *p_var, uint16_t size) +{ + uint16_t inc; + + for(inc = 0; inc < size; inc++) + { + *p_var = 0x00; + p_var++; + } +} + +/*============================================================================== + Function to get the input data from user. + */ +uint16_t get_input_data +( + uint8_t* location, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +) +{ + uint16_t count = 0u; + + /* Clear the memory location. */ + clear_variable(location, size); + + /* Read data from UART terminal. */ + count = get_data_from_uart(location, size, msg, msg_size); + + return count; +} + +/*============================================================================== + Function to get the key from user. + */ +void get_key +( + uint8_t key_type, + uint8_t* location, + uint8_t size, + const uint8_t* msg, + uint8_t msg_size +) +{ + uint8_t status = 0u; + const uint8_t invalid_ms[] = "\r\n Invalid key type. "; + + if(status == VALID) + { + /* Read the 16 bytes of input data from UART terminal. */ + get_input_data(location, size, msg, msg_size); + } + else + { + UART_send(&g_uart, invalid_ms, sizeof( invalid_ms)); + } +} + +/*============================================================================== + Convert ASCII value to hex value. + */ +uint8_t convert_ascii_to_hex(uint8_t* dest, const uint8_t* src) +{ + uint8_t error_flag = 0u; + + if((*src >= '0') && (*src <= '9')) + { + *dest = (*src - '0'); + } + else if((*src >= 'a') && (*src <= 'f')) + { + *dest = (*src - 'a') + 10u; + } + else if((*src >= 'A') && (*src <= 'F')) + { + *dest = (*src - 'A') + 10u; + } + else if(*src != 0x00u) + { + UART_send(&g_uart, (const uint8_t *)"\r\n Invalid data.", sizeof("\r\n Invalid data.")); + error_flag = 1u; + } + return error_flag; +} + +/*============================================================================== + Validate the input hex value . + */ +uint8_t validate_input(uint8_t ascii_input) +{ + uint8_t valid_key = 0u; + + if(((ascii_input >= 'A') && (ascii_input <= 'F')) || \ + ((ascii_input >= 'a') && (ascii_input <= 'f')) || \ + ((ascii_input >= '0') && (ascii_input <= '9'))) + { + valid_key = 1u; + } + else + { + valid_key = 0u; + } + return valid_key; +} + +const uint8_t hex_chars[16] = { '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + +/*============================================================================== + Display content of buffer passed as parameter as hex values. + */ +void display_output +( + uint8_t* in_buffer, + uint32_t byte_length +) +{ + uint32_t inc; + uint8_t byte = 0; + + UART_send(&g_uart, (const uint8_t*)" ", sizeof(" ")); + for(inc = 0; inc < byte_length; ++inc) + { + if((inc > 1u) &&(0u == (inc % 16u))) + { + UART_send(&g_uart, (const uint8_t*)"\r\n ", sizeof("\r\n ")); + } + + byte = in_buffer[inc]; + UART_send(&g_uart, &hex_chars[((byte & 0xF0) >> 4) ], 1); + UART_send(&g_uart, &hex_chars[(byte & 0x0F)], 1); + } + +} + +/*============================================================================== + Function to read data from UART terminal and stored it. + */ +uint16_t get_data_from_uart +( + uint8_t* src_ptr, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +) +{ + uint8_t complete = 0u; + uint8_t rx_buff[1]; + uint8_t rx_size = 0u; + uint16_t count = 0u; + uint16_t ret_size = 0u; + uint8_t first = 0u; + uint16_t src_ind = 0u; + uint8_t prev = 0; + uint8_t curr = 0; + uint8_t temp = 0; + uint8_t next_byte = 0; + uint16_t read_data_size = 0; + + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, msg, msg_size); + + if(size != 1) + { + read_data_size = size * 2; + } + else + { + read_data_size = size; + } + + /* Read the key size sent by user and store it. */ + count = 0u; + while(!complete) + { + rx_size = UART_get_rx(&g_uart, rx_buff, sizeof(rx_buff)); + if(rx_size > 0u) + { + /* Is it to terminate from the loop */ + if(ENTER == rx_buff[0]) + { + complete = 1u; + } + /* Is entered key valid */ + else if(validate_input(rx_buff[0]) != 1u) + { + UART_send(&g_uart, rx_buff, sizeof(rx_buff)); + UART_send(&g_uart, (const uint8_t *)"\r\n Invalid input.", + sizeof("\r\n Invalid input.")); + UART_send(&g_uart, msg, msg_size); + complete = 0u; + count = 0u; + first = 0u; + clear_variable(src_ptr, 4); + } + else + { + if(next_byte == 0) + { + convert_ascii_to_hex(&src_ptr[src_ind], &rx_buff[0]); + prev = src_ptr[src_ind]; + next_byte = 1; + } + else + { + convert_ascii_to_hex(&curr, &rx_buff[0]); + temp = ((prev << 4) & 0xF0); + src_ptr[src_ind] = (temp | curr); + next_byte = 0; + src_ind++; + } + + + /* Switching to next line after every 8 bytes */ + if(((count % 32u) == 0x00u) && (count > 0x00u) && (complete != 0x01u)) + { + UART_send(&g_uart, (const uint8_t *)"\n\r", sizeof("\n\r")); + first = 0u; + } + + if(first == 0u) + { + UART_send(&g_uart, (const uint8_t *)" ", sizeof(" ")); + first++; + } + UART_send(&g_uart, rx_buff, sizeof(rx_buff)); + count++; + if(read_data_size == count) + { + complete = 1u; + } + } + } + } + + if((count%2) == 0) + { + ret_size = count/2; + } + else + { + if(size!=1) + { + temp = src_ptr[src_ind]; + src_ptr[src_ind] = ((temp << 4) & 0xF0); + + ret_size = (count/2)+1; + } + else + { + ret_size = 1; + } + } + + return ret_size; +} + +/*============================================================================== + Function to get the key from user. + */ +uint8_t enable_dma +( + const uint8_t* msg, + uint8_t msg_size +) +{ + volatile uint8_t invalid_ip = 1u; + uint8_t dma_enable = 0; + + const uint8_t invalid_ms[] = "\r\n Invalid input. "; + + while(invalid_ip != 0) + { + /* Read the 16 bytes of input data from UART terminal. */ + get_input_data(&dma_enable, 1, msg, msg_size); + + if(dma_enable >= 2) + { + UART_send(&g_uart, invalid_ms, sizeof( invalid_ms)); + } + else + { + invalid_ip = 0; + } + } + + return dma_enable; +} diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/application/helper.h b/applications/user-crypto/miv-rv32-keytree-services/src/application/helper.h new file mode 100644 index 0000000..7f21b6e --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/application/helper.h @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file helper.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Helper function public API. + * + */ +#ifndef __HELPER_H_ +#define __HELPER_H_ 1 + +/****************************************************************************** + * Maximum buffer size. + *****************************************************************************/ +#define MAX_RX_DATA_SIZE 256 +#define MASTER_TX_BUFFER 10 + +/*============================================================================== + Macro + */ +#define VALID 0U +#define INVALID 1U +#define ENTER 13u + +/****************************************************************************** + * CoreUARTapb instance data. + *****************************************************************************/ + +uint16_t get_input_data +( + uint8_t* location, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +); +void get_key +( + uint8_t key_type, + uint8_t* location, + uint8_t size, + const uint8_t* msg, + uint8_t msg_size +); +uint16_t get_data_from_uart +( + uint8_t* src_ptr, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +); +uint8_t enable_dma +( + const uint8_t* msg, + uint8_t msg_size +); +void display_output +( + uint8_t* in_buffer, + uint32_t byte_length +); +#endif /* __HELPER_H_ */ diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/application/main.c b/applications/user-crypto/miv-rv32-keytree-services/src/application/main.c new file mode 100644 index 0000000..e88cd65 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/application/main.c @@ -0,0 +1,188 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file main.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief This example project demonstrates the usage of PolarFire User Crypto + * key tree services. + * + */ +#include +#include +#include +#include "stdint.h" +#include "helper.h" +#include "hal/hal.h" +#include "fpga_design_config/fpga_design_config.h" +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" +#include "drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h" +#include "drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h" + +#include "cal/calpolicy.h" +#include "cal/pk.h" +#include "cal/pkx.h" +#include "cal/pkxlib.h" +#include "cal/calini.h" +#include "cal/utils.h" +#include "cal/hash.h" +#include "cal/drbgf5200.h" +#include "cal/drbg.h" +#include "cal/nrbg.h" +#include "cal/sym.h" +#include "cal/shaf5200.h" +#include "cal/calenum.h" + +#define DATA_LENGTH_32_BYTES 32 + +/****************************************************************************** + * CoreUARTapb instance data. + *****************************************************************************/ +UART_instance_t g_uart; + +uint32_t g_user_crypto_base_addr = 0x62000000UL; + +/*============================================================================== + Messages displayed over the UART. + */ +const uint8_t g_greeting_msg[] = +"\r\n\r\n\ +******************************************************************************\r\n\ +************* PolarFire User Crypto Key Tree Example Project *****************\r\n\ +******************************************************************************\r\n\ + This example project demonstrates the use of the User Crypto Key Tree service.\r\n"; + +static const uint8_t g_separator[] = +"\r\n\ +------------------------------------------------------------------------------"; +const uint8_t read_key_input[] = +"\r\n Enter the 256 bit key to be used: \r\n"; +const uint8_t read_op_type[] = +"\r\n Enter user operation type:\r\n"; +const uint8_t read_path_nonce_input[] = +"\r\n Enter the 256 bit path nonce: \r\n"; +const uint8_t path_nonce_option[] = +"\r\n\r\n\ +--------------------------------------------------------------------------------\r\n\ +1. Press 1 to enter 256 bit path nonce value \r\n\ +2. press 2 to generate 256 bit path nonce \r\n "; + + + +/*============================================================================== + Key Tree service + */ +void keytree(void) +{ + uint8_t status = 0x00u; + uint32_t key[8] = {0x00}; + uint8_t op_type = 0; + uint8_t opt = 0 ; + uint8_t path_nonce[NONCE_SERVICE_RESP_LEN] = {0x00}; + uint32_t g_key_out[100] = {0x00}; + + /* Read the 32 bytes of key input data from UART terminal. */ + get_input_data((uint8_t*)&key[0], sizeof(key), read_key_input, + sizeof(read_key_input)); + + /* Read the 1 bytes of operation type data from UART terminal. */ + get_input_data(&op_type, sizeof(op_type), read_op_type, sizeof(read_op_type)); + + /* As bPathSizeSel is set to SAT_TRUE, read the 16 bytes of path nonce + * input data from UART terminal. + */ + get_input_data(&opt, sizeof(opt), path_nonce_option, sizeof(path_nonce_option)); + + if( opt != 1 ) + { + + SYS_init((unsigned int) CORESYS_SERV_BASE_ADDR); + + status = SYS_nonce_service(path_nonce, 0); + if (status == SYS_SUCCESS) + { + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_polled_tx_string(&g_uart,(uint8_t*)"\r\nGenerated Path_Nonce: \r\n"); + display_output((uint8_t*)&path_nonce[0], DATA_LENGTH_32_BYTES); + } + else + { + + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_polled_tx_string(&g_uart,(uint8_t*)"\r\n Error In path Nonce generation \r\n"); + } + } + else + { + + get_input_data((uint8_t*)&path_nonce[0], sizeof(path_nonce), read_path_nonce_input, + sizeof(read_path_nonce_input)); + + /* Change the endianness of data received from UART terminal. */ + CALWordReverse((uint32_t*)&path_nonce, (sizeof(path_nonce)/4)); + CALByteReverseWord((uint32_t*)&path_nonce, (sizeof(path_nonce)/4)); + } + + + /* Change the endianness of data received from UART terminal. */ + CALWordReverse((uint32_t*)&key, (sizeof(key)/4)); + CALByteReverseWord((uint32_t*)&key, (sizeof(key)/4)); + + /* Derive a secret key */ + status = CALKeyTree(1, key, op_type, (uint32_t*)&path_nonce[0], g_key_out); + + /* Display the secret key in hex format. */ + if(SATR_SUCCESS == status) + { + status = CALPKTrfRes(SAT_TRUE); + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, (const uint8_t *)"\r\n Key tree successful \ + \r\n Secret key:\r\n", sizeof("\r\n Key tree successful \ + \r\n Secret key:\r\n")); + display_output((uint8_t*)&g_key_out[0], DATA_LENGTH_32_BYTES); + } + else + { + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, (const uint8_t *)"\r\n Key tree service fail\r\n", + sizeof("\r\n Key tree service fail\r\n")); + } +} + +/*============================================================================== + Display greeting message when application is started. + */ +static void display_greeting(void) +{ + UART_send(&g_uart, g_greeting_msg,sizeof(g_greeting_msg)); +} + + +/****************************************************************************** + * main function. + *****************************************************************************/ +int main( void ) +{ + + uint8_t rx_buff[1]; + size_t rx_size = 0; + /* Initialize CoreUARTapb with its base address, baud value, and line + configuration. */ + UART_init(&g_uart, COREUARTAPB0_BASE_ADDR, BAUD_VALUE_115200, + (DATA_8_BITS | NO_PARITY)); + + /* Initializes the Athena Processor */ + CALIni(); + + /* Display greeting message. */ + display_greeting(); + + /* Perform Key tree */ + + for(;;) + { + + keytree(); + } +} diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h b/applications/user-crypto/miv-rv32-keytree-services/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h new file mode 100644 index 0000000..3fd1438 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h @@ -0,0 +1,156 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file fpga_design_config.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Sample design configuration settings. + * + */ + /*========================================================================*//** + @mainpage + Example file detailing how the fpga_design_config.h should be constructed + for the SoftConsole project targeted for Mi-V processors. + + @section intro_sec Introduction + The SoftConsole project targeted for Mi-V processors now have an improved + folder structure. Detailed description of the folder structure is available + at https://github.com/Mi-V-Soft-RISC-V/miv-rv32-documentation. + + The fpga_design_config.h must be stored as shown below + /boards//fpga_design_config.h + + Currently this file must be hand crafted when using the Mi-V Soft Processor. + In future, all the design and soft IP configurations will be automatically + generated from the Libero design description data. + + You can use this sample file as an example. + Rename this file from sample_fpga_design_config.h to fpga_design_config.h + and then customize it per your hardware design. + + @section Project configuration Instructions + 1. Change SYS_CLK_FREQ define to frequency of Mi-V Soft processor clock + 2 Add all the soft IP core BASE addresses + 3. Add the peripheral Core Interrupts to Mi-V Soft processor IRQ number + mappings + 4. Define MSCC_STDIO_UART_BASE_ADDR if you want a CoreUARTapb mapped to + STDIO + + **NOTE** + In the legacy folder structures, the file hw_config.h as was used at the + root of the project folder. This file is now depricated. + +*//*=========================================================================*/ + +#ifndef FPGA_DESIGN_CONFIG_H_ +#define FPGA_DESIGN_CONFIG_H_ + +/***************************************************************************//** + * Soft-processor clock definition + * This is the only clock brought over from the Mi-V Libero design. + */ +#ifndef SYS_CLK_FREQ +#define SYS_CLK_FREQ 83000000UL +#endif + +/***************************************************************************//** + * Peripheral base addresses. + * Format of define is: + * __BASE_ADDR + * The field is optional if there is only one instance of the core + * in the design + * MIV_ESS is an extended peripheral subsystem IP core with peripherals + * connections as defined below. + * The system can be further extended by attaching APB peripherals to the + * empty APB slots. + */ +#define COREUARTAPB0_BASE_ADDR 0x70000000UL +#define COREGPIO_OUT_BASE_ADDR 0x70001000UL +#define CORESPI_BASE_ADDR 0x70002000UL +#define CORESYS_SERV_BASE_ADDR 0x70003000UL + +/***************************************************************************//** + * Peripheral Interrupts are mapped to the corresponding Mi-V Soft processor + * interrupt in the Libero design. + * + * On the legacy RV32 cores, there can be up to 31 external interrupts (IRQ[30:0] + * pins). The legacy RV32 Soft processor external interrupts are defined in the + miv_rv32_plic.h + * + * These are of the form + * typedef enum +{ + NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + . + . + . + External_31_IRQn = 31 +} IRQn_Type; + + On the legacy RV32 processors, the PLIC identifies the interrupt and passes it + on to the processor core. The interrupt 0 is not used. The pin IRQ[0] should + map to External_1_IRQn likewise IRQ[30] should map to External_31_IRQn + +e.g + +#define TIMER0_IRQn External_30_IRQn +#define TIMER1_IRQn External_31_IRQn + + The MIV_RV32 soft processor has up to six optional system interrupts, MSYS_EI[n] + in addition to one EXT_IRQ. + The MIV_RV32 does not have an inbuilt PLIC and all the interrupts are directly + delivered to the processor core, hence unlike legacy RV32 cores, no interrupt + number mapping is necessary on MIV_RV32 core. + */ + +/**************************************************************************** + * Baud value to achieve a 115200 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ +#define BAUD_VALUE_115200 ((SYS_CLK_FREQ / (16 * 115200)) - 1) + +/****************************************************************************** + * Baud value to achieve a 57600 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + #define BAUD_VALUE_57600 ((SYS_CLK_FREQ / (16 * 57600)) - 1) + +/***************************************************************************//** + * Define MSCC_STDIO_THRU_CORE_UART_APB in the project settings if you want the + * standard IOs to be redirected to a terminal via UART. + */ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +/* + * A base address mapping for the STDIO printf/scanf mapping to CortUARTapb + * must be provided if it is being used + * + * e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR + */ +#define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB0_BASE_ADDR + +#ifndef MSCC_STDIO_UART_BASE_ADDR +#error MSCC_STDIO_UART_BASE_ADDR not defined- e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR +#endif + +#ifndef MSCC_STDIO_BAUD_VALUE +/* + * The MSCC_STDIO_BAUD_VALUE define should be set in your project's settings to + * specify the baud value used by the standard output CoreUARTapb instance for + * generating the UART's baud rate if you want a different baud rate from the + * default of 115200 baud + */ +#define MSCC_STDIO_BAUD_VALUE 115200 +#endif /*MSCC_STDIO_BAUD_VALUE*/ + +#endif /* end of MSCC_STDIO_THRU_CORE_UART_APB */ +/******************************************************************************* + * End of user edit section + */ +#endif /* FPGA_DESIGN_CONFIG_H_ */ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld b/applications/user-crypto/miv-rv32-keytree-services/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld new file mode 100644 index 0000000..8541db6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld @@ -0,0 +1,160 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-ram.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * debug image executing in SRAM. + * + * This linker script assumes that a RAM is connected at on Mi-V soft processor + * memory space pointed by the reset vector address. + * + * NOTE : Modify the memory section address and the size according to your + * Libero design. + * For example: + * 1) If you want to download and step debug at a different RAM memory address in + * your design (For example TCM base address) than the one provided in this file. + * 2) The MIV_RV32, when used with MIV_ESS IP, provides ways to copy the executable + * HEX file from external Non-Volatile memory into the TCM at reset. In this + * case your executable must be linked to the TCM address. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +MEMORY +{ + ram (rwx) : ORIGIN = 0x80000000, LENGTH = 64k + crypto_ram (rw) : ORIGIN = 0x61000000, LENGTH = 32k +} + +RAM_START_ADDRESS = 0x80000000; /* Must be the same value MEMORY region ram ORIGIN above. */ +RAM_SIZE = 64k; /* Must be the same value MEMORY region ram LENGTH above. */ +STACK_SIZE = 2k; /* needs to be calculated for your application */ +HEAP_SIZE = 0k; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > ram + + .text : ALIGN(0x10) + { + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } > ram + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } > ram + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } > ram + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram + + . = 0x61000000; + .crypto_data : ALIGN(0x10) + { + . = ALIGN(0x10); + *(.crypto_data) + } > crypto_ram +} + diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/aesf5200.h b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/aesf5200.h new file mode 100644 index 0000000..889dddd --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/aesf5200.h @@ -0,0 +1,104 @@ +/* ------------------------------------------------------------------- + $Rev: 1293 $ $Date: 2017-07-27 14:09:14 -0400 (Thu, 27 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for F5200 AES function hardware implementation for + CAL. + ------------------------------------------------------------------- */ + +#ifndef AESF5200_H +#define AESF5200_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef AESF5200_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATR aesf5200aes (SATSYMTYPE eSymType, SATSYMMODE eMode, + void *pIV, SATBOOL bLoadIV, const void *pSrc, void *pDest, SATUINT32_t uiLen, + SATBOOL bDecrypt); + +extern SATR aesf5200aesk (SATSYMTYPE eSymType, const SATUINT32_t *puiKey); + +extern SATR aesf5200gcm (SATSYMTYPE eSymType, SATSYMMODE eMode, void *pIV, + const void *pSrc, void *pDest, SATUINT32_t uiEncLen, + const void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, SATUINT32_t uiMACLen, + SATBOOL bDecrypt); + +extern SATR aesf5200gcmdma(SATSYMTYPE eSymType, SATSYMMODE eMode, void *pIV, + const void *pSrc, void *pDest, SATUINT32_t uiEncLen, const void *pAuth, + SATUINT32_t uiAuthLen, void *pMAC, SATUINT32_t uiMACLen, SATBOOL bDecrypt, + SATUINT32_t uiDMAChConfig); + +extern SATR aesf5200kw(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR aesf5200kwp(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR aesf5200kr(SATSYMTYPE eSymType, SATSYMMODE eMode, + const SATUINT32_t *puiKey, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKrf, SATBOOL bDecrypt); + +extern SATR aesf5200dma(SATSYMTYPE eSymType, SATSYMMODE eMode, void *pIV, + SATBOOL bLoadIV, const void *pExtSrc, void *pExtDest, SATUINT32_t uiLen, + SATUINT32_t uiDMAChConfig, SATBOOL bDecrypt); + +extern SATR aesf5200krdma(SATSYMTYPE eSymType, SATSYMMODE eMode, + const SATUINT32_t *puiKey, void *pIV, SATBOOL bLoadIV, const void *pExtSrc, + void *pExtDest, SATUINT32_t uiLen, SATUINT32_t uiKrf, + SATUINT32_t uiDMAChConfig, SATBOOL bDecrypt); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/calcontext.h b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/calcontext.h new file mode 100644 index 0000000..fc408c2 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/calcontext.h @@ -0,0 +1,88 @@ +/* ------------------------------------------------------------------- + $Rev: 1298 $ $Date: 2017-08-04 13:04:19 -0400 (Fri, 04 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL context management functions. + ------------------------------------------------------------------- */ + +#ifndef CALCONTEXT_H +#define CALCONTEXT_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* Function resource handle. */ +/* ----- ------ ------- ---- */ +#define SATRES_DEFAULT (SATRESHANDLE)0U +#define SATRES_CALSW (SATRESHANDLE)1U + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ +typedef struct{ + SATUINT32_t uiBase; + SATRESCONTEXTPTR pContext; + }SATRESHANDLESTRUCT; + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALCONTEXT_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATRESCONTEXTPTR CALContextCurrent(const SATRESHANDLE hResource); + +extern SATR CALContextLoad(const SATRESHANDLE hResource, + const SATRESCONTEXTPTR pContext); + +extern SATR CALContextRemove(const SATRESHANDLE hResource); + +extern SATR CALContextUnload(const SATRESHANDLE hResource); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern void init_reshandles(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/calenum.h b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/calenum.h new file mode 100644 index 0000000..6281f3f --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/calenum.h @@ -0,0 +1,289 @@ +/* ------------------------------------------------------------------- + $Rev: 1566 $ $Date: 2018-09-14 11:04:30 -0400 (Fri, 14 Sep 2018) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + This file defines common types in the CAL. + + Most CAL types and constants are defined with the "SAT" prefix to + reduce the chance of name space collisions with other users. + ------------------------------------------------------------------- */ + +#ifndef CALENUM_H +#define CALENUM_H + +/* -------- */ +/* Includes */ +/* -------- */ + +/* CAL base types. */ +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ +/* NULL definitions. */ +#define SAT_NULL 0 + +/* Boolean definitions. */ +#define SAT_TRUE ((SATBOOL)1) +#define SAT_FALSE ((SATBOOL)0) + + +/* Major cipher key/SSP type. */ +/* ----- ------ ------- ----- */ +#define SATSSPTYPE_NULL (SATSSPTYPE)0 +#define SATSSPTYPE_SYMKEY (SATSSPTYPE)1 +#define SATSSPTYPE_ASYMKEY (SATSSPTYPE)2 +/* Special marker for end of list. */ +#define SATSSPTYPE_LAST (SATSSPTYPE)3 + + +/* Asymmetric Ciphers */ +/* ---------- ------- */ +#define SATASYMTYPE_NULL (SATASYMTYPE)0U +#define SATASYMTYPE_DSA_SIGN (SATASYMTYPE)1U +#define SATASYMTYPE_DSA_VERIFY (SATASYMTYPE)2U +#define SATASYMTYPE_RSA_ENCRYPT (SATASYMTYPE)3U +#define SATASYMTYPE_RSA_DECRYPT (SATASYMTYPE)4U +#define SATASYMTYPE_DH (SATASYMTYPE)5U +#define SATASYMTYPE_ECDSA_SIGN (SATASYMTYPE)6U +#define SATASYMTYPE_ECDSA_VERIFY (SATASYMTYPE)7U +#define SATASYMTYPE_ECDH (SATASYMTYPE)8U +#define SATASYMTYPE_RSA_SIGN (SATASYMTYPE)9U +#define SATASYMTYPE_RSA_VERIFY (SATASYMTYPE)10U +/* Special marker for end of list. */ +#define SATASYMTYPE_LAST (SATASYMTYPE)11U + + +/* Encoding Types */ +/* -------- ----- */ +#define SATRSAENCTYPE_NULL (SATRSAENCTYPE)0U +#define SATRSAENCTYPE_PKCS (SATRSAENCTYPE)1U +#define SATRSAENCTYPE_ANSI (SATRSAENCTYPE)2U +#define SATRSAENCTYPE_PSS (SATRSAENCTYPE)3U +/* Special marker for end of list. */ +#define SATRSAENCTYPE_LAST (SATRSAENCTYPE)4U + + +/* Symmetric Ciphers */ +/* --------- ------- */ + +/* Cipher Type. */ +#define SATSYMTYPE_NULL (SATSYMTYPE)0U +#define SATSYMTYPE_AES128 (SATSYMTYPE)1U +#define SATSYMTYPE_AES192 (SATSYMTYPE)2U +#define SATSYMTYPE_AES256 (SATSYMTYPE)3U +#define SATSYMTYPE_AESKS128 (SATSYMTYPE)4U +#define SATSYMTYPE_AESKS192 (SATSYMTYPE)5U +#define SATSYMTYPE_AESKS256 (SATSYMTYPE)6U +/* Special marker for end of list. */ +#define SATSYMTYPE_LAST (SATSYMTYPE)7U + +/* Names for common cipher key lengths, in bits. */ +#define SATSYMKEYSIZE_AES128 (SATSYMKEYSIZE)128U +#define SATSYMKEYSIZE_AES192 (SATSYMKEYSIZE)192U +#define SATSYMKEYSIZE_AES256 (SATSYMKEYSIZE)256U +#define SATSYMKEYSIZE_AESKS128 (SATSYMKEYSIZE)256U +#define SATSYMKEYSIZE_AESKS192 (SATSYMKEYSIZE)384U +#define SATSYMKEYSIZE_AESKS256 (SATSYMKEYSIZE)512U + +/* Cipher Mode. */ +#define SATSYMMODE_NULL (SATSYMMODE)0U +#define SATSYMMODE_ECB (SATSYMMODE)1U +#define SATSYMMODE_CBC (SATSYMMODE)2U +#define SATSYMMODE_CFB (SATSYMMODE)3U +#define SATSYMMODE_OFB (SATSYMMODE)4U +#define SATSYMMODE_CTR (SATSYMMODE)5U +#define SATSYMMODE_GCM (SATSYMMODE)6U +#define SATSYMMODE_GHASH (SATSYMMODE)8U +/* Special marker for end of list. */ +#define SATSYMMODE_LAST (SATSYMMODE)9U + + +/* Hashes */ +/* ------ */ +#define SATHASHTYPE_NULL (SATHASHTYPE)0U +#define SATHASHTYPE_SHA1 (SATHASHTYPE)1U +#define SATHASHTYPE_SHA224 (SATHASHTYPE)2U +#define SATHASHTYPE_SHA256 (SATHASHTYPE)3U +#define SATHASHTYPE_SHA384 (SATHASHTYPE)4U +#define SATHASHTYPE_SHA512 (SATHASHTYPE)5U +#define SATHASHTYPE_SHA512_224 (SATHASHTYPE)6U +#define SATHASHTYPE_SHA512_256 (SATHASHTYPE)7U +/* Special marker for end of list. */ +#define SATHASHTYPE_LAST (SATHASHTYPE)8U + +/* Hash sizes defined in bits */ +#define SATHASHSIZE_NULL (SATHASHSIZE)0U +#define SATHASHSIZE_SHA1 (SATHASHSIZE)160U +#define SATHASHSIZE_SHA224 (SATHASHSIZE)224U +#define SATHASHSIZE_SHA256 (SATHASHSIZE)256U +#define SATHASHSIZE_SHA384 (SATHASHSIZE)384U +#define SATHASHSIZE_SHA512 (SATHASHSIZE)512U +#define SATHASHSIZE_SHA512_224 (SATHASHSIZE)224U +#define SATHASHSIZE_SHA512_256 (SATHASHSIZE)256U + +#define SATHASHSIZE_HASH160 (SATHASHSIZE)160U +#define SATHASHSIZE_HASH192 (SATHASHSIZE)192U +#define SATHASHSIZE_HASH224 (SATHASHSIZE)224U +#define SATHASHSIZE_HASH256 (SATHASHSIZE)256U +#define SATHASHSIZE_HASH320 (SATHASHSIZE)320U +#define SATHASHSIZE_HASH384 (SATHASHSIZE)384U +#define SATHASHSIZE_HASH512 (SATHASHSIZE)512U +#define SATHASHSIZE_HASH521 (SATHASHSIZE)521U + + +/* Message Authentication Codes */ +/* ------- -------------- ----- */ + +/* Message Authentication Types */ +#define SATMACTYPE_NULL (SATMACTYPE)0U +#define SATMACTYPE_SHA1 (SATMACTYPE)1U +#define SATMACTYPE_SHA224 (SATMACTYPE)2U +#define SATMACTYPE_SHA256 (SATMACTYPE)3U +#define SATMACTYPE_SHA384 (SATMACTYPE)4U +#define SATMACTYPE_SHA512 (SATMACTYPE)5U +#define SATMACTYPE_SHA512_224 (SATMACTYPE)6U +#define SATMACTYPE_SHA512_256 (SATMACTYPE)7U +#define SATMACTYPE_AESCMAC128 (SATMACTYPE)10U +#define SATMACTYPE_AESCMAC192 (SATMACTYPE)11U +#define SATMACTYPE_AESCMAC256 (SATMACTYPE)12U +#define SATMACTYPE_AESGMAC (SATMACTYPE)13U +/* Special marker for end of list. */ +#define SATMACTYPE_LAST (SATMACTYPE)14U + + +/* Message Authentication Flags */ +#define SATMACFLAG_OP (SATMACTYPEFLAG)0U +#define SATMACFLAG_FIRSTPASS (SATMACTYPEFLAG)1U +#define SATMACFLAG_FINALPASS (SATMACTYPEFLAG)2U +#define SATMACFLAG_IKEYFINAL (SATMACTYPEFLAG)4U +#define SATMACFLAG_OKEYFINAL (SATMACTYPEFLAG)8U + + +/* Non-deterministic Random Bit Generator */ +/* ------- -------------- ----- */ + +/* NRBG register write enables */ +#define SATNRBGCONFIG_NONE 0x0 +#define SATNRBGCONFIG_RNG_CSR 0x1 +#define SATNRBGCONFIG_RNG_CNTLIM 0x2 +#define SATNRBGCONFIG_RNG_VOTIMER 0X4 +#define SATNRBGCONFIG_RNG_FMSK 0X8 + +/* RNG_CSR access defines */ +#define SATNRBGCONFIG_CSR_RODIS 0x0 +#define SATNRBGCONFIG_CSR_ROEN 0x1 +#define SATNRBGCONFIG_CSR_ROFATAL 0x2 +#define SATNRBGCONFIG_CSR_ROFATALCLR 0X4 + +/* RNG_FMSK mask values */ +#define SATNRBGCONFIG_FMSK_ROOSCF 0xFF +#define SATNRBGCONFIG_FMSK_MONOBITF 0x10000 +#define SATNRBGCONFIG_FMSK_POKERF 0x20000 +#define SATNRBGCONFIG_FMSK_RUNSF 0x40000 +#define SATNRBGCONFIG_FMSK_LRUNSF 0x80000 +#define SATNRBGCONFIG_FMSK_F1401 0xF0000 +#define SATNRBGCONFIG_FMSK_REPCNTF 0x100000 +#define SATNRBGCONFIG_FMSK_APROPF 0x200000 +#define SATNRBGCONFIG_FMSK_SP800 0x300000 + +/* RNG_ROHEALTH mask values */ +#define SATNRBGCONFIG_HLTH_ROOSCF 0x3FC0 +#define SATNRBGCONFIG_HLTH_APROPF 0x20 +#define SATNRBGCONFIG_HLTH_REPCNTF 0x10 +#define SATNRBGCONFIG_HLTH_LRUNSF 0x8 +#define SATNRBGCONFIG_HLTH_RUNSF 0x4 +#define SATNRBGCONFIG_HLTH_POKERF 0x2 +#define SATNRBGCONFIG_HLTH_MONOBITF 0x1 + + +/* Return Codes */ +/* ------ ----- */ +#define SATR_SUCCESS (SATR)0U +#define SATR_FAIL (SATR)1U +#define SATR_BADPARAM (SATR)2U +#define SATR_VERIFYFAIL (SATR)3U +#define SATR_KEYSFULL (SATR)4U +#define SATR_BUSY (SATR)5U +#define SATR_ROFATAL (SATR)6U +#define SATR_PARITYFLUSH (SATR)7U +#define SATR_SIGNFAIL (SATR)8U +#define SATR_VALIDATEFAIL (SATR)9U +#define SATR_PAF (SATR)10U +#define SATR_VALPARMX (SATR)11U +#define SATR_VALPARMY (SATR)12U +#define SATR_VALPARMB (SATR)13U +#define SATR_DCMPPARMX (SATR)14U +#define SATR_DCMPPARMB (SATR)15U +#define SATR_DCMPPARMP (SATR)16U +#define SATR_SIGNPARMD (SATR)17U +#define SATR_SIGNPARMK (SATR)18U +#define SATR_VERPARMR (SATR)19U +#define SATR_VERPARMS (SATR)20U +#define SATR_MSBICV1 (SATR)21U +#define SATR_MSBICV2 (SATR)22U +#define SATR_PADLEN (SATR)23U +#define SATR_LSB0PAD (SATR)24U +#define SATR_BADLEN (SATR)25U +#define SATR_BADHASHTYPE (SATR)26U +#define SATR_BADTYPE (SATR)27U +#define SATR_BADMODE (SATR)28U +#define SATR_BADCONTEXT (SATR)29U +#define SATR_BADHASHLEN (SATR)30U +#define SATR_BADMACTYPE (SATR)31U +#define SATR_BADMACLEN (SATR)32U +#define SATR_BADHANDLE (SATR)33U +#define SATR_FNP (SATR)34U +#define SATR_HFAULT (SATR)35U +#define SATR_NOPEND (SATR)36U +#define SATR_BADRSAENC (SATR)37U +#define SATR_BADMOD (SATR)38U +/* Special marker for end of list. */ +#define SATR_LAST (SATR)39U + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* See caltypes.h for type definitions associated with defines above. */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALENUM_C +#ifdef __cplusplus +extern "C" { +#endif + +/* NOTE: this header file does not have an associated C file. */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/calini.h b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/calini.h new file mode 100644 index 0000000..62461d1 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/calini.h @@ -0,0 +1,69 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL initialization + ------------------------------------------------------------------- */ + +#ifndef CALINI_H +#define CALINI_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALINI_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALIni(void); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/calpolicy.h b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/calpolicy.h new file mode 100644 index 0000000..2a43445 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/calpolicy.h @@ -0,0 +1,183 @@ +/* ------------------------------------------------------------------- + $Rev: 1293 $ $Date: 2017-07-27 14:09:14 -0400 (Thu, 27 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file defining CAL policy for endianess, HW/SW, etc. + ------------------------------------------------------------------- */ + +#ifndef CALPOLICY_H +#define CALPOLICY_H + +/* -------- */ +/* Includes */ +/* -------- */ + +/* The following include provides a custom configuration header file when + CALCONFIGH is defined +*/ +#ifdef CALCONFIGH +# include CALCONFIGH +#else +# error "CALCONFIGH not defined. CAL requires a custom configuration header \ +defined by CALCONFIGH. Review CAL README." +#endif + +/* ------- */ +/* Defines */ +/* ------- */ + +/* Context switching */ +#ifndef MAXRESHANDLES +# define MAXRESHANDLES 1 +#endif + +/* Little Endian (default) / Big Endian */ +#ifndef SAT_LITTLE_ENDIAN +# define SAT_LITTLE_ENDIAN 1 +#endif + +/* PK SW Point Validate Checking */ +#ifndef PKSWCHKVALPT +# define PKSWCHKVALPT 1 +#endif + +/* DMA */ +#ifndef USE_X52EXEC_DMA +# define USE_X52EXEC_DMA 0 +#endif + +/* SHA */ +#define MAXHASHLEN 512 +#define MAXHMACKEYLEN 512 + +/* RNG */ +#define NRBGSIMNUMRO 16 +#define ENTROPYMEMBLOCKS 7 +#define BUFMEMBLOCKS 3 +#ifndef RNXBLKLEN +#define RNXBLKLEN 32 +#endif +#ifndef RNXBLKOUTLEN +#define RNXBLKOUTLEN 4 +#endif + +#ifndef USENRBGSW +# define USENRBGSW 0 +#endif + +/* PK */ +#ifndef PKX0_BASE +# define PKX0_BASE 0xE0000000u +#endif + +#if USEPKSW +# ifndef MAXMODSIZE +# define MAXMODSIZE 8192 +# endif +# ifndef PKSWBUFSIZE +# define PKSWBUFSIZE 15*(MAXMODSIZE/32) +# endif +#else +# define USEPKSW 0 +#endif + +/* Set default values for X52 configuration defines. */ +#ifndef X52_CFG_OPT +# define X52_CFG_OPT 0 +#endif +#ifndef X52_LIR_LEN +# define X52_LIR_LEN 0x800 +#endif +#ifndef X52_BER_LEN +# define X52_BER_LEN 0x400 +#endif +#ifndef X52_MMR_LEN +# define X52_MMR_LEN 0x400 +#endif +#ifndef X52_TSR_LEN +# define X52_TSR_LEN 0x400 +#endif +#ifndef X52_FPR_LEN +# define X52_FPR_LEN 0x400 +#endif +#if X52_LIR_ROM_LEN>0 && X52_LIR_LEN>X52_LIR_ROM_LEN +# define PKX_OFFSET 2048 +#else +# define PKX_OFFSET 0 +#endif + +/* X52 Configuration Options */ +#define AESPKX (X52_CFG_OPT&0x00000001u) +#define AESPKXGCM (X52_CFG_OPT&0x00000008u) +#define AESPKXFASTKEY (X52_CFG_OPT&0x01000000u) +#define SHAPKXOPT1 (X52_CFG_OPT&0x00000020u) +#define SHAPKXOPT224 (X52_CFG_OPT&0x00000040u) +#define SHAPKXOPT256 (X52_CFG_OPT&0x00000080u) +#define SHAPKXOPT384 (X52_CFG_OPT&0x00000100u) +#define SHAPKXOPT512 (X52_CFG_OPT&0x00000200u) +#define SHAPKXOPT5124 (X52_CFG_OPT&0x00400000u) +#define SHAPKXOPT5126 (X52_CFG_OPT&0x00800000u) + +/* Define the maximum number of return values that may be handled using + CAL*TrfRes() function(s). +*/ +#define CAL_MAXTRFS 4 + +/* Volatile pointer operations */ +/* These access macros are designed so that they may be redefined by a + user compiling CAL. +*/ +#ifndef CALREAD32 +# define CALREAD32(ptr) ( *(ptr) ) +#endif +#ifndef CALWRITE32 +# define CALWRITE32(ptr, val) ( *(ptr)=val ) +#endif +#ifndef CALPOLL32 +# define CALPOLL32(ptr, val, mask) while ((*(ptr) & (mask)) != (val)); +#endif + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +#ifndef CALPOLICY_C +#ifdef __cplusplus +extern "C" { +#endif + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +/* NOTE: this header file does not have an associated C file. */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/caltypes.h b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/caltypes.h new file mode 100644 index 0000000..3b2fe0b --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/caltypes.h @@ -0,0 +1,328 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + This file defines common types in the CAL. + + Since support for the C99 stdint.h integer types is not universal, + these are defined herein and may require customization from compiler + to compiler, or use of the stdint.h header, if present (recommended). + + C99 supports 64-bit types; however, support in older compilers is + spotty. For those that do not support it, the macro NO64BITINT may be + defined by the user to prevent defintion of 64-bit types. This is + generally safe with CAL-PK and CAL-SYM; however, this is incompatible + with CAL-SW. + + Most CAL types and constants are defined with the "SAT" prefix to + reduce the chance of name space collisions with other users. + ------------------------------------------------------------------- */ + +#ifndef CALTYPES_H +#define CALTYPES_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* Base Types */ +/* ---- ----- */ + +/* The user may compile using stdint.h instead of the definitions below + by defining the macro INC_STDINT_H. */ +#ifdef INC_STDINT_H +#include +#endif + +/* Integer type abstraction layer. */ +#ifndef INC_STDINT_H + +typedef unsigned char uint8_t; +typedef signed char int8_t; + +typedef unsigned short uint16_t; +typedef signed short int16_t; + +typedef unsigned int uint32_t; +typedef int int32_t; + +/* stdint.h is a C99 feature, and C99 supports 64-bit ints, so this is + immune to the macro used to disable 64-bit int support. +*/ +typedef unsigned long long uint64_t; +typedef long long int64_t; + +typedef long uintptr_t; + +#endif + +/* Boolean type. */ +typedef uint8_t SATBOOL; + +/* Unsigned integer type */ +typedef uint8_t SATUINT8_t; +typedef uint16_t SATUINT16_t; +typedef uint32_t SATUINT32_t; +#ifdef INC_STDINT_H +typedef uint64_t SATUINT64_t; +#else +#ifndef NO64BITINT +typedef uint64_t SATUINT64_t; +#endif +#endif + +/* Integer type */ +typedef int8_t SATINT8_t; +typedef int16_t SATINT16_t; +typedef int32_t SATINT32_t; +#ifdef INC_STDINT_H +typedef int64_t SATINT64_t; +#else +#ifndef NO64BITINT +typedef int64_t SATINT64_t; +#endif +#endif + +typedef uintptr_t SATUINTPTR_t; + +/* Major cipher key/SSP type. */ +/* ----- ------ ------- ----- */ +typedef uint8_t SATSSPTYPE; +typedef SATSSPTYPE * SATSSPTYPEPTR; + + +/* Asymmetric Ciphers */ +/* ---------- ------- */ + +/* Cipher type. */ +typedef uint8_t SATASYMTYPE; +typedef SATASYMTYPE * SATASYMTYPEPTR; + +/* Cipher size type. */ +typedef uint16_t SATASYMSIZE; +typedef SATASYMSIZE * SATASYMSIZEPTR; + +/* Cipher encoding */ +typedef uint8_t SATRSAENCTYPE; +typedef SATRSAENCTYPE * SATRSAENCTYPEPTR; + +/* DSA public/private key. */ +typedef struct { + uint16_t ui16PLen; /* Length of modulus p. */ + uint16_t ui16QLen; /* Length of prime divisor q. */ + uint32_t *pui32P; /* Prime modulus p. */ + uint32_t *pui32Q; /* Prime divisor q. */ + uint32_t *pui32G; /* Generator g, length==p. */ + uint32_t *pui32X; /* Private key x, length==p. */ + uint32_t *pui32Y; /* Private key y, length==q. */ +} SATASYMDSADOMAIN; +typedef SATASYMDSADOMAIN * SATASYMDSADOMAINPTR; + + +/* Symmetric Ciphers */ +/* --------- ------- */ + +/* Cipher type. */ +typedef uint8_t SATSYMTYPE; +typedef SATSYMTYPE * SATSYMTYPEPTR; + +/* Cipher key size type (in bits). */ +typedef uint16_t SATSYMKEYSIZE; +typedef SATSYMKEYSIZE * SATSYMKEYSIZEPTR; + +/* Cipher mode type. */ +typedef uint8_t SATSYMMODE; +typedef SATSYMMODE * SATSYMMODEPTR; + +/* Cipher key object. */ +/* Other fields are only valid when sstCipher!=SATSYMTYPE_NULL. */ +typedef struct { + SATSYMTYPE sstCipher; + SATSYMKEYSIZE ssksKeyLen; + uint32_t *pui32Key; +} SATSYMKEY; +typedef SATSYMKEY * SATSYMKEYPTR; + + +/* Hashes */ +/* ------ */ + +/* Hash type. */ +typedef uint8_t SATHASHTYPE; +typedef SATHASHTYPE * SATHASHTYPEPTR; + +/* Hash size type (in bits). */ +typedef uint16_t SATHASHSIZE; +typedef SATHASHSIZE * SATHASHSIZEPTR; + + +/* Context switching. */ +/* ----- ------ ------- ----- */ + +typedef uint32_t SATRESHANDLE; +typedef SATRESHANDLE * SATRESHANDLEPTR; + +typedef struct { + SATHASHTYPE sshashtype; + uint32_t uiRunLen; + uint32_t uiHash[MAXHASHLEN/32]; /* holds intermed hash */ +} SHACTX; + +typedef struct { + SATHASHTYPE sshashtype; + uint32_t uiRunLen; + uint32_t uiKeyLen; + uint32_t uiHash[MAXHASHLEN/32]; /* holds intermed hash */ + uint32_t uiKey[MAXHMACKEYLEN/32]; /* holds intermed key */ +} SHAHMACCTX; + +typedef struct { + uint8_t uiContextType; + union{ + SHACTX ctxSHA; + SHAHMACCTX ctxMAC; + }CTXUNION; +} SATRESCONTEXT; +typedef SATRESCONTEXT * SATRESCONTEXTPTR; + + +/* Message Authentication Codes */ +/* ------- -------------- ----- */ + +/* MAC type. */ +typedef uint8_t SATMACTYPE; +typedef SATMACTYPE * SATMACTYPEPTR; +typedef uint8_t SATMACTYPEFLAG; + + +/* Random Number Generator */ +/* ------ ------ --------- */ +typedef union { + uint32_t u32[4]; + uint8_t u8[16]; +} uint128_t; + +typedef struct { + uint128_t ui128V; + uint128_t ui128K[2]; + uint32_t uiReseedCnt; + uint32_t uiReseedLim; + uint32_t uiEntropyFactor; + SATSYMKEYSIZE eStrength; + SATBOOL bTesting; + +} DRBGCTX; + +typedef DRBGCTX * DRBGCTXPTR; + + +/* Function Return Code */ +/* -------- ------ ---- */ +typedef uint16_t SATR ; +typedef SATR * SATRPTR ; + + +/* Transfer Results */ +/* -------- ------- */ +typedef struct { + SATUINT32_t uiLen; + volatile SATUINT32_t* vpuiSrc; + void* pDest; +} SATDATATRF; + +typedef struct { + SATUINT32_t uiResType; + SATUINT32_t uiNumDataTrf; + SATDATATRF dtrfArray[CAL_MAXTRFS]; +} SATRESULT; + + +/* EC Ultra Structs */ +/* -- ----- ------- */ +typedef uint32_t SATECTYPE; + +typedef struct { + SATUINT32_t uiLen; + SATUINT32_t* puiX; + SATUINT32_t* puiY; +} SATECPOINT; + +typedef struct { + SATUINT32_t uiLen; + SATUINT32_t* puiMod; + SATUINT32_t* puiMontPrecompute; + SATUINT32_t* puiRSqd; +} SATECMONTMOD; + +typedef struct { + SATUINT32_t uiCurveSize; + SATECTYPE eCurveType; + SATECPOINT* pBasePoint; + SATECMONTMOD* pModP; + SATECMONTMOD* pModN; + SATUINT32_t* puiA; + SATUINT32_t* puiB; +} SATECCURVE; + +typedef struct { + SATUINT32_t uiLen; + SATUINT32_t* puiSigR; + SATUINT32_t* puiSigS; + SATUINT32_t* puiSigX; + SATUINT32_t* puiSigY; +} SATECDSASIG; + +typedef struct { + SATHASHSIZE sHashLen; + SATUINT32_t* puiHash; +} SATHASH; + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALTYPES_C +#ifdef __cplusplus +extern "C" { +#endif + +/* NOTE: this header file does not have an associated C file. */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/config_user.h b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/config_user.h new file mode 100644 index 0000000..3728565 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/config_user.h @@ -0,0 +1,44 @@ +/* ------------------------------------------------------------------- + $Rev: 727 $ $Date: 2017-10-20 16:50:53 -0400 (Fri, 20 Oct 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + + User configuration file to include/exclude CAL components. + ------------------------------------------------------------------- */ + +#ifndef CALCONFIG_F5200_H +#define CALCONFIG_F5200_H + +#include "x52cfg_user.h" +#include + +extern uint32_t g_user_crypto_base_addr; + +#define SAT_LITTLE_ENDIAN 1 +#define PKX0_BASE (g_user_crypto_base_addr) +#define USEPKX 1 +#define USEAESPKX 1 +#define USESHAPKX 1 +#define USEDRBGPKX 1 +#define USENRBGPKX 1 +#define USECALCTX 1 + +#endif diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/drbg.h b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/drbg.h new file mode 100644 index 0000000..dba16f7 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/drbg.h @@ -0,0 +1,91 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for DRBG functions for CAL + ------------------------------------------------------------------- */ + +#ifndef DRBG_H +#define DRBG_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ +#define CALDRBGENTROPYFACTOR 2 + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef DRBG_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALDRBGInstantiate(const SATUINT32_t *puiNonce, + SATUINT32_t uiNonceLen, const SATUINT32_t *puiPzStr, + SATUINT32_t uiPzStrLen, SATSYMKEYSIZE eStrength, + SATUINT32_t uiEntropyFactor, SATUINT32_t uiReseedLim, SATBOOL bTesting); + +extern SATR CALDRBGReseed(const SATUINT32_t *puiAddIn, SATUINT32_t uiAddInLen); + +extern SATR CALDRBGGenerate(const SATUINT32_t *puiAddIn, SATUINT32_t uiAddInLen, + SATBOOL bPredResist, SATUINT32_t *puiOut, SATUINT32_t uiOutBlocks); + +extern SATR CALDRBGUninstantiate(void); + +extern SATR CALDRBGGetCtx(DRBGCTXPTR drbgCtxExt); + +extern SATR CALDRBGLoadCtx(DRBGCTXPTR drbgCtxExt); + +extern SATR CALDRBGGetbInst(void); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +extern SATR CALDrbgTrfRes(SATBOOL bBlock); + +extern void CALDrbgIni(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/drbgf5200.h b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/drbgf5200.h new file mode 100644 index 0000000..d7f6c4c --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/drbgf5200.h @@ -0,0 +1,120 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for F5200 DRBG function hardware implementations + in CAL. + ------------------------------------------------------------------- */ + +#ifndef DRBGF5200_H +#define DRBGF5200_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ +#define RNXEFACTOR (X52BER+2) +#define RNXIRLEN (X52BER+2) +#define RNXKEYORD (X52BER+3) +#define RNXRESPRED (X52BER+4) +#define RNXTESTSEL (X52BER+5) +#define RNXBADDIN (X52BER+6) +#define RNXPPSTR (X52BER+7) +#define RNXPCTX (X52BER+8) +#define RNXPRENT (X52BER+13) +#define RNXITMP3 (X52BER+20) +#define RNXPCTX2 (X52BER+22) +/* These use same locs as tb generator, but can change */ +#define RNXRDATA (X52BER_ENDIAN+0x24) +#define RNXAIDATAOFF 0x0062 +#define RNXAIDATA (X52BER_ENDIAN+RNXAIDATAOFF) +#define RNXCTXOFF 0x0094 +#define RNXCTX (X52FPR+RNXCTXOFF) +#define RNXCTXV (X52FPR_ENDIAN+RNXCTXOFF+6) +#define RNXCTXVMMR (X52MMR_ENDIAN+RNXCTXOFF+6) +#define RNXTESTENT (X52TSR_ENDIAN+8) + +#define RNXCTXWORDS 18 +#define RNXBLENLOC (RNXCTX+RNXCTXWORDS) +#define RNXBOUTLENLOC (RNXCTX+RNXCTXWORDS+1) + +#define RNXMAXTESTENT32 512 +#define CALDRBGMAXADDINLEN X52_BER_LEN-RNXAIDATAOFF-4 +#define CALDRBGMAXPSNONCELEN X52_BER_LEN-RNXAIDATAOFF-4 + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef DRBGF5200_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATR drbgf5200Ini(void); + +extern SATR drbgf5200TrfRes(SATBOOL bBlock); + +extern SATR drbgf5200instantiate(const SATUINT32_t *puiNonce, + SATUINT32_t uiNonceLen, const SATUINT32_t *puiPzStr, SATUINT32_t uiPzStrLen, + SATSYMKEYSIZE eStrength, SATUINT32_t uiEntropyFactor, + SATUINT32_t uiReseedLim, SATBOOL bTesting); + +extern SATR drbgf5200reseed(const SATUINT32_t *puiAddIn, + SATUINT32_t uiAddInLen); + +extern SATR drbgf5200generate(const SATUINT32_t *puiAddIn, + SATUINT32_t uiAddInLen, SATBOOL bPredResist, SATUINT32_t uiReqLen, + SATUINT32_t *puiOut); + +extern SATR drbgf5200uninstantiate(void); + +extern SATR drbgf5200getctx(DRBGCTXPTR drbgCtxExt); + +extern SATR drbgf5200loadctx(DRBGCTXPTR drbgCtxExt); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/hash.h b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/hash.h new file mode 100644 index 0000000..f3fd6d4 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/hash.h @@ -0,0 +1,102 @@ +/* ------------------------------------------------------------------- + $Rev: 1293 $ $Date: 2017-07-27 14:09:14 -0400 (Thu, 27 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL hash functions. + ------------------------------------------------------------------- */ + +#ifndef HASH_H +#define HASH_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ +extern const SATHASHSIZE uiHashWordLen[SATHASHTYPE_LAST]; + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef HASH_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALHash(SATHASHTYPE eHashType, const void *pMsg, + SATUINT32_t uiMsgLen, void *pHash); + +extern SATR CALHashDMA(SATHASHTYPE eHashType, const void *pMsg, + SATUINT32_t uiMsgLen, void *pHash, SATUINT32_t uiDMAChConfig); + +extern SATR CALHashCtx(const SATRESHANDLE hResource, + const SATRESCONTEXTPTR pContext, const void *pMsg, SATUINT32_t uiMsgLen, + void *pHash, const SATBOOL bFinal); + +extern SATR CALHashCtxIni(const SATRESCONTEXTPTR pContext, + const SATHASHTYPE eHashType); + +extern SATR CALHashIni(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen); + +extern SATR CALHashWrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR CALHashRead(void *pHash); + +extern SATR CALKeyTree(SATBOOL bPathSizeSel, const SATUINT32_t* puiKey, + SATUINT8_t uiOpType, const SATUINT32_t* puiPath, SATUINT32_t* puiKeyOut); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATUINT32_t iGetHashLen(SATHASHTYPE eHashType); + +extern SATUINT32_t iGetBlockLen(SATHASHTYPE eHashType); + +extern SATR CALHashCtxLoad(const SATRESHANDLE hResource, + SATRESCONTEXTPTR const pContext, SATUINT32_t uiRunLen); + +extern SATUINT32_t iGetRunLen(SATRESCONTEXTPTR const pContext); + +extern SATR CALHashTypeIni(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/mac.h b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/mac.h new file mode 100644 index 0000000..acdc767 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/mac.h @@ -0,0 +1,95 @@ +/* ------------------------------------------------------------------- + $Rev: 1296 $ $Date: 2017-08-01 13:54:48 -0400 (Tue, 01 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL MAC functions. + ------------------------------------------------------------------- */ + +#ifndef MAC_H +#define MAC_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef MAC_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALMAC(SATMACTYPE eMACType, const SATUINT32_t *pKey, SATUINT32_t uiKeyLen, + const void *pMsg, SATUINT32_t uiMsgLen, void *pMAC); + +extern SATR CALMACDMA(SATMACTYPE eMACType, const SATUINT32_t *pKey, + SATUINT32_t uiKeyLen, const void *pMsg, SATUINT32_t uiMsgLen, + const void *pMAC, SATUINT32_t uiDMAChConfig); + +extern SATR CALMACIni(SATMACTYPE eMACType, const SATUINT32_t *pKey, + SATUINT32_t uiKeyLen, SATUINT32_t uiMsgLen); + +extern SATR CALMACCtx(const SATRESHANDLE hResource, + const SATRESCONTEXTPTR pContext, const void *pMsg, SATUINT32_t uiMsgLen, + void *pHash, const SATUINT8_t uiFlag); + +extern SATR CALMACCtxIni(const SATRESCONTEXTPTR pContext, const SATHASHTYPE eHashType, + const SATUINT32_t *pKey, SATUINT32_t uiKeyLen); + +extern SATR CALMACWrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR CALMACRead(void *pMAC); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATUINT32_t iGetMACKeyLen(SATMACTYPE eMACType); + +extern SATR CALMACCtxLoad(const SATRESHANDLE hResource, + SATRESCONTEXTPTR const pContext, SATUINT32_t uiRunLen); + +extern SATUINT32_t iGetMACRunLen(SATRESCONTEXTPTR const pContext); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/miv-rv32i-user-crypto-lib.a b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/miv-rv32i-user-crypto-lib.a new file mode 100644 index 0000000..5fda638 Binary files /dev/null and b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/miv-rv32i-user-crypto-lib.a differ diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/miv-rv32imc-user-crypto-lib.a b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/miv-rv32imc-user-crypto-lib.a new file mode 100644 index 0000000..ee7bcf4 Binary files /dev/null and b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/miv-rv32imc-user-crypto-lib.a differ diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/nrbg.h b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/nrbg.h new file mode 100644 index 0000000..d517065 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/nrbg.h @@ -0,0 +1,83 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for NRBG functions for CAL. + ------------------------------------------------------------------- */ + +#ifndef NRBG_H +#define NRBG_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef NRBG_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALNRBGSetTestEntropy(SATUINT32_t * puiEntropy, + SATUINT32_t uiEntLen32); + +extern SATR CALNRBGGetEntropy(SATUINT32_t * puiEntropy, SATUINT32_t uiEntLen32, + SATBOOL bTesting); + +extern SATR CALNRBGConfig(SATUINT32_t uiWriteEn, SATUINT32_t uiCSR, + SATUINT32_t uiCntLim, SATUINT32_t uiVoTimer, SATUINT32_t uiFMsk, + SATUINT32_t* puiStatus); + +extern SATUINT32_t CALNRBGHealthStatus(void); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATUINT32_t CALNRBGGetTestEntLen(void); + +extern SATR nrbgpkxgetentropy(SATUINT32_t * puiEntropy, + SATUINT32_t uiEntLen32); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/pk.h b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/pk.h new file mode 100644 index 0000000..5983d9a --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/pk.h @@ -0,0 +1,302 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for for CAL PK. + ------------------------------------------------------------------- */ + +#ifndef PK_H +#define PK_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef PK_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALPKTrfRes(SATBOOL bBlock); + +extern SATR CALDSASign(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALDSASignCM(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALDSASignHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, const SATUINT32_t* puiK, + const SATUINT32_t* puiX, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, SATUINT32_t uiN, + SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALDSASignHashCM(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, const SATUINT32_t* puiK, + const SATUINT32_t* puiX, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, SATUINT32_t uiN, + SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALDSAVerify(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiY, const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, + const SATUINT32_t* puiQMu, SATUINT32_t uiN, SATUINT32_t uiL); + +extern SATR CALDSAVerifyHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, const SATUINT32_t* puiY, + const SATUINT32_t* puiR, const SATUINT32_t* puiS, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALECDHC(const SATUINT32_t* puiS, const SATUINT32_t* puiWx, + const SATUINT32_t* puiWy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t* puiK, const SATUINT32_t* puiR, + const SATUINT32_t* puiRMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiZ); + +extern SATR CALECDSASign(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALECDSASignTwist(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALECDSASignCM(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALECDSASignTwistCM(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALECDSASignHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiK, const SATUINT32_t* puiD, const SATUINT32_t* puiB, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSASignHashCM(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiK, const SATUINT32_t* puiD, const SATUINT32_t* puiB, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSASignTwistHash(const SATUINT32_t* puiMsg, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSAVerify(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS,const + SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress); + +extern SATR CALECDSAVerifyTwist(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALECDSAVerifyHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSAVerifyTwistHash(const SATUINT32_t* puiMsg, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALECMult(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECMultCM(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t* puiN, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress, SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECMultTwist(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiLen, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECMultTwistCM(const SATUINT32_t* puiMul, + const SATUINT32_t* puiPx, const SATUINT32_t* puiPy, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiMod,const SATUINT32_t* puiMu, + const SATUINT32_t* puiN, SATUINT32_t uiLen, SATUINT32_t* puiRx, + SATUINT32_t* puiRy); + +extern SATR CALECMultAdd(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiB, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen, SATUINT32_t uiPtPCompress, SATUINT32_t uiPtQCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECPtValidate(const SATUINT32_t* puiPx, const SATUINT32_t* puiPy, + const SATUINT32_t* puiB, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen); + +extern SATR CALECKeyPairGen(const SATUINT32_t* puiC, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + const SATUINT32_t* puiNM1, const SATUINT32_t* puiNM1Mu, const SATUINT32_t* puiB, + SATUINT32_t* puiD, SATUINT32_t* puiQx, SATUINT32_t* puiQy, SATUINT32_t uiLen); + +extern SATR CALExpo(const SATUINT32_t* puiBase, const SATUINT32_t* puiExpo, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALExpoCM(const SATUINT32_t* puiBase, const SATUINT32_t* puiExpo, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALMMult(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALMMultAdd(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiC, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALModRed(const SATUINT32_t* puiA, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiALen, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPreCompute(const SATUINT32_t* puiMod, SATUINT32_t* puiMu, + SATUINT32_t uiModLen); + +extern SATR CALRSACRT(const SATUINT32_t* puiCipher, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ,const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiLen, SATUINT32_t* puiPlain); + +extern SATR CALRSACRTCM(const SATUINT32_t* puiCipher, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t * puiE, const SATUINT32_t* puiP, + const SATUINT32_t* puiQ, const SATUINT32_t * puiN, + const SATUINT32_t * puiNMu, SATUINT32_t uiLen, SATUINT32_t uiELen, + SATUINT32_t* puiPlain); + +extern SATR CALRSACRTSign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + const SATUINT32_t* puiN, SATUINT32_t uiLen, SATUINT32_t* puiSig); + +extern SATR CALRSACRTSignCM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, const SATUINT32_t* puiQ, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSig); + +extern SATR CALRSACRTSignHash(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ,const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + const SATUINT32_t* puiN, SATUINT32_t uiMsgLen, SATUINT32_t uiModLen, + SATUINT32_t* puiSig, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALRSACRTSignHashCM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, const SATUINT32_t* puiQ, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, SATUINT32_t* puiSig, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALRSASign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiD, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, SATUINT32_t* puiSig); + +extern SATR CALRSASignHash(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiD, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, SATUINT32_t uiModLen, + SATUINT32_t* puiSig, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALRSAVerify(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, + const SATUINT32_t* puiSig); + +extern SATR CALRSAVerifyHash(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiE, SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, const SATUINT32_t* puiSig, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPurge52(SATBOOL bVerify); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/pkx.h b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/pkx.h new file mode 100644 index 0000000..c23dda4 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/pkx.h @@ -0,0 +1,409 @@ +/* ------------------------------------------------------------------- + $Rev: 1298 $ $Date: 2017-08-04 13:04:19 -0400 (Fri, 04 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for for CAL PK. + ------------------------------------------------------------------- */ + +#ifndef PKX_H +#define PKX_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* X5200 Addressing */ +#define X52BER ((volatile SATUINT32_t *) (PKX0_BASE + 0x00000000u)) +#define X52MMR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00001000u)) +#define X52TSR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00002000u)) +#define X52FPR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00003000u)) +#define X52LIR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00004000u)) +#define X52CSR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00007F80u)) +#define X52CSRMERRS ((volatile SATUINT32_t *) (PKX0_BASE + 0x00007F8Cu)) +#define X52CSRMERRT0 ((volatile SATUINT32_t *) (PKX0_BASE + 0x00007F94u)) + +#if SAT_LITTLE_ENDIAN +#define X52BER_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00008000u)) +#define X52MMR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00009000u)) +#define X52TSR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x0000A000u)) +#define X52FPR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x0000B000u)) +#define X52DMACONFIG_ENDIAN 0x8 +#else +#define X52BER_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00000000u)) +#define X52MMR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00001000u)) +#define X52TSR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00002000u)) +#define X52FPR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00003000u)) +#define X52DMACONFIG_ENDIAN 0x0 +#endif + +/* X5200 Macros */ +#define X52GO(x) (0x10 | ((x)<<8)) + +/* Counter Measures */ +#define RANDLEN 4 + +/* X5200 CSRMAIN bit field masks. */ +#define X52CSRMAINRST 1 +#define X52CSRMAINCCMPLT 2 +#define X52CSRMAINCMPLT 4 +#define X52CSRMAINBUSY 8 +#define X52CSRMAINGO 0x10 +#define X52CSRMAINPURGE 0x20 +#define X52CSRMAINECDIS 0x40 +#define X52CSRMAINALARM 0x80 +#define X52CSRMAINLIRA ((0xFFF) << 8) +#define X52CSRMERRSSEC ((0x2) << 24) +#define X52CSRMERRSA 0x1FFF + +/* Address pointers for ROM'd P-curve moduli */ +#define P192_MOD (&uiROMMods[0]) +#define P224_MOD (&uiROMMods[1]) +#define P256_MOD (&uiROMMods[2]) +#define P384_MOD (&uiROMMods[3]) +#define P521_MOD (&uiROMMods[4]) + +/* X5200 Addressing Flags */ +#define X52BYTEREVERSE_FLAG 1 +#define X52WORDREVERSE_FLAG 2 +#define X52BYTEREVERSE 0x00002000 +#define X52WORDREVERSE 0x00004000 +#define X52ADDRESSRANGE 0x2000 + +/* X5200 DMA channel configuration constants. */ +#define X52CCR_DEFAULT 0 /* BSIZE=auto, ESWP=none, PROT=user, INC=inc */ +#define X52CCR_BSIZEAUTO 0 /* BSIZE=auto */ +#define X52CCR_BSIZEBYTE 0x10 /* BSIZE=byte */ +#define X52CCR_BSIZEHWORD 0x20 /* BSIZE=half word */ +#define X52CCR_BSIZEWORD 0x30 /* BSIZE=word */ +#define X52CCR_ESWPNONE 0 /* ESWP=none */ +#define X52CCR_ESWPWORD 0x8 /* ESWP=swap bytes in word [0123]->[3210] */ +#define X52CCR_PROTUSER 0 /* PROT=user */ +#define X52CCR_PROTPRIV 0x2 /* PROT=priv */ +#define X52CCR_INCADDR 0 /* INC=inc */ +#define X52CCR_NOINCADDR 0x1 /* INC=non-inc */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef PKX_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern void CALPKXIni(void); + +extern void CALPKMem32Load(volatile SATUINT32_t * puiDst, + const SATUINT32_t * puiSrc, SATUINT32_t uiNum ); + +extern SATR CALPKXTrfRes(SATBOOL bBlock); + +extern SATR CALPKXPreCompute(const SATUINT32_t* puiMod, SATUINT32_t* puiMu, + SATUINT32_t uiModLen); + +extern SATR CALPKXExpo(const SATUINT32_t* puiBase, const SATUINT32_t* puiExpo, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALPKXExpoCM(const SATUINT32_t* puiBase, + const SATUINT32_t* puiExpo, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPKXDSASign(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXDSASignCM(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXDSASHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATUINT32_t uiDMAChConfig, const SATBOOL bCM); + +extern SATR CALPKXDSAVerify(const SATUINT32_t *puiHash, + const SATUINT32_t *puiG, const SATUINT32_t *puiY, + const SATUINT32_t *puiSigR, const SATUINT32_t *puiSigS, + const SATUINT32_t *puiP, const SATUINT32_t *puiPMu, + const SATUINT32_t *puiQ, const SATUINT32_t *puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL); + +extern SATR CALPKXDSAVHDMA(const SATUINT32_t *puiExtInput, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t *puiG, const SATUINT32_t *puiY, + const SATUINT32_t *puiSigR, const SATUINT32_t *puiSigS, + const SATUINT32_t *puiP, const SATUINT32_t *puiPMu, const SATUINT32_t *puiQ, + const SATUINT32_t *puiQMu, SATUINT32_t uiN, SATUINT32_t uiL, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXModRed(const SATUINT32_t* puiA, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiALen, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPKXMMult(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPKXMMultAdd(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiC, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALPKXECMult(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECMultTwist(const SATUINT32_t* puiMul, + const SATUINT32_t* puiPx,const SATUINT32_t* puiPy, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen, SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECMultCM(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t * puiN, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress, SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECMultTwistCM(const SATUINT32_t* puiMul, + const SATUINT32_t* puiPx, const SATUINT32_t* puiPy, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + const SATUINT32_t * puiN, SATUINT32_t uiLen, SATUINT32_t* puiRx, + SATUINT32_t* puiRy); + +extern SATR CALPKXECMultAdd(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiB, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen, SATUINT32_t uiPtPCompress, SATUINT32_t uiPtQCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECDSASign(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASignTwist(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx,const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASignCM(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASignTwistCM(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASH(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + const SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASHCM(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + const SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, SATUINT32_t uiDMAChConfig, + const SATBOOL bCM); + +extern SATR CALPKXECDSASTwistH(const SATUINT32_t* puiHash, + const SATHASHTYPE eHashType, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiK, const SATUINT32_t* puiD, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, const SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASTwistHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECDSAVerify(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVerifyTwist(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVH(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB,const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + const SATUINT32_t uiLen, const SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB,const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECDSAVTwistH(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, const SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVTwistHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECDHC(const SATUINT32_t* puiS, const SATUINT32_t* puiWx, + const SATUINT32_t* puiWy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t* puiK, const SATUINT32_t* puiR, + const SATUINT32_t* puiRMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiZ); + +extern SATR CALPKXRSACRT(const SATUINT32_t* puiCipher, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, SATUINT32_t uiLen, + SATUINT32_t* puiPlain); + +extern SATR CALPKXRSACRTCM(const SATUINT32_t* puiCipher, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiE, + const SATUINT32_t* puiP, const SATUINT32_t* puiQ, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, const SATUINT32_t uiLen, const SATUINT32_t uiELen, + SATUINT32_t* puiPlain); + +extern SATR CALPKXRSACRTSign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiCipher, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, + const SATUINT32_t* puiQMu, const SATUINT32_t* puiN, SATUINT32_t uiLen, + SATUINT32_t* puiS); + +extern SATR CALPKXRSACRTSignCM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, + const SATUINT32_t* puiP, const SATUINT32_t* puiQ, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSig); + +extern SATR CALPKXRSACRTSHDMA(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + const SATUINT32_t* puiN, SATUINT32_t uiMsgLen, SATUINT32_t uiModLen, + SATUINT32_t* puiSig, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXRSACRTSHDMACM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, + const SATUINT32_t* puiP, const SATUINT32_t* puiQ, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, SATUINT32_t uiLen, + SATUINT32_t* puiSig, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXRSASign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiD, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, SATUINT32_t* puiSig); + +extern SATR CALPKXRSASHDMA(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiD, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, SATUINT32_t* puiSig, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXRSAVerify(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, + const SATUINT32_t* puiS); + +extern SATR CALPKXRSAVHDMA(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiE,SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, const SATUINT32_t* puiS, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECPtValidate(const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiLen); + +extern SATR CALPKXECKeyPairGen(const SATUINT32_t* puiC, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + const SATUINT32_t* puiNM1, const SATUINT32_t* puiNM1Mu, const SATUINT32_t* puiB, + SATUINT32_t* puiD, SATUINT32_t* puiQx, SATUINT32_t* puiQy, SATUINT32_t uiLen); + +extern SATR CALPKXPurge52(SATBOOL bVerify); + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ +extern SATRESULT SATResults; + +/* -------- ------ --------- */ +/* External Global Constants */ +/* -------- ------ --------- */ +extern const SATUINT32_t uiROMMods[]; + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/pkxlib.h b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/pkxlib.h new file mode 100644 index 0000000..fb4c0fc --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/pkxlib.h @@ -0,0 +1,95 @@ +/* ------------------------------------------------------------------- + $Rev: 1434 $ $Date: 2017-10-20 16:46:16 -0400 (Fri, 20 Oct 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for PKX-5200 Library. + ------------------------------------------------------------------- */ + +#ifndef PKXLIB_H +#define PKXLIB_H + +#include "caltypes.h" +#include "calpolicy.h" + +#define PKX_JMP_NONE (0xFFFFu + PKX_OFFSET) + +/* jump table entry points: starting PC value */ +#define PKX_JMP_RECIP_PRECOMPUTE (0x0000 + PKX_OFFSET) +#define PKX_JMP_MOD_EXP (0x0002 + PKX_OFFSET) +#define PKX_JMP_RSA_CRT (0x0004 + PKX_OFFSET) +#define PKX_JMP_EC_PTMUL (0x0006 + PKX_OFFSET) +#define PKX_JMP_EC_DSA_SIGN (0x0008 + PKX_OFFSET) +#define PKX_JMP_EC_DSA_VERIFY (0x000A + PKX_OFFSET) +#define PKX_JMP_DSA_SIGN (0x000C + PKX_OFFSET) +#define PKX_JMP_DSA_VERIFY (0x000E + PKX_OFFSET) +#define PKX_JMP_MOD_MULT (0x0010 + PKX_OFFSET) +#define PKX_JMP_MOD_RED (0x0012 + PKX_OFFSET) +#define PKX_JMP_EC_PTDECOMP (0x0014 + PKX_OFFSET) +#define PKX_JMP_EC_DHC (0x0016 + PKX_OFFSET) +#define PKX_JMP_MOD_MULT_ADD (0x0018 + PKX_OFFSET) +#define PKX_JMP_EC_PTMUL_ADD (0x001A + PKX_OFFSET) +#define PKX_JMP_EC_PTVALIDATE (0x001C + PKX_OFFSET) +#define PKX_JMP_F5200_SHA (0x001E + PKX_OFFSET) +#define PKX_JMP_F5200_AES (0x0020 + PKX_OFFSET) +#define PKX_JMP_F5200_AESK (0x0022 + PKX_OFFSET) +#define PKX_JMP_F5200_GCM (0x0024 + PKX_OFFSET) +#define PKX_JMP_F5200_GHA (0x0026 + PKX_OFFSET) +#define PKX_JMP_F5200_AESKW (0x0028 + PKX_OFFSET) +#define PKX_JMP_F5200_AESKWP (0x002A + PKX_OFFSET) +#define PKX_JMP_RNG_INSTANTIATE (0x002C + PKX_OFFSET) +#define PKX_JMP_RNG_RESEED (0x002E + PKX_OFFSET) +#define PKX_JMP_RNG_GENERATE (0x0030 + PKX_OFFSET) +#define PKX_JMP_RNG_UNINSTANTIATE (0x0032 + PKX_OFFSET) +#define PKX_JMP_RNG_GETENTROPY (0x0034 + PKX_OFFSET) +#define PKX_JMP_F5200_SHA_HMAC (0x0036 + PKX_OFFSET) +#define PKX_JMP_F5200_AES_DMA (0x0038 + PKX_OFFSET) +#define PKX_JMP_RNG_CTRLSTATUS (0x003A + PKX_OFFSET) +#define PKX_JMP_F5200_SHA_DMA (0x003C + PKX_OFFSET) +#define PKX_JMP_SHX_KEYTREE (0x003E + PKX_OFFSET) +#define PKX_JMP_PKX_DSA_DMA (0x0040 + PKX_OFFSET) +#define PKX_JMP_PKX_RSACRT_SIGN (0x0042 + PKX_OFFSET) +#define PKX_JMP_PKX_RSA_SIGN (0x0044 + PKX_OFFSET) +#define PKX_JMP_PKX_RSA_VERIFY (0x0046 + PKX_OFFSET) +#define PKX_JMP_PKX_EC_DSA_DMA (0x0048 + PKX_OFFSET) +#define PKX_JMP_F5200_AES_KEYROLL (0x004A + PKX_OFFSET) +#define PKX_JMP_EXPM (0x004C + PKX_OFFSET) +#define PKX_JMP_RSACRTM (0x004E + PKX_OFFSET) +#define PKX_JMP_EC_PTMULM (0x0050 + PKX_OFFSET) +#define PKX_JMP_DSA_SIGN_M (0x0052 + PKX_OFFSET) +#define PKX_JMP_EC_DSA_SIGN_M (0x0054 + PKX_OFFSET) +#define PKX_JMP_EC_KEYPAIRGEN (0x0056 + PKX_OFFSET) +#define PKX_JMP_RSACRTCM_SIGN (0x0058 + PKX_OFFSET) +#define PKX_JMP_F5200_GCM_NEW (0x005A + PKX_OFFSET) +/* PKX PKRev 2180 */ +/* PKX SHARev 2160 */ +/* PKX AESRev 2135 */ +/* Hex Checksum: 0xd0d79866 */ + +extern const SATUINT32_t uiPKX_Flags; +extern const SATUINT32_t uiPKX_BERWords; +extern const SATUINT32_t uiPKX_LIRWords; +extern const SATUINT32_t uiPKX_Rev; +extern const SATUINT32_t uiPKX_LibSize; +extern const SATUINT32_t uiPKX_LibChksum; +extern const SATUINT32_t uiPKX_Lib[]; +extern SATBOOL bMPF300TS_ES; + +#endif diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/shaf5200.h b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/shaf5200.h new file mode 100644 index 0000000..da598d1 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/shaf5200.h @@ -0,0 +1,101 @@ +/* ------------------------------------------------------------------- + $Rev: 1296 $ $Date: 2017-08-01 13:54:48 -0400 (Tue, 01 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for SHA function hardware implementation for CAL. + ------------------------------------------------------------------- */ + +#ifndef SHAF5200_H +#define SHAF5200_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef SHAF5200_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATR shapkxctx(SATRESCONTEXTPTR const pContext, const void *pBuffer, + SATUINT32_t uiBufLen,void *pHash, const SATBOOL bFinal); + +extern SATR shapkxhmacctx(SATRESCONTEXTPTR const pContext, const void *pBuffer, + SATUINT32_t uiBufLen, void *pHash, const SATUINT8_t uiFlag); + +extern SATR shapkxctxload(SATRESCONTEXTPTR const pContext); + +extern void shapkxctxunload(SATRESCONTEXTPTR const pContext); + +extern SATR shapkxini(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen); + +extern SATR shapkxhmacini(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, + const void *pKey, SATUINT32_t uiKeyLen); + +extern SATR shapkxwrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR shapkxhmacwrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR shapkxread(void *pHash, SATUINT32_t uiRevFlag); + +extern SATR shapkxkeytree(SATBOOL bPathSizeSel, const SATUINT32_t* puiKey, + SATUINT8_t uiOpType, const SATUINT32_t* puiPath, SATUINT32_t* puiKeyOut); + +extern SATR shapkxdma(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, + const void *pExtSrc, const void *pExtDest, SATUINT32_t uiDMAChConfig); + +extern SATR shapkxhmacdma(SATMACTYPE eMACType, const SATUINT32_t *pKey, + SATUINT32_t uiKeyLen, const void *pMsg, SATUINT32_t uiMsgLen, + const void *pMAC, SATUINT32_t uiDMAChConfig); + +extern SATR shapkxhashtypeini(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/sym.h b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/sym.h new file mode 100644 index 0000000..2e07faa --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/sym.h @@ -0,0 +1,129 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for Symmetric Key Cryptography in CAL. + ------------------------------------------------------------------- */ + +#ifndef SYM_H +#define SYM_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef SYM_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALSymTrfRes(SATBOOL bBlock); + +extern SATR CALSymEncrypt(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen); + +extern SATR CALSymDecrypt(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen); + +extern SATR CALSymEncryptDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymDecryptDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymEncryptKR(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF); + +extern SATR CALSymDecryptKR(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF); + +extern SATR CALSymEncryptKRDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymDecryptKRDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymEncAuth(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen); + +extern SATR CALSymDecVerify(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen); + +extern SATR CALSymKw(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR CALSymKwp(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR CALSymEncAuthDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymDecVerifyDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen, SATUINT32_t uiDMAChConfig); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/utils.h b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/utils.h new file mode 100644 index 0000000..91474f0 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/utils.h @@ -0,0 +1,93 @@ +/* ------------------------------------------------------------------- + $Rev: 1300 $ $Date: 2017-08-07 11:36:02 -0400 (Mon, 07 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL utility functions. + ------------------------------------------------------------------- */ + +#ifndef UTILS_H +#define UTILS_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef UTILS_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern void CALMemCopy(void *pDst, const void *pSrc, SATUINT32_t uiNum8); + +extern void CALMemClear( void * pLoc, SATUINT32_t uiNum ); + +extern void CALMemClear32( SATUINT32_t* puiLoc, SATUINT32_t uiLen32 ); + +extern SATBOOL CALMemCmp(const void *pA, const void *pB, SATUINT32_t uiNum); + +extern void CALVol32MemLoad(volatile SATUINT32_t * puiDst, const void * pSrc, + SATUINT32_t uiNum32); + +extern void CALVol32MemRead(void * pDst, volatile SATUINT32_t * puiSrc, + SATUINT32_t uiNum32); + +extern void CALByteReverse(SATUINT32_t* puiArray, SATINT32_t iNumberBytes); + +extern void CALByteReverseWord(SATUINT32_t* puiArray, SATINT32_t iNumberWords); + +extern void CALWordReverse(SATUINT32_t *puiArray, SATINT32_t iNumberWords); + +extern void vAppendNonzero(void *puiArray, SATUINT32_t uiLen, + SATUINT32_t uiBlockSize); + +extern void vAppendZero(void *puiArray, SATUINT32_t uiLen, + SATUINT32_t uiBlockSize); + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/x52cfg_user.h b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/x52cfg_user.h new file mode 100644 index 0000000..c8d8648 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/middleware/cal/x52cfg_user.h @@ -0,0 +1,72 @@ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ +/* X5200 configuration */ +/* $Date: 2015-07-23 14:30:19 -0400 (Thu, 23 Jul 2015) $ $Rev: 2093 $ */ +/* ------------------------------------------------------------------- + Options: + * LIR ROM size : 4096 + * LIR RAM size : 2048 + * BER size : 1024 + * MMR size : 1024 + * TSR size : 1024 + * FPR size : 1024 + * Single error correct, dual error detect (SECDED) memory parity + * DMA enabled + * FPGA multipliers disabled + * AES enabled + - Fast key schedule generation + - GCM/GHASH enabled + - AES countermeasures enabled + * RNG enabled + * External PRNG disabled + * SHA enabled + - Fast SHA enabled + - SHA-1 enabled + - SHA-224 enabled + - SHA-256 enabled + - SHA-384 enabled + - SHA-512 enabled + - SHA-512/224 enabled + - SHA-512/256 enabled + - SHA countermeasures enabled + * P-curves populated in FCR: + - P-192 populated + - P-224 populated + - P-256 populated + - P-384 populated + - P-521 populated + * Data memory scrambling enabled + + ------------------------------------------------------------------- */ + +#ifndef X52CFG_H +#define X52CFG_H + +#define X52_CFG_MODEL 0xf5200 +#define X52_CFG_DATE 0x15072720 +#define X52_CFG_REV 0x0000082e +#define X52_CFG_OPT 0x0fd87ff9 +#define X52_CFG_OPT2 0xc0000000 +#define X52_LIR_LEN 0x1800 +#define X52_LIR_ROM_LEN 0x1000 +#define X52_LIR_RAM_LEN 0x0800 +#define X52_BER_LEN 0x400 +#define X52_MMR_LEN 0x400 +#define X52_TSR_LEN 0x400 +#define X52_FPR_LEN 0x400 + +#endif diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/README.md b/applications/user-crypto/miv-rv32-keytree-services/src/platform/README.md new file mode 100644 index 0000000..f7f6030 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/README.md @@ -0,0 +1,27 @@ +# Mi-V soft processor platform source code + +## Repo organization + +``` + + | + |-- drivers + | |- fpga_ip + | | | CoreGPIO + | | | CoreSysServices_PF + | | | CoreUARTapb + | | + | |- off_chip + | | | . + | | | . + | | + |-- hal + | | + |-- miv_rv32_hal + + +``` + +The drivers published here are compatible with the improved SoftConsole project folder structure being used in the latest [example projects](https://github.com/Mi-V-Soft-RISC-V/miv-rv32-bare-metal-examples). +These drivers can also be used with the legacy folder structure (projects released via Firmware Catalog) by defining the **LEGACY_DIR_STRUCTURE** macro in the SoftConsole project settings. + diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c new file mode 100644 index 0000000..1a0073f --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c @@ -0,0 +1,533 @@ +/******************************************************************************* + * (c) Copyright 2008-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file core_gpio.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreGPIO bare metal driver implementation. + * + */ +#include "coregpio_regs.h" +#include "core_gpio.h" + +/*-------------------------------------------------------------------------*//** + * + */ +#define GPIO_INT_ENABLE_MASK (uint32_t)0x00000008UL +#define OUTPUT_BUFFER_ENABLE_MASK 0x00000004UL + + +#define NB_OF_GPIO 32 + +#define CLEAR_ALL_IRQ32 (uint32_t)0xFFFFFFFF +#define CLEAR_ALL_IRQ16 (uint16_t)0xFFFF +#define CLEAR_ALL_IRQ8 (uint8_t)0xFF + +/*-------------------------------------------------------------------------*//** + * GPIO_init() + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_init +( + gpio_instance_t * this_gpio, + addr_t base_addr, + gpio_apb_width_t bus_width +) +{ + uint8_t i = 0; + addr_t cfg_reg_addr = base_addr; + + this_gpio->base_addr = base_addr; + this_gpio->apb_bus_width = bus_width; + + /* Clear configuration. */ + for( i = 0, cfg_reg_addr = base_addr; i < NB_OF_GPIO; ++i ) + { + HW_set_8bit_reg( cfg_reg_addr, 0 ); + cfg_reg_addr += 4; + } + /* Clear any pending interrupts */ + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, CLEAR_ALL_IRQ32 ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, (uint16_t)CLEAR_ALL_IRQ16 ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, (uint16_t)CLEAR_ALL_IRQ16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, (uint8_t)CLEAR_ALL_IRQ8 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_config + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_config +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint32_t config +) +{ + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + uint32_t cfg_reg_addr = this_gpio->base_addr; + cfg_reg_addr += (port_id * 4); + HW_set_32bit_reg( cfg_reg_addr, config ); + + /* + * Verify that the configuration was correctly written. Failure to read + * back the expected value may indicate that the GPIO port was configured + * as part of the hardware flow and cannot be modified through software. + * It may also indicate that the base address passed as parameter to + * GPIO_init() was incorrect. + */ + HAL_ASSERT( HW_get_32bit_reg( cfg_reg_addr ) == config ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_set_outputs + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_set_outputs +( + gpio_instance_t * this_gpio, + uint32_t value +) +{ + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, GPIO_OUT, value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, GPIO_OUT0, (uint16_t)value ); + HAL_set_16bit_reg( this_gpio->base_addr, GPIO_OUT1, (uint16_t)(value >> 16) ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT0, (uint8_t)value ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT1, (uint8_t)(value >> 8) ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT2, (uint8_t)(value >> 16) ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT3, (uint8_t)(value >> 24) ); + break; + + default: + HAL_ASSERT(0); + break; + } + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( GPIO_get_outputs( this_gpio ) == value ); +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_inputs + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_inputs +( + gpio_instance_t * this_gpio +) +{ + uint32_t gpio_in = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + gpio_in = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_IN ); + break; + + case GPIO_APB_16_BITS_BUS: + gpio_in |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_IN0 ); + gpio_in |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_IN1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + gpio_in |= HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN0 ); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN1 ) << 8); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN2 ) << 16); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return gpio_in; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_outputs + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_outputs +( + gpio_instance_t * this_gpio +) +{ + uint32_t gpio_out = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + gpio_out = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ); + break; + + case GPIO_APB_16_BITS_BUS: + gpio_out |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT0 ); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + gpio_out |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT0 ); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT1 ) << 8); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT2 ) << 16); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return gpio_out; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_set_output + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_set_output +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint8_t value +) +{ + HAL_ASSERT( port_id < NB_OF_GPIO ); + + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + { + uint32_t outputs_state; + + outputs_state = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ); + if ( 0 == value ) + { + outputs_state &= ~(1 << port_id); + } + else + { + outputs_state |= 1 << port_id; + } + HAL_set_32bit_reg( this_gpio->base_addr, GPIO_OUT, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ) == outputs_state ); + } + break; + + case GPIO_APB_16_BITS_BUS: + { + uint16_t outputs_state; + uint32_t gpio_out_reg_addr = this_gpio->base_addr + GPIO_OUT_REG_OFFSET + ((port_id >> 4) * 4); + + outputs_state = HW_get_16bit_reg( gpio_out_reg_addr ); + if ( 0 == value ) + { + outputs_state &= ~(1 << (port_id & 0x0F)); + } + else + { + outputs_state |= 1 << (port_id & 0x0F); + } + HW_set_16bit_reg( gpio_out_reg_addr, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HW_get_16bit_reg( gpio_out_reg_addr ) == outputs_state ); + } + break; + + case GPIO_APB_8_BITS_BUS: + { + uint8_t outputs_state; + uint32_t gpio_out_reg_addr = this_gpio->base_addr + GPIO_OUT_REG_OFFSET + ((port_id >> 3) * 4); + + outputs_state = HW_get_8bit_reg( gpio_out_reg_addr ); + if ( 0 == value ) + { + outputs_state &= ~(1 << (port_id & 0x07)); + } + else + { + outputs_state |= 1 << (port_id & 0x07); + } + HW_set_8bit_reg( gpio_out_reg_addr, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HW_get_8bit_reg( gpio_out_reg_addr ) == outputs_state ); + } + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_drive_inout + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_drive_inout +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + gpio_inout_state_t inout_state +) +{ + uint32_t config; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + switch( inout_state ) + { + case GPIO_DRIVE_HIGH: + /* Set output high */ + GPIO_set_output( this_gpio, port_id, 1 ); + + /* Enable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config |= OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + case GPIO_DRIVE_LOW: + /* Set output low */ + GPIO_set_output( this_gpio, port_id, 0 ); + + /* Enable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config |= OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + case GPIO_HIGH_Z: + /* Disable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config &= ~OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_enable_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_enable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t cfg_value; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + cfg_reg_addr += (port_id * 4); + cfg_value = HW_get_8bit_reg( cfg_reg_addr ); + cfg_value |= GPIO_INT_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, cfg_value ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_disable_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_disable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t cfg_value; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + cfg_reg_addr += (port_id * 4); + cfg_value = HW_get_8bit_reg( cfg_reg_addr ); + cfg_value &= ~GPIO_INT_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, cfg_value ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_clear_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_clear_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t irq_clr_value = ((uint32_t)1) << ((uint32_t)port_id); + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, irq_clr_value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, irq_clr_value >> 16 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, irq_clr_value >> 24 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_irq_sources + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_irq_sources +( + gpio_instance_t * this_gpio +) +{ + uint32_t intr_src = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + intr_src = HAL_get_32bit_reg( this_gpio->base_addr, IRQ ); + break; + + case GPIO_APB_16_BITS_BUS: + intr_src |= HAL_get_16bit_reg( this_gpio->base_addr, IRQ0 ); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + intr_src |= HAL_get_16bit_reg( this_gpio->base_addr, IRQ0 ); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ1 ) << 8); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ2 ) << 16); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return intr_src; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_clear_all_irq_sources + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_clear_all_irq_sources +( + gpio_instance_t * this_gpio, + uint32_t bitmask +) +{ + uint32_t irq_clr_value = bitmask; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, irq_clr_value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, irq_clr_value >> 16 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, irq_clr_value >> 24 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h new file mode 100644 index 0000000..88ba178 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h @@ -0,0 +1,722 @@ +/******************************************************************************* + * (c) Copyright 2008-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file core_gpio.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreGPIO bare metal driver public API. + * + */ + +/*=========================================================================*//** + @mainpage CoreGPIO Bare Metal Driver. + + @section intro_sec Introduction + The CoreGPIO hardware IP includes up to 32 general-purpose input/output GPIOs. + This driver provides a set of functions for controlling the GPIOs as part of a + bare-metal system where no operating system is available. These drivers + can be adapted for use as part of an operating system, but the implementation + of the adaptation layer between this driver and the operating system's driver + model is outside the scope of this driver. + + @section driver_configuration Driver Configuration + The individual IOs of CoreGPIO can be configured either in the hardware flow + or as part of the software application through calls to the GPIO_config() + function. GPIOs configured as part of the hardware are fixed and cannot be + modified using a call to the GPI_config() function. + + @section theory_op Theory of Operation + The CoreGPIO driver uses the Actel Hardware Abstraction Layer (HAL) to access + hardware registers. You must ensure that the Actel HAL is included as part of + your software project. The Actel HAL is available through the Actel Firmware + Catalog. + + The CoreGPIO driver functions are logically grouped into the following groups: + - Initialization + - Configuration + - Reading and writing GPIO state + - Interrupt control + + The CoreGPIO driver is initialized through a call to the GPIO_init() function. + The GPIO_init() function must be called before any other GPIO driver functions + can be called. + + Each GPIO port is individually configured through a call to the + GPIO_config() function. Configuration includes deciding if a GPIO port is + going to be used as input, output, or both. GPIO ports configured as inputs + are further configured to generate interrupts based on the state of input. + Interrupts is either level- or edge-sensitive. + Note that a CoreGPIO hardware instance is generated as part of the hardware + flow with a fixed configuration for some or all of its IOs. + Attempting to modify the configuration of such a hardware-configured IO using + the GPIO_config() function has no effect. + + The state of the GPIO ports can be read and written using the following + functions: + - GPIO_get_inputs() + - GPIO_get_outputs() + - GPIO_set_outputs() + - GPIO_drive_inout() + + Interrupts generated by GPIO ports configured as inputs are controlled using + the following functions: + - GPIO_enable_irq() + - GPIO_disable_irq() + - GPIO_clear_irq() + - GPIO_get_irq_sources() + - GPIO_clear_all_irq_sources() + + *//*=========================================================================*/ +#ifndef CORE_GPIO_H_ +#define CORE_GPIO_H_ + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + The gpio_id_t enumeration is used to identify GPIOs as part of the + parameter to functions: + - GPIO_config(), + - GPIO_drive_inout(), + - GPIO_enable_int(), + - GPIO_disable_int(), + - GPIO_clear_int() + */ +typedef enum __gpio_id_t +{ + GPIO_0 = 0, + GPIO_1 = 1, + GPIO_2 = 2, + GPIO_3 = 3, + GPIO_4 = 4, + GPIO_5 = 5, + GPIO_6 = 6, + GPIO_7 = 7, + GPIO_8 = 8, + GPIO_9 = 9, + GPIO_10 = 10, + GPIO_11 = 11, + GPIO_12 = 12, + GPIO_13 = 13, + GPIO_14 = 14, + GPIO_15 = 15, + GPIO_16 = 16, + GPIO_17 = 17, + GPIO_18 = 18, + GPIO_19 = 19, + GPIO_20 = 20, + GPIO_21 = 21, + GPIO_22 = 22, + GPIO_23 = 23, + GPIO_24 = 24, + GPIO_25 = 25, + GPIO_26 = 26, + GPIO_27 = 27, + GPIO_28 = 28, + GPIO_29 = 29, + GPIO_30 = 30, + GPIO_31 = 31 +} gpio_id_t; + +/*-------------------------------------------------------------------------*//** + Possible width of the APB bus + */ +typedef enum __gpio_apb_width_t +{ + GPIO_APB_8_BITS_BUS = 0, + GPIO_APB_16_BITS_BUS = 1, + GPIO_APB_32_BITS_BUS = 2, + GPIO_APB_UNKNOWN_BUS_WIDTH = 3 +} gpio_apb_width_t; + +/*-------------------------------------------------------------------------*//** + Structure instance holding all data regarding the CoreGPIO + */ +typedef struct __gpio_instance_t +{ + addr_t base_addr; + gpio_apb_width_t apb_bus_width; +} gpio_instance_t; + +/*-------------------------------------------------------------------------*//** + GPIO ports definitions used to identify GPIOs as part of the parameter to + function GPIO_set_outputs(). + These definitions are also be used to identity GPIO through logical operations + on the return value of function GPIO_get_inputs(). + # GPIO_0_MASK + # GPIO_1_MASK + # GPIO_2_MASK + # GPIO_3_MASK + # GPIO_4_MASK + # GPIO_5_MASK + # GPIO_6_MASK + # GPIO_7_MASK + # GPIO_8_MASK + # GPIO_9_MASK + # GPIO_10_MASK + # GPIO_11_MASK + # GPIO_12_MASK + # GPIO_13_MASK + # GPIO_14_MASK + # GPIO_15_MASK + # GPIO_16_MASK + # GPIO_17_MASK + # GPIO_18_MASK + # GPIO_19_MASK + # GPIO_20_MASK + # GPIO_21_MASK + # GPIO_22_MASK + # GPIO_23_MASK + # GPIO_24_MASK + # GPIO_25_MASK + # GPIO_26_MASK + # GPIO_27_MASK + # GPIO_28_MASK + # GPIO_29_MASK + # GPIO_30_MASK + # GPIO_31_MASK + */ +#define GPIO_0_MASK 0x00000001UL +#define GPIO_1_MASK 0x00000002UL +#define GPIO_2_MASK 0x00000004UL +#define GPIO_3_MASK 0x00000008UL +#define GPIO_4_MASK 0x00000010UL +#define GPIO_5_MASK 0x00000020UL +#define GPIO_6_MASK 0x00000040UL +#define GPIO_7_MASK 0x00000080UL +#define GPIO_8_MASK 0x00000100UL +#define GPIO_9_MASK 0x00000200UL +#define GPIO_10_MASK 0x00000400UL +#define GPIO_11_MASK 0x00000800UL +#define GPIO_12_MASK 0x00001000UL +#define GPIO_13_MASK 0x00002000UL +#define GPIO_14_MASK 0x00004000UL +#define GPIO_15_MASK 0x00008000UL +#define GPIO_16_MASK 0x00010000UL +#define GPIO_17_MASK 0x00020000UL +#define GPIO_18_MASK 0x00040000UL +#define GPIO_19_MASK 0x00080000UL +#define GPIO_20_MASK 0x00100000UL +#define GPIO_21_MASK 0x00200000UL +#define GPIO_22_MASK 0x00400000UL +#define GPIO_23_MASK 0x00800000UL +#define GPIO_24_MASK 0x01000000UL +#define GPIO_25_MASK 0x02000000UL +#define GPIO_26_MASK 0x04000000UL +#define GPIO_27_MASK 0x08000000UL +#define GPIO_28_MASK 0x10000000UL +#define GPIO_29_MASK 0x20000000UL +#define GPIO_30_MASK 0x40000000UL +#define GPIO_31_MASK 0x80000000UL + +/*-------------------------------------------------------------------------*//** + * GPIO modes + * # GPIO_INPUT_MODE + * # GPIO_OUTPUT_MODE + * # GPIO_INOUT_MODE + */ +#define GPIO_INPUT_MODE 0x0000000002UL +#define GPIO_OUTPUT_MODE 0x0000000005UL +#define GPIO_INOUT_MODE 0x0000000003UL + +/*-------------------------------------------------------------------------*//** + * Possible GPIO inputs interrupt configurations. + * # GPIO_IRQ_LEVEL_HIGH + * # GPIO_IRQ_LEVEL_LOW + * # GPIO_IRQ_EDGE_POSITIVE + * # GPIO_IRQ_EDGE_NEGATIVE + * # GPIO_IRQ_EDGE_BOTH + */ +#define GPIO_IRQ_LEVEL_HIGH 0x0000000000UL +#define GPIO_IRQ_LEVEL_LOW 0x0000000020UL +#define GPIO_IRQ_EDGE_POSITIVE 0x0000000040UL +#define GPIO_IRQ_EDGE_NEGATIVE 0x0000000060UL +#define GPIO_IRQ_EDGE_BOTH 0x0000000080UL + +/*-------------------------------------------------------------------------*//** + * Possible states for GPIO configured as INOUT + */ +typedef enum gpio_inout_state +{ + GPIO_DRIVE_LOW = 0, + GPIO_DRIVE_HIGH, + GPIO_HIGH_Z +} gpio_inout_state_t; + +/*-------------------------------------------------------------------------*//** + The GPIO_init() function initializes a CoreGPIO hardware instance and the data + structure associated with the CoreGPIO hardware instance. + Note that a CoreGPIO hardware instance is generated with a fixed configuration + for some or all of its IOs as part of the hardware flow. + Attempting to modify the configuration of such a hardware-configured IO using + the GPIO_config() function has no effect. + + @param this_gpio + Pointer to the gpio_instance_t data structure instance holding all data + regarding the CoreGPIO hardware instance being initialized. A pointer to the + same data structure is used in subsequent calls to the CoreGPIO driver + functions in order to identify the CoreGPIO instance that must perform the + operation implemented by the called driver function. + + @param base_addr + The base_addr parameter is the base address in the memory map of the + processor for the registers of the GPIO instance being initialized. + + @param bus_width + The bus_width parameter informs the driver of the APB bus width selected + during the hardware flow configuration of the CoreGPIO hardware instance. It + indicates to the driver whether the CoreGPIO hardware registers are visible + as 8, 16, or 32-bits registers. Allowed values are: + - GPIO_APB_8_BITS_BUS + - GPIO_APB_16_BITS_BUS + - GPIO_APB_32_BITS_BUS + + @return + none. + + @example + @code + #define COREGPIO_BASE_ADDR 0xC2000000 + + gpio_instance_t g_gpio; + + void system_init( void ) + { + GPIO_init( &g_gpio, COREGPIO_BASE_ADDR, GPIO_APB_32_BITS_BUS ); + } + @endcode + */ +void GPIO_init +( + gpio_instance_t * this_gpio, + addr_t base_addr, + gpio_apb_width_t bus_width +); + +/*-------------------------------------------------------------------------*//** + The GPIO_config() function is used to configure an individual GPIO port. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO port to be configured. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @param config + The config parameter specifies the configuration to be applied to the GPIO + port identified by the first parameter. It is a logical OR of GPIO mode and + interrupt mode. The interrupt mode is only relevant if the GPIO is + configured as an input. + - Possible modes are: + - GPIO_INPUT_MODE, + - GPIO_OUTPUT_MODE, + - GPIO_INOUT_MODE. + - Possible interrupt modes are: + - GPIO_IRQ_LEVEL_HIGH, + - GPIO_IRQ_LEVEL_LOW, + - GPIO_IRQ_EDGE_POSITIVE, + - GPIO_IRQ_EDGE_NEGATIVE, + - GPIO_IRQ_EDGE_BOTH + + @return + none. + + @example + For example, the following call configures GPIO 4 as an input that generates + interrupts on a low-to-high transition of the input: + @code + GPIO_config( &g_gpio, GPIO_4, GPIO_INPUT_MODE | GPIO_IRQ_EDGE_POSITIVE ); + @endcode + */ +void GPIO_config +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint32_t config +); + +/*-------------------------------------------------------------------------*//** + The GPIO_set_outputs() function is used to set the state of the GPIO ports + configured as outputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param value + The value parameter specifies the state of the GPIO ports configured as + outputs. It is a bit mask of the form (GPIO_n_MASK | GPIO_m_MASK), where n + and m are numbers identifying GPIOs. + For example, (GPIO_0_MASK | GPIO_1_MASK | GPIO_2_MASK ) specifies that the + first, second, and third GPIO must be set high and all other outputs set + low. + + @return + none. + + @example + Set GPIO 0 and 8 outputs high and all other GPIO outputs low. + @code + GPIO_set_outputs( &g_gpio, GPIO_0_MASK | GPIO_8_MASK ); + @endcode + + @example + Set GPIO 2 and 4 outputs low without affecting the other GPIO outputs. + @code + uint32_t gpio_outputs; + gpio_outputs = GPIO_get_outputs( &g_gpio ); + gpio_outputs &= ~( GPIO_2_MASK | GPIO_4_MASK ); + GPIO_set_outputs( &g_gpio, gpio_outputs ); + @endcode + + @see GPIO_get_outputs() + */ +void GPIO_set_outputs +( + gpio_instance_t * this_gpio, + uint32_t value +); + +/*-------------------------------------------------------------------------*//** + The GPIO_set_output() function is used to set the state of a single GPIO port + configured as an output. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter specifies the GPIO port that has its output set by a + call to this function. + + @param value + The value parameter specifies the desired state for the GPIO output. A value + of 0 sets the output low, and a value of 1 sets the port high. + + @return + none. + */ +void GPIO_set_output +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint8_t value +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_inputs() function is used to read the state of all GPIOs + configured as inputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @return + This function returns a 32-bit unsigned integer, where each bit represents + the state of an input. The least significant bit represents the state of + GPIO 0, and the most significant bit represents the state of GPIO 31. + */ +uint32_t GPIO_get_inputs +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_outputs() function is used to read the current state of all + GPIO outputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @return + This function returns a 32-bit unsigned integer where each bit represents + the state of an output. The least significant bit represents the state + of GPIO 0, and the most significant bit represents the state of GPIO 31. + */ +uint32_t GPIO_get_outputs +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_drive_inout() function is used to set the output state of a + GPIO configured as INOUT. An INOUT GPIO is in one of three states: + - high + - low + - high impedance + + An INOUT output is typically be used where several devices drive the state of + a signal. The high and low states are equivalent to the high and low states of + a GPIO configured as an output. The high impedance state is used to prevent + the GPIO from driving the state of the output and therefore allow reading the + state of the GPIO as an input. + Note that the GPIO port you wish to use as INOUT through this function + must be configurable through software. Therefore, the GPIO ports used as INOUT + must not have a fixed configuration selected as part of the hardware flow. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO for which this function will + change the output state. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @param inout_state + The inout_state parameter specifies the state of the I/O identified by the + first parameter. Possible states are: + - GPIO_DRIVE_HIGH, + - GPIO_DRIVE_LOW, + - GPIO_HIGH_Z (high impedance) + + @return + none. + + @example + The call to GPIO_drive_inout() below will set the GPIO 7 output to + high impedance state. + @code + GPIO_drive_inout( &g_gpio, GPIO_7, GPIO_HIGH_Z ); + @endcode + */ +void GPIO_drive_inout +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + gpio_inout_state_t inout_state +); + +/*-------------------------------------------------------------------------*//** + The GPIO_enable_irq() function is used to enable an interrupt to be + generated based on the state of the input identified as a parameter. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO input that the call to + GPIO_enable_irq() enables to generate interrupts. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + @example + The call to GPIO_enable_irq() below allows GPIO 8 to generate interrupts. + + @code + GPIO_enable_irq( &g_gpio, GPIO_8 ); + @endcode + */ +void GPIO_enable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_disable_irq() function is used to disable interrupts from being + generated based on the state of the input specified as a parameter. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO input that the call to + GPIO_disable_irq() disables from generating interrupts. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + @example + The call to GPIO_disable_irq() below prevents GPIO 8 from generating + interrupts. + @code + GPIO_disable_irq( &g_gpio, GPIO_8 ); + @endcode + */ +void GPIO_disable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_clear_irq() function is used to clear the interrupt generated by + the GPIO specified as a parameter. The GPIO_clear_irq() function must be + called as part of a GPIO interrupt service routine (ISR) in order to prevent + the same interrupt event from re-triggering a call to the GPIO ISR. + Note that interrupts may also need to be cleared in the processor's + interrupt controller. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO input for which to clear the + interrupt. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + @example + The example below demonstrates the use of the GPIO_clear_irq() function as + part of the GPIO-9 interrupt service routine. + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + GPIO_clear_irq( &g_gpio, GPIO_9 ); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +void GPIO_clear_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_irq_sources() function is used to identify the source of the + interrupt. i.e. to That is the GPIO input line, whose state change triggered + the interrupt. The GPIO_get_irq_sources() function must be called as part of + a GPIO interrupt service routine (ISR) in order to determine the interrupt + source. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @return + This function returns a 32-bit unsigned integer, where each bit represents + the pin number of a GPIO. + + @example + The example below demonstrates the use of the GPIO_get_irq_sources() + function as part of the GPIO-9 interrupt service routine. + + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + GPIO_clear_all_irq_sources(g_p_mygpio, GPIO_get_irq_sources(g_p_mygpio)); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +uint32_t GPIO_get_irq_sources +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_clear_all_irq_sources() function is used to clear all the active + interrupts generated by the GPIO specified as a parameter. The + GPIO_clear_all_irq_sources() function must be called as part of a GPIO + interrupt service routine (ISR) in order to prevent the same interrupt event + from re-triggering a call to the GPIO ISR. + Note that interrupts may also need to be cleared in the processor's + interrupt controller. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param bitmask + This bitmask parameter is a 32-bit unsigned integer where each bit + represents the GPIO pin used to clear the interrupt bit register of the + corresponding GPIO bit. The least significant bit represents the status of + GPIO 0, and the most significant bit represents the status of GPIO 31. + + @return + none. + + @example + The example below demonstrates the use of the GPIO_clear_all_irq_sources() + function as part of the GPIO-9 interrupt service routine. + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + do_interrupt_processing(); + + GPIO_clear_all_irq_sources(g_p_mygpio, GPIO_get_irq_sources(g_p_mygpio)); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +void GPIO_clear_all_irq_sources +( + gpio_instance_t * this_gpio, + uint32_t bitmask +); + +#ifdef __cplusplus +} +#endif + +#endif /* CORE_GPIO_H_ */ diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h new file mode 100644 index 0000000..41f5b7c --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h @@ -0,0 +1,45 @@ +/******************************************************************************* + * (c) Copyright 2008-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file coregpio_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreGPIO register definitions + * + */ + +#ifndef __CORE_GPIO_REGISTERS_H +#define __CORE_GPIO_REGISTERS_H 1 + +/*------------------------------------------------------------------------------ + * + */ +#define IRQ_REG_OFFSET 0x80 + +#define IRQ0_REG_OFFSET 0x80 +#define IRQ1_REG_OFFSET 0x84 +#define IRQ2_REG_OFFSET 0x88 +#define IRQ3_REG_OFFSET 0x8C + +/*------------------------------------------------------------------------------ + * + */ +#define GPIO_IN_REG_OFFSET 0x90 + +#define GPIO_IN0_REG_OFFSET 0x90 +#define GPIO_IN1_REG_OFFSET 0x94 +#define GPIO_IN2_REG_OFFSET 0x98 +#define GPIO_IN3_REG_OFFSET 0x9C + +/*------------------------------------------------------------------------------ + * + */ +#define GPIO_OUT_REG_OFFSET 0xA0 + +#define GPIO_OUT0_REG_OFFSET 0xA0 +#define GPIO_OUT1_REG_OFFSET 0xA4 +#define GPIO_OUT2_REG_OFFSET 0xA8 +#define GPIO_OUT3_REG_OFFSET 0xAC + +#endif /* __CORE_GPIO_REGISTERS_H */ diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c new file mode 100644 index 0000000..1fd3dd6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c @@ -0,0 +1,1495 @@ +/******************************************************************************* + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * CoreI2C software driver implementation. + * + */ + +#include "core_smbus_regs.h" +#include "core_i2c.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * I2C transaction direction. + */ +#define WRITE_DIR 0u +#define READ_DIR 1u + +/* -- TRANSACTIONS TYPES -- */ +#define NO_TRANSACTION 0u +#define MASTER_WRITE_TRANSACTION 1u +#define MASTER_READ_TRANSACTION 2u +#define MASTER_RANDOM_READ_TRANSACTION 3u +#define WRITE_SLAVE_TRANSACTION 4u +#define READ_SLAVE_TRANSACTION 5u + +/* -- SMBUS H/W STATES -- */ +/* -- MASTER STATES -- */ +#define ST_BUS_ERROR 0x00u /* Bus error during MST or selected slave modes */ +#define ST_I2C_IDLE 0xF8u /* No activity and no interrupt either... */ +#define ST_START 0x08u /* start condition sent */ +#define ST_RESTART 0x10u /* repeated start */ +#define ST_SLAW_ACK 0x18u /* SLA+W sent, ack received */ +#define ST_SLAW_NACK 0x20u /* SLA+W sent, nack received */ +#define ST_TX_DATA_ACK 0x28u /* Data sent, ACK'ed */ +#define ST_TX_DATA_NACK 0x30u /* Data sent, NACK'ed */ +#define ST_LOST_ARB 0x38u /* Master lost arbitration */ +#define ST_SLAR_ACK 0x40u /* SLA+R sent, ACK'ed */ +#define ST_SLAR_NACK 0x48u /* SLA+R sent, NACK'ed */ +#define ST_RX_DATA_ACK 0x50u /* Data received, ACK sent */ +#define ST_RX_DATA_NACK 0x58u /* Data received, NACK sent */ +#define ST_RESET_ACTIVATED 0xD0u /* Master reset is activated */ +#define ST_STOP_TRANSMIT 0xE0u /* Stop has been transmitted */ + +/* -- SLAVE STATES -- */ +#define ST_SLAVE_SLAW 0x60u /* SLA+W received */ +#define ST_SLAVE_SLAR_ACK 0xA8u /* SLA+R received, ACK returned */ +#define ST_SLV_LA 0x68u /* Slave lost arbitration */ +#define ST_GCA 0x70u /* GCA received */ +#define ST_GCA_LA 0x78u /* GCA lost arbitration */ +#define ST_RDATA 0x80u /* Data received */ +#define ST_SLA_NACK 0x88u /* Slave addressed, NACK returned */ +#define ST_GCA_ACK 0x90u /* Previously addresses with GCA, data ACKed */ +#define ST_GCA_NACK 0x98u /* GCA addressed, NACK returned */ +#define ST_RSTOP 0xA0u /* Stop received */ +#define ST_SLARW_LA 0xB0u /* Arbitration lost */ +#define ST_RACK 0xB8u /* Byte sent, ACK received */ +#define ST_SLAVE_RNACK 0xC0u /* Byte sent, NACK received */ +#define ST_FINAL 0xC8u /* Final byte sent, ACK received */ +#define ST_SLV_RST 0xD8u /* Slave reset state */ + + +/* I2C Channel base offset */ +#define CHANNEL_BASE_SHIFT 5u +#define CHANNEL_MASK 0x1E0u + +/* + * Maximum address offset length in slave write-read transactions. + * A maximum of two bytes will be interpreted as address offset within the slave + * tx buffer. + */ +#define MAX_OFFSET_LENGTH 2u + +/*------------------------------------------------------------------------------ + * I2C interrupts control functions implemented "i2c_interrupt.c". + * the implementation of these functions depend on the underlying hardware + * design and how the CoreI2C interrupt line is connected to the system's + * interrupt controller. + */ +void I2C_enable_irq( i2c_instance_t * this_i2c ); +void I2C_disable_irq( i2c_instance_t * this_i2c ); +static void enable_slave_if_required(i2c_instance_t * this_i2c); + +/*------------------------------------------------------------------------------ + * I2C_init() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_init +( + i2c_instance_t * this_i2c, + addr_t base_address, + uint8_t ser_address, + i2c_clock_divider_t ser_clock_speed +) +{ + psr_t saved_psr; + uint_fast16_t clock_speed = (uint_fast16_t)ser_clock_speed; + + /* + * We need to disable ints while doing this as there is no guarantee we + * have not been called already and the ISR is active. + */ + saved_psr = HAL_disable_interrupts(); + + /* + * Initialize all items of the this_i2c data structure to zero. This + * initializes all state variables to their init value. It relies on + * the fact that NO_TRANSACTION, I2C_SUCCESS and I2C_RELEASE_BUS all + * have an actual value of zero. + */ + memset(this_i2c, 0, sizeof(i2c_instance_t)); + + /* + * Set base address of I2C hardware used by this instance. + */ + this_i2c->base_address = base_address; + + /* + * Update Serial address of the device + */ + this_i2c->ser_address = ((uint_fast8_t)ser_address << 1u); + + /* + * Configure hardware. + */ + HAL_set_8bit_reg_field(this_i2c->base_address, ENS1, 0x00); /* Reset I2C hardware. */ + HAL_set_8bit_reg_field(this_i2c->base_address, ENS1, 0x01); /* set enable bit */ + HAL_set_8bit_reg_field(this_i2c->base_address, CR2, ( (clock_speed >> 2) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c->base_address, CR1, ( (clock_speed >> 1) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c->base_address, CR0, ( clock_speed & 0x01) ); + + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS, this_i2c->ser_address); + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, this_i2c->ser_address); + + /* + * Finally safe to enable interrupts. + */ + HAL_restore_interrupts( saved_psr ); +} +/*------------------------------------------------------------------------------ + * I2C_channel_init() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_channel_init +( + i2c_instance_t * this_i2c_channel, + i2c_instance_t * this_i2c, + i2c_channel_number_t channel_number, + i2c_clock_divider_t ser_clock_speed +) +{ + psr_t saved_psr; + uint_fast16_t clock_speed = (uint_fast16_t)ser_clock_speed; + + HAL_ASSERT(channel_number < I2C_MAX_CHANNELS); + HAL_ASSERT(I2C_CHANNEL_0 != channel_number); + + /* + * Cannot allow channel 0 in this function as we will trash the hardware + * base address and slave address. + */ + if ((channel_number < I2C_MAX_CHANNELS) && + (I2C_CHANNEL_0 != channel_number)) + { + /* + * We need to disable ints while doing this as the hardware should already + * be active at this stage. + */ + saved_psr = HAL_disable_interrupts(); + + /* + * Initialize channel data. + */ + memset(this_i2c_channel, 0, sizeof(i2c_instance_t)); + + this_i2c_channel->base_address = + ((this_i2c->base_address) & ~((addr_t)CHANNEL_MASK)) + | (((addr_t)channel_number) << CHANNEL_BASE_SHIFT); + + this_i2c_channel->ser_address = this_i2c->ser_address; + + HAL_set_8bit_reg_field(this_i2c_channel->base_address, ENS1, 0x00); /* Reset I2C channel hardware. */ + HAL_set_8bit_reg_field(this_i2c_channel->base_address, ENS1, 0x01); /* set enable bit */ + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR2, ( (clock_speed >> 2) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR1, ( (clock_speed >> 1) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR0, ( clock_speed & 0x01) ); + /* + * Finally safe to enable interrupts. + */ + HAL_restore_interrupts( saved_psr ); + } +} + +/*------------------------------------------------------------------------------ + * I2C_write() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_write +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * write_buffer, + uint16_t write_size, + uint8_t options +) +{ + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + saved_psr = HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_WRITE_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_WRITE_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + this_i2c->dir = WRITE_DIR; + this_i2c->master_tx_buffer = write_buffer; + this_i2c->master_tx_size = write_size; + this_i2c->master_tx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_read() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +) +{ + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + saved_psr = HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_READ_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_READ_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + + this_i2c->dir = READ_DIR; + + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_write_read() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_write_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * addr_offset, + uint16_t offset_size, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +) +{ + HAL_ASSERT(offset_size > 0u); + HAL_ASSERT(addr_offset != (uint8_t *)0); + HAL_ASSERT(read_size > 0u); + HAL_ASSERT(read_buffer != (uint8_t *)0); + + this_i2c->master_status = I2C_FAILED; + + if((read_size > 0u) && (offset_size > 0u)) + { + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + saved_psr = HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_RANDOM_READ_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_RANDOM_READ_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + + this_i2c->dir = WRITE_DIR; + + this_i2c->master_tx_buffer = addr_offset; + this_i2c->master_tx_size = offset_size; + this_i2c->master_tx_idx = 0u; + + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + + HAL_restore_interrupts( saved_psr ); + } +} + +/*------------------------------------------------------------------------------ + * I2C_get_status() + * See "core_i2c.h" for details of how to use this function. + */ +i2c_status_t I2C_get_status +( + i2c_instance_t * this_i2c +) +{ + i2c_status_t i2c_status ; + + i2c_status = this_i2c->master_status ; + + return i2c_status; +} + +/*------------------------------------------------------------------------------ + * I2C_wait_complete() + * See "core_i2c.h" for details of how to use this function. + */ +i2c_status_t I2C_wait_complete +( + i2c_instance_t * this_i2c, + uint32_t timeout_ms +) +{ + i2c_status_t i2c_status; + psr_t saved_psr; + /* + * Because we have no idea of what CPU we are supposed to be running on + * we need to guard this write to the timeout value to avoid ISR/user code + * interaction issues. Checking the status below should be fine as only a + * single byte should change in that. + */ + saved_psr = HAL_disable_interrupts(); + this_i2c->master_timeout_ms = timeout_ms; + HAL_restore_interrupts( saved_psr ); + + /* Run the loop until state returns I2C_FAILED or I2C_SUCESS*/ + do { + i2c_status = this_i2c->master_status; + } while(I2C_IN_PROGRESS == i2c_status); + return i2c_status; +} + +/*------------------------------------------------------------------------------ + * I2C_system_tick() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_system_tick +( + i2c_instance_t * this_i2c, + uint32_t ms_since_last_tick +) +{ + if(this_i2c->master_timeout_ms != I2C_NO_TIMEOUT) + { + if(this_i2c->master_timeout_ms > ms_since_last_tick) + { + this_i2c->master_timeout_ms -= ms_since_last_tick; + } + else + { + psr_t saved_psr; + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + /* + * Mark current transaction as having timed out. + */ + this_i2c->master_status = I2C_TIMED_OUT; + this_i2c->transaction = NO_TRANSACTION; + this_i2c->is_transaction_pending = 0; + + HAL_restore_interrupts( saved_psr ); + + /* + * Make sure we do not incorrectly signal a timeout for subsequent + * transactions. + */ + this_i2c->master_timeout_ms = I2C_NO_TIMEOUT; + } + } +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_tx_buffer() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_tx_buffer +( + i2c_instance_t * this_i2c, + const uint8_t * tx_buffer, + uint16_t tx_size +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + this_i2c->slave_tx_buffer = tx_buffer; + this_i2c->slave_tx_size = tx_size; + this_i2c->slave_tx_idx = 0u; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_rx_buffer() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_rx_buffer +( + i2c_instance_t * this_i2c, + uint8_t * rx_buffer, + uint16_t rx_size +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + this_i2c->slave_rx_buffer = rx_buffer; + this_i2c->slave_rx_size = rx_size; + this_i2c->slave_rx_idx = 0u; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_mem_offset_length() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_mem_offset_length +( + i2c_instance_t * this_i2c, + uint8_t offset_length +) +{ + HAL_ASSERT(offset_length <= MAX_OFFSET_LENGTH); + + /* + * Single byte update, should be interrupt safe + */ + if(offset_length > MAX_OFFSET_LENGTH) + { + this_i2c->slave_mem_offset_length = MAX_OFFSET_LENGTH; + } + else + { + this_i2c->slave_mem_offset_length = offset_length; + } +} + +/*------------------------------------------------------------------------------ + * I2C_register_write_handler() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_register_write_handler +( + i2c_instance_t * this_i2c, + i2c_slave_wr_handler_t handler +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + this_i2c->slave_write_handler = handler; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_enable_slave() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_enable_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register and slave mode flag without the I2C ISR interrupting + * us. + */ + saved_psr = HAL_disable_interrupts(); + + /* Set the Assert Acknowledge bit. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + /* Enable slave mode */ + this_i2c->is_slave_enabled = 1u; + + HAL_restore_interrupts( saved_psr ); + + /* Enable I2C IRQ*/ + I2C_enable_irq( this_i2c ); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_slave() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_disable_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + /* Reset the assert acknowledge bit. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + + /* Disable slave mode with IRQ blocked to make whole change atomic */ + this_i2c->is_slave_enabled = 0u; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * + */ +static void enable_slave_if_required +( + i2c_instance_t * this_i2c +) +{ + /* + * This function is only called from within the ISR and so does not need + * guarding on the register access. + */ + if( 0 != this_i2c->is_slave_enabled ) + { + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x01u ); + } +} +/*------------------------------------------------------------------------------ + * I2C_set_slave_second_addr() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_slave_second_addr +( + i2c_instance_t * this_i2c, + uint8_t second_slave_addr +) +{ + uint8_t second_slave_address; + + /* + This function does not support CoreI2C hardware configured with a fixed + second slave address. The current implementation of the ADDR1[0] register + bit makes it difficult for the driver to support both programmable and + fixed second slave address, so we choose to support programmable only. + With the programmable configuration, ADDR1[0] and ADDR0[0] both control + enable/disable of GCA recognition, as an effective OR of the 2 bit fields. + Therefore we set ADDR1[0] to 0 here, so that only ADDR0[0] controls GCA. + */ + second_slave_address = (uint8_t)((second_slave_addr << 1u) & (~SLAVE1_EN_MASK)); + + /* + * Single byte register write, should be interrupt safe + */ + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, second_slave_address); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_slave_second_addr() + * See "i2c.h" for details of how to use this function. + */ +void I2C_disable_slave_second_addr +( + i2c_instance_t * this_i2c +) +{ + /* + We are disabling the second slave address by setting the value of the 2nd + slave address to the primary slave address. The reason for using this method + of disabling 2nd slave address is that ADDRESS1[0] has different meaning + depending on hardware configuration. Its use would likely interfere with + the intended GCA setting. + */ + /* + * Single byte register write, should be interrupt safe + */ + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, this_i2c->ser_address); +} + +/*------------------------------------------------------------------------------ + * i2C_set_gca() + * See "i2c.h" for details of how to use this function. + */ + +void I2C_set_gca +( + i2c_instance_t * this_i2c +) +{ + /* + * This read modify write access should be interrupt safe as the address + * register is not written to in the ISR. + */ + /* accept GC addressing. */ + HAL_set_8bit_reg_field(this_i2c->base_address, GC, 0x01u); +} + +/*------------------------------------------------------------------------------ + * I2C_clear_gca() + * See "i2c.h" for details of how to use this function. + */ +void I2C_clear_gca +( + i2c_instance_t * this_i2c +) +{ + /* + * This read modify write access should be interrupt safe as the address + * register is not written to in the ISR. + */ + /* Clear GC addressing. */ + HAL_set_8bit_reg_field(this_i2c->base_address, GC, 0x00u); +} + +/*------------------------------------------------------------------------------ + * I2C_isr() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_isr +( + i2c_instance_t * this_i2c +) +{ + volatile uint8_t status; + uint8_t data; + uint8_t hold_bus; + uint8_t clear_irq = 1u; + + status = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + + switch( status ) + { + /************** MASTER TRANSMITTER / RECEIVER *******************/ + + case ST_START: /* start has been xmt'd */ + case ST_RESTART: /* repeated start has been xmt'd */ + HAL_set_8bit_reg_field( this_i2c->base_address, STA, 0x00u); + HAL_set_8bit_reg( this_i2c->base_address, DATA, this_i2c->target_addr); /* write call address */ + HAL_set_8bit_reg_field( this_i2c->base_address, DIR, this_i2c->dir); /* set direction bit */ + if(this_i2c->dir == WRITE_DIR) + { + this_i2c->master_tx_idx = 0u; + } + else + { + this_i2c->master_rx_idx = 0u; + } + + /* + * Clear the pending transaction. This condition will be true if the slave + * has acquired the bus to carry out pending master transaction which + * it had received during its slave transmission or reception mode. + */ + if(this_i2c->is_transaction_pending) + { + this_i2c->is_transaction_pending = 0u; + } + + /* + * Make sure to update proper transaction after master START + * or RESTART + */ + if(this_i2c->transaction != this_i2c->pending_transaction) + { + this_i2c->transaction = this_i2c->pending_transaction; + } + break; + + case ST_LOST_ARB: + /* Set start bit. Let's keep trying! Don't give up! */ + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + break; + + case ST_STOP_TRANSMIT: + /* Stop has been transmitted. Do nothing */ + break; + + /******************* MASTER TRANSMITTER *************************/ + case ST_SLAW_NACK: + /* SLA+W has been transmitted; not ACK has been received - let's stop. */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_FAILED; + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + case ST_SLAW_ACK: + case ST_TX_DATA_ACK: + /* data byte has been xmt'd with ACK, time to send stop bit or repeated start. */ + if (this_i2c->master_tx_idx < this_i2c->master_tx_size) + { + HAL_set_8bit_reg(this_i2c->base_address, DATA, (uint_fast8_t)this_i2c->master_tx_buffer[this_i2c->master_tx_idx++]); + } + else if ( this_i2c->transaction == MASTER_RANDOM_READ_TRANSACTION ) + { + /* We are finished sending the address offset part of a random read transaction. + * It is is time to send a restart in order to change direction. */ + this_i2c->dir = READ_DIR; + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + else /* done sending. let's stop */ + { + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + hold_bus = this_i2c->options & I2C_HOLD_BUS; + + /* Store the information of current I2C bus status in the bus_status*/ + this_i2c->bus_status = hold_bus; + if ( hold_bus == 0u ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); /*xmt stop condition */ + enable_slave_if_required(this_i2c); + } + else + { + I2C_disable_irq( this_i2c ); + clear_irq = 0u; + } + this_i2c->master_status = I2C_SUCCESS; + } + break; + + case ST_TX_DATA_NACK: + /* data byte SENT, ACK to be received + * In fact, this means we've received a NACK (This may not be + * obvious, but if we've rec'd an ACK then we would be in state + * 0x28!) hence, let's send a stop bit + */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u);/* xmt stop condition */ + this_i2c->master_status = I2C_FAILED; + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + /********************* MASTER (or slave?) RECEIVER *************************/ + + /* STATUS codes 08H, 10H, 38H are all covered in MTX mode */ + case ST_SLAR_ACK: /* SLA+R tx'ed. */ + /* Let's make sure we ACK the first data byte received (set AA bit in CTRL) unless + * the next byte is the last byte of the read transaction. + */ + if(this_i2c->master_rx_size > 1u) + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + } + else if(1u == this_i2c->master_rx_size) + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + else /* this_i2c->master_rx_size == 0u */ + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_SUCCESS; + this_i2c->transaction = NO_TRANSACTION; + } + break; + + case ST_SLAR_NACK: /* SLA+R tx'ed; let's release the bus (send a stop condition) */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_FAILED; + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + case ST_RX_DATA_ACK: /* Data byte received, ACK returned */ + /* First, get the data */ + this_i2c->master_rx_buffer[this_i2c->master_rx_idx++] = HAL_get_8bit_reg(this_i2c->base_address, DATA); + if( this_i2c->master_rx_idx >= (this_i2c->master_rx_size - 1u)) + { + /* If we're at the second last byte, let's set AA to 0 so + * we return a NACK at the last byte. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + break; + + case ST_RX_DATA_NACK: /* Data byte received, NACK returned */ + /* Get the data, then send a stop condition */ + this_i2c->master_rx_buffer[this_i2c->master_rx_idx] = HAL_get_8bit_reg(this_i2c->base_address, DATA); + + hold_bus = this_i2c->options & I2C_HOLD_BUS; + + /* Store the information of current I2C bus status in the bus_status*/ + this_i2c->bus_status = hold_bus; + if ( hold_bus == 0u ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); /*xmt stop condition */ + + /* Bus is released, now we can start listening to bus, if it is slave */ + enable_slave_if_required(this_i2c); + } + else + { + I2C_disable_irq( this_i2c ); + clear_irq = 0u; + } + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + this_i2c->master_status = I2C_SUCCESS; + break; + + /******************** SLAVE RECEIVER **************************/ + case ST_GCA_NACK: /* NACK after, GCA addressing */ + case ST_SLA_NACK: /* Re-enable AA (assert ack) bit for future transmissions */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + this_i2c->transaction = NO_TRANSACTION; + this_i2c->slave_status = I2C_SUCCESS; + + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + break; + + case ST_GCA_LA: /* Arbitr. lost (GCA rec'd) */ + case ST_SLV_LA: /* Arbitr. lost (SLA rec'd) */ + /* + * We lost arbitration and either the GCE or our address was the + * one received so pend the master operation we were starting. + */ + this_i2c->is_transaction_pending = 1u; + /* Fall through to normal ST processing as we are now in slave mode */ + + case ST_GCA: /* General call address received, ACK returned */ + case ST_SLAVE_SLAW: /* SLA+W received, ACK returned */ + this_i2c->transaction = WRITE_SLAVE_TRANSACTION; + this_i2c->slave_rx_idx = 0u; + this_i2c->random_read_addr = 0u; + /* + * If Start Bit is set clear it, but store that information since it is because of + * pending transaction + */ + if(HAL_get_8bit_reg_field(this_i2c->base_address, STA)) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + this_i2c->is_transaction_pending = 1u; + } + this_i2c->slave_status = I2C_IN_PROGRESS; +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + /* Fall through to put address as first byte in payload buffer */ +#else + /* Only break from this case if the slave address must NOT be included at the + * beginning of the received write data. */ + break; +#endif + case ST_GCA_ACK: /* DATA received; ACK sent after GCA */ + case ST_RDATA: /* DATA received; must clear DATA register */ + if((this_i2c->slave_rx_buffer != (uint8_t *)0) + && (this_i2c->slave_rx_idx < this_i2c->slave_rx_size)) + { + data = HAL_get_8bit_reg(this_i2c->base_address, DATA); + this_i2c->slave_rx_buffer[this_i2c->slave_rx_idx++] = data; + +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + if((ST_RDATA == status) || (ST_GCA_ACK == status)) + { + /* Ignore the slave address byte in the random read address + computation in the case where INCLUDE_SLA_IN_RX_PAYLOAD + is defined. */ +#endif + this_i2c->random_read_addr = (this_i2c->random_read_addr << 8) + data; +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + } +#endif + } + + if(this_i2c->slave_rx_idx >= this_i2c->slave_rx_size) + { + /* Rx buffer is full. NACK next received byte. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + break; + + case ST_RSTOP: + /* STOP or repeated START occurred. */ + /* We cannot be sure if the transaction has actually completed as + * this hardware state reports that either a STOP or repeated START + * condition has occurred. We assume that this is a repeated START + * if the transaction was a write from the master to this point.*/ + if ( this_i2c->transaction == WRITE_SLAVE_TRANSACTION ) + { + if ( this_i2c->slave_rx_idx == this_i2c->slave_mem_offset_length ) + { + this_i2c->slave_tx_idx = this_i2c->random_read_addr; + } + /* Call the slave's write transaction handler if it exists. */ + if ( this_i2c->slave_write_handler != 0u ) + { + i2c_slave_handler_ret_t h_ret; + h_ret = this_i2c->slave_write_handler( this_i2c, this_i2c->slave_rx_buffer, (uint16_t)this_i2c->slave_rx_idx ); + if ( I2C_REENABLE_SLAVE_RX == h_ret ) + { + /* There is a small risk that the write handler could + * call I2C_disable_slave() but return + * I2C_REENABLE_SLAVE_RX in error so we only enable + * ACKs if still in slave mode. */ + enable_slave_if_required(this_i2c); + } + else + { + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x0u ); + /* Clear slave mode flag as well otherwise in mixed + * master/slave applications, the AA bit will get set by + * subsequent master operations. */ + this_i2c->is_slave_enabled = 0u; + } + } + else + { + /* Re-enable address acknowledge in case we were ready to nack the next received byte. */ + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x01u ); + } + } + else /* A stop or repeated start outside a write/read operation */ + { + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * See if we need to re-enable acknowledgement as some error conditions, such + * as a master prematurely ending a transfer, can see us get here with AA set + * to 0 which will disable slave operation if we are not careful. + */ + enable_slave_if_required(this_i2c); + } + + /* Mark any previous master write transaction as complete. */ + this_i2c->slave_status = I2C_SUCCESS; + + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + + break; + + case ST_SLV_RST: /* SMBUS ONLY: timeout state. must clear interrupt */ + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction. + */ + this_i2c->transaction = NO_TRANSACTION; + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * Clear status to I2C_FAILED only if there was an operation in progress. + */ + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->slave_status = I2C_FAILED; + } + + enable_slave_if_required(this_i2c); /* Make sure AA is set correctly */ + + break; + + /****************** SLAVE TRANSMITTER **************************/ + case ST_SLAVE_SLAR_ACK: /* SLA+R received, ACK returned */ + case ST_SLARW_LA: /* Arbitration lost, and: */ + case ST_RACK: /* Data tx'ed, ACK received */ + if ( status == ST_SLAVE_SLAR_ACK ) + { + this_i2c->transaction = READ_SLAVE_TRANSACTION; + this_i2c->random_read_addr = 0u; + this_i2c->slave_status = I2C_IN_PROGRESS; + /* If Start Bit is set clear it, but store that information since it is because of + * pending transaction + */ + if(HAL_get_8bit_reg_field(this_i2c->base_address, STA)) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + this_i2c->is_transaction_pending = 1u; + } + } + if (this_i2c->slave_tx_idx >= this_i2c->slave_tx_size) + { + /* Ensure 0xFF is returned to the master when the slave specifies + * an empty transmit buffer. */ + HAL_set_8bit_reg(this_i2c->base_address, DATA, 0xFFu); + } + else + { + /* Load the data the data byte to be sent to the master. */ + HAL_set_8bit_reg(this_i2c->base_address, DATA, (uint_fast8_t)this_i2c->slave_tx_buffer[this_i2c->slave_tx_idx++]); + } + /* Determine if this is the last data byte to send to the master. */ + if (this_i2c->slave_tx_idx >= this_i2c->slave_tx_size) /* last byte? */ + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + /* Next read transaction will result in slave's transmit buffer + * being sent from the first byte. */ + this_i2c->slave_tx_idx = 0u; + } + break; + + case ST_SLAVE_RNACK: /* Data byte has been transmitted; not-ACK has been received. */ + case ST_FINAL: /* Last Data byte tx'ed, ACK received */ + /* We assume that the transaction will be stopped by the master. + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. */ + this_i2c->slave_tx_idx = 0u; + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + /* Mark previous state as complete */ + this_i2c->slave_status = I2C_SUCCESS; + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + + break; + + /* Master Reset has been activated Wait 35 ms for interrupt to be set, + * clear interrupt and proceed to 0xF8 state. */ + case ST_RESET_ACTIVATED: + case ST_BUS_ERROR: /* Bus error during MST or selected slave modes */ + default: + /* Some undefined state has encountered. Clear Start bit to make + * sure, next good transaction happen */ + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction. + */ + this_i2c->transaction = NO_TRANSACTION; + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * Clear statuses to I2C_FAILED only if there was an operation in progress. + */ + if(I2C_IN_PROGRESS == this_i2c->master_status) + { + this_i2c->master_status = I2C_FAILED; + } + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->slave_status = I2C_FAILED; + } + + break; + } + + if ( clear_irq ) + { + /* clear interrupt. */ + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + /* Read the status register to ensure the last I2C registers write took place + * in a system built around a bus making use of posted writes. */ + status = HAL_get_8bit_reg( this_i2c->base_address, STATUS); +} + +/*------------------------------------------------------------------------------ + * I2C_smbus_init() + * See "i2c.h" for details of how to use this function. + */ + +/* + * SMBSUS_NO = 1 + * SMBALERT_NO = 1 + * SMBus enable = 1 + */ +#define INIT_AND_ENABLE_SMBUS 0x54u +void I2C_smbus_init +( + i2c_instance_t * this_i2c +) +{ + /* + * Single byte register write, should be interrupt safe + */ + /* Enable SMBUS */ + HAL_set_8bit_reg(this_i2c->base_address, SMBUS, INIT_AND_ENABLE_SMBUS); +} + +/*------------------------------------------------------------------------------ + * I2C_enable_smbus_irq() + * See "i2c.h" for details of how to use this function. + */ +void I2C_enable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + if ( irq_type & I2C_SMBALERT_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_IE, 0x01u); + } + if ( irq_type & I2C_SMBSUS_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_IE, 0x01u); + } + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_smbus_irq() + * See "i2c.h" for details of how to use this function. + */ +void I2C_disable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + if ( irq_type & I2C_SMBALERT_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_IE, 0x00u); + } + if (irq_type & I2C_SMBSUS_IRQ ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_IE, 0x00u); + } + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_suspend_smbus_slave() + * See "i2c.h" for details of how to use this function. + */ +void I2C_suspend_smbus_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_NO_CONTROL, 0x00u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_resume_smbus_slave() + * See "i2c.h" for details of how to use this function. + */ +void I2C_resume_smbus_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_NO_CONTROL, 0x01u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_reset_smbus() + * See "i2c.h" for details of how to use this function. + */ +void I2C_reset_smbus +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + HAL_set_8bit_reg_field(this_i2c->base_address, SMBUS_MST_RESET, 0x01u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_smbus_alert() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_smbus_alert +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_NO_CONTROL, 0x00u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_clear_smbus_alert() + * See "i2c.h" for details of how to use this function. + */ +void I2C_clear_smbus_alert +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_NO_CONTROL, 0x01u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_get_irq_status() + * See "i2c.h" for details of how to use this function. + */ +uint8_t I2C_get_irq_status +( + i2c_instance_t * this_i2c +) +{ + uint8_t status ; + uint8_t irq_type = I2C_NO_IRQ ; + + status = HAL_get_8bit_reg(this_i2c->base_address, SMBUS); + + if( status & (uint8_t)SMBALERT_NI_STATUS_MASK ) + { + irq_type |= I2C_SMBALERT_IRQ ; + } + + if( status & (uint8_t)SMBSUS_NI_STATUS_MASK ) + { + irq_type |= I2C_SMBSUS_IRQ ; + } + + status = HAL_get_8bit_reg(this_i2c->base_address, CONTROL); + + if( status & (uint8_t)SI_MASK ) + { + irq_type |= I2C_INTR_IRQ ; + } + return(irq_type); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_addr2() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_user_data +( + i2c_instance_t * this_i2c, + void * p_user_data +) +{ + this_i2c->p_user_data = p_user_data ; +} + +/*------------------------------------------------------------------------------ + * I2C_get_user_data() + * See "i2c.h" for details of how to use this function. + */ +void * I2C_get_user_data +( + i2c_instance_t * this_i2c +) +{ + return( this_i2c->p_user_data); +} + +#ifdef __cplusplus +} +#endif + diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h new file mode 100644 index 0000000..3891ce0 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h @@ -0,0 +1,2306 @@ +/***************************************************************************//** + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * CoreI2C software driver Application Programming Interface. + * This file contains defines and function declarations allowing to interface + * with the CoreI2C software driver. + * + */ +/*=========================================================================*//** + @mainpage CoreI2C Bare Metal Driver. + The CoreI2C bare metal software driver supports I2C master and slave + operations. + + ============================================================================== + Introduction + ============================================================================== + The CoreI2C driver provides a set of functions for controlling the Microchip + CoreI2C hardware IP. The driver supports up to 16 separate I2C channels per + CoreI2C instance, with common slave address settings shared between channels + on a device. + + Optional features of the CoreI2C allow it to operate with I2C based protocols + such as System Management Bus (SMBus), Power Management Bus (PMBus), and + Intelligent Platform Management Interface (IPMI). This driver provides support + for these features when enabled in the CoreI2C IP. + + The major features provided by CoreI2C driver: + - Provides support to configuring the I2C channels of each CoreI2C peripheral device. + - I2C master operations. + - I2C slave operations. + - SMBus related operations. + + This driver is used as part of a bare metal system where no operating + system is available. The driver gets adapted as a part of an operating system, + but the implementation of the adaptation layer between the driver and the operating + system's driver model is outside the scope of this driver. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + Your application software should configure the CoreI2C driver through + calls to the I2C_init() function for each CoreI2C instance in the + hardware design. The configuration parameters include the CoreI2C hardware + instance base address and other runtime parameters, such as the I2C serial + clock frequency and the I2C device address. + + Once channel 0 of a CoreI2C peripheral has been initialized by I2C_init(), + any additional channels present should be configured by calling + I2C_channel_init() for each of the remaining channels. + + Apart from the CoreI2C hardware instance base address, no CoreI2C hardware configuration + parameters are used by the driver. Hence, no additional configuration files are required + to use the driver. + + -------------------------------- + Interrupt Control + -------------------------------- + The CoreI2C driver has to enable and disable the generation of interrupts by + CoreI2C at various times when it is operating. This enabling and disabling of + interrupts must be done through the system’s interrupt controller. For that + reason, the method of controlling the CoreI2C interrupt is system specific + and it is necessary to customize the I2C_enable_irq() and I2C_disable_irq() + functions. These functions are available in the i2c_interrupt.c file. + The default implementation calls HAL_ASSERT(0) to indicate to the application + developer that a suitable implementations for these functions must be provided. + + The implementation of the I2C_enable_irq() function should permit interrupts + generated by a CoreI2C instance to interrupt the processor. The implementation + of the I2C_disable_irq() function should prevent interrupts generated by a + CoreI2C instance from interrupting the processor. See the provided example + projects for a working implementation of these functions. + + The I2C_register_write_handler() function registers a write handler + function with the CoreI2C driver that calls on completion of an I2C write + transaction by the CoreI2C slave. It is your responsibility to create and + register the implementation of this handler function that processes or + trigger the processing of the received data. + + The SMBSUS and SMBALERT interrupts are related to the SMBus interface and are + enabled and disabled through I2C_enable_smbus_irq() and + I2C_disable_smbus_irq() respectively. It is your responsibility to create + interrupt handler functions in your application to get the desired response + for the SMBus interrupts. + + Note: You must include the path to any application header files that are + included in the i2c_interrupt.c file, as an include path in your + project's compiler settings. The details of how to do this will depend + on your development software. + + -------------------------------- + SMBus Logic Options + -------------------------------- + SMBus related APIs does not have any effect if the "Generate SMBus Logic" + is not enabled in the CoreI2C hardware configuration. Following are API's + that does not give the desired results if SMBus Logic is disabled. + + - I2C_smbus_init() + - I2C_reset_smbus() + - I2C_enable_smbus_irq() + - I2C_disable_smbus_irq() + - I2C_suspend_smbus_slave() + - I2C_resume_smbus_slave() + - I2C_set_smsbus_alert() + - I2C_clear_smsbus_alert() + - I2C_get_irq_status() + + -------------------------------- + Fixed Baud Rate Values + -------------------------------- + The serial clock frequency parameter passed to the I2C_init() and + I2C_channel_init() functions may not have any effect if fixed values were + selected for Baud rate in the hardware configuration of CoreI2C. When fixed + values are selected for these baud rates, the driver cannot overwrite + the fixed values. + + ----------------------------------- + Fixed Slave Address Options Values + ----------------------------------- + The primary slave address parameter passed to the I2C_init() function and + secondary address value passed to the I2C_set_slave_second_addr() function, + may not have the desired effect if fixed values were selected for the slave 0 + address and slave 1 address respectively. Proper operation of this version of + the driver requires the slave addresses to be programmable. + + ============================================================================== + Theory of Operation + ============================================================================== + The CoreI2C software driver is designed to allow the control of multiple + instances of CoreI2C with one or more I2C channels. Each channel in an + instance of CoreI2C in the hardware design is associated with a single + instance of the i2c_instance_t structure in the software. You must allocate + memory for one unique i2c_instance_t structure instance for each channel of + each CoreI2C hardware instance. The contents of these data structures are + initialised by calling I2C_init() and if necessary I2C_channel_init(). + A pointer to the structure is passed to the subsequent driver functions in order + to identify the CoreI2C hardware instance and channel to perform the + requested operation. + + Note: Do not attempt to directly manipulate the contents of i2c_instance_t + structures. These structures are only intended to be modified by the driver + functions. + + The CoreI2C driver functions are grouped into the following categories: + - Initialization and configuration functions + - Interrupt control + - I2C slave addressing functions + - I2C master operations functions to handle write, read, and write-read + transactions + - I2C slave operations functions to handle write, read, and write-read + transactions + - Mixed master-slave operations + - SMBus interface configuration and control + + -------------------------------- + Initialization and Configuration + -------------------------------- + The CoreI2C device is first initialized by calling the I2C_init() + function. Since each CoreI2C peripheral supports up to 16 channels, an + additional function, I2C_channel_init(), is required to initialize the + remaining channels with their own data structures. + + I2C_init() function initializes channel 0 of a CoreI2C and the i2c_instance_t + for channel 0 acts as the basis for further channel initialization as the + hardware base address and I2C serial address are same across all the channels. + Ensure to call I2C_init() function before calling any other I2C driver function + calls. The I2C_init() call for each CoreI2C takes the I2C serial address assigned + to the I2C and the serial clock divider to generate its I2C clock as configuration + parameters. + + I2C_channel_init() function takes as input parameters a pointer to the CoreI2C + i2c_instance_t which has been initialized by calling the I2C_init() and a pointer + to a separate i2c_instance_t which represents this new channel. Another input + parameter which is required by this function is serial clock divider which generates + its I2C clock. + + -------------------------------- + Interrupt Control + -------------------------------- + The CoreI2C driver is interrupt driven and it uses each channels INT + interrupt to drive the state machine which is at the heart of the driver. + The application is responsible for providing the link between the interrupt + generating hardware and the CoreI2C interrupt handler and must ensure that + the I2C_isr() function is called with the correct i2c_instance_t structure + pointer for the CoreI2C channel initiating the interrupt. + + The driver enables and disables the generation of INT interrupts by CoreI2C + at various times when it is operating through the user supplied + I2C_enable_irq() and I2C_disable_irq() functions. + + The I2C_register_write_handler() function is used to register a write + handler function with the CoreI2C driver which is called on completion + of an I2C write transaction by the CoreI2C slave. It is the user + applications responsibility to create and register the implementation of + this handler function that processes or triggers the processing of the + received data. + + The other two interrupt sources in the CoreI2C are related to SMBus + operation and are enabled and disabled through I2C_enable_smbus_irq() and + I2C_disable_smbus_irq() respectively. Due to the application specific + nature of the response to SMBus interrupts, you must design interrupt + handler functions in the application to get the desired behaviour for + SMBus related interrupts. + + If enabled, the SMBA_INT signal from the CoreI2C is asserted if an + SMBALERT condition is signalled on the SMBALERT_NI input for the channel. + + If enabled, the SMBS_INT signal from the CoreI2C is asserted if an + SMBSUSPEND condition is signalled on the SMBSUS_NI input for the channel. + + ## I2C Slave Addressing Functions + A CoreI2C peripheral responds to the following three slave addresses: + - Slave address 0 - This is the primary slave address that accesses + a CoreI2C channel when it acts as a slave in + I2C transactions. You must configure the primary slave + address using I2C_init(). + + - Slave address 1 - This is the secondary slave address which might be + required in certain application specific scenarios. + The secondary slave address is configured by + I2C_set_slave_second_addr() and is disabled by + I2C_disable_slave_second_addr(). + + - General call address - A CoreI2C slave can be configured to respond to + a broadcast command by a master transmitting the + general call address of 0x00. Use the I2C_set_gca() + function to enable the slave to respond to the general + call address. If the CoreI2C slave is not required to + respond to the general call address, disable this + address by calling I2C_clear_gca(). + + Note: All channels on a CoreI2C instance share the same slave address logic. + This means that they cannot have separate slave addresses and rely on + the separate physical I2C bus connections to distinguish them. + + -------------------------------- + Transaction Types + -------------------------------- + The I2C driver is designed to handle three types of I2C transaction: + - Write transactions + - Read transactions + - Write-read transactions + + ## Write Transaction + The master I2C device initiates a write transaction by sending a START bit + as soon as the bus becomes free. The START bit is followed by the 7-bit + serial address of the target slave device followed by the read/write bit + indicating the direction of the transaction. The slave acknowledges the + receipt of it's address with an acknowledge bit. The master sends data one + byte at a time to the slave, which must acknowledge the receipt of each byte + for the next byte to be sent. The master sends a STOP bit to complete the + transaction. The slave can abort the transaction by replying with a + non-acknowledge bit instead of an acknowledge bit. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ## Read Transaction + The master I2C device initiates a read transaction by sending a START bit + as soon as the bus becomes free. The START bit is followed by the 7-bit + serial address of the target slave device followed by the read/write bit + indicating the direction of the transaction. The slave acknowledges the + receipt of it's slave address with an acknowledge bit. The slave sends + data one byte at a time to the master, which must acknowledge the receipt of + each byte for the next byte to be sent. The master sends a non-acknowledge + bit following the last byte it wishes to read followed by a STOP bit. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ## Write-Read Transaction + The write-read transaction is a combination of a write transaction + immediately followed by a read transaction. There is no STOP bit in between + the write and read phases of a write-read transaction. A repeated START + bit is sent between the write and read phases. + + Whilst the write handler is being executed, the slave holds the clock line + low to stretch the clock until the response is ready. + + The write-read transaction is typically used to send a command or offset + in the write transaction specifying the logical data to be transferred + during the read phase. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ## Master Operations + The application can use the I2C_write(), I2C_read(), and I2C_write_read() + functions to initiate an I2C bus transaction. The application can then wait + for the transaction to complete using the I2C_wait_complete() function + or poll the status of the I2C transaction using the I2C_get_status() + function until it returns a value different from I2C_IN_PROGRESS. The + I2C_system_tick() function is used to set a time base for the + I2C_wait_complete() function's time out delay. + + ## Slave Operations + To configure the I2C driver to operate as an I2C slave requires the use + of the following functions: + - I2C_set_slave_tx_buffer() + - I2C_set_slave_rx_buffer() + - I2C_set_slave_mem_offset_length() + - I2C_register_write_handler() + - I2C_enable_slave() + + Use of all functions is not required if the slave I2C does not need to support + all types of I2C read transactions. The subsequent sections list the functions + that must be used to support each transaction type. + + ## Responding to Read Transactions + The following functions are used to configure the CoreI2C driver to + respond to I2C read transactions: + • I2C_set_slave_tx_buffer() + • I2C_enable_slave() + + The I2C_set_slave_tx_buffer() function specifies the data buffer that + is transmitted when the I2C slave is the target of an I2C read + transaction. It is then up to the application to manage the content of + that buffer to control the data that will be transmitted to the I2C + master as a result of the read transaction. + + The I2C_enable_slave() function enables the I2C hardware instance + to respond to the I2C transactions. It must be called after the I2C driver + has been configured to respond to the required transaction types. + + ## Responding to Write Transactions + The following functions are used to configure the I2C driver to respond + to I2C write transactions: + • I2C_set_slave_rx_buffer() + • I2C_register_write_handler() + • I2C_enable_slave() + + The I2C_set_slave_rx_buffer() function specifies the data buffer that + stored the data received by the I2C slave when it targets an I2C write + transaction. + + The I2C_register_write_handler() function specifies the handler function + that must be called on completion of the I2C write transaction. It is this + handler function that processes or triggers the processing of the received + data. + + The I2C_enable_slave() function enables the I2C hardware instance + to respond to I2C transactions. It must be called after the I2C driver + has been configured to respond to the required transaction types. + + ## Responding to Write-Read Transactions + The following functions are used to configure the CoreI2C driver to + respond to write-read transactions: + - I2C_set_slave_mem_offset_length() + - I2C_set_slave_tx_buffer() + - I2C_set_slave_rx_buffer() + - I2C_register_write_handler() + - I2C_enable_slave() + + The I2C_set_slave_mem_offset_length() function specifies the number of + bytes expected by the I2C slave during the write phase of the write-read + transaction. + + The I2C_set_slave_tx_buffer() function specifies the data that is + transmitted to the I2C master during the read phase of the write-read + transaction. The value received by the I2C slave during the write phase of + the transaction will be used as an index into the transmit buffer + specified by this function. It decides which part of the transmit buffer + will be transmitted to the I2C master as part of the read phase of the + write-read transaction. + + The I2C_set_slave_rx_buffer() function specifies the data buffer that + stores the data received by the I2C slave during the write phase of + the write-read transaction. This buffer must be large enough to accommodate + the number of bytes specified through the I2C_set_slave_mem_offset_length() + function. + + The I2C_register_write_handler() function can optionally be used to + specify a handler function that is called on completion of the write phase + of the I2C write-read transaction. If a handler function is registered, it + is responsible for processing the received data in the slave receive + buffer and populating the slave transmit buffer with the data that will be + transmitted to the I2C master as part of the read phase of the write-read + transaction. + + The I2C_enable_slave() function enables the CoreI2C hardware instance to + respond to the I2C transactions. It must be called after configuring the + CoreI2C driver to respond to the required transaction types. + + ## Mixed Master-Slave Operations + The CoreI2C device supports mixed master and slave operations. If the + CoreI2C slave has a transaction in progress and your application attempts to + begin a master mode transaction, the CoreI2C driver queues the master mode + transaction until the bus is released and the CoreI2C can switch to master + mode and acquire the bus. The CoreI2C master then starts the previously + queued master transaction. + + ## SMBus Control + The CoreI2C driver enables the CoreI2C peripheral’s SMBus functionality + using the I2C_smbus_init() function. + + The I2C_suspend_smbus_slave() function is used with a master mode CoreI2C + to force slave devices on the SMBus to enter their Power-Down/Suspend mode. + The I2C_resume_smbus_slave() function is used to end the suspend operation + on the SMBus. + + The I2C_reset_smbus() function is used with a master mode CoreI2C to force + all devices on the SMBus to reset their SMBUs interface. + + The I2C_set_smsbus_alert() function is used by a slave mode CoreI2C to + force communication with the SMBus master. Once communications with the + master is initiated, the I2C_clear_smsbus_alert() function clears the alert + condition. + + The I2C_enable_smbus_irq() and I2C_disable_smbus_irq() functions are used to + enable and disable the SMBSUS and SMBALERT SMBus interrupts. + + *//*=========================================================================*/ + +#ifndef CORE_I2C_H_ +#define CORE_I2C_H_ + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#include "hal_assert.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + I2C_RELEASE_BUS + ======================================= + The I2C_RELEASE_BUS constant is used to specify the options parameter to + functions I2C_read(), I2C_write() and I2C_write_read() to indicate + that a STOP bit must be generated at the end of the I2C transaction to release + the bus. + */ +#define I2C_RELEASE_BUS 0x00u + +/*-------------------------------------------------------------------------*//** + I2C_HOLD_BUS + ======================================= + The I2C_HOLD_BUS constant specify the options parameter to functions I2C_read(), + I2C_write(), and I2C_write_read() to indicate that a STOP bit must not be + generated at the end of the I2C transaction in order to retain the bus ownership. + This causes the next transaction to begin with a repeated START bit and no STOP + bit between the transactions. + */ +#define I2C_HOLD_BUS 0x01u + +/*-------------------------------------------------------------------------*//** + Interrupt Identifier Number + ======================================= + The following constants specify the interrupt identifier number which is + solely used by the driver API. This has nothing to do with hardware interrupt + line. I2C_INTR_IRQ is the primary interrupt signal which drives the state machine + of the CoreI2C driver. The I2C_SMBALERT_IRQ and I2C_SMBSUS_IRQ are used by + SMBus interrupt enable and disable functions. These IRQ numbers are also used + by I2C_get_irq_status(). + + | Constant | Description | + |--------------------|--------------------------------------------------------| + | I2C_NO_IRQ | No interrupt | + | I2C_SMBALERT_IRQ | Used by SMBus interrupt enable functions | + | I2C_SMBSUS_IRQ | Used by SMBus interrupt disable functions | + | I2C_INTR_IRQ | Primary interrupt signal which drives the state machine| + + */ +#define I2C_NO_IRQ 0x00u +#define I2C_SMBALERT_IRQ 0x01u +#define I2C_SMBSUS_IRQ 0x02u +#define I2C_INTR_IRQ 0x04u + +/*-------------------------------------------------------------------------*//** + I2C_NO_TIMEOUT + ======================================= + The I2C_wait_complete() function uses I2C_NO_TIMEOUT constant as a parameter + to indicate that the wait for completion of the transaction should not time out. + */ +#define I2C_NO_TIMEOUT 0u + +/***************************************************************************//** + The i2c_channel_number_t type is used to specify the channel number of a + CoreI2C instance. + */ +typedef enum i2c_channel_number { + I2C_CHANNEL_0 = 0u, + I2C_CHANNEL_1, + I2C_CHANNEL_2, + I2C_CHANNEL_3, + I2C_CHANNEL_4, + I2C_CHANNEL_5, + I2C_CHANNEL_6, + I2C_CHANNEL_7, + I2C_CHANNEL_8, + I2C_CHANNEL_9, + I2C_CHANNEL_10, + I2C_CHANNEL_11, + I2C_CHANNEL_12, + I2C_CHANNEL_13, + I2C_CHANNEL_14, + I2C_CHANNEL_15, + I2C_MAX_CHANNELS = 16u +} i2c_channel_number_t; + +/***************************************************************************//** + The i2c_clock_divider_t type specifies the divider to be applied + to the I2C PCLK or BCLK signal in order to generate the I2C clock. + The I2C_BCLK_DIV_8 value selects a clock frequency based on division of BCLK, + all other values select a clock frequency based on division of PCLK. + */ +typedef enum i2c_clock_divider { + I2C_PCLK_DIV_256 = 0u, + I2C_PCLK_DIV_224, + I2C_PCLK_DIV_192, + I2C_PCLK_DIV_160, + I2C_PCLK_DIV_960, + I2C_PCLK_DIV_120, + I2C_PCLK_DIV_60, + I2C_BCLK_DIV_8 +} i2c_clock_divider_t; + +/***************************************************************************//** + The i2c_status_t type is used to report the status of I2C transactions. + */ +typedef enum i2c_status +{ + I2C_SUCCESS = 0u, + I2C_IN_PROGRESS, + I2C_FAILED, + I2C_TIMED_OUT +} i2c_status_t; + +/***************************************************************************//** + The i2c_slave_handler_ret_t type is used by slave write handler functions + to indicate whether or not the received data buffer should be released. + */ +typedef enum i2c_slave_handler_ret { + I2C_REENABLE_SLAVE_RX = 0u, + I2C_PAUSE_SLAVE_RX = 1u +} i2c_slave_handler_ret_t; + +/***************************************************************************//** + This structure identifies various CoreI2C hardware instances in the system + and the I2C channels within them. The application software should declare + one instance of this structure for each channel of each instance of CoreI2C + in your system. I2C_init() and I2C_channel_init() functions initialize this + structure depending on whether it is channel 0 or one of the additional + channels, respectively. A pointer to an initialized instance of the + structure should be passed as the first parameter to the CoreI2C driver + functions, to identify which CoreI2C hardware instance and channel should + perform the requested operation. + + The contents of this data structure should not be modified or used outside of + the CoreI2C driver. Software using the CoreI2C driver should only need to + create one single instance of this data structure for each channel of each + CoreI2C hardware instance in the system then pass a pointer to these data + structures with each call to the CoreI2C driver in order to identify which + CoreI2C hardware instance to use. + */ +typedef struct i2c_instance i2c_instance_t ; +/***************************************************************************//* + Slave write handler functions prototype +/***************************************************************************//** + This defines the function prototype that must be followed by I2C slave write + handler functions. These functions are registered with the CoreI2C driver + through the I2C_register_write_handler() function. + + Declaring and Implementing Slave Write Handler Functions: + + Slave write handler functions should follow the following prototype: + @code + i2c_slave_handler_ret_t write_handler + ( + i2c_instance_t *instance, uint8_t * data, uint16_t size + ); + @endcode + + The instance parameter is a pointer to the i2c_instance_t for which this + slave write handler has been declared. + + The data parameter is a pointer to a buffer (received data buffer) holding + the data written to the I2C slave. + + Define the INCLUDE_SLA_IN_RX_PAYLOAD macro for the driver to insert the + actual address used to access the slave as the first byte in the buffer. + This allows the applications to tailor their response based on the actual + address used to access the slave (primary address, secondary address, or GCA). + + The size parameter is the number of bytes held in the received data buffer. + Handler functions must return one of the following values: + - I2C_REENABLE_SLAVE_RX + - I2C_PAUSE_SLAVE_RX + + If the handler function returns I2C_REENABLE_SLAVE_RX, the driver releases + the received data buffer and allows further I2C write transactions to the + I2C slave. + + If the handler function returns I2C_PAUSE_SLAVE_RX, the I2C slave responds + to subsequent write requests with a non-acknowledge bit (NACK), until the + received data buffer content gets processed by some other part of the + software application. + + Call the I2C_enable_slave() after returning the I2C_PAUSE_SLAVE_RX to release + the received data buffer in order to store the data received by the subsequent + I2C write transactions. + */ +typedef i2c_slave_handler_ret_t (*i2c_slave_wr_handler_t)(i2c_instance_t *instance, uint8_t *, uint16_t ); + +/***************************************************************************//** + This structure is used to identify the various CoreI2C hardware instances in + your system and the I2C channels within them. Your application software should + declare one instance of this structure for each channel of each instance of + CoreI2C in your system. The functions I2C_init() and I2C_channel_init() + initialize this structure depending on whether it is channel 0 or one of the + additional channels respectively. A pointer to an initialized instance of the + structure should be passed as the first parameter to the CoreI2C driver + functions, to identify which CoreI2C hardware instance and channel should + perform the requested operation. + + The contents of this data structure should not be modified or used outside of + the CoreI2C driver. Software using the CoreI2C driver should only need to + create one single instance of this data structure for each channel of each + CoreI2C hardware instance in the system then pass a pointer to these data + structures with each call to the CoreI2C driver in order to identify the + CoreI2C hardware instance it wishes to use. + */ +struct i2c_instance +{ + addr_t base_address; + uint_fast8_t ser_address; + + /* Transmit related info:*/ + uint_fast8_t target_addr; + + /* Current transaction type (WRITE, READ, RANDOM_READ)*/ + uint8_t transaction; + + uint_fast16_t random_read_addr; + + uint8_t options; + + /* Master TX INFO: */ + const uint8_t * master_tx_buffer; + uint_fast16_t master_tx_size; + uint_fast16_t master_tx_idx; + uint_fast8_t dir; + + /* Master RX INFO: */ + uint8_t * master_rx_buffer; + uint_fast16_t master_rx_size; + uint_fast16_t master_rx_idx; + + /* Master Status */ + volatile i2c_status_t master_status; + uint32_t master_timeout_ms; + + /* Slave TX INFO */ + const uint8_t * slave_tx_buffer; + uint_fast16_t slave_tx_size; + uint_fast16_t slave_tx_idx; + + /* Slave RX INFO */ + uint8_t * slave_rx_buffer; + uint_fast16_t slave_rx_size; + uint_fast16_t slave_rx_idx; + /* Slave Status */ + volatile i2c_status_t slave_status; + + /* Slave data: */ + uint_fast8_t slave_mem_offset_length; + i2c_slave_wr_handler_t slave_write_handler; + uint8_t is_slave_enabled; + + /* user specific data */ + void *p_user_data ; + + /* I2C bus status */ + uint8_t bus_status; + + /* Is transaction pending flag */ + uint8_t is_transaction_pending; + + /* I2C Pending transaction */ + uint8_t pending_transaction; +}; + +/*------------------------Public Function-------------------------------------*/ + +/***************************************************************************//** + The I2C_init() function configures channel 0 of a CoreI2C instance. It sets + the base hardware address which is used to locate the CoreI2C instance + in memory and also used internally by I2C_channel_init() to calculate the + register addresses for any additional channels. The slave serial address set + is shared by all channels on a CoreI2C instance. + + If only one channel is configured in a CoreI2C, the address of the + i2c_instance_t used in I2C_Init() will also be used in subsequent calls to the + CoreI2C driver functions. If more than one channel is configured in the + CoreI2C, I2C_channel_init() will be called after I2C_init(), which initializes + the i2c_instance_t data structure for a specific channel. + + @param this_i2c + Pointer to the i2c_instance_t data structure that holds all the data + related to channel 0 of the CoreI2C instance is initialized. A pointer + to this structure is used in all subsequent calls to the CoreI2C driver + functions which operates on channel 0 of this CoreI2C instance. + + @param base_address + Base address in the processor's memory map of the registers of the CoreI2C + instance being initialized. + + @param ser_address + This parameter sets the primary I2C serial address (SLAVE0 address) for the + CoreI2C to initialize. It is the principal I2C bus address to which the + CoreI2C instance will respond. CoreI2C can operate in master mode or slave + mode and the serial address is significant only in the case of I2C slave + mode. In master mode, CoreI2C does not require a serial address and the + value of this parameter is not important. If you do not intend to use the + CoreI2C device in slave mode, then provide any dummy slave address value + to this parameter. However, in systems where the CoreI2C is expected to + switch from master mode to slave mode, it is advisable to initialize the + CoreI2C device with a valid serial slave address. Call the I2C_init() + function whenever it is required to change the primary slave address as + there is no separate function to set the primary slave address of the + I2C device. The serial address initialized through this function is + basically the primary slave address or slave address0. + I2C_set_slave_second_addr() is used to set the secondary slave address + or slave address 1. + Note : ser_address parameter does not have any affect if fixed slave + address is enabled in CoreI2C hardware design. CoreI2C will + be always addressed with the hardware configured fixed slave + address. + Note : ser_address parameter will not have any affect if the CoreI2C + instance is only used in master mode. + + @param ser_clock_speed + This parameter sets the I2C serial clock frequency. It selects the divider + that generates the serial clock from the APB PCLK or from the BCLK. + It can be one of the following: + - I2C_PCLK_DIV_256 + - I2C_PCLK_DIV_224 + - I2C_PCLK_DIV_192 + - I2C_PCLK_DIV_160 + - I2C_PCLK_DIV_960 + - I2C_PCLK_DIV_120 + - I2C_PCLK_DIV_60 + - I2C_BCLK_DIV_8 + Note: serial_clock_speed value does not have any affect if the fixed baud + rate is enabled in CoreI2C hardware instance configuration dialogue + window. The fixed baud rate divider value overrides the value passed + as parameter in this function. + Note: serial_clock_speed value is not critical for devices that only operate + as slaves and can be set to any of the above values. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void system_init( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + } + @endcode + */ +void I2C_init +( + i2c_instance_t * this_i2c, + addr_t base_address, + uint8_t ser_address, + i2c_clock_divider_t ser_clock_speed +); + +/***************************************************************************//** + The I2C_channel_init() function initializes and configures hardware and data + structures of one of the additional channels of a CoreI2C instance. + I2C_init() must be called before calling this function to set the CoreI2C + instance hardware base address and I2C serial address. I2C_channel_init() also + initializes I2C serial clock divider to set the serial clock baud rate. + The pointer to data structure i2c_instance_t used for a particular channel + is used as an input parameter to subsequent CoreI2C driver functions + which operate on this channel. + + @param this_i2c_channel + Pointer to the i2c_instance_t data structure that holds all data related to + the CoreI2C channel gets initialized. A pointer to the same data structure + is used in subsequent calls to the CoreI2C driver functions in order to + identify the CoreI2C channel instance that should perform the operation + implemented by the called driver function. + + @param this_i2c + This is a pointer to an i2c_instance_t structure, previously initialized by + I2C_init(). It holds information regarding the hardware base address and + I2C serial address for the CoreI2C containing the channel to be + initialized. This information is required by I2C_channel_init() to + initialize the i2c_instance_t structure pointed by this_i2c_channel as + all channels in a CoreI2C instance share the same base address and serial + address. It is very important that the i2c_instance_t structure pointed + by this_i2c must be previously initialized by calling I2C_init(). + + @param channel_number + This parameter of type i2c_channel_number_t identifies the channel to be + initialized. + + @param ser_clock_speed + This parameter sets the I2C serial clock frequency. It selects the divider + that is used to generate the serial clock from the APB PCLK or from + the BCLK. It can be one of the following: + - I2C_PCLK_DIV_256 + - I2C_PCLK_DIV_224 + - I2C_PCLK_DIV_192 + - I2C_PCLK_DIV_160 + - I2C_PCLK_DIV_960 + - I2C_PCLK_DIV_120 + - I2C_PCLK_DIV_60 + - I2C_BCLK_DIV_8 + Note: serial_clock_speed value does not have any affect if the fixed baud + rate is enabled in CoreI2C hardware instance configuration dialogue + window. The fixed baud rate divider value will supersede the value + passed as parameter in this function. + Note: ser_clock_speed value is not critical for devices that only operate + as slaves and can be set to any of the above values. + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_SER_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + i2c_instance_t g_i2c_channel_1_inst; + + uint8_t tx_buffer[DATA_LENGTH]; + uint8_t write_length = DATA_LENGTH; + + void system_init( void ) + { + uint8_t target_slave_addr = 0x12; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize CoreI2C channel 1 with different clock speed + I2C_channel_init( &g_i2c_channel_1_inst, &g_i2c_inst, I2C_CHANNEL_1, + I2C_PCLK_DIV_224 ); + + // Write data to Channel 1 of CoreI2C instance. + I2C_write( &g_i2c_channel_1_inst, target_slave_addr, tx_buffer, + write_length, I2C_RELEASE_BUS ); + } + @endcode + +*/ +void I2C_channel_init +( + i2c_instance_t * this_i2c_channel, + i2c_instance_t * this_i2c, + i2c_channel_number_t channel_number, + i2c_clock_divider_t ser_clock_speed +); + +/***************************************************************************//** + The I2C_isr function is the CoreI2C interrupt service routine. User must + call this function from their application level CoreI2C interrupt handler + function. This function runs the I2C state machine based on previous and + current status. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREINTERRUPT_BASE_ADDR 0xCC000000u + #define COREI2C_SER_ADDR 0x10u + #define I2C_IRQ_NB 2u + + i2c_instance_t g_i2c_inst; + + void core_i2c_isr( void ) + { + I2C_isr( &g_i2c_inst ); + } + + void main( void ) + { + CIC_init( COREINTERRUPT_BASE_ADDR ); + NVIC_init(); + CIC_set_irq_handler( I2C_IRQ_NB, core_i2c_isr ); + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + NVIC_enable_interrupt( NVIC_IRQ_0 ); + } + @endcode + */ +void I2C_isr +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//* + #Master Specific Functions + + The following functions are only used within an I2C master's implementation. +/***************************************************************************//** + This function initiates an I2C master write transaction. This function returns + immediately after initiating the transaction. The content of the write buffer + passed as parameter should not be modified until the write transaction + completes. It also means that the memory allocated for the write buffer should + not be freed or should not go out of scope before the write completes. You can + check for the write transaction completion using the I2C_status() function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr + This parameter specifies the serial address of the target I2C device. + + @param write_buffer + This parameter is a pointer to a buffer holding the data to be written to + the target I2C device. Do not to release the memory used by this buffer + before the write transaction completes. For example, it is not appropriate + to return from a function allocating this buffer as an auto array variable + before the write transaction completes as this would result in the buffer's + memory being de-allocated from the stack when the function returns. This + memory could then be subsequently reused and modified causing unexpected + data to be written to the target I2C device. + + @param write_size + Number of bytes held in the write_buffer to be written to the target I2C + device. + + @param options + The options parameter is used to indicate if the I2C bus should be released + on completion of the write transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the write transaction causing the bus to be released for other I2C + devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the write + transaction, preventing other I2C devices from initiating a bus transaction. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t tx_buffer[DATA_LENGTH]; + uint8_t write_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Write data to Channel 0 of CoreI2C instance. + I2C_write( &g_i2c_inst, target_slave_addr, tx_buffer, write_length, + I2C_RELEASE_BUS ); + + // Wait for completion and record the outcome + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_write +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * write_buffer, + uint16_t write_size, + uint8_t options +); + +/***************************************************************************//** + This function initiates an I2C master read transaction. This function returns + immediately after initiating the transaction. + The contents of the read buffer passed as parameter should not be modified + until the read transaction completes. It also means that the memory allocated + for the read buffer should not be freed or should not go out of scope before + the read completes. You can check for the read transaction completion using + the I2C_status() function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr + This parameter specifies the serial address of the target I2C device. + + @param read_buffer + This is a pointer to a buffer where the data received from the target device + gets stored. Do not to release the memory used by this buffer before the read + transaction completes. For example, it is not appropriate to return from a + function allocating this buffer as an auto array variable before the read + transaction completes as this would result in the buffer's memory being + de-allocated from the stack when the function returns. This memory could + then be subsequently reallocated resulting in the read transaction + corrupting the newly allocated memory. + + @param read_size + This parameter specifies the number of bytes to read from the target device. + This size must not exceed the size of the read_buffer buffer. + + @param options + The options parameter is used to indicate if the I2C bus should be released + on completion of the read transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the read transaction causing the bus to be released for other I2C + devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the read transaction, + preventing other I2C devices from initiating a bus transaction. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t rx_buffer[DATA_LENGTH]; + uint8_t read_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Read data from target slave Channel 0 of CoreI2C instance. + I2C_read( &g_i2c_inst, target_slave_addr, rx_buffer, read_length, + I2C_RELEASE_BUS ); + + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +); + +/***************************************************************************//** + This function initiates an I2C write-read transaction where data is first + written to the target device before issuing a restart condition and changing + the direction of the I2C transaction in order to read from the target device. + + The same warnings about buffer allocation in I2C_write() and I2C_read() + applies to this function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr + This parameter specifies the serial address of the target I2C device. + + @param addr_offset + This parameter is a pointer to the buffer containing the data that is sent + to the slave during the write phase of the write-read transaction. This + data is typically used to specify an address offset specifying to the I2C + slave device what data it must return during the read phase of the + write-read transaction. + + @param offset_size + This parameter specifies the number of offset bytes to be written during the + write phase of the write-read transaction. This is typically the size of the + buffer pointed by the addr_offset parameter. + + @param read_buffer + This parameter is a pointer to the buffer where the data read from the I2C + slave will be stored. + + @param read_size + This parameter specifies the number of bytes to read from the target I2C + slave device. This size must not exceed the size of the buffer pointed by + the read_buffer parameter. + + @param options + The options parameter is used to indicate if the I2C bus should be released + on completion of the write-read transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the write-read transaction causing the bus to be released for other + I2C devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the write-read + transaction, preventing other I2C devices from initiating a bus transaction. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define TX_LENGTH 16u + #define RX_LENGTH 8u + + i2c_instance_t g_i2c_inst; + uint8_t rx_buffer[RX_LENGTH]; + uint8_t read_length = RX_LENGTH; + uint8_t tx_buffer[TX_LENGTH]; + uint8_t write_length = TX_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + I2C_write_read( &g_i2c_inst, target_slave_addr, tx_buffer, write_length, + rx_buffer, read_length, I2C_RELEASE_BUS ); + + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_write_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * addr_offset, + uint16_t offset_size, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +); + +/***************************************************************************//** + This function indicates the current state of a CoreI2C channel. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + The return value indicates the current state of a CoreI2C channel or the + outcome of the previous transaction if no transaction is in progress. + Following are the return values are: + - I2C_SUCCESS + The last I2C transaction has completed successfully. + - I2C_IN_PROGRESS + There is an I2C transaction in progress. + - I2C_FAILED + The last I2C transaction failed. + - I2C_TIMED_OUT + The request has failed to complete in the allotted time. + + @example + @code + i2c_instance_t g_i2c_inst; + + while( I2C_IN_PROGRESS == I2C_get_status( &g_i2c_inst ) ) + { + // Do something useful while waiting for I2C operation to complete + our_i2c_busy_task(); + } + + if( I2C_SUCCESS != I2C_get_status( &g_i2c_inst ) ) + { + // Something went wrong... + our_i2c_error_recovery( &g_i2c_inst ); + } + @endcode + */ +i2c_status_t I2C_get_status +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + This function waits for the current I2C transaction to complete. The return + value indicates whether the last I2C transaction was successful or not. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + @param timeout_ms + The timeout_ms parameter specifies the delay within which the current I2C + transaction should complete. The time out delay is given in + milliseconds. I2C_wait_complete() will return I2C_TIMED_OUT if the current + transaction has not completed after the time out delay has expired. This + parameter can be set to I2C_NO_TIMEOUT to indicate that I2C_wait_complete() + must not time out. + + @return + The return value indicates the outcome of the last I2C transaction. It can + be one of the following: + - I2C_SUCCESS + The last I2C transaction has completed successfully. + - I2C_FAILED + The last I2C transaction failed. + - I2C_TIMED_OUT + The last transaction failed to complete within the time out delay given + as second parameter. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t rx_buffer[DATA_LENGTH]; + uint8_t read_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Read data from Channel 0 of CoreI2C instance. + I2C_read( &g_i2c_inst, target_slave_addr, rx_buffer, read_length, + I2C_RELEASE_BUS ); + + // Wait for completion and record the outcome + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +i2c_status_t I2C_wait_complete +( + i2c_instance_t * this_i2c, + uint32_t timeout_ms +); + +/***************************************************************************//** + This function is used to control the expiration of the time out delay + specified as a parameter to the I2C_wait_complete() function. It must be + called from the interrupt service routine of a periodic interrupt source such + as the SysTick timer interrupt. It takes the period of the interrupt + source as its ms_since_last_tick parameter and uses it as the time base for + the I2C_wait_complete() function's time out delay. + + Note: This function does not need to be called if the I2C_wait_complete() + function is called with a timeout_ms value of I2C_NO_TIMEOUT. + + Note: If this function is not called then the I2C_wait_complete() function + will behave as if its timeout_ms was specified as I2C_NO_TIMEOUT and it + will not time out. + + Note: If this function is being called from an interrupt handler (for example, + SysTick) it is important that the calling interrupt have a lower priority + than the CoreI2C interrupt(s) to ensure any updates to the shared data are + protected. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + @param ms_since_last_tick + The ms_since_last_tick parameter specifies the number of milliseconds that + elapsed since the last call to I2C_system_tick(). This parameter would + typically be a constant specifying the interrupt rate of a timer used to + generate system ticks. + + @return None. + + @example + The following example shows how the I2C_system_tick() function. I2C_system_tick() + is called for each I2C channel from the SysTick timer interrupt service routine. + The following example shows how the SysTick is configured to generate an interrupt + in every 10 milliseconds. + @code + #define SYSTICK_INTERVAL_MS 10 + + void SysTick_Handler(void) + { + I2C_system_tick(&g_core_i2c0, SYSTICK_INTERVAL_MS); + I2C_system_tick(&g_core_i2c2, SYSTICK_INTERVAL_MS); + } + @endcode + */ +void I2C_system_tick +( + i2c_instance_t * this_i2c, + uint32_t ms_since_last_tick +); + +/***************************************************************************//* + #Slave Specific Functions + + The following functions are only used within the implementation of an I2C slave device. + +/***************************************************************************//** + This function specifies the memory buffer holding the data that will be sent + to the I2C master when this CoreI2C channel is the target of an I2C read or + write-read transaction. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param tx_buffer + This parameter is a pointer to the memory buffer holding the data to be + returned to the I2C master when this CoreI2C channel is the target of an + I2C read or write-read transaction. + + @param tx_size + Size of the transmit buffer pointed by the tx_buffer parameter. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Specify the transmit buffer containing the data that will be + // returned to the master during read and write-read transactions. + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + } + @endcode + */ +void I2C_set_slave_tx_buffer +( + i2c_instance_t * this_i2c, + const uint8_t * tx_buffer, + uint16_t tx_size +); + +/***************************************************************************//** + This function specifies the memory buffer that is used by the CoreI2C channel + to receive data when it is a slave. This buffer is the memory where data gets + stored when the CoreI2C channel is the target of an I2C master write + transaction (that is, when it is the slave). + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param rx_buffer + This parameter is a pointer to the memory buffer allocated by the caller + software to be used as a slave receive buffer. + + @param rx_size + Size of the slave receive buffer. This is the amount of memory allocated + to the buffer pointed by rx_buffer. + Note: Indirectly, this buffer size specifies the maximum I2C write + transaction length this CoreI2C channel targets. This is because + this CoreI2C channel responds to further received bytes with + a non-acknowledge bit (NACK) as soon as its receive buffer is + full. This causes the write transaction to fail. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_RX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_rx_buffer[SLAVE_RX_BUFFER_SIZE]; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Specify the buffer used to store the data written by the I2C master. + I2C_set_slave_rx_buffer( &g_i2c_inst, g_slave_rx_buffer, + sizeof(g_slave_rx_buffer) ); + } + @endcode + */ +void I2C_set_slave_rx_buffer +( + i2c_instance_t * this_i2c, + uint8_t * rx_buffer, + uint16_t rx_size +); + +/***************************************************************************//** + This function is used as part of the configuration of a CoreI2C channel to + operate as a slave supporting write-read transactions. It specifies the + number of bytes expected as part of the write phase of a write-read + transaction. The bytes received during the write phase of a write-read + transaction will be interpreted as an offset into the slave's transmit buffer. + This allows random access into the I2C slave transmit buffer from a remote + I2C master. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param offset_length + The offset_length parameter configures the number of bytes to be interpreted + by the CoreI2C slave as a memory offset value during the write phase of + write-read transactions. The maximum value for the offset_length parameter + is two. The value of offset_length has the following effect on the + interpretation of the received data. + • If offset_length is 0, the offset into the transmit buffer is fixed at 0. + • If offset_length is 1, a single byte of received data is interpreted as an + unsigned 8-bit offset value in the range 0 to 255. + • If offset_length is 2, 2 bytes of received data are interpreted as an + unsigned 16-bit offset value in the range 0 to 65535. The first byte + received in this case provides the high order bits of the offset and + the second byte provides the low order bits. + If the number of bytes received does not match the non 0 value of + offset_length, the transmit buffer offset is set to 0. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + I2C_set_slave_mem_offset_length( &g_i2c_inst, 1 ); + } + @endcode + */ +void I2C_set_slave_mem_offset_length +( + i2c_instance_t * this_i2c, + uint8_t offset_length +); + +/***************************************************************************//** + Register the function that is called to process the data written to this + CoreI2C channel when it is the slave in an I2C write transaction. + + Note: If a write handler is registered, it is called on completion of the + write phase of a write-read transaction and responsible for processing + the received data in the slave receive buffer and populating the slave + transmit buffer with the data that is transmitted to the I2C master + as part of the read phase of the write-read transaction. If a write + handler is not registered, the write data of a write-read transaction is + interpreted as an offset into the slave’s transmit buffer and handled by + the driver. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param handler + Pointer to the function that processes the I2C write request. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + // local function prototype + void slave_write_handler + ( + i2c_instance_t * this_i2c, + uint8_t * p_rx_data, + uint16_t rx_size + ); + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + I2C_set_slave_mem_offset_length( &g_i2c_inst, 1 ); + I2C_register_write_handler( &g_i2c_inst, slave_write_handler ); + } + @endcode +*/ +void I2C_register_write_handler +( + i2c_instance_t * this_i2c, + i2c_slave_wr_handler_t handler +); + +/***************************************************************************//** + This function enables slave mode operation for a CoreI2C channel. It enables + the CoreI2C slave to receive data when it is the target of an I2C read, write, + or write-read transaction. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + // Enable I2C slave + I2C_enable_slave( &g_i2c_inst ); + @endcode + */ +void I2C_enable_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + This function disables the slave mode operation for a CoreI2C channel. It stops + the CoreI2C slave that acknowledges the I2C read, write, or write-read + transactions targeted at it. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + // Disable I2C slave + I2C_disable_slave( &g_i2c_inst ); + @endcode + */ +void I2C_disable_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_slave_second_addr() function sets the secondary slave address for + a CoreI2C slave device. This is an additional slave address required in certain + applications, for example, to enable fail-safe operation in a system. As the + CoreI2C device supports 7-bit addressing, the highest value assigned to second + slave address is 127 (0x7F). + + Note: This function does not support CoreI2C hardware configured with a fixed + second slave address. The current implementation of the ADDR1[0] register + bit makes it difficult for the driver to support both programmable and + fixed second slave address, so we choose to support programmable only. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param second_slave_addr + The second_slave_addr parameter is the secondary slave address of the I2C + device. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SECOND_SLAVE_ADDR 0x20u + + i2c_instance_t g_i2c_inst; + void main( void ) + { + // Initialize the CoreI2C driver with its base address, primary I2C + // serial address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_second_addr( &g_i2c_inst, SECOND_SLAVE_ADDR ); + } + @endcode + */ +void I2C_set_slave_second_addr +( + i2c_instance_t * this_i2c, + uint8_t second_slave_addr +); + +/***************************************************************************//** + The I2C_disable_slave_second_addr() function disables the secondary slave + address of the CoreI2C slave device. + + Note: This version of the driver only supports CoreI2C hardware configured + with a programmable second slave address. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + i2c_instance_t g_i2c_inst; + I2C_disable_slave_second_addr( &g_i2c_inst); + @endcode + */ +void I2C_disable_slave_second_addr +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_gca() function is used to set the general call acknowledgement bit + of a CoreI2C slave device. This allows all channels of the CoreI2C slave + device to respond to a general call or broadcast message from an I2C master. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + i2c_instance_t g_i2c_inst; + + // Enable recognition of the General Call Address + I2C_set_gca( &g_i2c_inst ); + @endcode + */ +void I2C_set_gca +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_clear_gca() function is used to clear the general call acknowledgement + bit of a CoreI2C slave device. This will stop all channels of the I2C slave + device responding to any general call or broadcast message from the master. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + i2c_instance_t g_i2c_inst; + + // Disable recognition of the General Call Address + I2C_clear_gca( &g_i2c_inst ); + @endcode + */ + +void I2C_clear_gca +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//* + #I2C SMBUS Specific APIs + +/***************************************************************************//** + The I2C_smbus_init() function enables SMBus timeouts and status logic for a + CoreI2C channel. + + Note: This and any of the other SMBus related functionality will only have an + effect if the CoreI2C was instantiated with the Generate SMBus Logic + option checked. + + Note: If the CoreI2C was instantiated with the Generate IPMI Logic option + checked this function then enables the IPMI 3mS SCL low timeout but + none of the other SMBus functions will have any effect. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void system_init( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst); + } + @endcode + */ +void I2C_smbus_init +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_enable_smbus_irq() function is used to enable the CoreI2C channel’s + SMBSUS and SMBALERT SMBus interrupts. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param irq_type + The irq_type specify the SMBUS interrupt(s) which will be enabled. + The two possible interrupts are: + - I2C_SMBALERT_IRQ + - I2C_SMBSUS_IRQ + To enable both interrupts in one call, use I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ. + + @return + None + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both I2C_SMBALERT_IRQ & I2C_SMBSUS_IRQ interrupts + I2C_enable_smbus_irq( &g_i2c_inst, + (uint8_t)(I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ) ); + } + @endcode + */ +void I2C_enable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +); + +/***************************************************************************//** + The I2C_disable_smbus_irq() function disable the CoreI2C channel’s SMBSUS and + SMBALERT SMBus interrupts. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param irq_type + The irq_type specifies the SMBUS interrupt(s) which are disabled. + The two possible interrupts are: + • I2C_SMBALERT_IRQ + • I2C_SMBSUS_IRQ + To disable both ints in one call, use I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both SMBALERT & SMBSUS interrupts + I2C_enable_smbus_irq( &g_i2c_inst, + (uint8_t)(I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ)); + + ... + + // Disable the SMBALERT interrupt + I2C_disable_smbus_irq( &g_i2c_inst, I2C_SMBALERT_IRQ ); + } + @endcode + */ +void I2C_disable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +); + +/***************************************************************************//** + The I2C_suspend_smbus_slave() function forces any SMBUS slave devices + connected to a CoreI2C channel into Power-Down or Suspend mode by asserting + the channel's SMBSUS signal. The CoreI2C channel is the SMBus master in this + case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // suspend SMBus slaves + I2C_suspend_smbus_slave( &g_i2c_inst ); + + ... + + // Re-enable SMBus slaves + I2C_resume_smbus_slave( &g_i2c_inst ); + } + @endcode + */ +void I2C_suspend_smbus_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_resume_smbus_slave() function de-asserts the CoreI2C channel's SMBSUS + signal to take any connected slave devices out of the Suspend mode. The CoreI2C + channel is the SMBus master in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // suspend SMBus slaves + I2C_suspend_smbus_slave( &g_i2c_inst ); + + ... + + // Re-enable SMBus slaves + I2C_resume_smbus_slave( &g_i2c_inst ); + } + @endcode + */ +void I2C_resume_smbus_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_reset_smbus() function resets the CoreI2C channel's SMBus connection + by forcing SCLK low for 35 mS. The reset that automatically cleares after 35 ms + gets elapsed. The CoreI2C channel is the SMBus master in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Make sure the SMBus channel is in a known state by resetting it + I2C_reset_smbus( &g_i2c_inst ); + } + @endcode + */ +void I2C_reset_smbus +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_smbus_alert() function is used to force master communication with + an I2C slave device by asserting the CoreI2C channel's SMBALERT signal. The + CoreI2C channel is the SMBus slave in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Get the SMBus masters attention + I2C_set_smbus_alert( &g_i2c_inst ); + + ... + + // Once we are happy, drop the alert + I2C_clear_smbus_alert( &g_i2c_inst ); + } + @endcode + */ +void I2C_set_smbus_alert +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_clear_smbus_alert() function is used to de-assert the CoreI2C channel's + SMBALERT signal once a slave device gets a response from the master. The + CoreI2C channel is the SMBus slave in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Get the SMBus masters attention + I2C_set_smbus_alert( &g_i2c_inst ); + + ... + + // Once we are happy, drop the alert + I2C_clear_smbus_alert( &g_i2c_inst ); + } + @endcode + */ +void I2C_clear_smbus_alert +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_get_irq_status function returns information about which interrupts are + currently pending in a CoreI2C channel. + The interrupts supported by CoreI2C are: + • SMBUSALERT + • SMBSUS + • INTR + + The macros I2C_NO_IRQ, I2C_SMBALERT_IRQ, I2C_SMBSUS_IRQ, and I2C_INTR_IRQ are + provided to use with this function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + This function returns the status of the CoreI2C channel's interrupts as a + single byte bitmap where a bit is set to indicate a pending interrupt. + The following are the bit positions associated with each interrupt type: + Bit 0 - SMBUS_ALERT_IRQ + Bit 1 - SMBSUS_IRQ + Bit 2 - INTR_IRQ + It returns 0, if there are no pending interrupts. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + uint8_t irq_to_enable = I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ; + uint8_t pending_irq = 0u; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both I2C_SMBALERT_IRQ & I2C_SMBSUS_IRQ irq + I2C_enable_smbus_irq( &g_i2c_inst, irq_to_enable ); + + // Get I2C IRQ type + pending_irq = I2C_get_irq_status( &g_i2c_inst ); + + // Let's assume, in system, INTR and SMBALERT IRQ is pending. + // So pending_irq will return status of both the IRQs + + if( pending_irq & I2C_SMBALERT_IRQ ) + { + // if true, it means SMBALERT_IRQ is there in pending IRQ list + } + if( pending_irq & I2C_INTR_IRQ ) + { + // if true, it means I2C_INTR_IRQ is there in pending IRQ list + } + } + @endcode + */ +uint8_t I2C_get_irq_status +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_user_data() function allows the association of a block of application + specific data with a CoreI2C channel. The composition of the data block is an + application matter and the driver simply provides the means for the application + to set and retrieve the pointer. For example, this is used to provide additional + channel specific information to the slave write handler. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param p_user_data + The p_user_data parameter is a pointer to the user specific data block for + this channel. It is defined as void * as the driver does not know the actual + type of data being pointed to and simply stores the pointer for later + retrieval by the application. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + app_data_t channel_xdata; + + void main( void ) + { + app_data_t *p_xdata; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Store location of user data in instance structure + I2C_set_user_data( &g_i2c_inst, (void *)&channel_xdata ); + + ... + + // Retrieve location of user data and do some work on it + p_xdata = (app_data_t *)I2C_get_user_data( &g_i2c_inst ); + if( NULL != p_xdata ) + { + p_xdata->foo = 123; + } + } + @endcode + */ +void I2C_set_user_data +( + i2c_instance_t * this_i2c, + void * p_user_data +); + +/***************************************************************************//** + The I2C_get_user_data() function is used to allows the retrieval of the address + of a block of application specific data associated with a CoreI2C channel. + The composition of the data block is an application matter and the driver + simply provides the means for the application to set and retrieve the pointer. + For example, this is used to provide additional channel specific information + to the slave write handler. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + This function returns a pointer to the user specific data block for this + channel. It is defined as void * as the driver does not know the actual type + of data being pointed. If no user data has been registered for this channel + a NULL pointer is returned. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + app_data_t channel_xdata; + + void main( void ) + { + app_data_t *p_xdata; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Store location of user data in instance structure + I2C_set_user_data( &g_i2c_inst, (void *)&channel_xdata ); + + ... + + // Retrieve location of user data and do some work on it + p_xdata = (app_data_t *)I2C_get_user_data( &g_i2c_inst ); + if( NULL != p_xdata ) + { + p_xdata->foo = 123; + } + } + @endcode + */ +void * I2C_get_user_data +( + i2c_instance_t * this_i2c +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h new file mode 100644 index 0000000..b1d872d --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h @@ -0,0 +1,190 @@ +/******************************************************************************* + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + */ + +#ifndef __CORE_SMBUS_REGISTERS +#define __CORE_SMBUS_REGISTERS 1 + +/*------------------------------------------------------------------------------ + * CONTROL register details + */ +#define CONTROL_REG_OFFSET 0x00u + +/* + * CR0 bits. + */ +#define CR0_OFFSET 0x00u +#define CR0_MASK 0x01u +#define CR0_SHIFT 0u + +/* + * CR1 bits. + */ +#define CR1_OFFSET 0x00u +#define CR1_MASK 0x02u +#define CR1_SHIFT 1u + +/* + * AA bits. + */ +#define AA_OFFSET 0x00u +#define AA_MASK 0x04u +#define AA_SHIFT 2u + +/* + * SI bits. + */ +#define SI_OFFSET 0x00u +#define SI_MASK 0x08u +#define SI_SHIFT 3u + +/* + * STO bits. + */ +#define STO_OFFSET 0x00u +#define STO_MASK 0x10u +#define STO_SHIFT 4u + +/* + * STA bits. + */ +#define STA_OFFSET 0x00u +#define STA_MASK 0x20u +#define STA_SHIFT 5u + +/* + * ENS1 bits. + */ +#define ENS1_OFFSET 0x00u +#define ENS1_MASK 0x40u +#define ENS1_SHIFT 6u + +/* + * CR2 bits. + */ +#define CR2_OFFSET 0x00u +#define CR2_MASK 0x80u +#define CR2_SHIFT 7u + +/*------------------------------------------------------------------------------ + * STATUS register details + */ +#define STATUS_REG_OFFSET 0x04u + +/*------------------------------------------------------------------------------ + * DATA register details + */ +#define DATA_REG_OFFSET 0x08u + +/* + * TARGET_ADDR bits. + */ +#define TARGET_ADDR_OFFSET 0x08u +#define TARGET_ADDR_MASK 0xFEu +#define TARGET_ADDR_SHIFT 1u + +/* + * DIR bit. + */ +#define DIR_OFFSET 0x08u +#define DIR_MASK 0x01u +#define DIR_SHIFT 0u + + +/*------------------------------------------------------------------------------ + * ADDRESS register details + */ +#define ADDRESS_REG_OFFSET 0x0Cu + +/* + * GC bits. + */ +#define GC_OFFSET 0x0Cu +#define GC_MASK 0x01u +#define GC_SHIFT 0u + +/* + * ADR bits. + */ +#define OWN_SLAVE_ADDR_OFFSET 0x0Cu +#define OWN_SLAVE_ADDR_MASK 0xFEu +#define OWN_SLAVE_ADDR_SHIFT 1u + +/*------------------------------------------------------------------------------ + * SMBUS register details + */ +#define SMBUS_REG_OFFSET 0x10u + +/* + * SMBALERT_IE bits. + */ +#define SMBALERT_IE_OFFSET 0x10u +#define SMBALERT_IE_MASK 0x01u +#define SMBALERT_IE_SHIFT 0u + +/* + * SMBSUS_IE bits. + */ +#define SMBSUS_IE_OFFSET 0x10u +#define SMBSUS_IE_MASK 0x02u +#define SMBSUS_IE_SHIFT 1u + +/* + * SMB_IPMI_EN bits. + */ +#define SMB_IPMI_EN_OFFSET 0x10u +#define SMB_IPMI_EN_MASK 0x04u +#define SMB_IPMI_EN_SHIFT 2u + +/* + * SMBALERT_NI_STATUS bits. + */ +#define SMBALERT_NI_STATUS_OFFSET 0x10u +#define SMBALERT_NI_STATUS_MASK 0x08u +#define SMBALERT_NI_STATUS_SHIFT 3u + +/* + * SMBALERT_NO_CONTROL bits. + */ +#define SMBALERT_NO_CONTROL_OFFSET 0x10u +#define SMBALERT_NO_CONTROL_MASK 0x10u +#define SMBALERT_NO_CONTROL_SHIFT 4u + +/* + * SMBSUS_NI_STATUS bits. + */ +#define SMBSUS_NI_STATUS_OFFSET 0x10u +#define SMBSUS_NI_STATUS_MASK 0x20u +#define SMBSUS_NI_STATUS_SHIFT 5u + +/* + * SMBSUS_NO_CONTROL bits. + */ +#define SMBSUS_NO_CONTROL_OFFSET 0x10u +#define SMBSUS_NO_CONTROL_MASK 0x40u +#define SMBSUS_NO_CONTROL_SHIFT 6u + +/* + * SMBUS_MST_RESET bits. + */ +#define SMBUS_MST_RESET_OFFSET 0x10u +#define SMBUS_MST_RESET_MASK 0x80u +#define SMBUS_MST_RESET_SHIFT 7u + +/*------------------------------------------------------------------------------ + * SLAVE ADDRESS 1 register details + */ + +#define ADDRESS1_REG_OFFSET 0x1Cu + +/* + * SLAVE1_EN bit of Slave Address 1 . + */ +#define SLAVE1_EN_OFFSET 0x1Cu +#define SLAVE1_EN_MASK 0x01u +#define SLAVE1_EN_SHIFT 0u + +#endif /* __CORE_SMBUS_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c new file mode 100644 index 0000000..12e352d --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * CoreI2C driver interrupt control. + * + */ +#include "core_i2c.h" + +/*------------------------------------------------------------------------------ + * This function must be modified to enable interrupts generated from the + * CoreI2C instance identified as parameter. + */ +void I2C_enable_irq( i2c_instance_t * this_i2c ) +{ + HAL_ASSERT(0) +} + +/*------------------------------------------------------------------------------ + * This function must be modified to disable interrupts generated from the + * CoreI2C instance identified as parameter. + */ +void I2C_disable_irq( i2c_instance_t * this_i2c ) +{ + HAL_ASSERT(0) +} diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.c b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.c new file mode 100644 index 0000000..2e11750 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.c @@ -0,0 +1,1345 @@ +/***************************************************************************//** + * Copyright 2013-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * CoreSPI bare metal driver implementation for CoreSPI. + * + * This Core SPI driver provides functions for implementing SPI master or + * SPI slave operations with the CoreSPI version 4.2.xxx It is not compatible + * with CoreSPI version 3.0.xxx. + * + * @file core_spi.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreSPI software configuration + * + */ + +#include "core_spi.h" +#include "corespi_regs.h" +#include + +/******************************************************************************* + * Null parameters with appropriate type definitions + */ +#define NULL_ADDR ( ( addr_t ) 0u ) +#define NULL_INSTANCE ( ( spi_instance_t * ) 0u ) +#define NULL_BUFF ( ( uint8_t * ) 0u ) +#define NULL_FRAME_HANDLER ( ( spi_frame_rx_handler_t ) 0u ) +#define NULL_BLOCK_HANDLER ( ( spi_block_rx_handler_t ) 0u ) +#define NULL_SLAVE_TX_UPDATE_HANDLER ( ( spi_slave_frame_tx_handler_t ) 0u ) +#define NULL_SLAVE_CMD_HANDLER NULL_BLOCK_HANDLER + +#define SPI_ALL_INTS (0xFFu) /* For clearing all active interrupts */ + +/******************************************************************************* + * Possible states for different register bit fields + */ + +#define DISABLE 0u +#define ENABLE 1u + + +/******************************************************************************* + * Function return values + */ +enum { + FAILURE = 0u, + SUCCESS = 1u +}; + +/******************************************************************************* + * Local function declarations + */ +static void fill_slave_tx_fifo( spi_instance_t * this_spi ); +static void read_slave_rx_fifo( spi_instance_t * this_spi ); +static void recover_from_rx_overflow( const spi_instance_t * this_spi ); + +/******************************************************************************* + * SPI_init() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_init +( + spi_instance_t * this_spi, + addr_t base_addr, + uint16_t fifo_depth +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( NULL_ADDR != base_addr ); + HAL_ASSERT( SPI_MAX_FIFO_DEPTH >= fifo_depth ); + HAL_ASSERT( SPI_MIN_FIFO_DEPTH <= fifo_depth ); + + if( ( NULL_INSTANCE != this_spi ) && ( base_addr != NULL_ADDR ) ) + { + /* + * Initialize all transmit / receive buffers and handlers + * + * Relies on the fact that byte filling with 0x00 will equate + * to 0 for any non byte sized items too. + */ + + /* First fill struct with 0s */ + memset( this_spi, 0, sizeof(spi_instance_t) ); + + /* Configure CoreSPI instance attributes */ + this_spi->base_addr = (addr_t)base_addr; + + /* Store FIFO depth or fall back to minimum if out of range */ + if( ( SPI_MAX_FIFO_DEPTH >= fifo_depth ) && ( SPI_MIN_FIFO_DEPTH <= fifo_depth ) ) + { + this_spi->fifo_depth = fifo_depth; + } + else + { + this_spi->fifo_depth = SPI_MIN_FIFO_DEPTH; + } + /* Make sure the CoreSPI is disabled while we configure it */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Ensure all slaves are deselected */ + HAL_set_8bit_reg( this_spi->base_addr, SSEL, 0u ); + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Ensure RXAVAIL, TXRFM, SSEND and CMDINT are disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, 0u ); + /* + * Enable the CoreSPI in the reset default of master mode + * with TXUNDERRUN, RXOVFLOW and TXDONE interrupts disabled. + * The driver does not currently use interrupts in master mode. + */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL1, ENABLE | CTRL1_MASTER_MASK ); + } +} + +/***************************************************************************//** + * SPI_configure_slave_mode() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_configure_slave_mode +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Don't yet know what slave transfer mode will be used */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_NONE; + + /* Make sure the CoreSPI is disabled while we configure it */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Ensure RXAVAIL, TXRFM, SSEND and CMDINT are disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, 0u ); + /* + * Enable the CoreSPI in slave mode with TXUNDERRUN, RXOVFLOW and TXDONE + * interrupts disabled. The appropriate interrupts will be enabled later + * on when the transfer mode is configured. + */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL1, ENABLE ); + } +} + +/***************************************************************************//** + * SPI_configure_master_mode() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_configure_master_mode +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Disable the CoreSPI for a little while, while we configure the CoreSPI */ + HAL_set_8bit_reg_field(this_spi->base_addr, CTRL1_ENABLE, DISABLE); + + /* Reset slave transfer mode to unknown in case it has been set previously */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_NONE; + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Ensure RXAVAIL, TXRFM, SSEND and CMDINT are disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, 0u ); + + /* Enable the CoreSPI in master mode with TXUNDERRUN, RXOVFLOW and TXDONE interrupts disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL1, ENABLE | CTRL1_MASTER_MASK ); + } +} + +/***************************************************************************//** + * SPI_set_slave_select() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +) +{ + spi_slave_t temp = (spi_slave_t)(0x00u) ; + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( SPI_MAX_NB_OF_SLAVES > slave ); + + if( ( NULL_INSTANCE != this_spi ) && ( SPI_MAX_NB_OF_SLAVES > slave ) ) + { + /* This function is only intended to be used with an SPI master */ + if( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW ) ) + { + recover_from_rx_overflow( this_spi ); + } + /* Set the correct slave select bit */ + temp = (spi_slave_t)( HAL_get_8bit_reg( this_spi->base_addr, SSEL ) | ((uint32_t)1u << (uint32_t)slave) ); + HAL_set_8bit_reg( this_spi->base_addr, SSEL, (uint_fast8_t)temp ); + } + } +} + +/***************************************************************************//** + * SPI_clear_slave_select() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_clear_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +) +{ + spi_slave_t temp = (spi_slave_t) (0x00u) ; + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( SPI_MAX_NB_OF_SLAVES > slave ); + + if( ( NULL_INSTANCE != this_spi ) && ( SPI_MAX_NB_OF_SLAVES > slave ) ) + { + /* This function is only intended to be used with an SPI master. */ + if( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW) ) + { + recover_from_rx_overflow( this_spi ); + } + /* Clear the correct slave select bit */ + temp = (spi_slave_t)( HAL_get_8bit_reg( this_spi->base_addr, SSEL ) & ~((uint32_t)1u << (uint32_t)slave) ); + HAL_set_8bit_reg( this_spi->base_addr, SSEL, (uint_fast8_t)temp ) ; + } + } +} + +/***************************************************************************//** + * SPI_transfer_frame() + * See "core_spi.h" for details of how to use this function. + */ +uint32_t SPI_transfer_frame +( + spi_instance_t * this_spi, + uint32_t tx_bits +) +{ + volatile uint32_t rx_data = 0u; /* Ensure consistent return value if in slave mode */ + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI master. */ + if( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Flush the receive and transmit FIFOs by resetting both */ + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK); + + /* Send frame. */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, tx_bits ); + + /* Wait for frame Tx to complete. */ + while ( ENABLE != HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_DONE ) ) + { + ; + } + + /* Read received frame. */ + rx_data = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + } + } + + /* Finally, return the frame we received from the slave or 0 */ + return( rx_data ); +} + + +/***************************************************************************//** + * SPI_transfer_block() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_transfer_block +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_buffer, + uint16_t rx_byte_size +) +{ + uint32_t transfer_size = 0U; /* Total number of bytes to transfer. */ + uint16_t transfer_idx = 0U; /* Number of bytes transferred so far */ + uint16_t tx_idx = 0u; /* Number of valid data bytes sent */ + uint16_t rx_idx = 0u; /* Number of valid response bytes received */ + uint16_t transit = 0U; /* Number of bytes "in flight" to avoid FIFO errors */ + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI master. */ + if( ( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) && + /* Check for empty transfer as well */ + ( 0u != ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) ) ) + { + /* + * tansfer_size is one less than the real amount as we have to write + * the last frame separately to trigger the slave deselect in case + * the SPS option is in place. + */ + transfer_size = ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) - 1u; + /* Flush the receive and transmit FIFOs */ + HAL_set_8bit_reg(this_spi->base_addr, CMD, (uint32_t)(CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK )); + + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW) ) + { + recover_from_rx_overflow( this_spi ); + } + + /* Disable the Core SPI for a little bit, while we load the TX FIFO */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + while( ( tx_idx < transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out 0s to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + } + ++transit; + ++tx_idx; + } + + /* If room left to put last frame in before the off, then do it */ + if( ( tx_idx == transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data, not expecting any reply this time */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out last 0 to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + } + + ++transit; + ++tx_idx; + } + + /* FIFO is all loaded up so enable Core SPI to start transfer */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + + /* Perform the remainder of the transfer by sending a byte every time a byte + * has been received. This should ensure that no Rx overflow can happen in + * case of an interrupt occurring during this function. + * + * We break the transfer down into stages to minimise the processing in + * each loop as the SPI interface is very demanding at higher clock rates. + * This works well with FIFOs but might be less efficient if there is only + * a single frame buffer. + * + * First stage transfers remaining command bytes (if any). + * At this stage anything in the RX FIFO can be discarded as it is + * not part of a valid response. + */ + while( tx_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + /* Send another byte. */ + if( tx_idx == transfer_size ) /* Last frame is special... */ + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Read and discard. */ + HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now, we are writing dummy bytes to push through the response from + * the slave but we still have to keep discarding any read data that + * corresponds with one of our command bytes. + */ + while( transfer_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + if( tx_idx < transfer_size ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Read and discard. */ + HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now we are now only sending dummy data to push through the + * valid response data which we store in the response buffer. + */ + while( tx_idx < transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received byte. */ + rx_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* If we still need to send the last frame */ + while( tx_idx == transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received byte. */ + rx_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* + * Finally, we are now finished sending data and are only reading + * valid response data which we store in the response buffer. + */ + while( transfer_idx <= transfer_size ) + { + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received byte. */ + rx_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + } + } + } + } +} + +/***************************************************************************//** + * SPI_transfer_block_store_all_resp() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_transfer_block_store_all_resp +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_data_buffer, + uint16_t rx_byte_size, + uint8_t * cmd_response_buffer +) +{ + uint32_t transfer_size = 0U; /* Total number of bytes to transfer. */ + uint16_t transfer_idx = 0U; /* Number of bytes transferred so far */ + uint16_t tx_idx = 0u; /* Number of valid data bytes sent */ + uint16_t rx_idx = 0u; /* Number of valid response bytes received */ + uint16_t transit = 0U; /* Number of bytes "in flight" to avoid FIFO errors */ + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI master. */ + if( ( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) && + /* Check for empty transfer as well */ + ( 0u != ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) ) ) + { + /* + * tansfer_size is one less than the real amount as we have to write + * the last frame separately to trigger the slave deselect in case + * the SPS option is in place. + */ + transfer_size = ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) - 1u; + /* Flush the receive and transmit FIFOs */ + HAL_set_8bit_reg(this_spi->base_addr, CMD, (uint32_t)(CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK )); + + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW) ) + { + recover_from_rx_overflow( this_spi ); + } + + /* Disable the Core SPI for a little bit, while we load the TX FIFO */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + while( ( tx_idx < transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out 0s to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + } + ++transit; + ++tx_idx; + } + + /* If room left to put last frame in before the off, then do it */ + if( ( tx_idx == transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data, not expecting any reply this time */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out last 0 to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + } + + ++transit; + ++tx_idx; + } + + /* FIFO is all loaded up so enable Core SPI to start transfer */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + + /* Perform the remainder of the transfer by sending a byte every time a byte + * has been received. This should ensure that no Rx overflow can happen in + * case of an interrupt occurring during this function. + * + * We break the transfer down into stages to minimise the processing in + * each loop as the SPI interface is very demanding at higher clock rates. + * This works well with FIFOs but might be less efficient if there is only + * a single frame buffer. + * + * First stage transfers remaining command bytes (if any). + * At this stage anything in the RX FIFO can be discarded as it is + * not part of a valid response. + */ + while( tx_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + /* Send another byte. */ + if( tx_idx == transfer_size ) /* Last frame is special... */ + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received command byte. */ + cmd_response_buffer[transfer_idx] = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now, we are writing dummy bytes to push through the response from + * the slave, which we store in the command response buffer. + */ + while( transfer_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + if( tx_idx < transfer_size ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received command byte. */ + cmd_response_buffer[transfer_idx] = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now we are now only sending dummy data to push through the + * valid response data which we store in the data response buffer. + */ + while( tx_idx < transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received data byte. */ + rx_data_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* If we still need to send the last frame */ + while( tx_idx == transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received data byte. */ + rx_data_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* + * Finally, we are now finished sending data and are only reading + * valid response data which we store in the data response buffer. + */ + while( transfer_idx <= transfer_size ) + { + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received data byte. */ + rx_data_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + } + } + } + } +} +/***************************************************************************//** + * SPI_set_frame_rx_handler() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_frame_rx_handler +( + spi_instance_t * this_spi, + spi_frame_rx_handler_t rx_handler +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if(NULL_INSTANCE != this_spi) + { + /* This function is only intended to be used with an SPI slave. */ + if(DISABLE == HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER)) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Disable SSEND and CMD interrupts as we are not doing block transfers */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTSSEND, DISABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + + /* Disable block Rx handler as they are mutually exclusive. */ + this_spi->block_rx_handler = 0U; + + /* Keep a copy of the pointer to the Rx handler function. */ + this_spi->frame_rx_handler = rx_handler; + + if( SPI_SLAVE_XFER_FRAME != this_spi->slave_xfer_mode ) + { + /* + * Either just coming from init or were previously in block mode + * so no tx frame handler is set at this point in time... + * + * Don't allow TXDONE interrupts. + */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXDONE, DISABLE ); + } + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK); + + /* Enable Rx and FIFO error interrupts */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTRXOVFLOW, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXURUN, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTRXDATA, ENABLE ); + + /* Make sure correct mode is selected */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_FRAME; + + /* Finally re-enable the CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } + } +} + +/***************************************************************************//** + * SPI_set_slave_tx_frame() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_slave_tx_frame +( + spi_instance_t * this_spi, + uint32_t frame_value, + spi_slave_frame_tx_handler_t slave_tx_frame_handler +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI slave. */ + if( DISABLE == HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Disable SSEND and CMD interrupts as we are not doing block transfers */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTSSEND, DISABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + + if( SPI_SLAVE_XFER_FRAME != this_spi->slave_xfer_mode ) + { + /* + * Either just coming from init or were previously in block mode + * so no rx frame handler is set at this point in time... + * + * Don't allow RXDATA interrupts. + */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTRXDATA, DISABLE ); + } + + /* Disable slave block tx buffer as it is mutually exclusive with frame + * level handling. */ + this_spi->slave_tx_buffer = NULL_BUFF; + this_spi->slave_tx_size = 0U; + this_spi->slave_tx_idx = 0U; + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK); + + /* Assign the slave frame update handler - NULL_SLAVE_TX_UPDATE_HANDLER for none */ + this_spi->slave_tx_frame_handler = slave_tx_frame_handler; + + /* Keep a copy of the slave Tx frame value. */ + this_spi->slave_tx_frame = frame_value; + + /* Load one frame into Tx data register. */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, this_spi->slave_tx_frame ); + + /* Enable Tx Done interrupt in order to reload the slave Tx frame after each + * time it has been sent. */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXDONE, ENABLE ); + + /* Make sure correct mode is selected */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_FRAME; + + /* Ready to go so enable CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } + } +} + +/***************************************************************************//** + * SPI_set_slave_block_buffers() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_slave_block_buffers +( + spi_instance_t * this_spi, + const uint8_t * tx_buffer, + uint32_t tx_buff_size, + uint8_t * rx_buffer, + uint32_t rx_buff_size, + spi_block_rx_handler_t block_rx_handler +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI slave. */ + if( DISABLE == HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Make sure correct mode is selected */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_BLOCK; + /* + * No command handler should be setup at this stage so fake this + * to ensure 0 padding works. + */ + this_spi->cmd_done = 1u; + + /* Disable frame handlers as they are mutually exclusive with block Rx handler. */ + this_spi->frame_rx_handler = NULL_FRAME_HANDLER; + this_spi->slave_tx_frame_handler = NULL_SLAVE_TX_UPDATE_HANDLER; + + /* Keep a copy of the pointer to the block Rx handler function. */ + this_spi->block_rx_handler = block_rx_handler; + + /* Assign slave receive buffer */ + this_spi->slave_rx_buffer = rx_buffer; + this_spi->slave_rx_size = rx_buff_size; + this_spi->slave_rx_idx = 0U; + + /* Assign slave transmit buffer*/ + this_spi->slave_tx_buffer = tx_buffer; + this_spi->slave_tx_size = tx_buff_size; + this_spi->slave_tx_idx = 0U; + + /* Flush the receive and transmit FIFOs */ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Preload the transmit FIFO. */ + while( !(HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_TXFULL)) && + ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->slave_tx_buffer[this_spi->slave_tx_idx] ); + ++this_spi->slave_tx_idx; + } + /* + * Disable TXDATA interrupt as we will look after transmission in rx handling + * because we know that once we have read a frame it is safe to send another one. + */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTTXDATA, DISABLE ); + + /* Enable Rx, FIFO error and SSEND interrupts */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTRXOVFLOW, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXURUN, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTRXDATA, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTSSEND, ENABLE ); + + /* Disable command handler until it is set explicitly */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + + /* Now enable the CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } + } +} + +/***************************************************************************//** + * SPI_set_cmd_handler() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_cmd_handler +( + spi_instance_t * this_spi, + spi_block_rx_handler_t cmd_handler, + uint32_t cmd_size +) +{ + uint32_t ctrl2 = 0u; + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( NULL_SLAVE_CMD_HANDLER != cmd_handler ); + HAL_ASSERT( 0u < cmd_size ); + + if( ( NULL_INSTANCE != this_spi ) && ( 0u < cmd_size ) && + ( NULL_SLAVE_CMD_HANDLER != cmd_handler ) ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + /* + * Note we don't flush the FIFOs as this has been done already when + * block mode was configured. + * + * Clear this flag so zero padding is disabled until command response + * has been taken care of. + */ + this_spi->cmd_done = 0u; + + /* Assign user handler for Command received interrupt */ + this_spi->cmd_handler = cmd_handler; + + /* Configure the command size and Enable Command received interrupt */ + ctrl2 = HAL_get_8bit_reg( this_spi->base_addr, CTRL2 ); + + /* First clear the count field then insert count and int enables */ + ctrl2 &= ~(uint32_t)CTRL2_CMDSIZE_MASK; + ctrl2 |= (uint32_t)((cmd_size & CTRL2_CMDSIZE_MASK) | CTRL2_INTCMD_MASK | CTRL2_INTRXDATA_MASK); + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, ctrl2 ); + + /* Now enable the CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } +} + +/***************************************************************************//** + * SPI_set_cmd_response() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_cmd_response +( + spi_instance_t * this_spi, + const uint8_t * resp_tx_buffer, + uint32_t resp_buff_size +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( NULL_BUFF != resp_tx_buffer ); + HAL_ASSERT( 0u < resp_buff_size ); + + if( ( NULL_INSTANCE != this_spi ) && ( 0u < resp_buff_size ) && + ( NULL_BUFF != resp_tx_buffer ) ) + { + this_spi->resp_tx_buffer = resp_tx_buffer; + this_spi->resp_buff_size = resp_buff_size; + this_spi->resp_buff_tx_idx = 0u; + + fill_slave_tx_fifo(this_spi); + } +} + + +/***************************************************************************//** + * SPI_enable() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_enable +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } +} + + +/***************************************************************************//** + * SPI_disable() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_disable +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + } +} + + +/***************************************************************************//** + * SPI interrupt service routine. + */ +void SPI_isr +( + spi_instance_t * this_spi +) +{ + uint32_t rx_frame; + int32_t guard; + +/* + * The assert and the NULL check here can be commented out to reduce the interrupt + * latency once you are sure the interrupt vector code is correct. + */ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + if( NULL_INSTANCE != this_spi ) + { + /* Handle receive. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_RXDATA ) ) + { + /* + * Service receive data according to transfer mode in operation. + * + * We check block mode first as this is most likely to have back to back + * transfers with multiple bytes. + * + * Note the order of the checks here will effect interrupt latency and + * for critical timing the mode you are using most often should probably be + * be the first checked. + */ + if( SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode ) /* Block handling mode. */ + { + while( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Read irrespective to clear the RX IRQ */ + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + if( this_spi->slave_rx_idx < this_spi->slave_rx_size ) + { + this_spi->slave_rx_buffer[this_spi->slave_rx_idx] = (uint8_t)rx_frame; + } + ++this_spi->slave_rx_idx; + } + /* + * Now handle updating of tx FIFO to keep the data flowing. + * First see if there is anything in slave_tx_buffer to send. + */ + while( ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) + && ( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->slave_tx_buffer[this_spi->slave_tx_idx] ); + ++this_spi->slave_tx_idx; + } + /* + * Next see if there is anything in resp_tx_buffer to send. + */ + if( this_spi->slave_tx_idx >= this_spi->slave_tx_size ) + { + while( ( this_spi->resp_buff_tx_idx < this_spi->resp_buff_size ) + && ( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->resp_tx_buffer[this_spi->resp_buff_tx_idx] ); + ++this_spi->resp_buff_tx_idx; + } + } + /* + * Lastly, see if we are ready to pad with 0s . + */ + if( this_spi->cmd_done && ( this_spi->slave_tx_idx >= this_spi->slave_tx_size ) && + ( this_spi->resp_buff_tx_idx >= this_spi->resp_buff_size ) ) + { + guard = 1 + ((int32_t)this_spi->fifo_depth / 4); + while( ( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) + && ( 0 != guard ) ) + { + /* + * Pad TX FIFO with 0s for consistent behaviour if the master + * tries to transfer more than we expected. + */ + HAL_set_32bit_reg(this_spi->base_addr, TXDATA, 0x00u); + /* + * We use the guard count to cover the event that we are never + * seeing the TX FIFO full because the data is being pulled + * out as fast as we can stuff it in. In this case we never spend + * more than our allocated time spinning here. + */ + guard--; + } + } + } + else if( SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode ) /* Single frame handling mode. */ + { + while( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + if( NULL_FRAME_HANDLER != this_spi->frame_rx_handler ) + { + this_spi->frame_rx_handler( rx_frame ); + } + } + } + else /* Slave transfer mode not set up so discard anything in RX FIFO */ + { + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_RXFIFORST_MASK ); + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_RXDATA, ENABLE ); + } + + /* Handle transmit. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_TXDONE ) ) + { + /* + * Note, the driver only currently uses the txdone interrupt when + * in frame transmit mode. In block mode all TX handling is done by the + * receive interrupt handling code as we know that for every frame received + * a frame must be placed in the TX FIFO. + */ + if( SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode ) + { + /* Execute the user callback to update the slave_tx_frame */ + if( NULL_SLAVE_TX_UPDATE_HANDLER != this_spi->slave_tx_frame_handler ) + { + this_spi->slave_tx_frame_handler ( this_spi ); + } + + /* Reload slave tx frame into Tx data register. */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, this_spi->slave_tx_frame ); + } + else if( SPI_SLAVE_XFER_BLOCK != this_spi->slave_xfer_mode ) + { + /* Slave transfer mode not set up so discard anything in TX FIFO */ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK ); + } + else + { + /* Nothing to do, no slave mode configured */ + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_TXDONE, ENABLE ); + } + + + /* Handle receive overflow. */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, INTMASK_RXOVERFLOW)) + { + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_RXFIFORST_MASK); + HAL_set_8bit_reg_field(this_spi->base_addr, INTCLR_RXOVERFLOW, ENABLE); + } + + /* Handle transmit under run. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_TXUNDERRUN ) ) + { + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK ); + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_TXUNDERRUN, ENABLE ); + } + + /* Handle command interrupt. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_CMDINT ) ) + { + read_slave_rx_fifo( this_spi ); + + /* + * Call the command handler if one exists. + */ + if( NULL_SLAVE_CMD_HANDLER != this_spi->cmd_handler ) + { + this_spi->cmd_handler( this_spi->slave_rx_buffer, this_spi->slave_rx_idx ); + } + this_spi->cmd_done = 1u; + /* Disable command interrupt until slave select becomes de-asserted to avoid retriggering. */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_CMDINT, ENABLE ); + } + + /* Handle slave select becoming de-asserted. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_SSEND) ) + { + /* Only supposed to do all this if transferring blocks... */ + if(SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode) + { + uint32_t rx_size; + + /* Empty any remaining bytes in RX FIFO */ + read_slave_rx_fifo( this_spi ); + rx_size = this_spi->slave_rx_idx; + /* + * Re-enable command interrupt if required. + * Must be done before re loading FIFO to ensure stale response + * data is not pushed into the FIFO. + */ + if(NULL_SLAVE_CMD_HANDLER != this_spi->cmd_handler) + { + this_spi->cmd_done = 0u; + this_spi->resp_tx_buffer = 0u; + this_spi->resp_buff_size = 0u; + this_spi->resp_buff_tx_idx = 0u; + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_CMDINT, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, ENABLE ); + } + /* + * Reset the transmit index to 0 to restart transmit at the start of the + * transmit buffer in the next transaction. This also requires flushing + * the Tx FIFO and refilling it with the start of Tx data buffer. + */ + this_spi->slave_tx_idx = 0u; + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + fill_slave_tx_fifo( this_spi ); + + /* Prepare to receive next packet. */ + this_spi->slave_rx_idx = 0u; + /* + * Call the receive handler if one exists. + */ + if( NULL_BLOCK_HANDLER != this_spi->block_rx_handler ) + { + this_spi->block_rx_handler( this_spi->slave_rx_buffer, rx_size ); + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_RXDATA, ENABLE ); + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_SSEND, ENABLE ); + } + } +} + +/******************************************************************************* + * Local function definitions + */ + +/***************************************************************************//** + * Fill the transmit FIFO (used for slave block transfers). + */ +static void fill_slave_tx_fifo +( + spi_instance_t * this_spi +) +{ + /* First see if slave_tx_buffer needs transmitting */ + while( ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) && + !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->slave_tx_buffer[this_spi->slave_tx_idx] ); + ++this_spi->slave_tx_idx; + } + + /* Then see if it is safe to look at putting resp_tx_buffer in FIFO? */ + if( this_spi->slave_tx_idx >= this_spi->slave_tx_size ) + { + while( ( this_spi->resp_buff_tx_idx < this_spi->resp_buff_size ) && + !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->resp_tx_buffer[this_spi->resp_buff_tx_idx] ); + ++this_spi->resp_buff_tx_idx; + } + } +} + +/***************************************************************************//** + * + */ +static void read_slave_rx_fifo +( + spi_instance_t * this_spi +) +{ + uint32_t rx_frame; + + if( SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode ) /* Block handling mode. */ + { + while( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); /* Read irresepective to clear the RX IRQ */ + if( this_spi->slave_rx_idx < this_spi->slave_rx_size ) + { + this_spi->slave_rx_buffer[this_spi->slave_rx_idx] = (uint8_t)rx_frame; + } + ++this_spi->slave_rx_idx; + } + } + else if( SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode ) /* Frame handling mode */ + { + while( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Single frame handling mode. */ + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + if( NULL_FRAME_HANDLER != this_spi->frame_rx_handler ) + { + this_spi->frame_rx_handler( rx_frame ); + } + } + } + else /* Slave transfer mode not set up so discard anything in RX FIFO */ + { + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_RXFIFORST_MASK ); + } +} + +/***************************************************************************//** + * This function is to recover the CoreSPI from receiver overflow. + * It temporarily disables the CoreSPI from interacting with external world, flushes + * the transmit and receiver FIFOs, clears all interrupts and then re-enables + * the CoreSPI instance referred by this_spi parameter. + */ +static void recover_from_rx_overflow +( + const spi_instance_t * this_spi +) +{ + /* Disable CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Reset TX and RX FIFOs */ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Enable CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); +} + + diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.h b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.h new file mode 100644 index 0000000..c6873f7 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.h @@ -0,0 +1,1324 @@ +/***************************************************************************//** + * Copyright 2013-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Core SPI bare metal software driver public API. + * + * This Core SPI driver provides functions for implementing SPI master or + * SPI slave operations with the CoreSPI version 4.2.xxx It is not compatible + * with CoreSPI version 3.0.xxx. + * + * The Core SPI driver supports two classes of data transfer operation: + * SPI frame operation or SPI block transfer operations. + * + * Frame operations allow transferring individual SPI frames from 4 to 32-bits + * in length. Block operations allow transferring blocks of data organized as + * 8-bit frames. + * + * @file core_spi.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreSPI prototypes + * + */ + +/*=========================================================================*//** + @mainpage Core SPI Bare Metal Driver. + + ============================================================================== + Introduction + ============================================================================== + CoreSPI is an IP component that implements a full-duplex, synchronous, and + configurable serial peripheral interface (SPI) with frame sizes from 4 to 32 + bits and bus interface sizes of 8-, 16-, or 32-bit. Each CoreSPI instance + communicates with up to eight slave devices. + + This driver provides a set of functions for controlling CoreSPI as part of + the bare metal system where no operating system is available. These drivers + can be adapted to be used as a part of an operating system, but the + implementation of the adaptation layer between driver and the operating + system's driver model is outside the scope of this User's Guide. + + ============================================================================== + Driver Configuration + ============================================================================== + Your application software should configure the CoreSPI driver through calls + to the SPI_init() function for each CoreSPI instance in the hardware design. + This function configures a default set of parameters that include a CoreSPI + hardware instance base address and the depth of the FIFOs for this instance. + + The CoreSPI instance is configured at the time of instantiation in hardware + design for APB width, frame size, FIFO depth, serial clock speed, serial + clock polarity, serial clock phase, and slave select state parameters. + + CoreSPI can communicate with up to eight different slave devices that match + the CoreSPI configuration at the time of hardware instantiation. + + The functions SPI_configure_slave_mode() and SPI_configure_master_mode() are + used to configure the CoreSPI instance as a master or slave as required by + the application. + + When CoreSPI wishes to communicate with a specific slave device, call + the SPI_set_slave_select() function with the slave number as an argument. + This function selects the slave device. A previously selected slave gets + unselected by calling the SPI_clear_slave_select() function. + + ============================================================================== + Theory of Operation + ============================================================================== + The CoreSPI driver functions are grouped into the following categories: + • Initialization + • Configuration for either master or slave operations + • SPI master frame transfer control + • SPI master block transfer control + • SPI slave frame transfer control + • SPI slave block transfer control + + Frame transfers allow CoreSPI to write or read up to 32-bits of data in a + single SPI transaction. For example, a frame transfer of 12-bits might be used + to read the result of an ADC conversion from a SPI analog to digital converter. + + Block transfers allow CoreSPI to write and/or read a number of bytes in a single + SPI transaction. With the driver as is, block transfer transactions allow data + transfers in multiples of 8-bits (8, 16, 24, 32, 40,...) and the CoreSPI instance + has to be configured for 8-bit frames. For other frame sizes, the + SPI_transfer_block() code can act as a template for developing a frame block + transfer function. + Block transfers are typically used with byte oriented devices like SPI + FLASH devices. + + Note: The CoreSPI instance in the hardware design must be configured for + the frame size required by the application; configuration by driver is + not possible. + + -------------------------------- + Initialization + -------------------------------- + The CoreSPI driver is initialized through a call to the SPI_init() function. + The SPI_init() function takes a pointer to the global CoreSPI instance data + structure of type spi_instance_t and the base address of the CoreSPI instance + as defined by the hardware design. The CoreSPI instance global data structure + is used by the driver to store state information for each CoreSPI instance. + A pointer to these data structures is also used as the first parameter to + any of the driver functions to identify which CoreSPI will be used by the + called function. It is the responsibility of the application programmer to + create and maintain these global CoreSPI instance data structures. Any call + to a CoreSPI driver function should be of the form SPI_function_name + ( &g_core_spi0, ... ). + The SPI_init() function resets the transmit and receives FIFOs of CoreSPI + instance being initialized. + The SPI_init() function must be called before any other CoreSPI driver + functions can be called. + + ---------------------------------------------------- + Configuration + ---------------------------------------------------- + A CoreSPI instance can operate either as a master or as a slave SPI device. + There are two distinct functions for configuring a CoreSPI instance for + master or slave operations. + + ## Master Configuration + The SPI_configure_master_mode() function configures the specified CoreSPI + block for operations as an SPI master. This function must be called once + before the CoreSPI block communicates with an SPI slave device. + + ## Slave Configuration + The SPI_configure_slave_mode() function configures the specified CoreSPI + block for operations as a SPI slave. This function must be called after + calling the SPI_init() to configure the CoreSPI instance referred by this_spi + parameter to operate in the slave mode. + + ------------------------------------- + SPI Master Frame Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI master frame transfers: + • SPI_set_slave_select() + • SPI_transfer_frame() + • SPI_clear_slave_select() + + The master must first select the target slave or slaves to be addressed by + calling the SPI_set_slave_select() function. This causes the relevant select + line(s) to become asserted while data is clocked out onto the SPI data line. + + A function call is then made to SPI_transfer_frame() specifying the value + of the data frame to be sent and returning the value read. + + After the transfer is complete, use the SPI_clear_slave_select() function + to prevent this slave select line from being asserted during subsequent SPI + transactions. A call to this function is required only if the master is + communicating with multiple slave devices. + + ------------------------------------- + SPI Master Block Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI master block transfers: + • SPI_set_slave_select() + • SPI_transfer_block() + • SPI_clear_slave_select() + + The master must first select the target slave or slaves by calling + SPI_set_slave_select(). This causes the relevant slave select line(s) to + become asserted while data is clocked out onto the SPI data line. + Alternatively, a general purpose input/output (GPIO) can be used to control + the state of the target slave device's chip select signal. + + A call is then made to the SPI_transfer_block() function. The parameters of + this function specify the following: + • The number of bytes to be transmitted + • A pointer to the buffer containing the data to be transmitted + • The number of bytes to be received + • A pointer to the buffer where the received data gets stored + + The number of bytes to be transmitted can be set to zero to indicate that the + transfer is purely a block read transfer. The number of bytes to be received + can be set to zero to specify that the transfer is purely a block write + transfer. + + Block mode transfers as implemented by the driver are effectively half duplex + as we do not store the values received from the slave device whilst we are + transmitting. If full duplex operation is required, the driver + SPI_transfer_block() function can serve as a starting point for implementing + full duplex block transfers. + + The SPI_clear_slave_select() function can be used after the transfer is + complete to prevent this slave select line from being asserted during + subsequent SPI transactions. A call to this function is only required if + the master is communicating with multiple slave devices. + + ------------------------------------- + SPI Slave Frame Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI slave frame transfers: + • SPI_set_frame_rx_handler() + • SPI_set_slave_tx_frame() + + The SPI_set_frame_rx_handler() function specifies the receive handler + function that is called when a frame of data has been received by the + SPI when it is configured as a slave. The receive handler function specified + through this call processes the frame data written over the SPI bus to the + SPI slave by the remote SPI master. The receive handler function must be + implemented as part of the application. It is only required if the SPI slave + is the target of SPI frame write transactions. + + The SPI_set_slave_tx_frame() function specifies the frame data that is + returned to the SPI master. The frame data specified through this function + is the value that will be read over the SPI bus by the remote SPI master, + when it initiates a transaction. Call the SPI_set_slave_tx_frame() function + only if the SPI slave is the target of SPI read transactions. That is, if + data is meant to be read over CoreSPI. + + If both frame handlers are required, call the SPI_set_frame_rx_handler() + first, otherwise the initial TX frame gets discarded when SPI_set_frame_rx_handler() + clears the FIFOs as part of its initialization. + + ------------------------------------- + SPI Slave Block Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI slave block transfers: + • SPI_set_slave_block_buffers() + • SPI_set_cmd_handler() + • SPI_set_cmd_response() + + The SPI_set_slave_block_buffers() function is used to configure an SPI slave + for block transfer operations. It specifies the following: + • The buffer containing the data that will be returned to the remote SPI + master + • The buffer where data received from the remote SPI master will be + stored + • The optional handler function that will be called after the receive + buffer is filled + + The SPI_set_cmd_handler() function specifies a command handler function that + is called by the driver once a specific number of frames have been + received after the SPI chip select signal becomes active. The number of + bytes making up the command part of the transaction is specified as part of + the parameters to the SPI_set_cmd_handler() function. The command handler + function is implemented as a part of the application making use of the SPI + driver and typically calls the SPI_set_cmd_response() function. + + The SPI_set_cmd_response() function specifies the data that gets returned + to the master. Typically, the SPI_set_slave_block_buffers() function is + called as a part of the system initialisation to specify the data sent to + the master while the command bytes are being received. The transmit buffer + specified through calling the SPI_set_slave_block_buffers() function would + also typically include one or more bytes allowing the turn around time + for the command handler function to execute and call the + SPI_set_cmd_response() function. + + *//*=========================================================================*/ +#ifndef CORE_SPI_H_ +#define CORE_SPI_H_ + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#include "hal_assert.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + SPI FIFO Depth + ======================================= + SPI_MAX_FIFO_DEPTH & SPI_MIN_FIFO_DEPTH constants define the maximum and minimum + FIFO depths allowed for the CoreSPI instance. User need to inform the driver of + the FIFO depth for each CoreSPI instance to ensure that the FIFOs are managed correctly. + + | Constant | Description | + |--------------------|----------------------------------------------------| + | SPI_MAX_FIFO_DEPTH | Maximum FIFO depth allowed for the CoreSPI instance| + | SPI_MIN_FIFO_DEPTH | Minimum FIFO depth allowed for the CoreSPI instance| + + */ +#define SPI_MAX_FIFO_DEPTH 32u +#define SPI_MIN_FIFO_DEPTH 1u + +/***************************************************************************//** + Instances of this structure are used to identify the specific CoreSPI hardware + instances. A pointer to an instance of the spi_instance_t structure is passed + as the first parameter to the CoreSPI driver functions to identify which SPI + performs the requested operation. + */ +typedef struct spi_instance spi_instance_t; + +/***************************************************************************//** + This function pointer type is to assign a callback function for TX interrupt + when slave wants to send the next updated frame. + + Declaring and Implementing Slave Frame Transmit Handler Functions: + Slave transmit frame update handler functions should follow the following + prototype: + void slave_tx_frame_update_handler ( spi_instance_t * this_spi ); + The actual name of the transmit handler is unimportant. You can use any name + of your choice for the frame update handler. + + A common handler function may be used when multiple CoreSPI instances are + configured as slave, as the particular slave device currently requiring + service is indicated by the function parameter. + */ +typedef void (*spi_slave_frame_tx_handler_t)( spi_instance_t * this_spi ); + +/***************************************************************************//** + This defines the function prototype that must be followed by the SPI slave + frame receive handler functions. These functions are registered with the SPI + driver through the SPI_set_frame_rx_handler() function. + + Declaring and Implementing the Slave Frame Receive Handler Functions: + The Slave frame receive handler functions should follow the following + prototype: + void slave_frame_receive_handler(uint32_t rx_frame); + The actual name of the receive handler is unimportant. You can use any name + of your choice for the receive frame handler. The rx_frame parameter contains + the value of the received frame. + + Separate handler functions are required for each slave instance as there is + no indication of the slave requiring service passed to the handler. + + */ +typedef void (*spi_frame_rx_handler_t)( uint32_t rx_frame ); + +/***************************************************************************//** + This defines the function prototype that must be followed by SPI slave + block receive handler functions. These functions are registered with the + SPI driver through the SPI_set_slave_block_buffers() function. + + Declaring and Implementing Slave Block Receive Handler Functions: + Slave block receive handler functions should follow the following prototype: + void spi_block_rx_handler ( uint8_t * rx_buff, uint16_t rx_size ); + The actual name of the receive handler is unimportant. You can use any name + of your choice for the receive frame handler. The rx_buff parameter contains + a pointer to the start of the received block. The rx_size parameter contains + the number of bytes of the received block. + + Separate handler functions are required for each slave instance as there is + no indication of the slave requiring service passed to the handler. + + */ +typedef void (*spi_block_rx_handler_t)( uint8_t * rx_buff, uint32_t rx_size ); + +/***************************************************************************//** + This enumeration is used to select a specific SPI slave device (0 to 7). It is + used as a parameter to the SPI_configure_master_mode(), SPI_set_slave_select(), + and SPI_clear_slave_select() functions. + */ +typedef enum __spi_slave_t +{ + SPI_SLAVE_0 = 0, + SPI_SLAVE_1 = 1, + SPI_SLAVE_2 = 2, + SPI_SLAVE_3 = 3, + SPI_SLAVE_4 = 4, + SPI_SLAVE_5 = 5, + SPI_SLAVE_6 = 6, + SPI_SLAVE_7 = 7, + SPI_MAX_NB_OF_SLAVES = 8 +} spi_slave_t; + +/***************************************************************************//** + This enumeration is used to indicate the current slave mode transfer type so + that we are not relying on buffer comparisons to dictate the logic of the driver. + */ +typedef enum __spi_sxfer_mode_t +{ + SPI_SLAVE_XFER_NONE = 0, /* Not configured yet */ + SPI_SLAVE_XFER_BLOCK = 1, /* Block transfers, with SSEND delimiting end of block */ + SPI_SLAVE_XFER_FRAME = 2 /* Single frame transfers */ +} spi_sxfer_mode_t; + +/***************************************************************************//** + There is one instance of this structure for each of the core SPIs. Instances + of this structure are used to identify a specific SPI. A pointer to an + instance of the spi_instance_t structure is passed as the first parameter to + SPI driver functions to identify which SPI should perform the requested operation. + */ +struct spi_instance{ + + /* Base address in the processor's memory map for the + registers of the CoreSPI instance being initialized */ + addr_t base_addr; /* Base address of SPI hardware instance */ + + uint32_t rx_frame; /* received data */ + + /* Internal transmit state: */ + const uint8_t * slave_tx_buffer; /* Pointer to slave transmit buffer */ + uint32_t slave_tx_size; /* Size of slave transmit buffer */ + uint32_t slave_tx_idx; /* Current index into slave transmit buffer */ + + /* Slave command response buffer: */ + const uint8_t * resp_tx_buffer; + uint32_t resp_buff_size; + uint32_t resp_buff_tx_idx; + spi_block_rx_handler_t cmd_handler; + uint32_t cmd_done; /* Flag which indicates response has been set up and + it is safe to pad with 0s once the response is sent */ + + /* Internal receive state: */ + uint8_t * slave_rx_buffer; /* Pointer to buffer where data received by a slave will be stored */ + uint32_t slave_rx_size; /* Slave receive buffer size */ + uint32_t slave_rx_idx; /* Current index into slave receive buffer */ + + /* Slave received frame handler: */ + spi_frame_rx_handler_t frame_rx_handler; /* Pointer to function that will be called when a frame + is received when the SPI block is configured as slave */ + /* Slave transmitted frame handler: */ + uint32_t slave_tx_frame; /* Value of the data frame that will be transmitted + when the SPI block is configured as slave */ + spi_slave_frame_tx_handler_t slave_tx_frame_handler; /* Callback function pointer to update slave_tx_frame */ + + /* Slave block rx handler: */ + spi_block_rx_handler_t block_rx_handler; /* Pointer to the function that will be called when a data block has been received */ + + /* Per instance specific hardware information that the driver needs to know */ + uint16_t fifo_depth; /* Depth of RX and TX FIFOs in frames */ + + /* How we are expecting to deal with slave transfers */ + spi_sxfer_mode_t slave_xfer_mode; /* Current slave mode transfer configuration */ +}; + +/*------------------------Public Function-------------------------------------*/ + +/***************************************************************************//** + The SPI_init() function initializes the hardware and data structures of a + CoreSPI instance referenced by this_spi parameter. This function must be + called for each CoreSPI instance with a unique this_spi and base_addr + parameter combination. The SPI_init() function must be called before any + other CoreSPI driver functions are called. + + After calling the SPI_init() the CoreSPI is configured as a master, + all interrupt sources will be masked and all the slaves are deselected. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to be initialized. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @param base_addr + The base_addr parameter is the base address in the processor's memory map for + the registers of the CoreSPI instance being initialized. It is assumed that + any non NULL value passed in here points to a valid instance of a CoreSPI as + the driver has no way of verifying this. Failure to pass in a valid address + can result in system instability. + + @param fifo_depth + The fifo_depth parameter specifies the number of frames in the receive + and transmit FIFOs of the CoreSPI instance being initialized. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + @endcode + */ +void SPI_init +( + spi_instance_t * this_spi, + addr_t base_addr, + uint16_t fifo_depth +); + +/***************************************************************************//** + The SPI_configure_slave_mode() function is used when a CoreSPI instance is + to be configured as a SPI slave. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to be configured. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + + int main(void) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_slave_mode ( &g _spi0 ); + } + @endcode + */ +void SPI_configure_slave_mode +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_configure_master_mode() function is used when a CoreSPI instance is + to be configured as a SPI master. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to be configured. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + + int main(void) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_master_mode ( &g _spi0 ); + } + @endcode + */ +void SPI_configure_master_mode +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_set_slave_select() function is used by a CoreSPI master to select a + specific slave. This function causes the relevant slave select signal to be + asserted while data is clocked out onto the SPI data line. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param slave + The slave parameter is one of the spi_slave_t enumerated constants + identifying a slave. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + const uint32_t master_tx_frame = 0x0100A0E1; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0 ); + SPI_transfer_frame( &g_spi0, master_tx_frame ); + SPI_clear_slave_select( &g_spi0, SPI_SLAVE_0 ); + + @endcode + */ +void SPI_set_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +); + +/***************************************************************************//** + The SPI_clear_slave_select() function is used by a CoreSPI master to + deselect a specific slave. This function causes the relevant slave select + signal to be de-asserted. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param slave + The slave parameter is one of the spi_slave_t enumerated constants + identifying a slave. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + const uint32_t master_tx_frame = 0x0100A0E1; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0 ); + SPI_transfer_frame( &g_spi0, master_tx_frame ); + SPI_clear_slave_select( &g_spi0, SPI_SLAVE_0 ); + @endcode + */ +void SPI_clear_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +); + +/***************************************************************************//** + The SPI_transfer_frame() function is used by a SPI master to transmit and + receive a single frame of the size that has been configured at the time of + CoreSPI hardware instantiation. This function is typically used for + transactions with a SPI slave where the number of transmit and receive bits + are not divisible by 8 or where full duplex exchange of frames is required. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param tx_bits + The tx_bits parameter is a 32-bit word containing the value that will be + transmitted. If the frame size configured for the CoreSPI is less than 32-bits, + the upper bits will be ignored. + Note: The bit length of the value to be transmitted to the slave is + set when the CoreSPI is instantiated in the hardware design. + + @return + This function returns a 32-bit word containing the value that is received + from the slave. If the frame size configured for the CoreSPI in question is + less that 32-bits, the upper bits will be 0. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + const uint32_t master_tx_frame = 0x0100A0E1; + uint32_t master_rx; + + SPI_init(&g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ); + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0 ); + master_rx = SPI_transfer_frame( &g_spi0, master_tx_frame ); + SPI_clear_slave_select( &g_spi0, SPI_SLAVE_0 ); + @endcode + */ +uint32_t SPI_transfer_frame +( + spi_instance_t * this_spi, + uint32_t tx_bits +); + +/***************************************************************************//** + The SPI_transfer_block() function is used by the SPI master to transmit and + receive blocks of data organized as a specified number of 8-bit frames. It + can be used for the following: + • Writing a data block to a slave + • Reading a data block from a slave + • Sending a command to a slave followed by reading the outcome of + the command in a single SPI transaction. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param cmd_buffer + The cmd_buffer parameter is a pointer to the buffer that contains the data + sent by the master from the beginning of the transfer. This pointer can be + null (0) if the master does not need to send a command before reading data. + + @param cmd_byte_size + The cmd_byte_size parameter specifies the number of bytes in cmd_buffer that + will be sent. A value ‘0’ indicates that no data needs to be sent to the slave. + + @param rx_buffer + The rx_buffer parameter is a pointer to the buffer that stores the data received + from the slave after sending the command. This pointer can be null (0) if the + master does not receive any data from the slave. + + @param rx_byte_size + The rx_byte_size parameter specifies the number of bytes received from + the slave and stored in the rx_buffer. A value ‘0’ indicates that no data is + to be read from the slave. + + @return + This function does not return any value. + + @example + @code + Polled write transfer example + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + + uint8_t master_tx_buffer[MASTER_TX_BUFFER] = + { + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A + }; + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0) ; + SPI_transfer_block + ( + &g_spi0, + master_tx_buffer, + sizeof(master_tx_buffer), + 0, + 0 + ); + SPI_clear_slave_select(&g_spi0, SPI_SLAVE_0 ); + @endcode + */ +void SPI_transfer_block +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_buffer, + uint16_t rx_byte_size +); + +/***************************************************************************//** + The SPI_transfer_block_store_all_resp() function is used by the SPI master + to transmit and receive blocks of data organized as a specified number + of 8-bit frames. It can be used for the following: + • Writing a data block to a slave + • Reading a data block from a slave + • Sending a command to a slave followed by reading the outcome of + the command in a single SPI transaction + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param cmd_buffer + The cmd_buffer parameter is a pointer to the buffer that contains the data sent by + the master from the beginning of the transfer. This pointer can be null (0) + if the master does not need to send a command before reading data. + + @param cmd_byte_size + The cmd_byte_size parameter specifies the number of bytes contained in + cmd_buffer that will be sent. A value ‘0’ indicates that no data needs + to be sent to the slave. + + @param rx_data_buffer + The rx_data_buffer parameter is a pointer to the buffer that stores the data received + from the slave after sending the command. This pointer can be null (0) if the + master does not receive any data from the slave. + + @param rx_byte_size + The rx_byte_size parameter specifies the number of bytes received from + the slave and stores in the rx_buffer. A value ‘0’ indicates that no data is + to be read from the slave. + + @param cmd_response_buffer + The cmd_response_buffer parameter is a pointer to the buffer which stores the + command response from the slave, while the master is transmitting the number + of bytes indicated by cmd_byte_size parameter. + + @return + This function does not return any value. + + @example + @code + Polled write transfer example + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + + uint8_t master_tx_buffer[MASTER_TX_BUFFER] = + { + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A + }; + + uint8_t cmd_rx_buffer[CMD_RX_BUFFER]={0}; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0) ; + SPI_transfer_block_store_all_resp + ( + &g_spi0, + master_tx_buffer, + sizeof(master_tx_buffer), + 0, + 0, + cmd_response_buffer + ); + SPI_clear_slave_select(&g_spi0, SPI_SLAVE_0 ); + @endcode + */ +void SPI_transfer_block_store_all_resp +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_data_buffer, + uint16_t rx_byte_size, + uint8_t * cmd_response_buffer +); + +/***************************************************************************//** + The SPI_set_frame_rx_handler() function is used by the SPI slaves to specify + the receive handler function that is called by the SPI driver interrupt + handler when a frame of data is received by the SPI slave. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param rx_handler + The rx_handler parameter is a pointer to the frame receive handler that must + be called when a frame is received by the CoreSPI slave. Passing in a NULL + pointer disables the receive handler but does enable the receive interrupt to + ensure the RX FIFO is empty each time a frame is received. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + uint32_t g_slave_rx_frame = 0; + spi_instance_t g_spi0; + + void slave_frame_handler(uint32_t rx_frame) + { + g_slave_rx_frame = rx_frame; + } + int setup_slave( void ) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_slave_mode( &g_spi0 ); + SPI_set_frame_rx_handler( &g_spi0, slave_frame_handler ); + } + @endcode + */ +void SPI_set_frame_rx_handler +( + spi_instance_t * this_spi, + spi_frame_rx_handler_t rx_handler +); + +/***************************************************************************//** + The SPI_set_slave_tx_frame() function is used by the SPI slaves to specify + the frame that gets transmitted when a transaction is initiated by the SPI + master. This function allows you to assign a slave_tx_frame_handler function, + which will be executed upon transmit interrupt when the SPI is in slave mode. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param frame_value + The frame_value parameter contains the value of the frame to be sent to the + master. + Note: The bit length of the value to be transmitted to the master is + set when the CoreSPI is instantiated in the hardware design. + + @param slave_tx_frame_handler + The slave_tx_frame_handler function pointer is executed upon occurrence of + transmit interrupt when CoreSPI is operating in slave mode. This parameter + is optional and if set to NULL it is assumed that the frame value is static or + updated asynchronously. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + const uint32_t slave_tx_frame[2] = { 0x0110F761, 0x0110F671 }; + uint32_t master_rx; + uint32_t slave_frame_idx = 0 ; + + slave_frame_update( spi_instance_t * this_spi ) + { + this_spi->slave_tx_frame = slave_tx_frame[slave_frame_idx++]; + if( slave_frame_idx > 2 ) + slave_frame_idx = 0; + } + main() + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ) ; + SPI_set_slave_tx_frame( &g_spi0, slave_tx_frame[slave_frame_idx++], + &slave_frame_update ); + } + @endcode + */ +void SPI_set_slave_tx_frame +( + spi_instance_t * this_spi, + uint32_t frame_value, + spi_slave_frame_tx_handler_t slave_tx_frame_handler +); + +/***************************************************************************//** + The SPI_set_slave_block_buffers() function is used to configure an SPI slave + for block transfer operations. It specifies one or more of the following: + • The data that is transmitted when accessed by a master. + • The buffer where the data received from a master is stored. + • The handler function that must be called after the receive buffer has + been filled. + • The number of bytes that must be received from the master before calling + the recieve handler function. + These parameters allow the following use cases: + • Slave performing an action after receiving a block of data from a + master containing a command. This action is performed by the + receive handler based on the content of the receive data buffer. + • Slave returning a block of data to the master. The type of information + is always the same but the actual values change over time. For example, + returning the voltage of a predefined set of analog inputs. + • Slave returning data based on a command contained in the first part of + the SPI transaction. For example, reading the voltage of the analog + input specified by the first data byte by the master. This is achieved + by using the SPI_set_slave_block_buffers() function in conjunction with + functions SPI_set_cmd_handler() and SPI_set_cmd_response(). + + See the SPI_set_cmd_handler() function description for details of + this use case. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param tx_buffer + The tx_buffer parameter is a pointer to a buffer containing the data that + will be sent to the master. This parameter can be set to ‘0’ if the SPI + slave is not intended to be the target of SPI read transactions. + + @param tx_buff_size + The tx_buff_size parameter specifies the number of bytes that are + transmitted by the SPI slave. It is the number of bytes contained in the + tx_buffer. This parameter can be set to ‘0’ if the SPI slave is not + intended to be the target of SPI read transactions. The driver returns 0s + to the master if there is no buffer specified or the master reads beyond the + end of the buffer. + Note: If SPI_transfer_block() is used to read from this slave and there is + no command handler involved, the buffer size here must be at least the + combined length of the command and response specified by the master. + On receiving this data, the master discards the data bytes equal to + command length bytes from the start of the received buffer. + + @param rx_buffer + The rx_buffer parameter is a pointer to the buffer where data received + from the master is stored. This parameter can be set to ‘0’ if the + SPI slave is not intended to be the target of SPI write or write-read + transactions. + + @param rx_buff_size + The rx_buff_size parameter specifies the size of the receive buffer. It is + also the number of bytes that must be received before the receive handler + is called, if a receive handler is specified using the block_rx_handler + parameter. Any bytes received in excess of the size specified by the + rx_buff_size parameter are discarded. This parameter can be set to ‘0’ + if the SPI slave is not intended to be the target of SPI write or + write-read transactions. + + @param block_rx_handler + The block_rx_handler parameter is a pointer to a function that is called + when receive buffer has been filled or the slave select has been de-asserted. + This parameter can be set to ‘0’ if the SPI slave is not intended to be the + target of SPI write or write-read transactions. + + @return + This function does not return any value. + + @example + @code + Slave Performing Operation Based on Master Command: + In this example the SPI slave is configured to receive 10 bytes of data + or command from the SPI slave, and process the data received from the master. + + #define SPI0_BASE_ADDR 0xC2000000 + + uint32_t nb_of_rx_handler_calls = 0; + spi_instance_t g_spi0; + + void spi1_block_rx_handler_b + ( + uint8_t * rx_buff, + uint16_t rx_size + ) + { + ++nb_of_rx_handler_calls; + } + + void setup_slave( void ) + { + uint8_t slave_rx_buffer[10] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_slave_mode( &g_spi0 ); + + SPI_set_slave_block_buffers + ( + &g_spi0, + 0, + 0, + slave_rx_buffer, + sizeof( master_tx_buffer ), + spi1_block_rx_handler_b + ); + } + @endcode + */ +void SPI_set_slave_block_buffers +( + spi_instance_t * this_spi, + const uint8_t * tx_buffer, + uint32_t tx_buff_size, + uint8_t * rx_buffer, + uint32_t rx_buff_size, + spi_block_rx_handler_t block_rx_handler +); + +/***************************************************************************//** + The SPI_isr() function is the top level interrupt handler function for the + CoreSPI driver. You must call SPI_isr() from the system level + (CoreInterrupt and NVIC level) interrupt handler assigned to the interrupt + triggered by the CoreSPI SPIINT signal. Your system level interrupt handler + must also clear the system level interrupt triggered by the CoreSPI SPIINT + signal before returning, to prevent a re-assertion of the same interrupt. + + This function supports all types of interrupt triggered by CoreSPI. It is not + a complete interrupt handler by itself; rather, it is a top level wrapper that + abstracts CoreSPI command interrupt and slave mode transmit interrupt handling + by calling lower level handler functions specific to each type of CoreSPI + interrupt. You must create the lower level handler functions to suit your + application and register them with the driver through calling the + SPI_set_cmd_handler(), SPI_set_cmd_response(), and SPI_set_slave_tx_frame() + functions. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + + @example + @code + + Example of configuring a CoreInterrupt connected to the Fabric Interrupt on a + SmartFusion device to handle CoreSPI interrupt. + + #define #define SPI1_INT_IRQ_NB 0 + spi_instance_t g_spi0; + + Void CIC_irq1_handler(void) + { + SPI_isr( &g_spi0 ); + } + + void Fabric_IRQHandler( void ) + { + // Call the CoreInterrupt driver ISR to determine the source of the + // interrupt and call the relevant ISR registered to it. + CIC_irq_handler(); + + // Clear NVIC interrupt status to allow further interrupts + NVIC_ClearPendingIRQ( Fabric_IRQn ); + } + + main() + { + ... + + CIC_init( CIC_BASE_ADDR ); + + // Install handler for SPI IRQ + CIC_set_irq_handler( SPI0_INT_IRQ_NB, CIC_irq1_handler ); + + NVIC_ClearPendingIRQ( Fabric_IRQn ); + NVIC_EnableIRQ( Fabric_IRQn ); + + CIC_enable_irq( SPI1_INT_IRQ_NB ); + + ... + } + @endcode + */ +void SPI_isr +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_set_cmd_handler() function specifies a command handler function that + will be called when the number of bytes received reaches the command size + specified as cmd_size parameter. + + This function is used by the SPI slaves performing block transfers. Its + purpose is to allow an SPI slave to decide the data that will be returned to + the master while an SPI transaction is taking place. Typically, one or more + command bytes are sent by the master to request some specific data. The slave + interprets the command byte(s) while one or more turn-around bytes are + transmitted. The slave adjusts its transmit data buffer based on the command + during the turn around time. + + The following table provides an example of the use of this function where the + SPI slave returns data bytes D0 to D6 based on the value of a command. The + 3 bytes long command is made up of a command opcode byte followed by an + address byte followed by a size byte. The cmd_handler() function specified + through an earlier call to SPI_set_cmd_handler() is called by the CoreSPI + driver once the third byte is received. The cmd_handler() function + interprets the command bytes and calls SPI_set_cmd_response() to set the SPI + slave's response transmit buffer with the data to be transmitted after the + turnaround bytes (T0 to T3). The number of turnaround bytes must be + sufficient to give enough time for the cmd_handler() to execute. The number + of turnaround bytes is specified by the protocol used on top of the SPI + transport layer so that master and slave agree on the number of turn around + bytes. + +|Timestamp| SPI Transaction | Bytes | Comments | +|---------|-------------|----------------------|---------------| +| t0|COMMAND|C A S |C - command opcode byte, A - address byte, S - size byte| +|t1| TURN-AROUND|T0 T1 |cmd_handler() called here (T0 to T3 are TURN-AROUND bytes)| +|t2|TURN-AROUND|T2 T3|SPI_set_cmd_response() called here by implementation of cmd_handler() +|| | |to set the data that will be transmitted by the SPI slave.| +|t3| DATA | D0 D1 D2 D3 D4 D5 D6 |Data transmition (SPI slave return data bytes)| + + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure identifying + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @param cmd_handler + The cmd_handler parameter is a pointer to a function with the prototype: + void cmd_handler(uint8_t * rx_buff, uint32_t rx_size); + It specifies the function that will be called when the number of bytes + specified by the cmd_size parameter has been received. + + @param cmd_size + The cmd_size parameter specifies the number of bytes that must be received + before calling the command handler function specified by the cmd_handler. + The CoreSPI supports cmd_size values in the range 1 to 7. + + @return + This function does not return any value. + + @example + @code + The following example demonstrates how to configure CoreSPI to implement + the protocol given as an example above. The configure_slave() function + configures CoreSPI. It sets receive and transmit buffers. The transmit + buffer specified through the call to SPI_set_slave_block_buffers() function + specifies the data that will be returned to the master in bytes between + t0 and t3. These bytes will be sent to the master while the master transmits + the command and dummy bytes. The spi_slave_cmd_handler() function will be + called by the driver at time t1 after the 3 command bytes have been received. + The spi_block_rx_handler() function will be called by the driver at time t4, + when the transaction completes and the slave select signal becomes + de-asserted. + + #define SPI0_BASE_ADDR 0xC2000000 + #define COMMAND_SIZE 3 + #define NB_OF_DUMMY_BYTES 4 + #define MAX_TRANSACTION_SIZE 16 + + spi_instance_t g_spi0; + uint8_t slave_tx_buffer[COMMAND_SIZE + NB_OF_DUMMY_BYTES]; + uint8_t slave_rx_buffer[MAX_TRANSACTION_SIZE]; + + void configure_slave( void ) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_slave_mode( &g_spi0 ); + SPI_set_slave_block_buffers + ( + &g_spi0, + slave_tx_buffer, + COMMAND_SIZE + NB_OF_DUMMY_BYTES, + slave_rx_buffer, + sizeof(slave_rx_buffer), + spi_block_rx_handler + ); + + SPI_set_cmd_handler + ( + &g_spi0, + spi_slave_cmd_handler, + COMMAND_SIZE + ); + } + + void spi_slave_cmd_handler + ( + uint8_t * rx_buff, + uint32_t rx_size + ) + { + uint8_t command; + uint8_t address; + uint8_t size; + uint8_t * p_response; + uint32_t response_size; + + command = rx_buff[0]; + address = rx_buff[1]; + size = rx_buff[2]; + + p_response = get_response_data( command, address, size, &response_size ); + SPI_set_cmd_response( &g_spi0, p_response, response_size ); + } + + void spi_block_rx_handler + ( + uint8_t * rx_buff, + uint32_t rx_size + ) + { + process_rx_data( rx_buff, rx_size ); + } + @endcode + */ +void SPI_set_cmd_handler +( + spi_instance_t * this_spi, + spi_block_rx_handler_t cmd_handler, + uint32_t cmd_size +); + +/***************************************************************************//** + The SPI_set_cmd_response() function specifies the data that will be returned + to the master. See the description of SPI_set_cmd_handler() for details. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param resp_tx_buffer + The resp_tx_buffer parameter is a pointer to the buffer containing the data + that must be returned to the host in the data phase of an SPI transaction. + + @param resp_buff_size + The resp_buff_size parameter specifies the size of the buffer pointed by the + resp_tx_buffer parameter. + + @return + This function does not return any value. + */ +void SPI_set_cmd_response +( + spi_instance_t * this_spi, + const uint8_t * resp_tx_buffer, + uint32_t resp_buff_size +); + +/***************************************************************************//** + The SPI_enable() function enables the CoreSPI and allows it to respond to the external + signals. It is usually called to re-enable a CoreSPI instance which has been + disabled previously via by calling the SPI_disable() as the normal state of a CoreSPI + after enabling the initialization. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + */ +void SPI_enable +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_disable() function disables the CoreSPI and stops responding to the + external signals. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + */ +void SPI_disable +( + spi_instance_t * this_spi +); + +#ifdef __cplusplus +} +#endif + +#endif /* CORE_SPI_H_*/ diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreSPI/corespi_regs.h b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreSPI/corespi_regs.h new file mode 100644 index 0000000..a3e5b2a --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreSPI/corespi_regs.h @@ -0,0 +1,270 @@ +/***************************************************************************//** + * Copyright 2011-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file corespi_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreSPI memory map + * + */ + +#ifndef CORESPI_REGS_H_ +#define CORESPI_REGS_H_ + +/******************************************************************************* + * Control register 1: + *------------------------------------------------------------------------------ + */ +#define CTRL1_REG_OFFSET 0x00u + +#define CTRL1_ENABLE_OFFSET 0x00u +#define CTRL1_ENABLE_MASK 0x01u +#define CTRL1_ENABLE_SHIFT 0x00 + +#define CTRL1_MASTER_OFFSET 0x00u +#define CTRL1_MASTER_MASK 0x02u +#define CTRL1_MASTER_SHIFT 0x01 + +#define CTRL1_INTRXDATA_OFFSET 0x00u +#define CTRL1_INTRXDATA_MASK 0x04u +#define CTRL1_INTRXDATA_SHIFT 0x02 + +#define CTRL1_INTTXDONE_OFFSET 0x00u +#define CTRL1_INTTXDONE_MASK 0x08u +#define CTRL1_INTTXDONE_SHIFT 0x03 + +#define CTRL1_INTRXOVFLOW_OFFSET 0x00u +#define CTRL1_INTRXOVFLOW_MASK 0x10u +#define CTRL1_INTRXOVFLOW_SHIFT 0x04 + +#define CTRL1_INTTXURUN_OFFSET 0x00u +#define CTRL1_INTTXURUN_MASK 0x20u +#define CTRL1_INTTXURUN_SHIFT 0x05 + +#define CTRL1_FRAMEURUN_OFFSET 0x00u +#define CTRL1_FRAMEURUN_MASK 0x40u +#define CTRL1_FRAMEURUN_SHIFT 0x06 + +#define CTRL1_OENOFF_OFFSET 0x00u +#define CTRL1_OENOFF_MASK 0x80u +#define CTRL1_OENOFF_SHIFT 0x07 + +/******************************************************************************* + * Interrupt clear register: + *------------------------------------------------------------------------------ + */ +#define INTCLR_REG_OFFSET 0x04u + +#define INTCLR_TXDONE_OFFSET 0x04u +#define INTCLR_TXDONE_MASK 0x01u +#define INTCLR_TXDONE_SHIFT 0x00 + +#define INTCLR_RXDONE_OFFSET 0x04u +#define INTCLR_RXDONE_MASK 0x02u +#define INTCLR_RXDONE_SHIFT 0x01 + +#define INTCLR_RXOVERFLOW_OFFSET 0x04u +#define INTCLR_RXOVERFLOW_MASK 0x04u +#define INTCLR_RXOVERFLOW_SHIFT 0x02 + +#define INTCLR_TXUNDERRUN_OFFSET 0x04u +#define INTCLR_TXUNDERRUN_MASK 0x08u +#define INTCLR_TXUNDERRUN_SHIFT 0x03 + +#define INTCLR_CMDINT_OFFSET 0x04u +#define INTCLR_CMDINT_MASK 0x10u +#define INTCLR_CMDINT_SHIFT 0x04 + +#define INTCLR_SSEND_OFFSET 0x04u +#define INTCLR_SSEND_MASK 0x20u +#define INTCLR_SSEND_SHIFT 0x05 + +#define INTCLR_RXDATA_OFFSET 0x04u +#define INTCLR_RXDATA_MASK 0x40u +#define INTCLR_RXDATA_SHIFT 0x06 + +#define INTCLR_TXDATA_OFFSET 0x04u +#define INTCLR_TXDATA_MASK 0x80u +#define INTCLR_TXDATA_SHIFT 0x07 + +/******************************************************************************* + * Receive data register: + *------------------------------------------------------------------------------ + */ +#define RXDATA_REG_OFFSET 0x08u + +/******************************************************************************* + * Transmit data register: + *------------------------------------------------------------------------------ + */ +#define TXDATA_REG_OFFSET 0x0Cu + +/******************************************************************************* + * Masked interrupt status register: + *------------------------------------------------------------------------------ + */ +#define INTMASK_REG_OFFSET 0x10u + +#define INTMASK_TXDONE_OFFSET 0x10u +#define INTMASK_TXDONE_MASK 0x01u +#define INTMASK_TXDONE_SHIFT 0x00 + +#define INTMASK_RXDONE_OFFSET 0x10u +#define INTMASK_RXDONE_MASK 0x02u +#define INTMASK_RXDONE_SHIFT 0x01 + +#define INTMASK_RXOVERFLOW_OFFSET 0x10u +#define INTMASK_RXOVERFLOW_MASK 0x04u +#define INTMASK_RXOVERFLOW_SHIFT 0x02 + +#define INTMASK_TXUNDERRUN_OFFSET 0x10u +#define INTMASK_TXUNDERRUN_MASK 0x08u +#define INTMASK_TXUNDERRUN_SHIFT 0x03 + +#define INTMASK_CMDINT_OFFSET 0x10u +#define INTMASK_CMDINT_MASK 0x10u +#define INTMASK_CMDINT_SHIFT 0x04 + +#define INTMASK_SSEND_OFFSET 0x10u +#define INTMASK_SSEND_MASK 0x20u +#define INTMASK_SSEND_SHIFT 0x05 + +#define INTMASK_RXDATA_OFFSET 0x10u +#define INTMASK_RXDATA_MASK 0x40u +#define INTMASK_RXDATA_SHIFT 0x06 + +#define INTMASK_TXDATA_OFFSET 0x10u +#define INTMASK_TXDATA_MASK 0x80u +#define INTMASK_TXDATA_SHIFT 0x07 + +/******************************************************************************* + * Raw interrupt status register: + *------------------------------------------------------------------------------ + */ +#define INTRAW_REG_OFFSET 0x14u + +#define INTRAW_TXDONE_OFFSET 0x14u +#define INTRAW_TXDONE_MASK 0x01u +#define INTRAW_TXDONE_SHIFT 0x00 + +#define INTRAW_RXDONE_OFFSET 0x14u +#define INTRAW_RXDONE_MASK 0x02u +#define INTRAW_RXDONE_SHIFT 0x01 + +#define INTRAW_RXOVERFLOW_OFFSET 0x14u +#define INTRAW_RXOVERFLOW_MASK 0x04u +#define INTRAW_RXOVERFLOW_SHIFT 0x02 + +#define INTRAW_TXUNDERRUN_OFFSET 0x14u +#define INTRAW_TXUNDERRUN_MASK 0x08u +#define INTRAW_TXUNDERRUN_SHIFT 0x03 + +#define INTRAW_CMDINT_OFFSET 0x14u +#define INTRAW_CMDINT_MASK 0x10u +#define INTRAW_CMDINT_SHIFT 0x04 + +#define INTRAW_SSEND_OFFSET 0x14u +#define INTRAW_SSEND_MASK 0x20u +#define INTRAW_SSEND_SHIFT 0x05 + +#define INTRAW_RXDATA_OFFSET 0x14u +#define INTRAW_RXDATA_MASK 0x40u +#define INTRAW_RXDATA_SHIFT 0x06 + +#define INTRAW_TXDATA_OFFSET 0x14u +#define INTRAW_TXDATA_MASK 0x80u +#define INTRAW_TXDATA_SHIFT 0x07 + +/******************************************************************************* + * Control register 2: + *------------------------------------------------------------------------------ + */ +#define CTRL2_REG_OFFSET 0x18u + +#define CTRL2_CMDSIZE_OFFSET 0x18u +#define CTRL2_CMDSIZE_MASK 0x07u +#define CTRL2_CMDSIZE_SHIFT 0x00 + +#define CTRL2_INTCMD_OFFSET 0x18u +#define CTRL2_INTCMD_MASK 0x10u +#define CTRL2_INTCMD_SHIFT 0x04 + +#define CTRL2_INTSSEND_OFFSET 0x18u +#define CTRL2_INTSSEND_MASK 0x20u +#define CTRL2_INTSSEND_SHIFT 0x05 + +#define CTRL2_INTRXDATA_OFFSET 0x18u +#define CTRL2_INTRXDATA_MASK 0x40u +#define CTRL2_INTRXDATA_SHIFT 0x06 + +#define CTRL2_INTTXDATA_OFFSET 0x18u +#define CTRL2_INTTXDATA_MASK 0x80u +#define CTRL2_INTTXDATA_SHIFT 0x07 + +/******************************************************************************* + * Command register: + *------------------------------------------------------------------------------ + */ +#define CMD_REG_OFFSET 0x1Cu + +#define CMD_RXFIFORST_OFFSET 0x1Cu +#define CMD_RXFIFORST_MASK 0x01u +#define CMD_RXFIFORST_SHIFT 0x00 + +#define CMD_TXFIFORST_OFFSET 0x1Cu +#define CMD_TXFIFORST_MASK 0x02u +#define CMD_TXFIFORST_SHIFT 0x01 + +/******************************************************************************* + * Status register: + *------------------------------------------------------------------------------ + */ +#define STATUS_REG_OFFSET 0x20u + +#define STATUS_FIRSTFRAME_OFFSET 0x20u +#define STATUS_FIRSTFRAME_MASK 0x01u +#define STATUS_FIRSTFRAME_SHIFT 0x00 + +#define STATUS_DONE_OFFSET 0x20u +#define STATUS_DONE_MASK 0x02u +#define STATUS_DONE_SHIFT 0x01 + +#define STATUS_RXEMPTY_OFFSET 0x20u +#define STATUS_RXEMPTY_MASK 0x04u +#define STATUS_RXEMPTY_SHIFT 0x02 + +#define STATUS_TXFULL_OFFSET 0x20u +#define STATUS_TXFULL_MASK 0x08u +#define STATUS_TXFULL_SHIFT 0x03 + +#define STATUS_RXOVFLOW_OFFSET 0x20u +#define STATUS_RXOVFLOW_MASK 0x10u +#define STATUS_RXOVFLOW_SHIFT 0x04 + +#define STATUS_TXUNDERRUN_OFFSET 0x20u +#define STATUS_TXUNDERRUN_MASK 0x20u +#define STATUS_TXUNDERRUN_SHIFT 0x05 + +#define STATUS_SSEL_OFFSET 0x20u +#define STATUS_SSEL_MASK 0x40u +#define STATUS_SSEL_SHIFT 0x06 + +#define STATUS_ACTIVE_OFFSET 0x20u +#define STATUS_ACTIVE_MASK 0x80u +#define STATUS_ACTIVE_SHIFT 0x07 + +/******************************************************************************* + * Slave select register: + *------------------------------------------------------------------------------ + */ +#define SSEL_REG_OFFSET 0x24u + +/******************************************************************************* + * Transmit data last register: + *------------------------------------------------------------------------------ + */ +#define TXLAST_REG_OFFSET 0x28u + + +#endif /*CORESPI_REGS_H_*/ diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.c b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.c new file mode 100644 index 0000000..b8adaed --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.c @@ -0,0 +1,889 @@ +/******************************************************************************* + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * PF_System_Services driver implementation. See file "core_syservices_pf.h" for + * description of the functions implemented in this file. + * + */ + +#include "core_sysservices_pf.h" +#include "coresysservicespf_regs.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define NULL_BUFFER (( uint8_t* ) 0) + +static uint8_t execute_ss_command +( + uint8_t cmd_opcode, + const uint8_t* cmd_data, + uint16_t cmd_data_size, + const uint8_t* p_response, + uint16_t response_size, + uint16_t mb_offset, + uint16_t response_offset +); + +uint32_t g_css_pf_base_addr = 0u; + +/***************************************************************************//** + * SYS_init() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +void +SYS_init +( + uint32_t base_addr +) +{ + g_css_pf_base_addr = base_addr; +} + +/***************************************************************************//** + * SYS_get_serial_number() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_serial_number +( + const uint8_t * p_serial_number, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if (p_serial_number == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(SERIAL_NUMBER_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_serial_number, + SERIAL_NUMBER_RESP_LEN, + mb_offset, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_get_user_code() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_user_code +( + const uint8_t * p_user_code, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_user_code == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(USERCODE_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_user_code, + USERCODE_RESP_LEN, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_get_design_info() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_design_info +( + const uint8_t * p_design_info, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_design_info == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(DESIGN_INFO_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_design_info, + DESIGN_INFO_RESP_LEN, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_get_device_certificate() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_device_certificate +( + const uint8_t * p_device_certificate, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_device_certificate == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(DEVICE_CERTIFICATE_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_device_certificate, + DEVICE_CERTIFICATE_RESP_LEN, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_read_digest() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_read_digest +( + const uint8_t * p_digest, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_digest == NULL_BUFFER) + { + return status; + } + +#ifndef CORESYSSERVICES_MPFS + status = execute_ss_command(READ_DIGEST_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_digest, + READ_DIGEST_RESP_LEN, + mb_offset, + 0u); +#else + status = execute_ss_command(READ_DIGEST_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_digest, + READ_DIGEST_MPFS_RESP_LEN, + mb_offset, + 0u); +#endif + return status; + +} + +/***************************************************************************//** + * SYS_query_security() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_query_security +( + uint8_t * p_security_locks, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint8_t idx = 0u; + + if(p_security_locks == NULL_BUFFER) + { + return status; + } + +#ifndef CORESYSSERVICES_MPFS + uint8_t buf[12] = {0}; + /* Actual QUERY_SECURITY_RESP_LEN is 9 or 33 but PF_System_Services core + * needs number of words instead of number of bytes to be written to or read + * from MailBox */ + status = execute_ss_command(QUERY_SECURITY_REQUEST_CMD, + NULL_BUFFER, + 0u, + buf, + (QUERY_SECURITY_RESP_LEN + 3u), + mb_offset, + 0u); + + for (idx = 0u; idx < 9u; idx++) + { + *(p_security_locks+idx) = buf[idx]; + } + +#else + uint8_t buf[36] = {0}; + + status = execute_ss_command(QUERY_SECURITY_REQUEST_CMD, + NULL_BUFFER, + 0u, + buf, + (QUERY_SECURITY_MPFS_RESP_LEN + 3u), + mb_offset, + 0u); + + for (idx = 0u; idx < 33u; idx++) + { + *(p_security_locks+idx) = buf[idx]; + } + +#endif + + return status; +} + +/***************************************************************************//** + * SYS_read_debug_info() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_read_debug_info +( + const uint8_t * p_debug_info, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_debug_info == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(READ_DEBUG_INFO_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_debug_info, + READ_DEBUG_INFO_RESP_LEN, + mb_offset, + 0u); + return status; +} + +#ifdef CORESYSSERVICES_MPFS +/***************************************************************************//** + * SYS_read_envm_parameter() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_read_envm_parameter +( + uint8_t * p_envm_param, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_envm_param == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(READ_ENVM_PARAM_REQUEST_CMD, + NULL_BUFFER, + 0, + p_envm_param, + READ_ENVM_PARAM_RESP_LEN, + mb_offset, + 0); + return status; +} + +#endif + +/***************************************************************************//** + * SYS_puf_emulation_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_puf_emulation_service +( + const uint8_t * p_challenge, + uint8_t op_type, + uint8_t* p_response, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint8_t mb_format[20] = {0x00}; + uint8_t index = 0u; + + if((p_response == NULL_BUFFER) || (p_challenge == NULL_BUFFER)) + { + return status; + } + + /* Frame the data required for mailbox */ + mb_format[index] = op_type; + + for (index = 4u; index < 20u; index++) + { + mb_format[index] = p_challenge[index - 4u]; + } + + status = execute_ss_command(PUF_EMULATION_SERVICE_REQUEST_CMD, + mb_format, + PUF_EMULATION_SERVICE_CMD_LEN, + p_response, + PUF_EMULATION_SERVICE_RESP_LEN, + mb_offset, + 5u); /* mentioning offset to number of words instead of bytes */ + + return status; +} + +/***************************************************************************//** + * SYS_digital_signature_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_digital_signature_service +( + const uint8_t* p_hash, + uint8_t format, + uint8_t* p_response, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if((p_hash == NULL_BUFFER) || (p_response == NULL_BUFFER)) + { + return status; + } + + if (format == DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD) + { + status = execute_ss_command(DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD, + p_hash, + DIGITAL_SIGNATURE_HASH_LEN, + p_response, + DIGITAL_SIGNATURE_RAW_FORMAT_RESP_SIZE, + mb_offset, + 12u); /* mentioning offset to number of words instead of bytes */ + } + else + { + status = execute_ss_command(DIGITAL_SIGNATURE_DER_FORMAT_REQUEST_CMD, + p_hash, + DIGITAL_SIGNATURE_HASH_LEN, + p_response, + DIGITAL_SIGNATURE_DER_FORMAT_RESP_SIZE, + mb_offset, + 12u); /* mentioning offset to number of words instead of bytes */ + } + + return status; +} + +/***************************************************************************//** + * SYS_secure_nvm_write() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_secure_nvm_write +( + uint8_t format, + uint8_t snvm_module, + const uint8_t* p_data, + const uint8_t* p_user_key, + uint16_t mb_offset +) +{ + uint8_t frame[256] = {0x00}; + uint8_t* p_frame = &frame[0]; + uint16_t index = 0u; + uint8_t status = SYS_PARAM_ERR; + + HAL_ASSERT(!(NULL_BUFFER == p_data)); + HAL_ASSERT(!(snvm_module >= 221u)); + if (format != SNVM_NON_AUTHEN_TEXT_REQUEST_CMD) + { + HAL_ASSERT(!(NULL_BUFFER == p_user_key)); + } + + if ((p_data == NULL_BUFFER) || (snvm_module >= 221)) + { + return status; + } + + if ((format != SNVM_NON_AUTHEN_TEXT_REQUEST_CMD) + && (p_user_key == NULL_BUFFER)) + { + return status; + } + + if ((format != SNVM_NON_AUTHEN_TEXT_REQUEST_CMD) + && (format != SNVM_AUTHEN_TEXT_REQUEST_CMD) + && (format != SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD)) + { + return status; + } + + *p_frame = snvm_module; /* SNVMADDR - SNVM module */ + + p_frame += 4u; /* Next 3 bytes RESERVED - For alignment */ + + /* Copy user key and send the command/data to mailbox. */ + if ((format == SNVM_AUTHEN_TEXT_REQUEST_CMD) || + (format == SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD)) + { + /* Copy user data */ + for (index = 0u; index < (AUTHENTICATED_TEXT_DATA_LEN - USER_SECRET_KEY_LEN - 4u); index++) + { + *p_frame = p_data[index]; + p_frame++; + } + + /* Copy user key */ + for (index = 0u; index < USER_SECRET_KEY_LEN; index++) + { + *p_frame = p_user_key[index]; + p_frame++; + } + + status = execute_ss_command(format, + &frame[0], + AUTHENTICATED_TEXT_DATA_LEN, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + } + else + { + /* Copy user data */ + for (index = 0u; index < (NON_AUTHENTICATED_TEXT_DATA_LEN - 4u); index++) + { + *(p_frame+index) = p_data[index]; + } + + status = execute_ss_command(format, + &frame[0], + NON_AUTHENTICATED_TEXT_DATA_LEN, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + } + + return status; +} + +/***************************************************************************//** + * SYS_secure_nvm_read() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_secure_nvm_read +( + uint8_t snvm_module, + const uint8_t* p_user_key, + uint8_t* p_admin, + uint8_t* p_data, + uint16_t data_len, + uint16_t mb_offset +) +{ + /* Frame the message. */ + uint8_t frame[16] = {0x00u}; + uint8_t* p_frame = &frame[0u]; + uint8_t status = SYS_PARAM_ERR; + uint8_t response[256] = {0x00u}; + uint16_t index = 0u; + + HAL_ASSERT(!(NULL_BUFFER == p_data)); + HAL_ASSERT(!(NULL_BUFFER == p_admin)); + HAL_ASSERT(!(snvm_module > 221u)); + + HAL_ASSERT(data_len == 236u || data_len == 252u); + + if((p_data == NULL_BUFFER) || + (snvm_module >= 221) || + (p_admin == NULL_BUFFER)) + { + return status; + } + + *p_frame = snvm_module; /* SNVMADDR - SNVM module */ + + p_frame += 4u; /* RESERVED - For alignment */ + + /* Copy user key */ + if (236u == data_len) + { + HAL_ASSERT(p_user_key != NULL_BUFFER); + + if(p_user_key == NULL_BUFFER) + { + return status; + } + + for (index = 0u; index < 12u; index++) + { + *p_frame = p_user_key[index]; + p_frame++; + } + } + else + { + p_frame += 12u; + } + + status = execute_ss_command(SNVM_READ_REQUEST_CMD, + &frame[0], + 16u, + response, + (data_len + 4u), + mb_offset, + 4u); /* mentioning offset to number of words instead of bytes */ + + if (SYS_SUCCESS == status) + { + for (index = 0u; index < 4u; index++) + { + *(p_admin+index) = (uint32_t)response[index]; + } + + + /* Copy data into user buffer. */ + for (index = 4u; index < (data_len + 4u); index++) + { + *(p_data + (index - 4u)) = response[index]; + } + } + else + { + ; + } + + return status; +} + +/***************************************************************************//** + * SYS_nonce_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_nonce_service +( + const uint8_t * p_nonce, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if((p_nonce == NULL_BUFFER)) + { + return status; + } + + status = execute_ss_command(NONCE_SERVICE_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_nonce, + NONCE_SERVICE_RESP_LEN, + mb_offset, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_bitstream_authenticate_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_bitstream_authenticate_service +( + uint32_t spi_flash_address, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint32_t l_spi_flash_address = spi_flash_address; + status = execute_ss_command(BITSTREAM_AUTHENTICATE_CMD, + (uint8_t* )&l_spi_flash_address, + 4u, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_IAP_image_authenticate_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_IAP_image_authenticate_service +( + uint8_t spi_idx +) +{ + uint8_t status = SYS_PARAM_ERR; + + HAL_ASSERT(!(spi_idx == 1u)); + + if (spi_idx == 1u) + { + return status; + } + + status = execute_ss_command(IAP_BITSTREAM_AUTHENTICATE_CMD, + NULL_BUFFER, + 0u, + NULL_BUFFER, + 0u, + spi_idx, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_digest_check_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_digest_check_service +( + uint32_t options, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint32_t l_options = options; + + status = execute_ss_command(DIGEST_CHECK_CMD, + (uint8_t* )&l_options, + 4u, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_iap_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_iap_service +( + uint8_t iap_cmd, + uint32_t spiaddr, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint16_t l_mb_offset = 0u; + uint16_t cmd_data_size = 0u; + uint8_t* cmd_data = NULL_BUFFER; + bool invalid_param = false; + + if (((IAP_PROGRAM_BY_SPIIDX_CMD == iap_cmd) + || (IAP_VERIFY_BY_SPIIDX_CMD == iap_cmd)) + && (1u == spiaddr)) + { + invalid_param = true; + HAL_ASSERT(!invalid_param); + } + + if (!invalid_param) + { + switch(iap_cmd) + { + case IAP_PROGRAM_BY_SPIIDX_CMD: + case IAP_VERIFY_BY_SPIIDX_CMD: + /*In SPI_IDX based program and verify commands, + * Mailbox is not Required. Instead of mailbox offset + * SPI_IDX is passed as parameter.*/ + l_mb_offset = (uint16_t)(0xFFu & spiaddr); + break; + + case IAP_PROGRAM_BY_SPIADDR_CMD: + case IAP_VERIFY_BY_SPIADDR_CMD: + /*In SPI_ADDR based program and verify commands, + * Mailbox is Required*/ + l_mb_offset = mb_offset; + /*command data size is four bytes holding the + * SPI Address in it.*/ + cmd_data_size = 4u; + cmd_data = (uint8_t*)&spiaddr; + break; + + case IAP_AUTOUPDATE_CMD: + /*In auto update command Mailbox is not Required*/ + l_mb_offset = 0u; + break; + + default: + l_mb_offset = 0u; + + } + + status = execute_ss_command( + (uint8_t)iap_cmd, + cmd_data, + cmd_data_size, + NULL_BUFFER, + 0, + (uint16_t)l_mb_offset, + 0); + } + + return status; +} + +/***************************************************************************//** + Internal functions. +*/ +/* +This function executes the SS command. If Mailbox input data is required by the +it will first load it from cmd_data into the Mailbox. If the service requires +the response data to be read from mailbox, it will do so and store it in p_response. +*/ +static uint8_t execute_ss_command +( + uint8_t cmd_opcode, + const uint8_t* cmd_data, + uint16_t cmd_data_size, + const uint8_t* p_response, + uint16_t response_size, + uint16_t mb_offset, + uint16_t response_offset +) +{ + /* Pointer used during Writing to Mailbox memory. */ + uint32_t status = 0u; + uint16_t idx = 0u; + uint16_t ss_command = 0u; + uint32_t* word_buf; + uint16_t timeout_count = SS_TIMEOUT_COUNT; + + /* making sure that the system controller is not executing any service i.e. + SS_USER_BUSY is gone 0 */ + + while (1u == HAL_get_32bit_reg_field(g_css_pf_base_addr, SS_USER_BUSY)) + { + --timeout_count; + + if (timeout_count == 0) + { + return SS_USER_BUSY_TIMEOUT; + } + } + + /* Form the SS command: bit 0to6 is the opcode, bit 7to15 is the Mailbox offset + For some services this field has another meaning + (e.g. for IAP bitstream auth. it means spi_idx) */ + ss_command = ((mb_offset << 7u) | (cmd_opcode & 0x7Fu)); + + /* Load the command register with the SS request command code*/ + HAL_set_32bit_reg(g_css_pf_base_addr, SS_CMD, ss_command); + + if (cmd_data_size > 0u) + { + HAL_ASSERT(!(NULL_BUFFER == cmd_data)); + HAL_ASSERT(!(cmd_data_size % 4u)); + + /* Load the MBX_WCNT register with number of words */ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_WCNT, (cmd_data_size/4u)); + + /* Load the MBX_WADDR register with offset of input data (write to Mailbox) + For all the services this offset remains either 0 or Not applicable + for the services in which no Mailbox write is required.*/ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_WADDR, (0x00u + mb_offset)); + + } + + if (response_size > 0u) + { + HAL_ASSERT(!(NULL_BUFFER == p_response)); + HAL_ASSERT(!(response_size % 4u)); + + /* + Load the MBX_RWCNT register with number of words to be read from Mailbox + */ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_RCNT, (response_size/4u)); + + /* + Load the MBX_RADRDESC register with offset address within the mailbox + format for that particular service. + It will be 0 for the services where there is no output data from G5CONTROL + is expected. + This function assumes that this value is pre-calculated by service specific + functions as this value is fixed for each service. + */ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_RADDR, (response_offset + mb_offset)); + } + + /*Set the request bit in SYS_SERV_REQ register to start the service*/ + HAL_set_32bit_reg_field(g_css_pf_base_addr, SS_REQ_REQ, 0x01u); + + if (cmd_data_size > 0u) + { + word_buf = (uint32_t*)cmd_data; + + /* Write the user data into mail box. */ + for (idx = 0u; idx < (cmd_data_size/4u); idx++) + { + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_WDATA, word_buf[idx]); + } + } + + timeout_count = SS_TIMEOUT_COUNT; + if (response_size > 0u) + { + word_buf = (uint32_t*)p_response; + + for (idx = 0u; idx < (response_size/4u); idx++) + { + while (0u == HAL_get_32bit_reg_field(g_css_pf_base_addr, + SS_USER_RDVLD)) + { + --timeout_count; + + if (timeout_count == 0) + { + return SS_USER_RDVLD_TIMEOUT; + } + } + word_buf[idx] = HAL_get_32bit_reg(g_css_pf_base_addr, MBX_RDATA); + } + } + + timeout_count = SS_TIMEOUT_COUNT; + /* make sure that service is complete i.e. SS_USER_BUSY is gone 0 */ + while (1u == HAL_get_32bit_reg_field(g_css_pf_base_addr, SS_USER_BUSY)) + { + --timeout_count; + + if (timeout_count == 0) + { + return SS_USER_RDVLD_TIMEOUT; + } + } + + /* Read the status returned by System Controller */ + status = HAL_get_32bit_reg(g_css_pf_base_addr, SS_STAT); + + return (uint8_t)status; +} + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h new file mode 100644 index 0000000..8e0ebb6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h @@ -0,0 +1,1249 @@ +/******************************************************************************* + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the + * CoreSysServices_PF bare metal driver. + */ +/*=========================================================================*//** + @mainpage CoreSysServices_PF Bare Metal Driver. + + @section intro_sec Introduction + The PolarFire System Services (PF_SYSTEM_SERVICES) SgCore enables executing + the system services on the PolarFire and PolarFire SoC device. The system services + are the system controller actions initiated by the System Controller's System + Service Interface (SSI). The PolarFire System Services "SgCore" provides a + method to initiate these system services. The PF_SYSTEM_SERVICES interacts + with the system controller on SSI and Mailbox interface to initiate system + services, exchange data required for that services, and to know the successful + completion or error status. + + The PF_SYSTEM_SERVICES provides an APB interface for controlling the registers + functions for controlling the PF_SYSTEM_SERVICES as part of a bare metal system + register implemented within it. This software driver provides a set of where no + part of an operating system but the implementation of the adaptation layer + operating system is available. This driver is adapted for use in + between this driver and the operating system's driver model is outside the + scope of this driver. + + ## Features + The CoreSysServices_PF driver provides the following features: + - Executing device and design information services + - Executing design services + - Executing data security services + - Executing Fabric services + + The CoreSysServices_PF driver is provided as C source code. + + @section Driver Configuration + The application software should configure the CoreSysServices_PF driver through + calling the SYS_init() function. Only one instance of PF_SYSTEM_SERVICES SgCore is + supported. No additional configuration files are required to use the driver. + If using this driver on RT PolarFire device FPGA, define RT_DEVICE_FAMILY + macro in application. + + @section theory_op Theory of Operation + The CoreSysServices_PF driver provides access to the PolarFire system services. + These system services are grouped into the following categories: + + Device and Design Information Service + - Serial Number Service + - USERCODE Service + - Design Info Service + - Device Certificate Services + - Read Digests + - Query Security + - Read Debug Info + - Read eNVM param + + Design Services + - Bitstream authentication service + - IAP bitstream authentication service + + Data Security Services + - Digital Signature Service + - Secure NVM (SNVM) Functions + - PUF Emulation Service + - Nonce Service + + Fabric Services + - Digest Check Service + - In Application programming(IAP)/Auto-Update service + + Initialization and Configuration + + The CoreSysServices_PF driver is initialized by calling the SYS_init() + function. The SYS_init() function must be called before calling any other + CoreSysServices_PF driver functions. + + Device and Design Information Services + + The CoreSysServices_PF driver is used to read information about the device + and the design using the following functions: + - SYS_get_serial_number() + - SYS_get_user_code() + - SYS_get_design_info() + - SYS_get_device_certificate() + - SYS_read_digest() + - SYS_query_security() + - SYS_read_debug_info() + + Design Authentication Services + + The CoreSysServices_PF driver is used to execute design services using the + following functions: + - SYS_bitstream_authenticate_service() + - SYS_IAP_image_authenticate_service() + + Data Security Services + + The CoreSysServices_PF driver is used to execute data security services + using the following functions: + - SYS_digital_signature_service() + - SYS_secure_nvm_write() + - SYS_secure_nvm_read() + - SYS_puf_emulation_service () + - SYS_nonce_service () + + Executing Fabric Services + + The CoreSysServices_PF driver is used to execute fabric services using the + following functions: + - SYS_digest_check_service() + - SYS_iap_service() + + All the service execution functions return the 8-bit status, which is returned + by the system controller on executing the given service. A '0' value indicates + successful execution of that service. A non-zero value indicates error. + The error codes for each service are different. See individual function + description to know the exact meanings of the error codes for each service. + + The function descriptions in this file mainly focus on the details required + by the user to use the APIs provided by this driver to execute the services. + To know the complete details of the system services, see the + PolarFire FPGA and PolarFire SoC FPGA System Services [document](https://onlinedocs.microchip.com/pr/GUID-1409CF11-8EF9-4C24-A94E-70979A688632-en-US-3/index.html) + + *//*=========================================================================*/ +#ifndef __CORE_SYSSERV_PF_H +#define __CORE_SYSSERV_PF_H 1 + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#include "hal_assert.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** +* # Service Execution Success and Error Status Codes +* +* The following status codes are the return values from the system service functions. +* For any service, a return value '0' indicates that the service was executed +* successfully. A non-zero return value indicates that the service was not +* executed successfully. For all the services, the return value represents the +* status code returned by the system controller for the respective service, +* except the values SYS_PARAM_ERR, SS_USER_BUSY_TIMEOUT, and SS_USER_RDVLD_TIMEOUT. +* These three values indicate the error conditions detected by this driver and +* they do not overlap with the status code returned by the system controller for +* any of the system service. +* +* SYS_SUCCESS +* System service executed successfully +* +* SYS_PARAM_ERR +* System service cannot be executed as one or more parameters are not as +* expected by this driver. No read/write access is performed with the +* IP. +* +* SS_USER_BUSY_TIMEOUT +* The System service request is initiated and the driver timed-out while +* waiting for the system service to complete. The System Service +* completion is indicated by de-assertion of the SS_USER_BUSY bit by the +* IP. +* +* SS_USER_RDVLD_TIMEOUT +* The System service request is initiated and the driver timed-out while +* waiting for SS_USER_RDVLD bit, which indicates availability of data to +* be read from the mailbox, to become active. +*/ +#define SYS_SUCCESS 0u +#define SYS_PARAM_ERR 0xFFu +#define SS_USER_BUSY_TIMEOUT 0xFAu +#define SS_USER_RDVLD_TIMEOUT 0xFBu + +/** +* # System Service Timeout Count +* +* The SS_TIMEOUT_COUNT value is used by the driver as a timeout count +* while waiting for either the SS_USER_BUSY or SS_USER_RDVLD. This empirical +* value is sufficiently large so that the operations are falsely +* timeout in the normal circumstance. It is provided as a way to provide +* more debug information to the application in case there are some +* unforeseen issues. You may change this value for your need based on your +* system design. +*/ +#define SS_TIMEOUT_COUNT 40000u +/* + * SYS_DCF_DEVICE_MISMATCH + * Public key or FSN do not match device + * + * + * SYS_DCF_INVALID_SIGNATURE + * Certificate signature is invalid + * + * SYS_DCF_SYSTEM_ERROR + * PUF or storage failure + */ +#define SYS_DCF_DEVICE_MISMATCH 1u +#define SYS_DCF_INVALID_SIGNATURE 2u +#define SYS_DCF_SYSTEM_ERROR 3u + +/* + * SYS_NONCE_PUK_FETCH_ERROR + * Error fetching PUK + * + * SYS_NONCE_SEED_GEN_ERROR + * Error generating seed + */ +#define SYS_NONCE_PUK_FETCH_ERROR 1u +#define SYS_NONCE_SEED_GEN_ERROR 2u + +/** + * # Secure Nvm Write Error Codes + * + * SNVM_WRITE_INVALID_SNVMADDR + * Illegal page address + * + * SNVM_WRITE_FAILURE + * PNVM program/verify failed + * + * SNVM_WRITE_SYSTEM_ERROR + * PUF or storage failure + * + * SNVM_WRITE_NOT_PERMITTED + * Write is not permitted + */ +#define SNVM_WRITE_INVALID_SNVMADDR 1u +#define SNVM_WRITE_FAILURE 2u +#define SNVM_WRITE_SYSTEM_ERROR 3u +#define SNVM_WRITE_NOT_PERMITTED 4u + +/** + * # Secure Nvm Read Error Codes + * + * SNVM_READ_INVALID_SNVMADDR + * Illegal page address + * + * SNVM_READ_AUTHENTICATION_FAILURE + * Storage corrupt or incorrect USK + * + * SNVM_READ_SYSTEM_ERROR + * PUF or storage failure + * + */ +#define SNVM_READ_INVALID_SNVMADDR 1u +#define SNVM_READ_AUTHENTICATION_FAILURE 2u +#define SNVM_READ_SYSTEM_ERROR 3u + +/** + * # Digital Signature Service Error Codes + * + * DIGITAL_SIGNATURE_FEK_FAILURE_ERROR + * Error retrieving FEK + * + * DIGITAL_SIGNATURE_DRBG_ERROR + * Failed to generate nonce + * + * DIGITAL_SIGNATURE_ECDSA_ERROR + * ECDSA failed + */ +#define DIGITAL_SIGNATURE_FEK_FAILURE_ERROR 1u +#define DIGITAL_SIGNATURE_DRBG_ERROR 2u +#define DIGITAL_SIGNATURE_ECDSA_ERROR 3u + +/** + * # Digest Check Error Codes + * + * NOTE: When these error occur, the DIGEST tamper flag is triggered. + * + * DIGEST_CHECK_FABRICERR + * Fabric digest check error + * + * DIGEST_CHECK_CCERR + * UFS Fabric Configuration (CC) segment digest check error + * + * DIGEST_CHECK_SNVMERR + * ROM digest in SNVM segment digest check error + * + * DIGEST_CHECK_ULERR + * UFS UL segment digest check error + * + * DIGEST_CHECK_UK0ERR + * UKDIGEST0 in User Key segment digest check error + * + * DIGEST_CHECK_UK1ERR + * UKDIGEST1 in User Key segment digest check error + * + * DIGEST_CHECK_UK2ERR + * UKDIGEST2 in User Key segment (UPK1) digest check error + * + * DIGEST_CHECK_UK3ERR + * UKDIGEST3 in User Key segment (UK1) digest check error + * + * DIGEST_CHECK_UK4ERR + * UKDIGEST4 in User Key segment (DPK) digest check error + * + * DIGEST_CHECK_UK5ERR + * UKDIGEST5 in User Key segment (UPK2) digest check error + * + * DIGEST_CHECK_UK6ERR + * UKDIGEST6 in User Key segment (UK2) digest check error + * + * DIGEST_CHECK_UPERR + * UFS Permanent Lock (UPERM) segment digest check error + * + * DIGEST_CHECK_SYSERR + * M3 ROM, Factory and Factory Key Segments digest check error + * + */ +#define DIGEST_CHECK_FABRICERR 0x00u +#define DIGEST_CHECK_CCERR 0x01u +#define DIGEST_CHECK_SNVMERR 0x02u +#define DIGEST_CHECK_ULERR 0x03u +#define DIGEST_CHECK_UK0ERR 0x04u +#define DIGEST_CHECK_UK1ERR 0x05u +#define DIGEST_CHECK_UK2ERR 0x06u +#define DIGEST_CHECK_UK3ERR 0x07u +#define DIGEST_CHECK_UK4ERR 0x08u +#define DIGEST_CHECK_UK5ERR 0x09u +#define DIGEST_CHECK_UK6ERR 0x10u +#define DIGEST_CHECK_UPERR 0x11u +#define DIGEST_CHECK_SYSERR 0x12u + +/** + * # Bitstream Authentication and Iap Bitstream Authentication Return Status + * + * BSTREAM_AUTH_CHAINING_MISMATCH_ERR + * Validator or hash chaining mismatch. Incorrectly constructed bitstream or + * wrong key used. + * + * BSTREAM_AUTH_UNEXPECTED_DATA_ERR + * Unexpected data received. + * Additional data received after end of EOB component. + * + * BSTREAM_AUTH_INVALID_ENCRY_KEY_ERR + * Invalid/corrupt encryption key. + * The requested key mode is disabled or the key could not be read/reconstructed. + * + * BSTREAM_AUTH_INVALID_HEADER_ERR + * Invalid component header + * + * BSTREAM_AUTH_BACK_LEVEL_NOT_SATISFIED_ERR + * Back level not satisfied + * + * BSTREAM_AUTH_ILLEGAL_BITSTREAM_MODE_ERR + * Illegal bitstream mode. + * Requested bitstream mode is disabled by user security. + * + * BSTREAM_AUTH_DNS_BINDING_MISMATCH_ERR + * DSN binding mismatch + * + * BSTREAM_AUTH_ILLEGAL_COMPONENT_SEQUENCE_ERR + * Illegal component sequence + * + * BSTREAM_AUTH_INSUFF_DEVICE_CAPAB_ERR + * Insufficient device capabilities + * + * BSTREAM_AUTH_INCORRECT_DEVICEID_ERR + * Incorrect DEVICEID + * + * BSTREAM_AUTH_PROTOCOL_VERSION_ERR + * Unsupported bitstream protocol version (regeneration required) + * + * BSTREAM_AUTH_VERIFY_ERR + * Verify not permitted on this bitstream + * + * BSTREAM_AUTH_INVALID_DEV_CERT_ERR + * Invalid Device Certificate. + * Device SCAC is invalid or not present. + * + * BSTREAM_AUTH_INVALID_DIB_ERR + * Invalid DIB + * + * BSTREAM_AUTH_SPI_NOT_MASTER_ERR + * Device not in SPI Master Mode. + * Error may occur only when bitstream is executed through IAP mode. + * + * BSTREAM_AUTH_AUTOIAP_NO_VALID_IMAGE_ERR + * No valid images found. + * Error may occur when bitstream is executed through Auto Update mode. + * Occurs when no valid image pointers are found. + * + * BSTREAM_AUTH_INDEXIAP_NO_VALID_IMAGE_ERR + * No valid images found. + * Error may occur when bitstream is executed through IAP mode via Index Mode. + * Occurs when No valid image pointers are found. + * + * BSTREAM_AUTH_NEWER_DESIGN_VERSION_ERR + * Programmed design version is newer than AutoUpdate image found. + * Error may occur when bitstream is executed through Auto Update mode. + * + * BSTREAM_AUTH_INVALID_IMAGE_ERR + * Selected image was invalid and no recovery was performed due to valid design + * in device. + * Error may occur only when bitstream is executed through Auto Update or IAP mode + * (This error is here for completeness but only can be observed by running the + * READ_DEBUG_INFO instruction and looking at IAP Error code field). + * + * BSTREAM_AUTH_IMAGE_PROGRAM_FAILED_ERR + * Selected and Recovery image failed to program. + * Error may occur only when bitstream is executed through Auto Update or + * IAP mode + * (This error is here for completeness but only can be observed by running the + * READ_DEBUG_INFO instruction and looking at IAP Error code field). + * + * BSTREAM_AUTH_ABORT_ERR + * Abort. + * Non-bitstream instruction executed during bitstream loading. + * + * BSTREAM_AUTH_NVMVERIFY_ERR + * Fabric/UFS verification failed (min or weak limit) + * + * BSTREAM_AUTH_PROTECTED_ERR + * Device security prevented modification of non-volatile memory + * + * BSTREAM_AUTH_NOTENA + * Programming mode not enabled + * + * BSTREAM_AUTH_PNVMVERIFY + * pNVM verify operation failed + * + * BSTREAM_AUTH_SYSTEM + * System hardware error (PUF or DRBG) + * + * BSTREAM_AUTH_BADCOMPONENT + * An internal error was detected in a component payload + * + * BSTREAM_AUTH_HVPROGERR + * HV programming subsystem failure (pump failure) + * + * BSTREAM_AUTH_HVSTATE + * HV programming subsystem in unexpected state (internal error) + * + */ +#define BSTREAM_AUTH_CHAINING_MISMATCH_ERR 1 +#define BSTREAM_AUTH_UNEXPECTED_DATA_ERR 2 +#define BSTREAM_AUTH_INVALID_ENCRY_KEY_ERR 3 +#define BSTREAM_AUTH_INVALID_HEADER_ERR 4 +#define BSTREAM_AUTH_BACK_LEVEL_NOT_SATISFIED_ERR 5 +#define BSTREAM_AUTH_ILLEGAL_BITSTREAM_MODE_ERR 6 +#define BSTREAM_AUTH_DNS_BINDING_MISMATCH_ERR 7 +#define BSTREAM_AUTH_ILLEGAL_COMPONENT_SEQUENCE_ERR 8 +#define BSTREAM_AUTH_INSUFF_DEVICE_CAPAB_ERR 9 +#define BSTREAM_AUTH_INCORRECT_DEVICEID_ERR 10 +#define BSTREAM_AUTH_PROTOCOL_VERSION_ERR 11 +#define BSTREAM_AUTH_VERIFY_ERR 12 +#define BSTREAM_AUTH_INVALID_DEV_CERT_ERR 13 +#define BSTREAM_AUTH_INVALID_DIB_ERR 14 +#define BSTREAM_AUTH_SPI_NOT_MASTER_ERR 21 +#define BSTREAM_AUTH_AUTOIAP_NO_VALID_IMAGE_ERR 22 +#define BSTREAM_AUTH_INDEXIAP_NO_VALID_IMAGE_ERR 23 +#define BSTREAM_AUTH_NEWER_DESIGN_VERSION_ERR 24 +/* 25 Reserved */ +#define BSTREAM_AUTH_INVALID_IMAGE_ERR 26 +#define BSTREAM_AUTH_IMAGE_PROGRAM_FAILED_ERR 27 +#define BSTREAM_AUTH_ABORT_ERR 127 +#define BSTREAM_AUTH_NVMVERIFY_ERR 128 +#define BSTREAM_AUTH_PROTECTED_ERR 129 +#define BSTREAM_AUTH_NOTENA 130 +#define BSTREAM_AUTH_PNVMVERIFY 131 +#define BSTREAM_AUTH_SYSTEM 132 +#define BSTREAM_AUTH_BADCOMPONENT 133 +#define BSTREAM_AUTH_HVPROGERR 134 +#define BSTREAM_AUTH_HVSTATE 135 + +/***************************************************************************//** + * # Mailbox ECC Status + * Provides ECC status when the mailbox is read. The values are as follows: + * 00: No ECC errors detected, data is correct. + * 01: Exactly one bit error occurred and has been corrected. + * 10: Exactly two bits error occurred and no correction performed. + * 11: Reserved. + */ +#define SYS_MBOX_ECC_NO_ERROR_MASK 0x00u +#define SYS_MBOX_ONEBIT_ERROR_CORRECTED_MASK 0x40u +#define SYS_MBOX_TWOBIT_ERROR_MASK 0xC0u + +/***************************************************************************//** + * Service request command opcodes: +*/ +#define SERIAL_NUMBER_REQUEST_CMD 0x00u +#define USERCODE_REQUEST_CMD 0x01u +#define DESIGN_INFO_REQUEST_CMD 0x02u +#define DEVICE_CERTIFICATE_REQUEST_CMD 0x03u +#define READ_DIGEST_REQUEST_CMD 0x04u +#define QUERY_SECURITY_REQUEST_CMD 0x05u +#define READ_DEBUG_INFO_REQUEST_CMD 0x06u +#define READ_ENVM_PARAM_REQUEST_CMD 0x07u +#define SNVM_NON_AUTHEN_TEXT_REQUEST_CMD 0x10u +#define SNVM_AUTHEN_TEXT_REQUEST_CMD 0x11u +#define SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD 0x12u +#define SNVM_READ_REQUEST_CMD 0x18u +#define DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD 0x19u +#define PUF_EMULATION_SERVICE_REQUEST_CMD 0x20u +#define NONCE_SERVICE_REQUEST_CMD 0x21u +#define DIGITAL_SIGNATURE_DER_FORMAT_REQUEST_CMD 0x1Au + +#define BITSTREAM_AUTHENTICATE_CMD 0x23u +#define IAP_BITSTREAM_AUTHENTICATE_CMD 0x22u + +#define DIGEST_CHECK_CMD 0x47u + +#define IAP_PROGRAM_BY_SPIIDX_CMD 0x42u +#define IAP_VERIFY_BY_SPIIDX_CMD 0x44u +#define IAP_PROGRAM_BY_SPIADDR_CMD 0x43u +#define IAP_VERIFY_BY_SPIADDR_CMD 0x45u +#define IAP_AUTOUPDATE_CMD 0x46u + +/***************************************************************************//** + * Service request Mailbox return data length + */ +#define SERIAL_NUMBER_RESP_LEN 16u +#define USERCODE_RESP_LEN 4u +#define DESIGN_INFO_RESP_LEN 36u +#define DEVICE_CERTIFICATE_RESP_LEN 1024u +#define READ_DIGEST_RESP_LEN 416u +#define QUERY_SECURITY_RESP_LEN 9u +#define READ_DEBUG_INFO_RESP_LEN 76u +#define READ_ENVM_PARAM_RESP_LEN 256u +#define NONCE_SERVICE_RESP_LEN 32u + +#define PUF_EMULATION_SERVICE_CMD_LEN 20u +#define PUF_EMULATION_SERVICE_RESP_LEN 32u + +#define DIGITAL_SIGNATURE_HASH_LEN 48u +#define DIGITAL_SIGNATURE_RAW_FORMAT_RESP_SIZE 96u +#define DIGITAL_SIGNATURE_DER_FORMAT_RESP_SIZE 104u + +#define USER_SECRET_KEY_LEN 12u + +/* Same driver can be used on PolarFire SoC platform and the response length + * is different for PolarFire SoC. Constants defined below are used only when the + * PF System services driver is used with PolarFire SoC Platform. + */ +#define READ_DIGEST_MPFS_RESP_LEN 576u +#define QUERY_SECURITY_MPFS_RESP_LEN 33u + +/* SNVM Input data length from sNVM write. */ +#ifndef RT_DEVICE_FAMILY +/* SNVMADDR + RESERVED + PT + USK */ +#define NON_AUTHENTICATED_TEXT_DATA_LEN 256u + +/* SNVMADDR + RESERVED + PT */ +#define AUTHENTICATED_TEXT_DATA_LEN 252u +#else +/* SNVMADDR + RESERVED + PT + USK */ +#define NON_AUTHENTICATED_TEXT_DATA_LEN 224u + +/* SNVMADDR + RESERVED + PT */ +#define AUTHENTICATED_TEXT_DATA_LEN 220u +#endif + +/** + * # Digest Check Input Options + * + * DIGEST_CHECK_FABRIC + * Carry out digest check on Fabric + * + * DIGEST_CHECK_CC + * Carry out digest check on UFS Fabric Configuration (CC) segment + * + * DIGEST_CHECK_SNVM + * Carry out digest check on ROM digest in SNVM segment + * + * DIGEST_CHECK_UL + * Carry out digest check on UFS UL segment + * + * DIGEST_CHECK_UKDIGEST0 + * Carry out digest check on UKDIGEST0 in User Key segment + * + * DIGEST_CHECK_UKDIGEST1 + * Carry out digest check on UKDIGEST1 in User Key segment + * + * DIGEST_CHECK_UKDIGEST2 + * Carry out digest check on UKDIGEST2 in User Key segment (UPK1) + * + * DIGEST_CHECK_UKDIGEST3 + * Carry out digest check on UKDIGEST3 in User Key segment (UK1) + * + * DIGEST_CHECK_UKDIGEST4 + * Carry out digest check on UKDIGEST4 in User Key segment (DPK) + * + * DIGEST_CHECK_UKDIGEST5 + * Carry out digest check on UKDIGEST5 in User Key segment (UPK2) + * + * DIGEST_CHECK_UKDIGEST6 + * Carry out digest check on UKDIGEST6 in User Key segment (UK2) + * + * DIGEST_CHECK_UPERM + * Carry out digest check on UFS Permanent lock (UPERM) segment + * + * DIGEST_CHECK_SYS + * Carry out digest check on Factory and Factory Key Segments + * + */ +#define DIGEST_CHECK_FABRIC (0x01<<0x00u) /*Fabric digest*/ +#define DIGEST_CHECK_CC (0x01<<0x01u) /*UFS Fabric Configuration (CC) segment*/ +#define DIGEST_CHECK_SNVM (0x01<<0x02u) /*ROM digest in SNVM segment*/ +#define DIGEST_CHECK_UL (0x01<<0x03u) /*UFS UL segment*/ +#define DIGEST_CHECK_UKDIGEST0 (0x01<<0x04u) /*UKDIGEST0 in User Key segment*/ +#define DIGEST_CHECK_UKDIGEST1 (0x01<<0x05u) /*UKDIGEST1 in User Key segment*/ +#define DIGEST_CHECK_UKDIGEST2 (0x01<<0x06u) /*UKDIGEST2 in User Key segment (UPK1)*/ +#define DIGEST_CHECK_UKDIGEST3 (0x01<<0x07u) /*UKDIGEST3 in User Key segment (UK1)*/ +#define DIGEST_CHECK_UKDIGEST4 (0x01<<0x08u) /*UKDIGEST4 in User Key segment (DPK)*/ +#define DIGEST_CHECK_UKDIGEST5 (0x01<<0x09u) /*UKDIGEST5 in User Key segment (UPK2)*/ +#define DIGEST_CHECK_UKDIGEST6 (0x01<<0x0au) /*UKDIGEST6 in User Key segment (UK2)*/ +#define DIGEST_CHECK_UPERM (0x01<<0x0bu) /*UFS Permanent lock (UPERM) segment*/ +#define DIGEST_CHECK_SYS (0x01<<0x0cu) /*Factory and Factory Key Segments.*/ + +/***************************************************************************//** + * The function SYS_init() is used to initialize the internal data structures of + * this driver. Currently this function is empty. + * + * @param base_addr The base_addr parameter specifies the base address of the + * PF_System_services core. + * + * @return This function does not return a value. + */ +void +SYS_init +( + uint32_t base_addr +); + +/***************************************************************************//** + * The function SYS_get_serial_number() is used to execute "serial number" system + * service. + * + * @param p_serial_number The p_serial_number parameter is a pointer to a buffer + * in which the data returned by system controller + * is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t +SYS_get_serial_number +( + const uint8_t * p_serial_number, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_get_user_code() is used to execute "USERCODE" system + * service. + * @param p_user_code The p_user_code parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t +SYS_get_user_code +( + const uint8_t * p_user_code, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_get_design_info() is used to execute "Get Design Info" system + * service. + * + * @param p_design_info The p_design_info parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. Total size of debug information is 36 bytes. + * The data from the system controller includes the 256-bit + * user-defined design ID, 16-bit design version, and 16-bit + * design back level. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t +SYS_get_design_info +( + const uint8_t * p_design_info, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_get_device_certificate() is used to execute "Get Device + * Certificate" system service. + * + * @param p_device_certificate The p_device_certificate parameter is a pointer + * to a buffer in which the data returned by the + * system controller is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code means that + * the service was executed successfully. + * + */ +uint8_t +SYS_get_device_certificate +( + const uint8_t * p_device_certificate, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_read_digest() is used to execute "Read Digest" system service. + * + * @param p_digest The p_digest parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t SYS_read_digest +( + const uint8_t * p_digest, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_query_security() is used to execute "Query Security" system + * service. + * + * @param p_security_locks The p_security_locks parameter is a pointer to a buffer + * in which the data returned by system controller is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code means that + * the service was executed successfully. + */ +uint8_t SYS_query_security +( + uint8_t * p_security_locks, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_read_debug_info() is used to execute "Read Debug info" system + * service. + * + * @param p_debug_info The p_debug_info parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t SYS_read_debug_info +( + const uint8_t * p_debug_info, + uint16_t mb_offset +); + +#ifdef CORESYSSERVICES_PFSOC +/***************************************************************************//** + * The function SYS_read_envm_parameter() is used to retrieve all parameters needed + * for the eNVM operation and programming. + * + * NOTE: This service is available only on PolarFire SoC Platform. + * This service is not yet supported by PF_SYSTEM_SERVICES 3.0.100. + * + * @param p_envm_param The p_envm_param parameter is a pointer to a buffer + * in which the data returned by system controller is copied. + * This buffer stores all the eNVM parameters. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_read_envm_parameter service will return zero if the + * service executed successfully, otherwise, it will return + * one indicating error. + */ +uint8_t SYS_read_envm_parameter +( + uint8_t * p_envm_param, + uint16_t mb_offset +); +#endif +/***************************************************************************//** + * The function SYS_puf_emulation_service() is used to authenticate a device. + * + * The SYS_puf_emulation_service() function accept a challenge comprising a + * 8-bit optype and 128-bit challenge and return a 256-bit response unique to + * the given challenge and the device. + * + * @param p_challenge The p_challenge parameter specifies the 128-bit challenge + * to generate the 256-bits unique response. + * + * @param op_type The op_type parameter specifies the operational parameter + * to generate the 256-bits unique response. + * + * @param p_response The p_response parameter is a pointer to a buffer where + * the data returned which is the response by system controller + * is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_puf_emulation_service function will return zero + * if the service executed successfully, otherwise, it will + * return one indicating error. + */ +uint8_t SYS_puf_emulation_service +( + const uint8_t * p_challenge, + uint8_t op_type, + uint8_t* p_response, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_digital_signature_service() function is used to generate P-384 ECDSA + * signature based on SHA384 hash value. + * + * @param p_hash The p_hash parameter is a pointer to the buffer which + * contain the 48 bytes SHA384 Hash value (input value). + * + * @param format The format parameter specifies the output format of + * generated SIGNATURE field. The different types of output + * signature formats are as follow: + * - DIGITAL_SIGNATURE_RAW_FORMAT + * - DIGITAL_SIGNATURE_DER_FORMAT + * + * @param p_response The p_response parameter is a pointer to a buffer that + * contains the generated ECDSA signature. The field may be + * 96 bytes or 104 bytes depending upon the output format. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digital_signature_service function returns + * zero if the service executed successfully, otherwise, it + * returns non-zero values indicating error. + */ +uint8_t SYS_digital_signature_service +( + const uint8_t* p_hash, + uint8_t format, + uint8_t* p_response, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_secure_nvm_write() function writes data in the sNVM region. + * Data gets stored in the following format: + * - Non-authenticated plaintext + * - Authenticated plaintext + * - Authenticated ciphertext + * + * Note: If you are executing this function with Authenticated plaintext + * or Authenticated ciphertext on a device whose sNVM was never previously + * written to, then the service may fail. For it to work, you must first write + * Authenticated data to the sNVM using Libero along with USK client and + * custom security. This flow generates the SMK. See UG0753 PolarFire FPGA + * Security User Guide for further details. + + * @param format The format parameter specifies the format used to write + * data in sNVM region. The different type of text formats + * are as follow: + * - NON_AUTHENTICATED_PLAINTEXT_FORMAT + * - AUTHENTICATED_PLAINTEXT_FORMAT + * - AUTHENTICATED_CIPHERTEXT_FORMAT + * + * @param snvm_module The snvm_module parameter specifies the the sNVM module + * in which the data need to be written. + * + * @param p_data The p_data parameter is a pointer to a buffer which + * contains the data to be stored in sNVM region. The data + * length to be written is fixed depending on the format + * parameter. If NON_AUTHENTICATED_PLAINTEXT_FORMAT is + * selected, then you can write 252 bytes in the sNVM module. + * For other two formats the data length is 236 bytes. + * + * @param p_user_key The p_user_key parameter is a pointer to a buffer which + * contain the 96-bit key USK (user secret key). This user + * secret key will enhance the security when authentication + * is used. That is, when Authenticated plaintext and + * Authenticated ciphertext format is selected. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digital_signature_service function returns + * zero if the service executed successfully, otherwise, it + * returns non-zero values indicating error. + */ +uint8_t SYS_secure_nvm_write +( + uint8_t format, + uint8_t snvm_module, + const uint8_t* p_data, + const uint8_t* p_user_key, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_secure_nvm_read() function is used to read data present in sNVM region. + * User should provide USK key, if the data was programmed using authentication. + * If the data was written in the sNVM using the authenticated plaintext or the + * authenticated ciphertext service option then this service will return the + * valid data only when authentication is successful. For more details, see + * SYS_secure_nvm_write() function. If the data was written in + * the sNVM using the authenticated plaintext or the authenticated ciphertext + * service option then this service will return the valid data only when + * authentication is successful. For more details, see SYS_secure_nvm_write() + * function and its parameter description. + * + * @param snvm_module The snvm_module parameter specifies the sNVM module + * from which the data need to be read. + * + * @param p_user_key The p_user_key parameter is a pointer to a buffer which + * contain the 96-bit key USK (user secret key). User should + * provide same secret key which is previously used for + * authentication while writing data in sNVM region. + * + * @param p_admin The p_admin parameter is a pointer to the buffer where + * the output page admin data is stored. The page admin + * data is 4 bytes long. + * + * @param p_data The p_data parameter is a pointer to a buffer which + * contains the data read from sNVM region. User should + * provide the buffer large enough to store the read data. + * + * @param data_len The data_len parameter specifies the number of bytes to be + * read from sNVM. + * The application should know whether the data written in the + * chose sNVM module was previously stored using Authentication + * or not. + * The data_len should be 236 bytes, for authenticated data. + * For not authenticated data the data_len should be 252 bytes. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digital_signature_service function returns + * zero if the service executed successfully, otherwise, it + * returns non-zero values indicating error. + */ +uint8_t SYS_secure_nvm_read +( + uint8_t snvm_module, + const uint8_t* p_user_key, + uint8_t* p_admin, + uint8_t* p_data, + uint16_t data_len, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_nonce_service() is used to issue "Nonce Service" system + * service to the system controller. + * + * @param p_nonce The p_nonce parameter is a pointer to a buffer + * in which the data returned by system controller is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code means + * that the service was executed successfully and a non-zero + * value indicates error. See the document link + * provided in the theory of operation section to know more + * about the service and service response. + */ +uint8_t SYS_nonce_service +( + const uint8_t * p_nonce, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_bitstream_authenticate_service() function is used to authenticate + * the Bitstream which is located in SPI through a system service routine. Prior + * to using the IAP service, it may be required to first validate the new + * bitstream before committing the device to reprogramming, thus avoiding the + * need to invoke recovery procedures if the bitstream is invalid. + * + * This service is applicable to bitstreams stored in SPI Flash memory only. + * + * @param spi_flash_address + * The spi_flash_address parameter specifies the address within + * SPI Flash memory where the bit-stream is stored. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_bitstream_authenticate_service function will return + * zero if the service executed successfully and the non-zero + * response from system controller indicates error. See + * the document link provided in the theory of + * operation section to know more about the service and service + * response. + */ +uint8_t SYS_bitstream_authenticate_service +( + uint32_t spi_flash_address, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_IAP_image_authenticate_service() function is used to authenticate + * the IAP image which is located in SPI through a system service routine. The + * service checks the image descriptor and the referenced bitstream and optional + * initialization data. If the image is authenticated successfully, then the + * image is guaranteed to be valid when used by an IAP function. + * + * This service is applicable to bitstreams stored in SPI Flash memory only. + * + * @param spi_idx + * The spi_idx parameter specifies the index in the SPI directory to + * be used where the IAP bit-stream is stored. + * Note: To support recovery SPI_IDX=1 should be an empty slot and the recovery + * image should be located in SPI_IDX=0. Since SPI_IDX=1 should be an + * empty slot, it shouldn’t be passed into the system service. + * + * @return The SYS_IAP_image_authenticate_service function will return + * zero if the service executed successfully the non-zero + * response from system controller indicates error. Please + * refer to the document link provided in the theory of + * operation section to know more about the service and service + * response. + */ +uint8_t SYS_IAP_image_authenticate_service +( + uint8_t spi_idx +); + +/***************************************************************************//** + * The SYS_digest_check_service() function is used to Recalculates and compares + * digests of selected non-volatile memories. If the fabric digest is to be + * checked, then the user design must follow all prerequisite steps for the + * FlashFreeze service before invoking this service. + * This service is applicable to bitstreams stored in SPI Flash memory only. + * @param options + * The options parameter specifies the digest check options which + * indicate the area on which the digest check should be performed. + * Below is the list of options. You can OR these options to indicate + * to perform digest check on multiple segments. + * Note: The options parameter is of 2 bytes when used with PF + * device and 4 bytes when used with PolarFire SoC device. + * Options[i] | Description + * ---------------|---------------------------------- + * 0x01 | Fabric digest + * 0x02 | Fabric Configuration (CC) segment + * 0x04 | ROM digest in SNVM segment + * 0x08 | UL segment + * 0x10 | UKDIGEST0 in User Key segment + * 0x20 | UKDIGEST1 in User Key segment + * 0x40 | UKDIGEST2 in User Key segment (UPK1) + * 0x80 | UKDIGEST3 in User Key segment (UK1) + * 0x100 | UKDIGEST4 in User Key segment (DPK) + * 0x200 | UKDIGEST5 in User Key segment (UPK2) + * 0x400 | UKDIGEST6 in User Key segment (UK2) + * 0x800 | UFS Permanent lock (UPERM) segment + * 0x1000 | Factory and Factory Key Segments. + * 0x2000 | UKDIGEST7 in User Key segment (HWM) (PFSoC) + * 0x4000 | ENVMDIGEST (PFSoC only) + * 0x8000 | UKDIGEST8 for MSS Boot Info (PFSoC only) + * 0x10000 | SNVM_RW_ACCESS_MAP Digest (PFSoC only) + * 0x20000 | SBIC revocation digest (PFSoC only) + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digest_check_service function will return + * zero if the service executed successfully the non-zero + * response from system controller indicates error. Pleaes + * refer to the document link provided in the theory of + * operation section to know more about the service and service + * response. + */ +uint8_t SYS_digest_check_service +( + uint32_t options, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_iap_service() function is used to IAP service. The IAP service allows + * the user to reprogram the device without the need for an external master. The + * user design writes the bitstream to be programmed into a SPI Flash connected + * to the SPI port. When the service is invoked, the System Controller + * automatically reads the bitstream from the SPI flash and programs the device. + * The service allows the image to be executed in either VERIFY or PROGRAM modes. + * Another option for IAP is to perform the auto-update sequence. In this case + * the newest image of the first two images in the SPI directory is chosen to be + * programmed. + * + * @param iap_cmd + * The iap_cmd parameter specifies the specific IAP command which + * depends upon VERIFY or PROGRAM modes and the SPI address method. + * iap_cmd | Description + * -----------------------|------------ + * IAP_PROGRAM_BY_SPIIDX_CMD | IAP program. + * IAP_VERIFY_BY_SPIIDX_CMD | Fabric Configuration (CC) segment + * IAP_PROGRAM_BY_SPIADDR_CMD | ROM digest in SNVM segment + * IAP_VERIFY_BY_SPIADDR_CMD | UL segment + * IAP_AUTOUPDATE_CMD | UKDIGEST0 in User Key segment + * + * @param spiaddr + * The spiaddr parameter specifies either the index + * in the SPI directory or the SPI address in the SPI Flash memory. + * Below is the list of the possible meaning of spiaddr parameter + * in accordance with the iap_cmd parameter. + * iap_cmd | spiaddr + * ----------------------|----------------- + * IAP_PROGRAM_BY_SPIIDX_CMD | Index in the SPI directory. + * IAP_VERIFY_BY_SPIIDX_CMD | Index in the SPI directory. + * IAP_PROGRAM_BY_SPIADDR_CMD | SPI address in the SPI Flash memory + * IAP_VERIFY_BY_SPIADDR_CMD | SPI address in the SPI Flash memory + * IAP_AUTOUPDATE_CMD | spiaddr is ignored as No index/address required for this command. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * Note: For the IAP services with command IAP_PROGRAM_BY_SPIIDX_CMD and + * IAP_VERIFY_BY_SPIIDX_CMD To support recovery SPI_IDX=1 should be an + * empty slot and the recovery image should be located in SPI_IDX=0. + * Since SPI_IDX=1 should be an empty slot it shouldn’t be passed into + * the system service. + * + * @return The SYS_iap_service function will return zero if the service + * executed successfully and the non-zero response from system + * controller indicates error. Please refer to the document + * link provided in the theory of operation section to know + * more about the service and service response. + */ +uint8_t SYS_iap_service +( + uint8_t iap_cmd, + uint32_t spiaddr, + uint16_t mb_offset +); + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_SYSSERV_PF_H */ diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h new file mode 100644 index 0000000..8b14b7e --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h @@ -0,0 +1,149 @@ +/******************************************************************************* + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Register bit offsets and masks definitions for CoreSysServices_PF driver. + */ + +#ifndef __CORE_SYSSERV_PF_REGISTERS +#define __CORE_SYSSERV_PF_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * SYS_SERV_CMD (offset 0x04) register details + */ +#define SS_CMD_REG_OFFSET 0x04u + +#define SS_CMD_OFFSET 0x04 +#define SS_CMD_MASK 0x0000FFFFu +#define SS_CMD_SHIFT 0u + +/*------------------------------------------------------------------------------ + * SYS_SERV_STAT (offset 0x08) register details + */ +#define SS_STAT_REG_OFFSET 0x08u + +#define SS_STAT_OFFSET 0x08 +#define SS_STAT_MASK 0x0000FFFFu +#define SS_STAT_SHIFT 0u + +/*------------------------------------------------------------------------------ + * SYS_SERV_REQ (offset 0x0C) register details + */ +#define SS_REQ_REG_OFFSET 0x0Cu + + +#define SS_REQ_REQ_OFFSET 0x0Cu +#define SS_REQ_REQ_MASK 0x00000001UL +#define SS_REQ_REQ_SHIFT 0u + +#define SS_REQ_ABUSY_OFFSET 0x0Cu +#define SS_REQ_ABUSY_MASK 0x00000002UL +#define SS_REQ_ABUSY_SHIFT 1u + +#define SS_REQ_NABUSY_OFFSET 0x0Cu +#define SS_REQ_NABUSY_MASK 0x00000004UL +#define SS_REQ_NABUSY_SHIFT 2u + +#define SS_REQ_SSBUSY_OFFSET 0x0Cu +#define SS_REQ_SSBUSY_MASK 0x00000008UL +#define SS_REQ_SSBUSY_SHIFT 3u + +#define SS_REQ_AREQ_OFFSET 0x0Cu +#define SS_REQ_AREQ_MASK 0x00000010UL +#define SS_REQ_AREQ_SHIFT 4u + +#define SS_REQ_NAREQ_OFFSET 0x0Cu +#define SS_REQ_NAREQ_MASK 0x00000020UL +#define SS_REQ_NAREQ_SHIFT 5u +/*------------------------------------------------------------------------------ + * MBX_ECCSTATUS (offset 0x10) register details + */ +#define MBX_ECCSTATUS_REG_OFFSET 0x10u + +#define MBX_ECCSTATUS_OFFSET 0x10 +#define MBX_ECCSTATUS_MASK 0x03u +#define MBX_ECCSTATUS_SHIFT 0u + + +/*------------------------------------------------------------------------------ + * MBX_WCNT (offset 0x14) register details + */ +#define MBX_WCNT_REG_OFFSET 0x14u + +#define MBX_WCNT_OFFSET 0x14 +#define MBX_WCNT_MASK 0x000001FFu +#define MBX_WCNT_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_RWCNT (offset 0x18) register details + */ +#define MBX_RCNT_REG_OFFSET 0x18u + +#define MBX_RCNT_OFFSET 0x18 +#define MBX_RCNT_MASK 0x000001FFu +#define MBX_RCNT_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_WADRDESC (offset 0x1C) register details + */ +#define MBX_WADDR_REG_OFFSET 0x1Cu + +#define MBX_WADDR_OFFSET 0x1C +#define MBX_WADDR_MASK 0x000001FFu +#define MBX_WADDR_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_RADRDESC (offset 0x20) register details + */ +#define MBX_RADDR_REG_OFFSET 0x20u + +#define MBX_RADDR_OFFSET 0x20 +#define MBX_RADDR_MASK 0x000001FFu +#define MBX_RADDR_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_WDATA (offset 0x28) register details + */ +#define MBX_WDATA_REG_OFFSET 0x28u + +#define MBX_WDATA_OFFSET 0x28 +#define MBX_WDATA_MASK 0xFFFFFFFFu +#define MBX_WDATA_SHIFT 0u + + +/*------------------------------------------------------------------------------ + * MBX_RDATA (offset 0x2C) register details + */ +#define MBX_RDATA_REG_OFFSET 0x2Cu + +#define MBX_RDATA_OFFSET 0x2C +#define MBX_RDATA_MASK 0xFFFFFFFFu +#define MBX_RDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * SS_USER (offset 0x30) register details + */ +#define SS_USER_REG_OFFSET 0x30u + +#define SS_USER_BUSY_OFFSET 0x30 +#define SS_USER_BUSY_MASK 0x00000001u +#define SS_USER_BUSY_SHIFT 0u + +#define SS_USER_RDVLD_OFFSET 0x30 +#define SS_USER_RDVLD_MASK 0x00000002u +#define SS_USER_RDVLD_SHIFT 1u + +#define SS_USER_CMDERR_OFFSET 0x30 +#define SS_USER_CMDERR_MASK 0x00000004u +#define SS_USER_CMDERR_SHIFT 2u + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_SYSSERV_PF_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c new file mode 100644 index 0000000..0c0a866 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c @@ -0,0 +1,297 @@ +/******************************************************************************* + * (c) Copyright 2007-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file core_uart_apb.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreUARTapb driver implementation. See file "core_uart_apb.h" for + * description of the functions implemented in this file. + * + */ + +#include "coreuartapb_regs.h" +#include "core_uart_apb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define NULL_INSTANCE ( ( UART_instance_t* ) 0 ) +#define NULL_BUFFER ( ( uint8_t* ) 0 ) + +#define MAX_LINE_CONFIG ( ( uint8_t )( DATA_8_BITS | ODD_PARITY ) ) +#define MAX_BAUD_VALUE ( ( uint16_t )( 0x1FFF ) ) +#define STATUS_ERROR_MASK ( ( uint8_t )( STATUS_PARITYERR_MASK | \ + STATUS_OVERFLOW_MASK | \ + STATUS_FRAMERR_MASK ) ) +#define BAUDVALUE_LSB ( (uint16_t) (0x00FF) ) +#define BAUDVALUE_MSB ( (uint16_t) (0xFF00) ) +#define BAUDVALUE_SHIFT ( (uint8_t) (5) ) + +#define STATUS_ERROR_OFFSET STATUS_PARITYERR_SHIFT + +/***************************************************************************//** + * UART_init() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_init +( + UART_instance_t * this_uart, + addr_t base_addr, + uint16_t baud_value, + uint8_t line_config +) +{ + uint8_t rx_full; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( line_config <= MAX_LINE_CONFIG ) + HAL_ASSERT( baud_value <= MAX_BAUD_VALUE ) + + if( ( this_uart != NULL_INSTANCE ) && + ( line_config <= MAX_LINE_CONFIG ) && + ( baud_value <= MAX_BAUD_VALUE ) ) + { + /* + * Store lower 8-bits of baud value in CTRL1. + */ + HAL_set_8bit_reg( base_addr, CTRL1, (uint_fast8_t)(baud_value & + BAUDVALUE_LSB ) ); + + /* + * Extract higher 5-bits of baud value and store in higher 5-bits + * of CTRL2, along with line configuration in lower 3 three bits. + */ + HAL_set_8bit_reg( base_addr, CTRL2, (uint_fast8_t)line_config | + (uint_fast8_t)((baud_value & + BAUDVALUE_MSB) >> BAUDVALUE_SHIFT ) ); + + this_uart->base_address = base_addr; +#ifndef NDEBUG + { + uint8_t config; + uint8_t temp; + uint16_t baud_val; + baud_val = HAL_get_8bit_reg( this_uart->base_address, CTRL1 ); + config = HAL_get_8bit_reg( this_uart->base_address, CTRL2 ); + /* + * To resolve operator precedence between & and << + */ + temp = ( config & (uint8_t)(CTRL2_BAUDVALUE_MASK ) ); + baud_val |= (uint16_t)( (uint16_t)(temp) << BAUDVALUE_SHIFT ); + config &= (uint8_t)(~CTRL2_BAUDVALUE_MASK); + HAL_ASSERT( baud_val == baud_value ); + HAL_ASSERT( config == line_config ); + } +#endif + + /* + * Flush the receive FIFO of data that may have been received before the + * driver was initialized. + */ + rx_full = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_RXFULL_MASK; + while ( rx_full ) + { + HAL_get_8bit_reg( this_uart->base_address, RXDATA ); + rx_full = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_RXFULL_MASK; + } + + /* + * Clear status of the UART instance. + */ + this_uart->status = (uint8_t)0; + } +} + +/***************************************************************************//** + * UART_send() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_send +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +) +{ + size_t char_idx; + uint8_t tx_ready; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( tx_buffer != NULL_BUFFER ) + HAL_ASSERT( tx_size > 0 ) + + if( (this_uart != NULL_INSTANCE) && + (tx_buffer != NULL_BUFFER) && + (tx_size > (size_t)0) ) + { + for ( char_idx = (size_t)0; char_idx < tx_size; char_idx++ ) + { + /* Wait for UART to become ready to transmit. */ + do { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( !tx_ready ); + /* Send next character in the buffer. */ + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)tx_buffer[char_idx] ); + } + } +} + +/***************************************************************************//** + * UART_fill_tx_fifo() + * See "core_uart_apb.h" for details of how to use this function. + */ +size_t +UART_fill_tx_fifo +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +) +{ + uint8_t tx_ready; + size_t size_sent = 0u; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( tx_buffer != NULL_BUFFER ) + HAL_ASSERT( tx_size > 0 ) + + /* Fill the UART's Tx FIFO until the FIFO is full or the complete input + * buffer has been written. */ + if( (this_uart != NULL_INSTANCE) && + (tx_buffer != NULL_BUFFER) && + (tx_size > 0u) ) + { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + if ( tx_ready ) + { + do { + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)tx_buffer[size_sent] ); + size_sent++; + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( (tx_ready) && ( size_sent < tx_size ) ); + } + } + return size_sent; +} + +/***************************************************************************//** + * UART_get_rx() + * See "core_uart_apb.h" for details of how to use this function. + */ +size_t +UART_get_rx +( + UART_instance_t * this_uart, + uint8_t * rx_buffer, + size_t buff_size +) +{ + uint8_t new_status; + uint8_t rx_full; + size_t rx_idx = 0u; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( rx_buffer != NULL_BUFFER ) + HAL_ASSERT( buff_size > 0 ) + + if( (this_uart != NULL_INSTANCE) && + (rx_buffer != NULL_BUFFER) && + (buff_size > 0u) ) + { + rx_idx = 0u; + new_status = HAL_get_8bit_reg( this_uart->base_address, STATUS ); + this_uart->status |= new_status; + rx_full = new_status & STATUS_RXFULL_MASK; + while ( ( rx_full ) && ( rx_idx < buff_size ) ) + { + rx_buffer[rx_idx] = HAL_get_8bit_reg( this_uart->base_address, + RXDATA ); + rx_idx++; + new_status = HAL_get_8bit_reg( this_uart->base_address, STATUS ); + this_uart->status |= new_status; + rx_full = new_status & STATUS_RXFULL_MASK; + } + } + return rx_idx; +} + +/***************************************************************************//** + * UART_polled_tx_string() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_polled_tx_string +( + UART_instance_t * this_uart, + const uint8_t * p_sz_string +) +{ + uint32_t char_idx; + uint8_t tx_ready; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( p_sz_string != NULL_BUFFER ) + + if( ( this_uart != NULL_INSTANCE ) && ( p_sz_string != NULL_BUFFER ) ) + { + char_idx = 0U; + while( 0U != p_sz_string[char_idx] ) + { + /* Wait for UART to become ready to transmit. */ + do { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( !tx_ready ); + /* Send next character in the buffer. */ + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)p_sz_string[char_idx] ); + char_idx++; + } + } +} + +/***************************************************************************//** + * UART_get_rx_status() + * See "core_uart_apb.h" for details of how to use this function. + */ +uint8_t +UART_get_rx_status +( + UART_instance_t * this_uart +) +{ + uint8_t status = UART_APB_INVALID_PARAM; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + /* + * Extract UART error status and place in lower bits of "status". + * Bit 0 - Parity error status + * Bit 1 - Overflow error status + * Bit 2 - Frame error status + */ + if( this_uart != NULL_INSTANCE ) + { + status = ( ( this_uart->status & STATUS_ERROR_MASK ) >> + STATUS_ERROR_OFFSET ); + /* + * Clear the sticky status for this instance. + */ + this_uart->status = (uint8_t)0; + } + return status; +} + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h new file mode 100644 index 0000000..c016403 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h @@ -0,0 +1,451 @@ +/******************************************************************************* + * (c) Copyright 2007-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file core_uart_apb.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief This file contains the application programming interface for the + * CoreUARTapb bare metal driver. + * + */ +/*=========================================================================*//** + @mainpage CoreUARTapb Bare Metal Driver. + + @section intro_sec Introduction + CoreUARTapb is an implementation of the Universal Asynchronous + Receiver/Transmitter aimed at minimal FPGA tile usage within a Microchip FPGA. + The CoreUARTapb bare metal software driver is designed to be used in systems + with no operating system. + + The CoreUARTapb driver provides functions for basic polled transmitting and + receiving operations. It also provide functions that allow the use of the + CoreUARTapb in interrupt-driven mode but leaves the management of interrupts + to the calling application, as interrupt enabling and disabling are not + controlled through the CoreUARTapb registers. The CoreUARTapb driver is + provided as C source code. + + @section driver_configuration Driver Configuration + Your application software should configure the CoreUARTapb driver by calling + the UART_init() function for each CoreUARTapb instance in the hardware design. + The configuration parameters include the CoreUARTapb hardware instance base + address and other runtime parameters, such as baud rate, bit width, and + parity. No CoreUARTapb hardware configuration parameters are needed by the + driver, apart from the CoreUARTapb hardware instance base address. Hence, no + additional configuration files are required to use the driver. + + A CoreUARTapb hardware instance is generated with fixed baud rate, character + size, and parity configuration settings as part of the hardware flow. The + baud_value and line_config parameter values passed to the UART_init() function + have no effect if fixed values were selected for the baud rate, character + size, and parity in the hardware configuration of CoreUARTapb. When fixed + values are selected for these hardware configuration parameters, the driver is + unable to overwrite the fixed values in the CoreUARTapb control registers, + CTRL1 and CTRL2. + + @section theory_op Theory of Operation + The CoreUARTapb software driver is designed to allow the control of multiple + instances of CoreUARTapb. Each instance of CoreUARTapb in the hardware design + is associated with a single instance of the UART_instance_t structure in the + software. You need to allocate memory for one unique UART_instance_t structure + instance for each CoreUARTapb hardware instance. The contents of these data + structures are initialized while calling the UART_init() function. A pointer + to the structure is passed to the subsequent driver functions in order to + identify the CoreUARTapb hardware instance you wish to perform the requested + operation on. + + Note: Do not attempt to directly manipulate the content of UART_instance_t + structures. This structure is only intended to be modified by the driver + function. + + Once initialized, the driver transmits and receives data. Transmit is + performed using the UART_send() function. If this function blocks, then it + returns only when the data passed to it has been sent to the CoreUARTapb + hardware. Data received by the CoreUARTapb hardware is read by the user + application using the UART_get_rx() function. + + The UART_fill_tx_fifo() function is also provided as a part of the + interrupt-driven transmit. This function fills the CoreUARTapb hardware + transmit FIFO with the content of a data buffer passed as a parameter before + returning. The control of the interrupts must be implemented outside the + driver, as the CoreUARTapb hardware does not provide the ability to enable + or disable its interrupt sources. + + The UART_polled_tx_string() function is provided to transmit a NULL-terminated + string in polled mode. If this function blocks, then it returns only when the + data passed to it has been sent to the CoreUARTapb hardware. + + The UART_get_rx_status() function returns the error status of the CoreUARTapb + receiver. This is used by applications to take appropriate action in case of + receiver errors. +*//*=========================================================================*/ +#ifndef __CORE_UART_APB_H +#define __CORE_UART_APB_H 1 + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + Data Bits Length Defines + ======================== + These constants define the data length in a UART packet. + | Constant | Description | + |-------------|---------------------------------------| + | DATA_7_BITS | Data length is 7-bits | + | DATA_8_BITS | Data length is 8-bits | + */ +#define DATA_7_BITS 0x00u +#define DATA_8_BITS 0x01u + +/***************************************************************************//** + Parity Defines + ============== + These constants define parity check options. + | Constant | Description | + |-------------|---------------------------------------| + | NO_PARITY | No Parity bit | + | EVEN_PARITY | Even Parity bit | + | ODD_PARITY | ODD Parity bit | + */ +#define NO_PARITY 0x00u +#define EVEN_PARITY 0x02u +#define ODD_PARITY 0x06u + +/***************************************************************************//** + Error Status Definitions + ======================== + These constants define the different types of possible errors in UART + transmission of data. + | Constant | Description | + |-------------------------|---------------------------------------| + | UART_APB_PARITY_ERROR | Data parity error | + | UART_APB_OVERFLOW_ERROR | Data overflow error | + | UART_APB_FRAMING_ERROR | Data framing error | + | UART_APB_NO_ERROR | No error | + | UART_APB_INVALID_PARAM | Invalid parameter | + */ +#define UART_APB_PARITY_ERROR 0x01u +#define UART_APB_OVERFLOW_ERROR 0x02u +#define UART_APB_FRAMING_ERROR 0x04u +#define UART_APB_NO_ERROR 0x00u +#define UART_APB_INVALID_PARAM 0xFFu + +/***************************************************************************//** + * There should be one instance of this structure for each instance of + * CoreUARTapb in your system. This structure instance identifies various UARTs + * in a system and should be passed as first parameter to UART functions to + * identify which UART performs the requested operation. The 'status' element in + * the structure is used to provide sticky status information. + */ +typedef struct +{ + addr_t base_address; + uint8_t status; +} UART_instance_t; + +/***************************************************************************//** + * The UART_init() function initializes the UART with the configuration passed + * as parameters. The configuration parameters are the baud_value that generates + * the baud rate and the line configuration (bit length and parity). + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data regarding + * this instance of the CoreUARTapb. This pointer is used to + * identify the target CoreUARTapb hardware instance in + * subsequent calls to the CoreUARTapb functions. + * @param base_addr The base_address parameter is the base address in the + * processor's memory map for the registers of the + * CoreUARTapb instance being initialized. + * @param baud_value The baud_value parameter selects the baud rate for the + * UART. The baud value is calculated from the frequency of + * the system clock in hertz and the desired baud rate using + * the following equation: + * baud_value = (clock / (baud_rate * 16)) - 1. + * The baud_value parameter must be a value in the range 0 + * to 8191 (or 0x0000 to 0x1FFF). + * @param line_config This parameter is the line configuration, specifies the + * bit length and parity settings. This is the logical OR of: + * - DATA_7_BITS + * - DATA_8_BITS + * - NO_PARITY + * - EVEN_PARITY + * - ODD_PARITY + * For example, 8 bits even parity would be specified as + * (DATA_8_BITS | EVEN_PARITY). + * @return This function does not return a value. + * @example + * @code + * #define BAUD_VALUE_57600 25 + * + * #define COREUARTAPB0_BASE_ADDR 0xC3000000UL + * + * UART_instance_t g_uart; + * int main() + * { + * UART_init(&g_uart, COREUARTAPB0_BASE_ADDR, + BAUD_VALUE_57600, (DATA_8_BITS | EVEN_PARITY)); + * } + * @endcode + */ +void +UART_init +( + UART_instance_t * this_uart, + addr_t base_addr, + uint16_t baud_value, + uint8_t line_config +); + +/***************************************************************************//** + * The UART_send() function is used to transmit data. It transfers the content + * of the transmitter data buffer, passed as a function parameter, into the + * UART's hardware transmitter FIFO. It returns when the full content of the + * transmitter data buffer has been transferred to the UART's transmitter FIFO. + * + * Note: You should not assume that the data you are sending using this function + * has been received at the other end by the time this function returns. The + * actual transmission over the serial connection is still be taking place at + * the time of the function return. It is safe to release or reuse the memory + * used as the transmit buffer once this function returns. + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data + * regarding this instance of the CoreUARTapbUART. + * @param tx_buffer The tx_buffer parameter is a pointer to a buffer that + * contains the data to be transmitted. + * @param tx_size The tx_size parameter is the size in bytes of the + * transmitted data. + * + * @return This function does not return a value. + * + * @example + * @code + * uint8_t testmsg1[] = {"\n\r\n\r\n\rUART_send() test message 1"}; + * UART_send(&g_uart,(const uint8_t *)&testmsg1,sizeof(testmsg1)); + * @endcode + */ +void +UART_send +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +); + +/***************************************************************************//** + * The UART_fill_tx_fifo() function fills the UART's transmitter hardware FIFO + * with the data found in the transmitter buffer that is passed in as a + * function parameter. The function returns either when the FIFO is full or + * when the complete contents of the transmitter buffer have been copied into + * the FIFO. It returns the number of bytes copied into the UART's transmitter + * hardware FIFO. This function is intended to be used as part of + * interrupt-driven transmission. + * + * Note: You should not assume that the data you transmit using this function + * has been received at the other end by the time this function returns. The + * actual transmission over the serial connection is still be taking place at + * the time of the function return. + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data + * regarding this instance of the UART. + * @param tx_buffer The tx_buffer parameter is a pointer to a buffer that + * contains the data to be transmitted. + * @param tx_size The tx_size parameter is the size in bytes of the + * transmitted data. + * @return This function returns the number of bytes copied into + * the UART's transmitter hardware FIFO. + * + * @example + * @code + * void send_using_interrupt + * ( + * uint8_t * pbuff, + * size_t tx_size + * ) + * { + * size_t size_in_fifo; + * size_in_fifo = UART_fill_tx_fifo( &g_uart, pbuff, tx_size ); + * } + * @endcode + */ +size_t +UART_fill_tx_fifo +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +); + +/***************************************************************************//** + * The UART_get_rx() function reads the content of the UART's receiver hardware + * FIFO and stores it in the receiver buffer that is passed in as a function + * parameter. It copies either the full contents of the FIFO into the receiver + * buffer, or just enough data from the FIFO to fill the receiver buffer, + * depending on the size of the receiver buffer. The size of the receiver + * buffer is passed in as a function parameter. UART_get_rx() returns the number + * of bytes copied into the receiver buffer. If no data was received at the time + * the function is called, the function returns 0. + * + * Note: This function reads and accumulates the receiver status of the + * CoreUARTapb instance before reading each byte from the receiver's + * data register/FIFO. This allows the driver to maintain a sticky + * record of any receiver errors that occur as the UART receives each + * data byte; receiver errors would otherwise be lost after each read + * from the receiver's data register. A call to the UART_get_rx_status() + * function returns any receiver errors accumulated during the execution + * of the UART_get_rx() function. + * + * Note: When FIFO mode is disabled in the CoreUARTapb hardware configuration, + * the driver accumulates a sticky record of any parity errors, framing + * errors, or overflow errors. When FIFO mode is enabled, the driver + * accumulates a sticky record of overflow errors only; in this case, + * interrupts must be used to handle parity errors or framing errors. + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data + * regarding this instance of the UART. + * @param rx_buffer The rx_buffer parameter is a pointer to a buffer where + * the received data is copied. + * @param buff_size The buff_size parameter is the size of the receive + * buffer in bytes. + * @return This function returns the number of bytes copied into + * the receive buffer. + * + * @example + * @code + * #define MAX_RX_DATA_SIZE 256 + * + * uint8_t rx_data[MAX_RX_DATA_SIZE]; + * uint8_t rx_size = 0; + * + * rx_size = UART_get_rx( &g_uart, rx_data, sizeof(rx_data) ); + * @endcode + */ +size_t +UART_get_rx +( + UART_instance_t * this_uart, + uint8_t * rx_buffer, + size_t buff_size +); + +/***************************************************************************//** + * The UART_polled_tx_string() function is used to transmit a NULL ('\0') + * terminated string. Internally, it polls for the transmit ready status and + * transfers the text starting at the address pointed by p_sz_string into + * the UART's hardware transmitter FIFO. It is a blocking function and returns + * only when the complete string has been transferred to the UART's transmit + * FIFO. + * + * Note: You should not assume that the data you transmit using this function + * has been received at the other end by the time this function returns. The + * actual transmission over the serial connection is still be taking place at + * the time of the function return. + * + * @param this_uart The this_uart parameter is the pointer to a + * UART_instance_t structure, which holds all data + * regarding this instance of the UART. + * @param p_sz_string The p_sz_string parameter is a pointer to a buffer + * containing the NULL ('\0') terminated string to be + * transmitted. + * @return This function does not return a value. + * + * @example + * @code + * uint8_t testmsg1[] = {"\r\n\r\nUART_polled_tx_string() test message 1\0"}; + * UART_polled_tx_string(&g_uart,(const uint8_t *)&testmsg1); + * @endcode + */ +void +UART_polled_tx_string +( + UART_instance_t * this_uart, + const uint8_t * p_sz_string +); + +/***************************************************************************//** + * The UART_get_rx_status() function returns the receiver error status of the + * CoreUARTapb instance. It reads both the current error status of the receiver + * and the accumulated error status from preceding calls to the UART_get_rx() + * function and combines them using a bitwise OR. It returns the cumulative + * parity, framing, and overflow error status of the receiver, since the + * previous call to UART_get_rx_status() as an 8-bit encoded value. + * + * Note: The UART_get_rx() function reads and accumulates the receiver status + * of the CoreUARTapb instance before reading each byte from the receiver's data + * register/FIFO. The driver maintains a sticky record of the cumulative error + * status, which persists after the UART_get_rx() function returns. The + * UART_get_rx_status() function clears this accumulated record of receiver + * errors before returning. + * + * @param this_uart The this_uart parameter is a pointer to a + * UART_instance_t structure which holds all data regarding + * this instance of the UART. + * @return This function returns the UART receiver error status as + * an 8-bit encoded value. The return value is 0, if there + * are no receiver errors occurred. The driver provides a + * set of bit mask constants, which should be compared with + * and/or used to mask the returned value to determine the + * receiver error status. + * When the return value is compared to the following bit + * masks, a non-zero result indicates that the + * corresponding error occurred: + * UART_APB_PARITY_ERROR (bit mask = 0x01) + * UART_APB_OVERFLOW_ERROR (bit mask = 0x02) + * UART_APB_FRAMING_ERROR (bit mask = 0x04) + * When the return value is compared to the following bit + * mask, a non-zero result indicates that no error + * occurred: + * UART_APB_NO_ERROR (0x00) + * + * @example + * @code + * UART_instance_t g_uart; + * uint8_t rx_data[MAX_RX_DATA_SIZE]; + * uint8_t err_status; + * err_status = UART_get_err_status(&g_uart); + * + * if(UART_APB_NO_ERROR == err_status ) + * { + * rx_size = UART_get_rx( &g_uart, rx_data, MAX_RX_DATA_SIZE ); + * } + * @endcode + */ +uint8_t +UART_get_rx_status +( + UART_instance_t * this_uart +); + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_UART_APB_H */ diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h new file mode 100644 index 0000000..c123cc3 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h @@ -0,0 +1,133 @@ +/******************************************************************************* + * (c) Copyright 2007-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file coreuartapb_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreUARTapb register definitions + */ + +#ifndef __CORE_UART_APB_REGISTERS +#define __CORE_UART_APB_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * TxData register details + */ +#define TXDATA_REG_OFFSET 0x0u + +/* + * TxData bits. + */ +#define TXDATA_OFFSET 0x0u +#define TXDATA_MASK 0xFFu +#define TXDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * RxData register details + */ +#define RXDATA_REG_OFFSET 0x4u + +/* + * RxData bits. + */ +#define RXDATA_OFFSET 0x4u +#define RXDATA_MASK 0xFFu +#define RXDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * ControReg1 register details + */ +#define CTRL1_REG_OFFSET 0x8u + +/* + * Baud value (Lower 8-bits) + */ +#define CTRL1_BAUDVALUE_OFFSET 0x8u +#define CTRL1_BAUDVALUE_MASK 0xFFu +#define CTRL1_BAUDVALUE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * ControReg2 register details + */ +#define CTRL2_REG_OFFSET 0xCu + +/* + * Bit length + */ +#define CTRL2_BIT_LENGTH_OFFSET 0xCu +#define CTRL2_BIT_LENGTH_MASK 0x01u +#define CTRL2_BIT_LENGTH_SHIFT 0u + +/* + * Parity enable. + */ +#define CTRL2_PARITY_EN_OFFSET 0xCu +#define CTRL2_PARITY_EN_MASK 0x02u +#define CTRL2_PARITY_EN_SHIFT 1u + +/* + * Odd/even parity selection. + */ +#define CTRL2_ODD_EVEN_OFFSET 0xCu +#define CTRL2_ODD_EVEN_MASK 0x04u +#define CTRL2_ODD_EVEN_SHIFT 2u + +/* + * Baud value (Higher 5-bits) + */ +#define CTRL2_BAUDVALUE_OFFSET 0xCu +#define CTRL2_BAUDVALUE_MASK 0xF8u +#define CTRL2_BAUDVALUE_SHIFT 3u + +/*------------------------------------------------------------------------------ + * StatusReg register details + */ +#define StatusReg_REG_OFFSET 0x10u + +#define STATUS_REG_OFFSET 0x10u + +/* + * Transmit ready. + */ +#define STATUS_TXRDY_OFFSET 0x10u +#define STATUS_TXRDY_MASK 0x01u +#define STATUS_TXRDY_SHIFT 0u + +/* + * Receive full. + */ +#define STATUS_RXFULL_OFFSET 0x10u +#define STATUS_RXFULL_MASK 0x02u +#define STATUS_RXFULL_SHIFT 1u + +/* + * Parity error. + */ +#define STATUS_PARITYERR_OFFSET 0x10u +#define STATUS_PARITYERR_MASK 0x04u +#define STATUS_PARITYERR_SHIFT 2u + +/* + * Overflow. + */ +#define STATUS_OVERFLOW_OFFSET 0x10u +#define STATUS_OVERFLOW_MASK 0x08u +#define STATUS_OVERFLOW_SHIFT 3u + +/* + * Frame Error. + */ +#define STATUS_FRAMERR_OFFSET 0x10u +#define STATUS_FRAMERR_MASK 0x10u +#define STATUS_FRAMERR_SHIFT 4u + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_UART_APB_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.c b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.c new file mode 100644 index 0000000..a2f4911 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.c @@ -0,0 +1,765 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Mi-V I2C Soft IP bare-metal driver. This module is delivered as part of + * Extended Sub System(ESS) MIV_ESS. + * Please refer to miv_i2c.h file for more information. + */ + +#include "miv_i2c.h" + +#define MIV_I2C_ERROR 0xFFu + +/*------------------------------------------------------------------------------ + * MIV I2C transaction direction. + */ +#define MIV_I2C_WRITE_DIR 0u +#define MIV_I2C_READ_DIR 1u + +/* -- TRANSACTIONS TYPES -- */ +#define MIV_I2C_NO_TRANSACTION 0u +#define MIV_I2C_MASTER_WRITE_TRANSACTION 1u +#define MIV_I2C_MASTER_READ_TRANSACTION 2u +#define MIV_I2C_MASTER_SEQUENTIAL_READ_TRANSACTION 3u + +/*------------------------------------------------------------------------------ + * MIV I2C HW states + */ +#define MIV_I2C_IDLE 0x00u +#define MIV_I2C_TX_STA_CB 0x01u +#define MIV_I2C_TX_DATA 0x02u +#define MIV_I2C_RX_DATA 0x03u + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_disable_irq() disables the Mi-V I2C interrupt. + */ +void +MIV_I2C_disable_irq +( + void +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_enable_irq() enables the Mi-V I2C interrupt. + */ +void +MIV_I2C_enable_irq +( + void +); + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_init +( + miv_i2c_instance_t *this_i2c, + addr_t base_addr +) +{ + /* Assign the base address + * Clock Prescale value set + * MIV_I2C interrupt enabled + * I2C core enable + */ + psr_t processor_state; + + /* Disabling the interrupts */ + processor_state = HAL_disable_interrupts(); + + /* + * Initialize all items of the this_miv_i2c data structure to zero. This + * initializes all state variables to their init value. It relies on + * the fact that NO_TRANSACTION, MIV_I2C_SUCCESS and I2C_RELEASE_BUS all + * have an actual value of zero. + */ + memset(this_i2c, 0, sizeof(miv_i2c_instance_t)); + + this_i2c->base_addr = base_addr; + + HAL_restore_interrupts(processor_state); +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_config +( + miv_i2c_instance_t *this_i2c, + uint16_t clk_prescale +) +{ + /* Assign the base address + * Clock Prescale value set + * MIV_I2C interrupt enabled + * I2C core enable + */ + psr_t processor_state; + + /* Disabling the interrupts */ + processor_state = HAL_disable_interrupts(); + + /* Before writing to prescale reg, the core enable must be zero */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CTRL_CORE_EN, 0x00u); + + /* Set the prescale value */ + HAL_set_16bit_reg(this_i2c->base_addr, PRESCALE, clk_prescale); + + /* Enable the MIV I2C interrupts */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CTRL_IRQ_EN, 0x01u); + + /* Enable the MIV I2C core */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CTRL_CORE_EN, 0x01u); + + this_i2c->master_state = MIV_I2C_IDLE; + + HAL_restore_interrupts(processor_state); +} + +/* + * Please refer to miv_i2c.h for more info + */ +uint8_t +MIV_I2C_start +( + miv_i2c_instance_t *this_i2c +) +{ + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + /* Generate I2C start condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + HAL_restore_interrupts(processor_state); + + return 0u; +} + +/* + * Please refer to miv_i2c.h for more info + */ +uint8_t +MIV_I2C_stop +( + miv_i2c_instance_t *this_i2c +) +{ + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + /* Generate I2C stop condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + HAL_restore_interrupts(processor_state); + + return 0u; +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_write +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t bus_options, + uint8_t ack_polling_options +) +{ + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + /* I2C write flow + * + * Check I2C status for ongoing transaction + * Populate the structure with input data + * Generate start condition + * Set the write_direction and target address. + */ + + /* Update the transaction only when there is no ongoing I2C transaction */ + if (this_i2c->transaction == MIV_I2C_NO_TRANSACTION) + { + this_i2c->transaction = MIV_I2C_MASTER_WRITE_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MIV_I2C_MASTER_WRITE_TRANSACTION ; + + /* Populate the i2c instance structure */ + + /* Set the target addr */ + this_i2c->target_addr = i2c_target_addr; + this_i2c->dir = MIV_I2C_WRITE_DIR; + + /* Set up the tx buffer */ + this_i2c->master_tx_buffer = write_buffer; + this_i2c->master_tx_size = write_size; + this_i2c->master_tx_idx = 0u; + + /* Set the I2C status in progress and setup the options */ + this_i2c->bus_options = bus_options; + this_i2c->ack_polling_options = ack_polling_options; + this_i2c->master_status = MIV_I2C_IN_PROGRESS; + + + /* Generate I2C start condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* write target address and write bit */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, MIV_I2C_WRITE_DIR); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, i2c_target_addr); + + /* Set WR bit to transmit start condition and control byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + /* Set current master hw state -> transmitted start condition and + * control byte + */ + this_i2c->master_state = MIV_I2C_TX_STA_CB; + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( MIV_I2C_HOLD_BUS == this_i2c->bus_status ) + { + /* Must toggle IACK bit to clear the MIV_I2C IRQ*/ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00); + } + + MIV_I2C_enable_irq(); + + HAL_restore_interrupts(processor_state); + +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_read +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +) +{ + psr_t processor_state; + uint8_t status = MIV_I2C_SUCCESS; + + processor_state = HAL_disable_interrupts(); + + /* MIV I2C Read operation flow + * + * Check for ongoing transaction + * Populate the i2c instance structure + * Generate the start condition + * Set the READ_direction bit and target addr + */ + + uint8_t read_stat = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_TIP); + + /* Update the transaction only when there is no ongoing I2C transaction */ + if (this_i2c->transaction == MIV_I2C_NO_TRANSACTION) + { + this_i2c->transaction = MIV_I2C_MASTER_READ_TRANSACTION; + } + + this_i2c->pending_transaction = MIV_I2C_MASTER_READ_TRANSACTION; + + /* Populate the MIV I2C instance structure */ + + this_i2c->target_addr = i2c_target_addr; + this_i2c->dir = MIV_I2C_READ_DIR; + + /* Populate read buffer */ + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set the BUS and ACK polling options */ + this_i2c->bus_options = bus_options; + this_i2c->ack_polling_options = ack_polling_options; + + /* Generate the start condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* Set the DIR bit and target addr */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, MIV_I2C_READ_DIR); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, i2c_target_addr); + + /* Set the WR bit to transmit the start condition and command byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + /* Set the i2c master state and status transmitting STA and Command Byte */ + this_i2c->master_state = MIV_I2C_TX_STA_CB; + this_i2c->master_status = MIV_I2C_IN_PROGRESS; + + /* Toggle the IACK bit if required */ + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( MIV_I2C_HOLD_BUS == this_i2c->bus_status ) + { + /* Must toggle IACK bit to clear the MIV_I2C IRQ*/ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00); + } + /* Enable the I2C interrupt */ + MIV_I2C_enable_irq(); + + HAL_restore_interrupts(processor_state); +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_write_read +( + miv_i2c_instance_t *this_i2c, + uint8_t target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +) +{ + uint8_t status = MIV_I2C_SUCCESS; + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + uint8_t read_stat = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_TIP); + + /* I2C write read operation flow + * + * Used to read the data from set address offset + * + * Configure the i2c instance structure + * generate the start and configure the dir and target addr + * set wr bit to transmit the start and command byte + * + */ + + /* Update the transaction only when there is no ongoing I2C transaction */ + if (this_i2c->transaction == MIV_I2C_NO_TRANSACTION) + { + this_i2c->transaction = MIV_I2C_MASTER_READ_TRANSACTION; + } + + this_i2c->pending_transaction = MIV_I2C_MASTER_READ_TRANSACTION; + + /* Populate the I2C instance */ + + this_i2c->target_addr = target_addr; + + /* setup the i2c direction */ + this_i2c->dir = MIV_I2C_WRITE_DIR; + + /* set up transmit buffer */ + this_i2c->master_tx_buffer = write_buffer; + this_i2c->master_tx_size = write_size; + this_i2c->master_tx_idx = 0u; + + /* set up receive buffer */ + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set the bus and ack polling options */ + this_i2c->bus_options = bus_options; + this_i2c->ack_polling_options = ack_polling_options; + + /* Generate the start command */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* Set the DIR and target addr */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + /* Set the WR bit to transmit the start command and command byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + /* Set the i2c master state and status transmitting STA and Command Byte */ + this_i2c->master_state = MIV_I2C_TX_STA_CB; + this_i2c->master_status = MIV_I2C_IN_PROGRESS; + + /* + * Clear interrupt if required + */ + if ( MIV_I2C_HOLD_BUS == this_i2c->bus_status ) + { + /* Must toggle IACK bit to clear the MIV_I2C IRQ*/ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00u); + } + + /* Enable the I2C interrupt */ + MIV_I2C_enable_irq(); + + HAL_restore_interrupts(processor_state); +} + +/* MIV_I2C_isr() + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_isr +( + miv_i2c_instance_t *this_i2c +) +{ + uint8_t i2c_state; + uint8_t i2c_ack_status; + uint8_t i2c_al_status; + uint8_t hold_bus; + + /* Read the I2C master state */ + i2c_state = this_i2c->master_state; + + /* Read the ack and al status */ + i2c_ack_status = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_RXACK); + i2c_al_status = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_AL); + + switch (i2c_state) + { + /* I2C ISR State Machine + * + * Cases: + * - Transmit start condition and control byte + * - Received ACK and bus arbitration was not lost (Read or Write) + * - Received NACK + * - Bus arbitration lost + * + * - Transmit data + * - Received ACK and bus arbitration was not lost (Read or Write) + * - Received NACK + * - Bus arbitration lost + * + * - Receive data + * - Received ACK and bus arbitration was not lost (Read or Write) + * - Bus arbitration lost + */ + + case MIV_I2C_TX_STA_CB: + + /* Received ACK from target and I2C bus arbitration is not lost */ + if (i2c_ack_status == 0u && i2c_al_status == 0u) + { + /* If I2C master write operation */ + if (this_i2c->dir == MIV_I2C_WRITE_DIR) + { + /* write first byte of data and set the WR bit to transfer the data */ + HAL_set_8bit_reg(this_i2c->base_addr, TRANSMIT, + this_i2c->master_tx_buffer[this_i2c->master_tx_idx]); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + /* Increment the index */ + this_i2c->master_tx_idx++; + + /* Set the master state to TX data */ + this_i2c->master_state = MIV_I2C_TX_DATA; + } + /* Master read operation */ + else + { + if (this_i2c->master_rx_size == 1u) + { + /* Send the ACK if the rx size is 1, transmit NACK to slave + * after receiving 1 byte to indicate slave to stop sending + * the data + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_ACK, 0x01u); + } + + /* Send the RD command to slave */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_RD, 0x01u); + + /* Increment the index */ + this_i2c->master_rx_idx++; + + /* Change state to receive data */ + this_i2c->master_state = MIV_I2C_RX_DATA; + } + } + else if (i2c_ack_status == 1u) + { + if (this_i2c->ack_polling_options == MIV_I2C_ACK_POLLING_ENABLE) + { + /* Target responded with NACK and ACK polling option is enabled + * + * Re-send the start condition and control byte + * + * TO-DO: This might become infinite loop check for timeout + * options. + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + this_i2c->master_tx_idx = 0u; + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + else + { + /* Target responded with NACK and ACK polling is disabled + * Abort the transaction and move to IDLE state + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + + this_i2c->master_status = MIV_I2C_FAILED; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + + this_i2c->master_state = MIV_I2C_IDLE; + } + } + + else if (i2c_al_status == 1u) + { + /* Arbitration was lost on the BUS during the transmission of + * previous start condition and control byte. + * Re-send the STA and CB + */ + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + break; + + /* Transmit master data */ + case MIV_I2C_TX_DATA: + + /* ACK received and arbitration was not lost */ + if (i2c_ack_status == 0u && i2c_al_status == 0u) + { + uint8_t tx_buff[this_i2c->master_tx_size]; + if (this_i2c->master_tx_idx < this_i2c->master_tx_size) + { + HAL_set_8bit_reg(this_i2c->base_addr, TRANSMIT, + this_i2c->master_tx_buffer[this_i2c->master_tx_idx]); + + tx_buff[this_i2c->master_tx_idx] = this_i2c->master_tx_buffer[this_i2c->master_tx_idx]; + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + /* Increment the index */ + this_i2c->master_tx_idx++; + + /* Set the master state to TX data */ + this_i2c->master_state = MIV_I2C_TX_DATA; + } + + /* All the bytes are transmitted */ + else if (this_i2c->master_tx_idx == this_i2c->master_tx_size) + { + /* If this is a MASTER_READ_TRANSACTION, hold bus and start a + new transfer in read mode now that the read address has been + written to the slave */ + if(this_i2c->transaction == MIV_I2C_MASTER_READ_TRANSACTION) + + { + //Switch direction to READ + this_i2c->dir = MIV_I2C_READ_DIR; + + // Set the STA bit + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* Set the DIR bit and target addr */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, MIV_I2C_READ_DIR); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, this_i2c->target_addr); + + /* Set the WR bit to transmit the start condition and command byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + // Reset the buffer index + this_i2c->master_tx_idx = 0u; + this_i2c->master_rx_idx = 0u; + + /* Set the master state to RX data */ + this_i2c->master_state = MIV_I2C_RX_DATA; + } + + else + { + /* If releasing the bus, transmit the stop condition at the end + * of the transfer. + */ + hold_bus = this_i2c->bus_status & MIV_I2C_HOLD_BUS; + + if (hold_bus == 0) + { + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + } + else + { + MIV_I2C_disable_irq(); + } + this_i2c->master_status = MIV_I2C_SUCCESS; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + this_i2c->master_state = MIV_I2C_IDLE; + } + } + } + + else if (i2c_ack_status == 1u) + { + /* Received NACK from target device + * + * Release the bus and end the transfer + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + + this_i2c->master_status = MIV_I2C_FAILED; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + + this_i2c->master_state = MIV_I2C_IDLE; + } + + else if (i2c_al_status == 1u) + { + /* Arbitration was lost on the BUS during the transmission of + * previous start condition and control byte. + * Re-send the STA and CB + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, + this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + break; + + /* Receive target device data */ + case MIV_I2C_RX_DATA: + + if (i2c_al_status == 0u) + { + if (this_i2c->master_rx_idx < this_i2c->master_rx_size) + { + this_i2c->master_rx_buffer[this_i2c->master_rx_idx - 1u] = + HAL_get_8bit_reg(this_i2c->base_addr, RECEIVE); + + /* If next byte is last one + * Send NACK to target device to stop sending data + */ + if (this_i2c->master_rx_idx == (this_i2c->master_rx_size - 1u)) + { + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_ACK, 0x01u); + } + + else + { + /* Send ACK to receive next bytes */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_ACK, 0x00u); + } + + /* Set RD bit to receive next byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_RD, 0x01u); + + this_i2c->master_rx_idx++; + } + + /* Received all bytes */ + else //if (this_i2c->master_rx_idx == this_i2c->master_rx_size) + { + this_i2c->master_rx_buffer[this_i2c->master_rx_idx - 1] = + HAL_get_8bit_reg(this_i2c->base_addr, RECEIVE); + + hold_bus = this_i2c->bus_status & MIV_I2C_HOLD_BUS; + + if (hold_bus == 0) + { + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + } + else + { + MIV_I2C_disable_irq(); + } + this_i2c->master_status = MIV_I2C_SUCCESS; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + + this_i2c->master_state = MIV_I2C_IDLE; + } + } + + else if (i2c_al_status == 1u) + { + /* Arbitration was lost on the BUS during the transmission of + * previous start condition and control byte. + * Re-send the STA and CB + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, + this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + break; + } + + /* Toggle the IACK bit to clear interrupt */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00u); +} + +/* + * Please refer to miv_i2c.h for more info + */ +uint8_t +MIV_I2C_get_status +( + miv_i2c_instance_t *this_i2c +) +{ + uint8_t i2c_status; + + i2c_status = HAL_get_8bit_reg(this_i2c->base_addr, STATUS); + + return i2c_status; +} diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.h b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.h new file mode 100644 index 0000000..c5e704d --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.h @@ -0,0 +1,854 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * I2C module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(MIV_ESS). + */ + +/*=========================================================================*//** + @mainpage Mi-V I2C Bare Metal Driver + + ============================================================================== + Introduction + ============================================================================== + The Mi-V I2C driver provides a set of functions for controlling the Mi-V I2C + Soft-IP module. This module is delivered as a part of the Mi-V Extended + Sub System(MIV_ESS). The driver provides a minimal APB-driven I2C interface, + supporting initiator read and write access to peripheral I2C devices. + + The major features provided by the Mi-V I2C driver are: + - Support for configuring the I2C instance. + - I2C master operations. + - I2C ISR. + + This driver can be used as part of a bare metal system where no operating + system is available. The driver can be adapted for use as part of an + operating system, but the implementation of the adaptation layer between the + driver and the operating system's driver model is outside the scope of this + driver. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + The application software should initialize and configure the Mi-V I2C through + the call to the MIV_I2C_init() and MIV_I2C_config() function for Mi-V I2C + instance in the design. The configuration parameter include base address and + Prescaler value. + + ------------------------------ + Interrupt Control + ------------------------------ + The Mi-V I2C driver has to enable and disable the generation of interrupts by + Mi-V I2C at various times while operating. This enabling and disabling of the + interrupts must be done through the Mi-V RV32 HAL provided interrupt handlers. + For that reason, the method controlling the Mi-V I2C interrupts is system + specific and it is necessary to customize the MIV_I2C_enable_irq() and + MIV_I2C_disable_irq() functions as per requirement. + + The implementation of MIV_I2C_enable_irq() should permit the interrupts + generated by the Mi-V I2C to the processor through a call to respective miv-hal + interrupt handler. The implementation of MIV_I2C_disable_irq() should prevent + the interrupts generated by a Mi-V I2C from interrupting the processor. + Please refer to the miv_i2c_interrupt.c for more information about the + implementation. + + No MIV_I2C hardware configuration parameters are used by the driver, apart + from the MIV_I2C base address. Hence, no additional configuration files + are required to use the driver. + + ============================================================================== + Theory of Operation + ============================================================================== + The Mi-V I2C software driver is designed to allow the control of multiple + instances of Mi-V I2C. Each instance of Mi-V I2C in the hardware design is + associated with a single instance of the miv_i2c_instance_t structure in the + software. User must allocate memory for one unique miv_i2c_instance_t + structure for each instance of Mi-V I2C in the hardware. + A pointer to the structure is passed to the subsequent driver functions in + order to identify the MIV_I2C hardware instance and to perform requested + operation. + + Note: Do not attempt to directly manipulate the contents of the + miv_i2c_instance_t structure. These structures are only intended to be modified + by the driver functions. + + The Mi-V I2C driver functions are grouped into following categories: + - Initialization and configuration + - I2C master operation functions to handle write, read and write_read + operations. + - Interrupt control + + -------------------------------- + Initialization and configuration + -------------------------------- + The Mi-V I2C device is first initialized by the call to MIV_I2C_init(). This + function initializes the instance of Mi-V I2C with the base address. + MIV_I2C_init() function must be called before any other Mi-V I2C driver API. + + The configuration of the Mi-V I2C instance is done via call to the + MIV_I2C_config() function. This function will set the prescale value which is + used to set the frequency of the I2C clock(SCLK) generated by I2C module. + + --------------------------------- + Transaction types + --------------------------------- + The driver is designed to handle three types of transactions: + - Write transactions + - Read transactions + - Write-Read transaction + + ### Write Transaction + The write transaction begins with master sending a start condition, followed + by device address byte with the R/W bit set to logic '0', and then by the + word address bytes. The slave acknowledges the receipt of its address with + acknowledge bit. The master sends one byte at a time to the slave, which must + acknowledge the receipt of each byte for the next byte to be sent. The master + sends STOP condition to complete the transaction. The slave can abort the + transaction by replying with negative acknowledge. + + The application programmer can choose not to send the STOP bit at the end of + the transaction causing repetitive start conditions. + + ### Read Transaction + The master I2C device initiates a read transaction by sending a START bit + as soon as the bus becomes free. The start condition is followed by the + control byte which contains 7-bit slave address followed by R/W bit set to + logic '1'. The slave sends data one byte at a time to the master, which must + acknowledge receipt of each byte for the next byte to be sent. The master + sends a non-acknowledge bit following the last byte it wishes to read + followed by a STOP bit. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ### Write-Read Transaction + The write read transaction is a combination of a write transaction + immediately followed by a read transaction. There is no STOP condition sent + between the write and read phase of write-read transaction. A repeated START + condition is sent between the write and read phases. + + Whilst the write handler is being executed, the slave holds the clock line + low to stretch the clock until the response is ready. + + The write-read transaction is typically used to send an memory/register + address in the write transaction specifying the start address of the data to + be transferred during the read phase. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ------------------------------------- + Interrupt Control + ------------------------------------- + The Mi-V I2C driver is interrupt driven and it uses the MIV_I2C_irq() function + to drive the ISR state machine which is at the heart of the driver. The + application is responsible for providing the link between the interrupt + generating hardware and the Mi-V I2C interrupt handler and must ensure that + the MIV_I2C_isr() function is called with the correct miv_i2c_instance_t + structure pointer for the Mi-V I2C instance initiating the interrupt. + +*//*=========================================================================*/ +#ifndef MIV_I2C_H_ +#define MIV_I2C_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "miv_i2c_regs.h" +#include + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#else +#include "hal.h" +#endif + +/*-------------------------------------------------------------------------*//** + The miv_i2c_status_t type is used to report the status of I2C transactions. + */ +typedef enum miv_i2c_status +{ + MIV_I2C_SUCCESS = 0u, + MIV_I2C_IN_PROGRESS, + MIV_I2C_FAILED, + MIV_I2C_TIMED_OUT +}miv_i2c_status_t; + +/*-------------------------------------------------------------------------*//** + This structure is used to identify the MIV_I2C hardware instances in a system. + Your application software should declare one instance of this structure for + each instance of the MIV_I2C in your system. The function MIV_I2C_init() + Initializes this structure. A pointer to an initialised instance of the structure + should be passed as the first parameter to the MIV_I2C driver functions, to + identify which MIV_I2C hardware instance should perform the requested operation. + + The contents of this data structure should not be modified or used outside of + the MIV_I2C driver. Software using the MIV_I2C driver should only need to + create one single instance of this data structure for each MIV_I2C hardware + instance in the system, then pass a pointer to these data structures with each + call to the MIV_I2C driver in order to identify the MIV_I2C hardware instance + it wishes to use. +*/ + +typedef struct miv_i2c_instance +{ + addr_t base_addr; + + /* Transmit related info:*/ + uint_fast8_t target_addr; + + /* Current transaction type */ + uint8_t transaction; + + uint8_t bus_options; + + uint8_t ack_polling_options; + + /* Current State of the I2C master */ + uint8_t master_state; + + /* Master TX INFO: */ + const uint8_t * master_tx_buffer; + uint_fast16_t master_tx_size; + uint_fast16_t master_tx_idx; + uint_fast8_t dir; + + /* Master RX INFO: */ + uint8_t * master_rx_buffer; + uint_fast16_t master_rx_size; + uint_fast16_t master_rx_idx; + + /* Master Status */ + volatile miv_i2c_status_t master_status; + uint32_t master_timeout_ms; + + /* user specific data */ + void *p_user_data ; + + /* I2C bus status */ + uint8_t bus_status; + + /* Is transaction pending flag */ + uint8_t is_transaction_pending; + + /* I2C Pending transaction */ + uint8_t pending_transaction; + +}miv_i2c_instance_t; + + +/*-------------------------------------------------------------------------*//** + MIV_I2C_RELEASE_BUS + ===================== + The MIV_I2C_RELEASE_BUS constant is used to specify the bus_options parameter + for MIV_I2C_read(), MIV_I2C_write() and MIV_I2C_write_read() to indicate + that a STOP bit must be generated at the end of the I2C transaction to release + the bus. + */ +#define MIV_I2C_RELEASE_BUS 0x00u + + +/*-------------------------------------------------------------------------*//** + MIV_I2C_HOLD_BUS + ===================== + The MIV_I2C_HOLD_BUS constant is used to specify the bus_optionsparameter + for MIV_I2C_read(), MIV_I2C_write() and MIV_I2C_write_read() to indicate + that a STOP bit must not be generated at the end of the I2C transaction in + order to retain the bus ownership. This causes the next transaction to + begin with a repeated START bit and no STOP bit between the transactions. + */ +#define MIV_I2C_HOLD_BUS 0x01u + +/*-------------------------------------------------------------------------*//** + MIV_I2C_ACK_POLLING_DISABLE + ===================== + The MIV_I2C_ACK_POLLING_DISABLE constant is used to specify the + ack_polling_options parameter to functions MIV_I2C_write(), + MIV_I2C_write_read() and MIV_I2C_read(). Acknowledgment polling is used when + working with I2C memory devices such as EEPROM, which feature an internal + write cycle. + + With acknowledgment polling disabled, if the target slave device responds to the + control byte with a NACK, the MIV_I2C will abort the transfer. + */ +#define MIV_I2C_ACK_POLLING_DISABLE 0x00u + +/*-------------------------------------------------------------------------*//** + MIV_I2C_ACK_POLLING_ENABLE + ===================== + The MIV_I2C_ACK_POLLING_ENABLE constant is used to specify the + ack_polling_options parameter to functions MIV_I2C_write(), + MIV_I2C_write_read() and MIV_I2C_read(). acknowledgment polling is used when + working with I2C memory devices such as EEPROM, which feature an internal + write cycle. + + With acknowledgment polling enabled, if the slave device responds to the + control byte with a NACK, the MIV_I2C will repeatedly transmit another control + byte until the slave device accepts the connection with an ACK, or the timeout + specified in the MIV_I2C_wait_complete() function is reached. Acknowledgment + polling allows for the next read/write operation to be started as soon as the + EEPROM has completed its internal write cycle. + */ +#define MIV_I2C_ACK_POLLING_ENABLE 0x01u + +/*--------------------------------Public APIs---------------------------------*/ + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_init() function is used to initialize the Mi-V I2C module instance + with the base address. + + Note: This function should be called before calling any other Mi-V I2C + functions. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + @param base_addr + Base address of the Mi-V I2C module instance in the MIV_ESS + soft IP. + + @return + This function does not return any value. + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + } + @endcode + */ +void +MIV_I2C_init +( + miv_i2c_instance_t *this_i2c, + addr_t base_addr +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_config() function is used to configure the Mi-V I2C module. This + function will set the prescale value which is used to set the frequency of + the I2C clock(SCLK) generated by I2C module and also enables the I2C core and + interrupts. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param clk_prescale + The value used to set the frequency of Mi-V I2C serial clock + (SCLK) generated by the Mi-V I2C module instance. The + prescaler value required to set particular frequency of + Mi-V I2C can be calculated using following formula: + + prescaler = (System Clock Frequency) / (5 * (Desired I2C Clock Frequency)) - 1 + + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + } + @endcode + */ +void +MIV_I2C_config +( + miv_i2c_instance_t *this_i2c, + uint16_t clk_prescale +); + + +uint8_t +MIV_I2C_start +( + miv_i2c_instance_t *this_i2c +); + + +uint8_t +MIV_I2C_stop +( + miv_i2c_instance_t *this_i2c +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_write() is used to set up and start the Mi-V I2C master write + transaction. This function is used for all Mi-V master write operation. + + For more information about the operation, please refer to the 'theory of + operations' section at the start of this document. + + This function returns immediately after initiating the transaction. The content + of the write buffer passed as parameter should not be modified until the write + transaction completes. It also means that the memory allocated for the write + buffer should not be freed or should not go out of scope before the write + completes. + You can check for the write transaction completion by polling the master_status + from miv_i2c_instance_t structure as shown in the sample code. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param i2c_target_addr + This parameter specifies the serial address for the slave + device. + + @param write_buffer + This parameter is a pointer to the buffer holding data to be + written to target I2C device. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param write_size + Number of bytes held in the write_buffer to be written to the + I2C device. + @param bus_options: + The bus_options parameter is used to indicate if the I2C bus + should be released on completion of the write transaction. + Using the MIV_I2C_RELEASE_BUS constant for the bus_options + parameter causes a STOP bit to be generated at the end of the + write transaction causing the bus to be released for other I2C + devices to use. Using the MIV_I2C_HOLD_BUS constant as + bus_options parameter prevents a STOP bit from being generated + at the end of the write transaction, preventing other I2C + devices from initiating a bus transaction. + + @param ack_polling_options: + The ack_polling_options parameter is used to indicate how the + MIV_I2C will respond if the slave device transmits a NACK to + the I2C control byte. Using the MIV_I2C_ACK_POLLING_DISABLE + constant for the ack_polling_options parameter causes the + MIV_I2C to abort the transfer if the slave device responds to + the I2C control byte with a NACK. Using the + MIV_I2C_ACK_POLLING_ENABLE constant for the ack_polling_options + parameter causes the MIV_I2C to repeatedly transmit a control + byte to the slave device until the slave device responds with + an ACK. + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + + MIV_I2C_write (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_tx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + } + @endcode + */ +void +MIV_I2C_write +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t bus_options, + uint8_t ack_polling_options +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_read() is used to set up and start the Mi-V I2C master read + transaction. This function is used for all MIV_I2C master read operation. + + For more information about the operation, please refer to the 'theory of + operations' section at the start of this document. + + This function returns immediately after initiating the transaction. The content + of the read buffer passed as parameter should not be modified until the write + transaction completes. It also means that the memory allocated for the read + buffer should not be freed or should not go out of scope before the read + completes. + You can check for the write transaction completion by polling the master_status + from miv_i2c_instance_t structure as shown in the sample code. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param i2c_target_addr + This parameter specifies the serial address for the slave + device. + + @param read_buffer + This parameter is a pointer to the buffer where the data + received from the I2C slave device is stored. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param read_size + Number of bytes held in the write_buffer to be read from the + I2C device. + + @param bus_options: + The bus_options parameter is used to indicate if the I2C bus + should be released on completion of the write transaction. + Using the MIV_I2C_RELEASE_BUS constant for the bus_options + parameter causes a STOP bit to be generated at the end of the + write transaction causing the bus to be released for other I2C + devices to use. Using the MIV_I2C_HOLD_BUS constant as + bus_options parameter prevents a STOP bit from being generated + at the end of the write transaction, preventing other I2C + devices from initiating a bus transaction. + + @param ack_polling_options: + The ack_polling_options parameter is used to indicate how the + MIV_I2C will respond if the slave device transmits a NACK to + the I2C control byte. Using the MIV_I2C_ACK_POLLING_DISABLE + constant for the ack_polling_options parameter causes the + MIV_I2C to abort the transfer if the slave device responds to + the I2C control byte with a NACK. Using the + MIV_I2C_ACK_POLLING_ENABLE constant for the ack_polling_options + parameter causes the MIV_I2C to repeatedly transmit a control + byte to the slave device until the slave device responds with + an ACK. + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + + MIV_I2C_write (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_tx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + + // reset miv_i2c_status variable + miv_i2c_status = 0u; + + MIV_I2C_read (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_rx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + } + @endcode + */ +void +MIV_I2C_read +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_write_read() is used to set up and start the Mi-V I2C master + write_read transaction. This function is used for all MIV_I2C master write_read + operation. + + This function is used in cases where data is being requested from a specific + address offset inside the target I2C slave device. + In this type of I2C operation, the I2C master starts by initiating a write + operation. During this write operation, the specific address offset is written + to the I2C slave. Once the address offset has been written to the I2C slave, + the I2C master transmits a repeated start, and initiates a read operation to + read data from the set address. + + For more information about the operation, please refer to the 'theory of + operations' section at the start of this document. + + This function returns immediately after initiating the transaction. The content + of the write and read buffer passed as parameter should not be modified until + the write transaction completes. It also means that the memory allocated for + the write and read buffer should not be freed or should not go out of scope + before the operation completes. + You can check for the write_read transaction completion by polling the + master_status from miv_i2c_instance_t structure. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param i2c_target_addr + This parameter specifies the serial address for the slave + device. + + @param write_buffer + This parameter is a pointer to the buffer holding data to be + written to target I2C device. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param write_size + Number of bytes held in the write_buffer to be written to the + I2C device. + + @param read_buffer + This parameter is a pointer to the buffer where the data + received from the I2C slave device is stored. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param read_size + Number of bytes held in the write_buffer to be read from the + I2C device. + + @param bus_options: + The bus_options parameter is used to indicate if the I2C bus + should be released on completion of the write transaction. + Using the MIV_I2C_RELEASE_BUS constant for the bus_options + parameter causes a STOP bit to be generated at the end of the + write transaction causing the bus to be released for other I2C + devices to use. Using the MIV_I2C_HOLD_BUS constant as + bus_options parameter prevents a STOP bit from being generated + at the end of the write transaction, preventing other I2C + devices from initiating a bus transaction. + + @param ack_polling_options: + The ack_polling_options parameter is used to indicate how the + MIV_I2C will respond if the slave device transmits a NACK to + the I2C control byte. Using the MIV_I2C_ACK_POLLING_DISABLE + constant for the ack_polling_options parameter causes the + MIV_I2C to abort the transfer if the slave device responds to + the I2C control byte with a NACK. Using the + MIV_I2C_ACK_POLLING_ENABLE constant for the ack_polling_options + parameter causes the MIV_I2C to repeatedly transmit a control + byte to the slave device until the slave device responds with + an ACK or the timeout specified in the MIV_I2C_wait_complete() + function is reached. + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + + MIV_I2C_write (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_tx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + + // reset miv_i2c_status variable + miv_i2c_status = 0u; + + uint8_t addr_offset[2] = {0x00, 0x00}; + MIV_I2C_write_read(&miv_i2c, + DUALEE_SLAVEADDRESS_1, + addr_offset, + sizeof(addr_offset), + i2c_rx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + } + @endcode + */ +void +MIV_I2C_write_read +( + miv_i2c_instance_t *this_i2c, + uint8_t target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_isr() function contains the MIV_I2C's interrupt service routine. + This ISR is at the heart of the MIV_I2C driver, and is used to control the + interrupt-driven, byte-by-byte I2C read and write operations. + + The ISR operates as a Finite State Machine (FSM), which uses the previously + completed I2C operation and its result to determine which I2C operation will + be performed next. + + The ISR operation is divided into following categories: + - MIV_I2C_IDLE + - MIV_I2C_TX_STA_CB + - MIV_I2C_TX_DATA + - MIV_I2C_RX_DATA + + ##### MIV_I2C_IDLE + The MIV_I2C_IDLE is entered on reset, or when an I2C master operation has been + completed or aborted. + Upon entering, the FSM will remain in this state until a write, read, or + write-read operation is requested + + ##### MIV_I2C_STA_CB + The MIV_I2C_TX_STA_CB operation is performed when the start condition and + control byte(i2c target address(7-bit) and direction of transaction(1-bit)) is + transmitted by the Mi-V I2C master device to the slave. + If the target I2C slave device responded to the previous START Condition + + Control Byte with an ACK, the MIV_I2C will start the requested I2C + read/write operation. + If the target slave I2C slave device responds with NACK, the MIV_I2C will + remain in this state or return to the idle state based on ack_polling + configuration. + + ##### MIV_I2C_TX_DATA + The MIV_I2C_TX_DATA state is entered after the target slave device accepts a + write request with an ACK. + This state is used to handle the byte-by-byte MIV_I2C write operations. + The FSM will remain in this state until either all data bytes have been + written to the target slave device, or an error occurs during the write + operation. + + ##### MIV_I2C_RX_DATA + The MIV_I2C_RX_DATA state is entered after the target slave device accepts a + read request with an ACK. + This state is used to handle the byte-by-byte MIV_I2C read operations. + The FSM will remain in this state until either all data bytes have been + received from the target slave device, or an error occurs. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + */ +void +MIV_I2C_isr +( + miv_i2c_instance_t *this_i2c +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_get_status() returns the 8-bit Mi-V I2C status register value. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + @return + This function returns 8-bit Mi-V I2C status register value. + */ +uint8_t +MIV_I2C_get_status +( + miv_i2c_instance_t *this_i2c +); + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_I2C_H_ */ diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_interrupt.c b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_interrupt.c new file mode 100644 index 0000000..871eafe --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_interrupt.c @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains functions used for MIV_I2C driver interrupt control. + * User should enable and disable the interrupts according to their design. + * Please refer to miv_i2c.h file for more information. + */ + +#include "miv_rv32_hal/miv_rv32_hal.h" + +void MIV_I2C_disable_irq(void) +{ +/* Disable I2C interrupt */ + MRV_disable_local_irq(MRV32_MSYS_EIE2_IRQn); +} + +void MIV_I2C_enable_irq(void) +{ +/* Enable I2C interrupt */ + MRV_enable_local_irq(MRV32_MSYS_EIE2_IRQn); +} + + diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_regs.h b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_regs.h new file mode 100644 index 0000000..9a4bfbf --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_regs.h @@ -0,0 +1,158 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP I2C module driver. This module is delivered as a part of Mi-V extended + * Sub-System(MIV_ESS). + */ + +#ifndef MIV_I2C_APB_REGISTERS +#define MIV_I2C_APB_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * Prescale register details + */ +#define PRESCALE_REG_OFFSET 0x00u + +/* Prescale register bits */ +#define PRESCALE_OFFSET 0x00u +#define PRESCALE_MASK 0xFFFFu +#define PRESCALE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Control register details + */ +#define CONTROL_REG_OFFSET 0x04u + +/* Control register bits */ +#define CONTROL_OFFSET 0x04u +#define CONTROL_MASK 0xC0u +#define CONTROL_SHIFT 0u + +/* Control register Core Enable Bit */ +#define CTRL_CORE_EN_OFFSET 0x04u +#define CTRL_CORE_EN_MASK 0x80u +#define CTRL_CORE_EN_SHIFT 7u + +/* Control register IRQ Enable bit */ +#define CTRL_IRQ_EN_OFFSET 0x04u +#define CTRL_IRQ_EN_MASK 0x40u +#define CTRL_IRQ_EN_SHIFT 6u + +/*------------------------------------------------------------------------------ + * Transmit register details + */ +#define TRANSMIT_REG_OFFSET 0x08u + +/* Transmit register bits */ +#define TRANSMIT_OFFSET 0x08u +#define TRANSMIT_MASK 0xFFu +#define TRANSMIT_SHIFT 0u + +/* Transmit register DIR bit */ +#define TX_DIR_OFFSET 0x08u +#define TX_DIR_MASK 0x01u +#define TX_DIR_SHIFT 0u + +/* Transmit register TARGET_ADDR bit */ +#define TX_TARGET_ADDR_OFFSET 0x08u +#define TX_TARGET_ADDR_MASK 0xFEu +#define TX_TARGET_ADDR_SHIFT 1u + +/*------------------------------------------------------------------------------ + * Receive register details + */ +#define RECEIVE_REG_OFFSET 0x0Cu + +/* Receive register bits */ +#define RECEIVE_OFFSET 0x0Cu +#define RECEIVE_MASK 0xFFu +#define RECEIVE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Command register details + */ +#define COMMAND_REG_OFFSET 0x10u + +/* Command register bits */ +#define COMMAND_OFFSET 0x10u +#define COMMAND_MASK 0xF9u +#define COMMAND_SHIFT 0u + +/* Command register IACK bit */ +#define CMD_IACK_OFFSET 0x10u +#define CMD_IACK_MASK 0x01u +#define CMD_IACK_SHIFT 0u + +/* Command register ACK bit */ +#define CMD_ACK_OFFSET 0x10u +#define CMD_ACK_MASK 0x08u +#define CMD_ACK_SHIFT 3u + +/* Command register WR bit */ +#define CMD_WR_OFFSET 0x10u +#define CMD_WR_MASK 0x10u +#define CMD_WR_SHIFT 4u + +/* Command register RD bit */ +#define CMD_RD_OFFSET 0x10u +#define CMD_RD_MASK 0x20u +#define CMD_RD_SHIFT 5u + +/* Command register STO bit */ +#define CMD_STO_OFFSET 0x10u +#define CMD_STO_MASK 0x40u +#define CMD_STO_SHIFT 6u + +/* Command register STA bit */ +#define CMD_STA_OFFSET 0x10u +#define CMD_STA_MASK 0x80u +#define CMD_STA_SHIFT 7u + +/*------------------------------------------------------------------------------ + * Status register details + */ +#define STATUS_REG_OFFSET 0x14u + +/* Command register bits */ +#define STATUS_OFFSET 0x14u +#define STATUS_MASK 0xFFu +#define STATUS_SHIFT 0u + +/* Status register Interrupt Flag(IF) bit */ +#define STAT_IF_OFFSET 0x14u +#define STAT_IF_MASK 0x01u +#define STAT_IF_SHIFT 0u + +/* Status register Transfer in Progress(TIP) bit */ +#define STAT_TIP_OFFSET 0x14u +#define STAT_TIP_MASK 0x02u +#define STAT_TIP_SHIFT 1u + +/* Status register Arbitration Lost(AL) bit */ +#define STAT_AL_OFFSET 0x14u +#define STAT_AL_MASK 0x20u +#define STAT_AL_SHIFT 5u + +/* Status register Busy(BUSY) bit */ +#define STAT_BUSY_OFFSET 0x14u +#define STAT_BUSY_MASK 0x40u +#define STAT_BUSY_SHIFT 6u + +/* Status register Ack received(RXACK) bit */ +#define STAT_RXACK_OFFSET 0x14u +#define STAT_RXACK_MASK 0x80u +#define STAT_RXACK_SHIFT 7u + + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_I2C_APB_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.c b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.c new file mode 100644 index 0000000..903f029 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.c @@ -0,0 +1,283 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * MI-V Soft IP fabric bare-metal driver for Mi-V PLIC module. This module is + * delivered as a part of Mi-V Extended Sub System(MIV_ESS). + * Please refer to miv_plic.h file for more information. + */ + +#include "miv_plic.h" + +/***************************************************************************//** + * Mi-V PLIC interrupt handler function declaration. + * These functions are called by the external interrupt handler of the MIV_RV32 + * core base on the PLIC source causing the interrupt. + */ +uint8_t Invalid_IRQHandler(void); +uint8_t MIV_PLIC_EXT0_IRQHandler(void); +uint8_t MIV_PLIC_EXT1_IRQHandler(void); +uint8_t MIV_PLIC_EXT2_IRQHandler(void); +uint8_t MIV_PLIC_EXT3_IRQHandler(void); +uint8_t MIV_PLIC_EXT4_IRQHandler(void); +uint8_t MIV_PLIC_EXT5_IRQHandler(void); +uint8_t MIV_PLIC_EXT6_IRQHandler(void); +uint8_t MIV_PLIC_EXT7_IRQHandler(void); +uint8_t MIV_PLIC_EXT8_IRQHandler(void); +uint8_t MIV_PLIC_EXT9_IRQHandler(void); +uint8_t MIV_PLIC_EXT10_IRQHandler(void); +uint8_t MIV_PLIC_EXT11_IRQHandler(void); +uint8_t MIV_PLIC_EXT12_IRQHandler(void); +uint8_t MIV_PLIC_EXT13_IRQHandler(void); +uint8_t MIV_PLIC_EXT14_IRQHandler(void); +uint8_t MIV_PLIC_EXT15_IRQHandler(void); +uint8_t MIV_PLIC_EXT16_IRQHandler(void); +uint8_t MIV_PLIC_EXT17_IRQHandler(void); +uint8_t MIV_PLIC_EXT18_IRQHandler(void); +uint8_t MIV_PLIC_EXT19_IRQHandler(void); +uint8_t MIV_PLIC_EXT20_IRQHandler(void); +uint8_t MIV_PLIC_EXT21_IRQHandler(void); +uint8_t MIV_PLIC_EXT22_IRQHandler(void); +uint8_t MIV_PLIC_EXT23_IRQHandler(void); +uint8_t MIV_PLIC_EXT24_IRQHandler(void); +uint8_t MIV_PLIC_EXT25_IRQHandler(void); +uint8_t MIV_PLIC_EXT26_IRQHandler(void); +uint8_t MIV_PLIC_EXT27_IRQHandler(void); +uint8_t MIV_PLIC_EXT28_IRQHandler(void); +uint8_t MIV_PLIC_EXT29_IRQHandler(void); +uint8_t MIV_PLIC_EXT30_IRQHandler(void); + +/***************************************************************************//** + * MIV_PLIC interrupt handler for external interrupts. + * The array of the function pointers pointing to the weak handler of the Mi-V + * PLIC interrupt handlers. + * These functions are called by the external interrupt handler of the MIV_RV32 + * core base on the PLIC source causing the interrupt. + */ +uint8_t (* const ext_irq_handler_table[32]) (void) = +{ + Invalid_IRQHandler, + MIV_PLIC_EXT0_IRQHandler, + MIV_PLIC_EXT1_IRQHandler, + MIV_PLIC_EXT2_IRQHandler, + MIV_PLIC_EXT3_IRQHandler, + MIV_PLIC_EXT4_IRQHandler, + MIV_PLIC_EXT5_IRQHandler, + MIV_PLIC_EXT6_IRQHandler, + MIV_PLIC_EXT7_IRQHandler, + MIV_PLIC_EXT8_IRQHandler, + MIV_PLIC_EXT9_IRQHandler, + MIV_PLIC_EXT10_IRQHandler, + MIV_PLIC_EXT11_IRQHandler, + MIV_PLIC_EXT12_IRQHandler, + MIV_PLIC_EXT13_IRQHandler, + MIV_PLIC_EXT14_IRQHandler, + MIV_PLIC_EXT15_IRQHandler, + MIV_PLIC_EXT16_IRQHandler, + MIV_PLIC_EXT17_IRQHandler, + MIV_PLIC_EXT18_IRQHandler, + MIV_PLIC_EXT19_IRQHandler, + MIV_PLIC_EXT20_IRQHandler, + MIV_PLIC_EXT21_IRQHandler, + MIV_PLIC_EXT22_IRQHandler, + MIV_PLIC_EXT23_IRQHandler, + MIV_PLIC_EXT24_IRQHandler, + MIV_PLIC_EXT25_IRQHandler, + MIV_PLIC_EXT26_IRQHandler, + MIV_PLIC_EXT27_IRQHandler, + MIV_PLIC_EXT28_IRQHandler, + MIV_PLIC_EXT29_IRQHandler, + MIV_PLIC_EXT30_IRQHandler +}; + +/* Mi-V PLIC interrupt weak handlers */ +__attribute__((weak)) uint8_t Invalid_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT0_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT1_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT2_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT3_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT4_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT5_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT6_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT7_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT8_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT9_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT10_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT11_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT12_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT13_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT14_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT15_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT16_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT17_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT18_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT19_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT20_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT21_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT22_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT23_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT24_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT25_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT26_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT27_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT28_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT29_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT30_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +/*-------------------------------------------------------------------------*//** + * Please refer to miv_plic.h for more information about this function. +*/ +void +MIV_PLIC_isr +( + miv_plic_instance_t *this_plic +) +{ + unsigned long hart_id = read_csr(mhartid); + + /* claim the interrupt from PLIC controller */ + + uint32_t int_num = HAL_get_32bit_reg(this_plic->base_addr + + (0x1000 * hart_id), INT_CLAIM_COMPLETE); + + uint8_t disable = EXT_IRQ_KEEP_ENABLED; + disable = ext_irq_handler_table[int_num](); + + /* Indicate the PLIC controller that the interrupt is processed and claim is + * complete. */ + HAL_set_32bit_reg(this_plic->base_addr + + (0x1000 * hart_id), INT_CLAIM_COMPLETE, int_num); + + if (EXT_IRQ_DISABLE == disable) + { + MIV_PLIC_disable_irq(this_plic, (miv_plic_irq_num_t)int_num); + } +} diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.h b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.h new file mode 100644 index 0000000..f5d64cd --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.h @@ -0,0 +1,425 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * PLIC module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(ESS). + */ + /*=========================================================================*//** + @mainpage Mi-V PLIC Bare Metal Driver + + ============================================================================== + Introduction + ============================================================================== + The Mi-V driver provides a set of functions for controlling the Mi-V PLIC + (platform level interrupt controller) soft-IP module. This module is delivered + as a part of the MIV_ESS. The PLIC multiplexes external interrupt signals into + a single interrupt signal that is connected to an external interrupt of the + processor. + + The major features provided by the driver are: + - Support for configuring the PLIC instances. + - Enabling and Disabling interrupts + - Interrupt Handling + + This driver can be used as part of a bare metal system where no operating + system is available. The driver can be adapted for use as part of an + operating system, but the implementation of the adaptation layer between the + driver and the operating system's driver model is outside the scope of this + driver. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + The application software should initialize the Mi-V PLIC through the call to + the MIV_PLIC_init() function for Mi-V PLIC instance in the design. + + No Mi-V PLIC hardware configuration parameters are used by the driver, apart + from the Mi-V PLIC base address. Hence, no additional configuration files + are required to use the driver. + + ============================================================================== + Theory of Operation + ============================================================================== + The operation of Mi-V PLIC driver is divided into following steps: + - Initialization + - Enabling and Disabling interrupts + - Interrupt control + + -------------------------------------------- + Initialization + -------------------------------------------- + The Mi-V PLIC module is first initialized by the call to MIV_PLIC_init(). This + function takes a pointer to the Mi-V PLIC instance data structure and the base + address of the Mi-V PLIC instance is defined by the hardware design. The + instance data structure is used to store the base address of the Mi-V PLIC + module and a pointer to the Mi-V PLIC register data structure. The Mi-V PLIC + register data structure maps the address of the Mi-V PLIC registers. + + --------------------------------------------- + Enabling and Disabling interrupts + --------------------------------------------- + The MIV_PLIC_enable_irq() function enables the specific interrupt provided by + user. A call to this function will allow the enabling of each of the global + interrupts corresponding to the bit in the interrupt enable register of Mi-V + PLIC. + The MIV_PLIC_disable_irq() function disables the specific interrupt provided + by the user. This function can be used to disable the interrupts from outside + of the external interrupt handler. + + ---------------------------------------- + Interrupt Control + ---------------------------------------- + When an interrupt occurs on an enabled interrupt, the PLIC gateway captures + the interrupt and asserts the corresponding interrupt pending bit. Once + the enable bit and pending bit are asserted, then the PLIC_IRQ signal asserts + until the interrupt is claimed by the driver interrupt handler MIV_PLIC_irq() + function. + When multiple interrupts assert then the lowest interrupt number will be + serviced first, for example, if interrupt 1 and 6 assert at the same time, + interrupt 1 will be serviced first, followed by interrupt 6. + +*/ + +#ifndef MIV_PLIC_H_ +#define MIV_PLIC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "miv_plic_regs.h" + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#include "miv_rv32_hal/miv_rv32_hal.h" +#else +#include "hal.h" +#include "miv_rv32_hal.h" +#endif + +/*-------------------------------------------------------------------------*//** + This enumeration is used to select a specific Mi-V PLIC interrupt. It is + used as a parameter to enable or disable the interrupt. +*/ +typedef enum miv_plic_irq_num +{ + NoInterrupt_IRQn = 0, + MIV_PLIC_EXT0_IRQn = 1, + MIV_PLIC_EXT1_IRQn = 2, + MIV_PLIC_EXT2_IRQn = 3, + MIV_PLIC_EXT3_IRQn = 4, + MIV_PLIC_EXT4_IRQn = 5, + MIV_PLIC_EXT5_IRQn = 6, + MIV_PLIC_EXT6_IRQn = 7, + MIV_PLIC_EXT7_IRQn = 8, + MIV_PLIC_EXT8_IRQn = 9, + MIV_PLIC_EXT9_IRQn = 10, + MIV_PLIC_EXT10_IRQn = 11, + MIV_PLIC_EXT11_IRQn = 12, + MIV_PLIC_EXT12_IRQn = 13, + MIV_PLIC_EXT13_IRQn = 14, + MIV_PLIC_EXT14_IRQn = 15, + MIV_PLIC_EXT15_IRQn = 16, + MIV_PLIC_EXT16_IRQn = 17, + MIV_PLIC_EXT17_IRQn = 18, + MIV_PLIC_EXT18_IRQn = 19, + MIV_PLIC_EXT19_IRQn = 20, + MIV_PLIC_EXT20_IRQn = 21, + MIV_PLIC_EXT21_IRQn = 22, + MIV_PLIC_EXT22_IRQn = 23, + MIV_PLIC_EXT23_IRQn = 24, + MIV_PLIC_EXT24_IRQn = 25, + MIV_PLIC_EXT25_IRQn = 26, + MIV_PLIC_EXT26_IRQn = 27, + MIV_PLIC_EXT27_IRQn = 28, + MIV_PLIC_EXT28_IRQn = 29, + MIV_PLIC_EXT29_IRQn = 30, + MIV_PLIC_EXT30_IRQn = 31 +} miv_plic_irq_num_t; + +/*--------------------------------------------------------------------------*//* + * This structure maps the priority threshold and claim complete register in + * the memory. + */ +typedef struct +{ + volatile uint32_t PRIORITY_THRESHOLD; + volatile uint32_t CLAIM_COMPLETE; + volatile uint32_t reserved[1022]; +} IRQ_Target_Type; + +/*--------------------------------------------------------------------------*//* + * This structure maps the Interrupt enable sources from 0 - 1023 for one + * context. + */ +typedef struct +{ + volatile uint32_t ENABLES[32]; +} Target_Enables_Type; + +/*-------------------------------------------------------------------------*//** + This structure holds the base address of the Mi-V PLIC module. This structure + is used by all the functions to access the Mi-V PLIC registers. +*/ +typedef struct miv_plic_instance +{ + addr_t base_addr; +} miv_plic_instance_t; + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_isr is the top level interrupt handler function for the Mi-V PLIC + * driver. You must call the MIV_PLIC_isr() from the system level interrupt + * handler(External_IRQHandler). + * This function must be called from the external interrupt handler function + * provided by the processor hardware abstraction layer. In case of MIV_RV32 + * soft processor, it must be called from External_IRQHandler() function + * provided by MIV_RV32 HAL. + * + * The MIV_PLIC_isr() function claims the interrupt number + * that triggered the interrupt and then invokes the appropriate PLIC interrupt + * handler. + * After handling the PLIC interrupt, this function will complete the interrupt + * by clearing the claim complete bit for the particular interrupt source. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * + * @return + * This function does not return any value. + * + * Example: + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * uint8_t MIV_PLIC_EXT0_IRQHandler(void) + * { + * *** ISR operation *** + * + * return(EXT_IRQ_KEEP_ENABLED); + * } + * + * void External_IRQHandler(void) + * { + * uint32_t reg_val = read_csr(mip); + * MIV_PLIC_isr(&g_plic); + * } + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * } + * @endcode + */ +void MIV_PLIC_isr(miv_plic_instance_t *this_plic); + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_init() function initializes the Mi-V PLIC instance with base + * address. This function resets the PLIC controller by disabling all the PLIC + * interrupts. + * + * Note: This function must be called before calling any other Mi-V PLIC driver + * function. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * + * @param base_addr + * Base address of the Mi-V PLIC instance in the MIV_ESS soft-IP. + * + * @param ext_intr_sources + * Number of interrupts initialized in the design. + * + * @return + * This function does not return any value. + * + * Example + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * } + * @endcode + */ +static inline void +MIV_PLIC_init +( + miv_plic_instance_t *this_plic, + addr_t base_addr, + uint8_t ext_intr_sources +) +{ + uint32_t inc; + unsigned long hart_id = read_csr(mhartid); + + this_plic->base_addr = base_addr; + + /* Disable all interrupts for the current hart. + * The PLIC_EXT_INTR_SOURCES should be defined in the hw_platform.h. This + * macro holds the number of PLIC interrupts enabled in the design. + */ + for(inc = 0; inc < ((ext_intr_sources + 32u) / 32u); ++inc) + { + HAL_set_32bit_reg( + (this_plic->base_addr + inc + (hart_id * 128)), INT_ENABLE , 0x0u); + } +} + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_enable_irq() function enables the PLIC interrupt provided with + * IRQn parameter. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * @param IRQn + * Number of PLIC interrupt to enable. + * + * @return + * This function does not return any value. + * + * Example + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * } + * @endcode + */ +static inline void +MIV_PLIC_enable_irq +( + miv_plic_instance_t *this_plic, + miv_plic_irq_num_t IRQn +) +{ + unsigned long hart_id = read_csr(mhartid); + + uint32_t current = HAL_get_32bit_reg( + (this_plic->base_addr + (IRQn/32) + (hart_id * 128)) , INT_ENABLE); + + current |= (uint32_t)1 << (IRQn % 32); + + HAL_set_32bit_reg( + (this_plic->base_addr + (IRQn/32) + (hart_id * 128)), INT_ENABLE, current); + +} + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_disable_irq() function disables the PLIC interrupt provided with + * IRQn parameter. + * + * NOTE: + * This function can be used to disable the PLIC interrupt from outside the + * external interrupt handler functions. + * If you wish to disable the PLIC interrupt from the external interrupt handler, + * you should use the return value of EXT_IRQ_DISABLE. This will disable the + * selected PLIC interrupt from the Mi-V PLIC driver interrupt handler. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * @param IRQn + * Number of PLIC interrupt to disable. + * + * @return + * This function does not return any value. + * + * Example + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * } + * @endcode + */ +static inline void +MIV_PLIC_disable_irq +( + miv_plic_instance_t *this_plic, + miv_plic_irq_num_t IRQn +) +{ + unsigned long hart_id = read_csr(mhartid); + + uint32_t current = HAL_get_32bit_reg((this_plic->base_addr + (IRQn/32) + (hart_id * 128)) , INT_ENABLE); + + current &= ~((uint32_t)1 << (IRQn % 32)); + + HAL_set_32bit_reg((this_plic->base_addr + (IRQn/32) + (hart_id * 128)), INT_ENABLE, current); + +} + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_PLIC_H_ */ diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic_regs.h b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic_regs.h new file mode 100644 index 0000000..76cbc0b --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic_regs.h @@ -0,0 +1,31 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP PLIC module driver. This module is delivered as a part of Mi-V extended + * Sub-System(MIV_ESS). + */ + +#ifndef MIV_PLIC_REGISTERS +#define MIV_PLIC_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Interrupt pending register offset */ +#define INT_PENDING_REG_OFFSET 0x1000u + +/* Interrupt enable register */ +#define INT_ENABLE_REG_OFFSET 0x2000u + +/* Interrupt claim complete register */ +#define INT_CLAIM_COMPLETE_REG_OFFSET 0x200004u + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_PLIC_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_timer/miv_timer.h b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_timer/miv_timer.h new file mode 100644 index 0000000..5f00889 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_timer/miv_timer.h @@ -0,0 +1,329 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Mi-V Timer Soft IP bare-metal driver. This module is delivered as part of + * the Mi-V Extended Sub System(ESS) MIV_ESS. + */ + +/*=========================================================================*//** + @mainpage Mi-V Timer Bare Metal Driver. + The Mi-V Timer bare metal software driver supports the timer module which + serves as a system timer for the Mi-V Extended Sub System(ESS). + + @section intro_sec Introduction + The MI-V Timer driver supports set of functions for controlling the Mi-V + Timer module. + The Mi-V Timer can generate a timer interrupt signal for the system based on + special system clock intervals specified by the parameters that can be passed + in by the user. + + The major features provided by Mi-V Timer driver are: + - Support for Mi-V Timer instance for each Mi-V Timer peripheral. + - Read current time + - Write to the machine time compare register + + @section hw_dependencies Hardware Flow dependency + The application should configure the Mi-V Timer driver through calls to + MIV_TIMER_init() functions for each MIV_TIMER instance in the hardware + design. The configuration parameter include the MIV_TIMER hardware instance, + base address and number of ticks to generate timer interrupt. + + MIV_RV32 core offers flexibility in terms of generating the MTIME and MTIMECMP + registers internal to the core or using external time reference. + When MIV_ESS is interfaced with MIV_RV32 core, the timer module in the MIV_ESS + can be configured as follows: + - Internal MTIME External MTIME IRQ + Generate the MTIME internally(MIV_RV32) and have a timer interrupt input + to the core as external pin(from MIV_ESS). + + - External MTIME Internal MTIME IRQ + Generate the time value externally(from MIV_ESS), in this case a 64-bit + port will open in the MIV_RV32 core as input and MIV_ESS will output the + 64-bit TIME_COUNT value. The generation of mtimecmp and interrupt is + done internally(MIV_RV32). + + - External MTIME External MTIME IRQ + Generate both the time and timer interrupt externally. + In this case 64-bit port will be available on the Mi-V RV32 core as input + and a 1 pin port will be available for timer interrupt. + + The design must be configured accordingly to use these combinations in the + firmware. + + No MIV_TIMER hardware configuration parameters are used by the driver, apart + from MIV_TIMER base address. Hence, no additional configuration files are + required to use the driver. + + @section theory_op Theory of Operation + + The MIV_TIMER module is a simple systick timer which can generate a timer + interrupt signal for the system at specific intervals specified by the + parameters that can be passed by the user. + These interrupt signal are then fed to the MIV_RV32 core via timer interrupt. + + The operation of MIV_TIMER is divided into following steps: + - Initialization + - Configuration + - Read/Write TIME + + ## Initialization + The MIV_TIMER is first initialized by a call to MIV_TIMER_init(). This + function initializes the instance of Mi-V TIMER with the base address. + The MIV_TIMER_init() function must be called before any other Mi-V Timer driver + function. + + ## Configuration + The Mi-V TIMER configuration includes writing the mtimecmp register with the + initial time value at which timer interrupt should be generated. + When the mtime register value becomes greater than or equal to mtimecmp value, + a timer interrupt signal(TIMER_IRQ) is generated. + + ## Read/Write TIME + The time value can be read by reading the mtime register via call to the + MIV_TIMER_read_mtime(). This function reads the MTIME register which contains + the 64-bit value of the timer count. The count increments by 1 every time the + prescale ticks. This function returns 64-bit MTIME_COUNT value which is the + current value of timer count. + + The time value read in the MIV_TIMER_read_mtime() function can be written to + the mtimecmp register by calling MIV_TIMER_write_mtimecmp() to generate + periodic interrupts. + The writing of the mtimecmp register should be done in the systick_handler() + function. + */ + +#ifndef MIV_TIMER_H_ +#define MIV_TIMER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#endif +/*-------------------------------------------------------------------------*//** +MIV_TIMER_SUCCESS +===================== + +The MIV_TIMER_SUCCESS constant indicates successful configuration of +Mi-V Timer module. +*/ +#define MIV_TIMER_SUCCESS 0u + +/*-------------------------------------------------------------------------*//** +MIV_TIMER_ERROR +===================== + +The MIV_TIMER_ERROR constant indicates that there is an error with +configuring the Mi-V Timer module. +*/ +#define MIV_TIMER_ERROR 1u + +/*-------------------------------------------------------------------------*//* +MIV_TIMER_MASK_32BIT +===================== + +32-bit mask constant used in calculation of 64-bit register value. +*/ +#define MIV_TIMER_MASK_32BIT 0xFFFFFFFFu + +/*-------------------------------------------------------------------------*//* +Mi-V Timer register offsets +===================== +The MTIMECMP is the 64-bit timer compare register, it pre-sets the threshold +which needs to be reached by the timer count register. +This 64-bit register is accessed with 2 32-bit address offset, lower 32-bits +and higher 32-bits. + - MIV_TIMER_MTIMECMP_L_REG_OFFSET + - MIV_TIMER_MTIMECMP_H_REG_OFFSET + +The MTIME is the 64-bit register that contains the 64-bit timer count. The +count increments by 1 every time the prescaler ticks. +This 64-bit register is accessed with 2 32-bit address offset, lower 32-bits +and higher 32-bits. + - MIV_TIMER_MTIME_L_REG_OFFSET + - MIV_TIMER_MTIME_H_REG_OFFSET + +The PRESCALE register is used to determine the amount of clock cycles the +selected clock needs to go through, for MTIME register to increment count. + - MIV_TIMER_PRESCALAR_REG_OFFSET +*/ + +/// @cond private +#define MIV_TIMER_MTIMECMP_L_REG_OFFSET 0x4000u +#define MIV_TIMER_MTIMECMP_H_REG_OFFSET 0x4004u + +#define MIV_TIMER_MTIME_L_REG_OFFSET 0xBFF8u +#define MIV_TIMER_MTIME_H_REG_OFFSET 0xBFFCu + +#define MIV_TIMER_PRESCALAR_REG_OFFSET 0x5000u +/// @endcond + +/*-------------------------------------------------------------------------*//** + This structure holds the base address of the Mi-V Timer module and instance + of the Mi-V Timer register structure. +*/ +typedef struct miv_timer_instance +{ + addr_t base_addr; +} miv_timer_instance_t; + +/** The MIV_TIMER_init() is used to initialize the Mi-V Timer module. This + function will assign the base addresses of the Mi-V Timer module. + User should call this function before calling any of the Mi-V Timer driver + APIs. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @param base_address + Base address of the Mi-V Timer module. + + @return + This function does not return any value. + */ +static inline void +MIV_TIMER_init +( + miv_timer_instance_t* this_timer, + addr_t base_addr +) +{ + this_timer->base_addr = base_addr; +} + +/** MIV_TIMER_read_current_time() is used to read the mtimecmp register values. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @return + This function returns 64-bit mtimecmp register value. + */ +static inline uint64_t +MIV_TIMER_read_current_time +( + miv_timer_instance_t* this_timer +) +{ + volatile uint64_t read_data = 0u; + volatile uint32_t mtime_hi = 0u; + volatile uint32_t mtime_lo = 0u; + + /* when mtime lower word is 0xFFFFFFFF, there will be rollover and + * returned value could be wrong. */ + do { + mtime_hi = HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIME_H); + mtime_lo = HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIME_L); + + } while(mtime_hi != HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIME_H)); + + read_data = mtime_hi; + + return(((read_data) << 32u) | mtime_lo); +} + +/** MIV_TIMER_write_compare_time() is used to write to the MTIMECMP register in + the event of interrupt. User must use this function in the interrupt handler + to de-assert the MIV_TIMER interrupt. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @param write_value + Value to write into the mtimecmp register. + + @return + This function does not return any value. + */ +static inline void +MIV_TIMER_write_compare_time +( + miv_timer_instance_t* this_timer, + uint64_t compare_reg_value +) +{ + HAL_set_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIMECMP_H, MIV_TIMER_MASK_32BIT); + + HAL_set_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIMECMP_L, + (compare_reg_value & MIV_TIMER_MASK_32BIT)); + + HAL_set_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIMECMP_H, + ((compare_reg_value >> 32u) & MIV_TIMER_MASK_32BIT)); +} + +/** The MIV_TIMER_config() is used to configure the MIV_ESS Timer module. The + prescale value serves to divide the count of clock cycles for the timer and + provides control over what point in time, the timer interrupt gets + asserted. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @param ticks + Number of ticks after which interrupt will be generated. + + @return + This function returns Mi-V Timer configuration status. + */ +static inline uint32_t +MIV_TIMER_config +( + miv_timer_instance_t* this_timer, + uint64_t ticks +) +{ + uint32_t ret_val = MIV_TIMER_ERROR; + uint64_t mtime_val = 0u; + uint32_t prescalar = 0u; + uint64_t miv_timer_increment = 0U; + + prescalar = HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_PRESCALAR); + + miv_timer_increment = (uint64_t)(ticks) / prescalar; + + if (miv_timer_increment > 0U) + { + mtime_val = MIV_TIMER_read_current_time(this_timer); + + MIV_TIMER_write_compare_time(this_timer ,(mtime_val + miv_timer_increment)); + + ret_val = MIV_TIMER_SUCCESS; + } + + return ret_val; +} + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_TIMER_H */ diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c new file mode 100644 index 0000000..cbd9652 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c @@ -0,0 +1,109 @@ +/******************************************************************************* + * (c) Copyright 2022-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Mi-V uDMA Soft IP bare-metal driver. This module is delivered as part of + * Mi-V Extended Sub System(MIV_ESS) + */ + +#include "miv_udma_regs.h" +#include "miv_udma.h" + +/***************************************************************************//** + * MIV_uDMA_init() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_init +( + miv_udma_instance_t* this_udma, + addr_t base_addr +) +{ + /* Assign the Mi-V uDMA base address to the uDMA instance structure */ + this_udma->base_address = base_addr; +} + +/***************************************************************************//** + * MIV_uDMA_config() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_config +( + miv_udma_instance_t* this_udma, + addr_t src_addr, + addr_t dest_addr, + uint32_t transfer_size, + uint32_t irq_config +) +{ + /* Source memory start address */ + HAL_set_32bit_reg(this_udma->base_address, SRC_START_ADDR, src_addr); + + /* Destination memory start address */ + HAL_set_32bit_reg(this_udma->base_address, DEST_START_ADDR, dest_addr); + + /* Data transfer size */ + HAL_set_32bit_reg(this_udma->base_address, BLK_SIZE, transfer_size); + + /* Configure the uDMA IRQ */ + HAL_set_32bit_reg(this_udma->base_address, IRQ_CFG, irq_config); +} + +/***************************************************************************//** + * MIV_uDMA_start() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_start +( + miv_udma_instance_t* this_udma +) +{ + /* Start the uDMA transfer */ + HAL_set_32bit_reg(this_udma->base_address, CONTROL_SR, CTRL_START_TX_MASK); +} + +/***************************************************************************//** + * MIV_uDMA_reset() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_reset +( + miv_udma_instance_t* this_udma +) +{ + /* Toggle the uDMA_reset bit to reset the uDMA. + * Resetting the uDMA will clear all the configuration made by + * MIV_uDMA_config(). + * + * This function should be called from the interrupt handler to clear the + * IRQ. + */ + HAL_set_32bit_reg_field(this_udma->base_address, CTRL_RESET_TX, 0x1u); + HAL_set_32bit_reg_field(this_udma->base_address, CTRL_RESET_TX, 0x0u); +} + +/***************************************************************************//** + * MIV_uDMA_read_status() + * See "miv_udma.h" for details of how to use this function. + */ +uint32_t +MIV_uDMA_read_status +( + miv_udma_instance_t* this_udma +) +{ + uint32_t status = 0u; + + /* Read the status of the uDMA transfer. + * The transfer status register can be Error or Busy depending on the + * current uDMA transfer. + */ + status = HAL_get_32bit_reg(this_udma->base_address, TX_STATUS); + + return status; +} diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h new file mode 100644 index 0000000..efa8731 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h @@ -0,0 +1,290 @@ +/******************************************************************************* + * Copyright 2022-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * uDMA module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(MIV_ESS). + */ + +/*=========================================================================*//** + @mainpage Mi-V uDMA Bare Metal Driver. + The Mi-V uDMA bare metal software driver. + + @section intro_sec Introduction + The Mi-V uDMA driver provides a set of functions to control the Mi-V uDMA + module in the Mi-V Extended Subsystem (MIV_ESS) soft-IP. The Mi-V uDMA module + allows peripherals with AHB interfaces to transfer data independently of the + MIV_RV32 RISC-V processor. + + Following are the major features provided by the Mi-V uDMA driver: + - Initialization and configuration + - Start and reset the transaction + + This driver can be used as part of a bare metal system where no operating + system is available. The driver can be adapted for use as part of an + operating system, but the implementation of the adaptation layer between the + driver and the operating system's driver model is outside the scope of this + driver. + + @section hw_dependencies Hardware Flow Dependency + The application software should initialize and configure the Mi-V uDMA through + calling the MIV_uDMA_init() and MIV_uDMA_config() functions for each Mi-V + uDMA instance in the design. + + The uDMA can operate in two possible transfer configurations: + + - AHBL Read -> AHBL Write: + In this configuration, the uDMA reads data from the source memory over an + AHBL (mirrored main/initiator) read interface and writes data to the + destination memory over an AHBL (mirrored main/initiator) write interface. + + - AHBL Read -> TAS Write: + In this configuration, the uDMA reads data from the source memory over an + AHBL (mirrored main/initiator) read interface and writes data to the + destination memory over the TAS (mirrored main/initiator) write interface. + + Note: The AHBL Read -> TAS Write configuration is out of scope for this + driver. + + @section theory_op Theory of Operation + The uDMA module in the Mi-V Extended Sub System (MIV_ESS) is a single-channel + uDMA module that allows peripherals to perform read-write operations between + source and destination memory. The Mi-V uDMA driver is used in + interrupt-driven mode and uses the Mi-V uDMA IRQ signal to drive the + interrupt service routine (ISR), which signifies a transfer has completed. + The status is checked in the ISR to ensure the transfer is completed + successfully. + The reset operation in the ISR resets the Mi-V uDMA controller. Once the Mi-V + uDMA transfer is complete, Mi-V uDMA retires. To initiate another + transaction, Mi-V uDMA needs to be configured again. + + The operation of the Mi-V uDMA driver is divided into the following + categories: + - Initialization + - Configuration + - Start and reset the transfer + + Initialization and configuration: + Mi-V uDMA is first initialized by calling MIV_uDMA_init() function. This + function initializes the instance of Mi-V uDMA with the base address. The + MIV_uDMA_init() function must be called before calling any other Mi-V uDMA + driver functions. + + The Mi-V uDMA is configured by calling MIV_uDMA_config() function. This + function configures the source_addr and dest_addr registers of the Mi-V + uDMA with source and destination addresses for Mi-V uDMA transfers. + This function also configures the transfer size and interrupt preference for + successful transfers using Mi-V uDMA. + + Start and reset the transfer: + Once the Mi-V uDMA is configured, initiate the transfers by calling the + MIV_uDMA_start() function. Once the Mi-V uDMA transfer is started, it cannot + be aborted, and the status of the transfer should be read from the ISR by + calling the MIV_uDMA_read_status() function. + + Reset the Mi-V uDMA to the default state by calling the MIV_uDMA_reset() + function. After performing the reset operation, reconfigure the Mi-V uDMA to + perform transfers as MIV_uDMA_reset() resets the Mi-V uDMA controller. + */ + +#ifndef MIV_uDMA_H_ +#define MIV_uDMA_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#include "hal/cpu_types.h" + +#else +#include "hal.h" +#include "cpu_types.h" +#endif + +/*-------------------------------------------------------------------------*//** + MIV_uDMA_CTRL_IRQ_CONFIG + ===================== + + The MIV_uDMA_CTRL_IRQ_CONFIG macro is used to assert the uDMA IRQ when an error + occurs during a uDMA transfer or on the completion of a uDMA transfer. + */ +#define MIV_uDMA_CTRL_IRQ_CONFIG 1u + +/*-------------------------------------------------------------------------*//** + MIV_uDMA_STATUS_BUSY + ===================== + + The MIV_uDMA_STATUS_BUSY macro is used to indicate that the uDMA transfer is + in progress. + */ +#define MIV_uDMA_STATUS_BUSY 1u + +/*-------------------------------------------------------------------------*//** + MIV_uDMA_STATUS_ERROR + ===================== + + The MIV_uDMA_STATUS_ERROR macro is used to indicate that the last uDMA + transfer has caused an error. + */ +#define MIV_uDMA_STATUS_ERROR 2u + +/***************************************************************************//** + * This structure holds the base of the Mi-V uDMA module, which is used in the + * other functions of the driver to access the uDMA registers. + */ +typedef struct miv_udma_instance +{ + addr_t base_address; +} miv_udma_instance_t; + +/***************************************************************************//** + * The MIV_uDMA_init() function assigns the base address of the Mi-V uDMA module + * to the uDMA instance structure. + * This address is used in a later part of the driver to access the uDMA + * registers. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure. + * + * @param base_addr + * Base address of the Mi-V uDMA module. + * + * @return + * This function does not return a value. + */ +void +MIV_uDMA_init +( + miv_udma_instance_t* this_udma, + addr_t base_addr +); + +/***************************************************************************//** + * The MIV_uDMA_config() function is used to configure the Mi-V uDMA controller. + * This function will set the source address, destination address, block size, + * and IRQ configuration register. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @param base_addr + * Base address of the Mi-V uDMA. + * + * @param src_addr + * Source address of memory from where the uDMA reads the data. + * + * @param dest_addr + * Destination address where the data is written from src_addr. + * + * @param transfer_size + * Number of 32-bit words to transfer. + * + * @param irq_config + * uDMA IRQ configuration + * - When set, the IRQ is asserted when an error occurs during a uDMA + * transfer or on the completion of the uDMA transfer. + * - When clear, the IRQ is only asserted when an error occurs during a + * uDMA transfer. + * + * @return + * This function does not return any value. + */ +void +MIV_uDMA_config +( + miv_udma_instance_t* this_udma, + addr_t src_addr, + addr_t dest_addr, + uint32_t transfer_size, + uint32_t irq_config +); + +/***************************************************************************//** + * The MIV_uDMA_start() function is used to start the uDMA transfer. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @return + * This function does not return any value. + */ +void +MIV_uDMA_start +( + miv_udma_instance_t* this_udma +); + +/***************************************************************************//** + * The MIV_uDMA_reset() function is used to clear the uDMA interrupt and reset + * the uDMA transfer. + * + * This function should be called from the interrupt handler to reset the values + * set during MIV_uDMA_config(). + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @return + * This function does not return any value. + */ +void +MIV_uDMA_reset +( + miv_udma_instance_t* this_udma +); + +/***************************************************************************//** + * The MIV_uDMA_read_status() function is used to read the status of the uDMA + * transfer. When interrupt is enabled, this function can be called from the + * interrupt handler to know the reason for a uDMA interrupt. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @return + * The return value indicates an error due to the busy status of the uDMA + * channel. + * + * |Bit Number| Name | Description | + * |----------|---------|------------------------------------------------------| + * | 0 | Busy | When set indicates that uDMA transfer is in progress| + * | 1 | Error | When set indicates that last uDMA transfer caused an| + * | | | error. | + */ +uint32_t +MIV_uDMA_read_status +( + miv_udma_instance_t* this_pdma +); + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_uDMA_H_ */ diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h new file mode 100644 index 0000000..14d0759 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h @@ -0,0 +1,94 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP uDMA module driver. This module is delivered as a part of Mi-V + * extended Sub-System(ESS) MIV_ESS. + */ + +#ifndef MIV_UDMA_APB_REGISTERS +#define MIV_UDMA_APB_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/**************************************************************************//** + * Control start/Reset register details + */ + +#define CONTROL_SR_REG_OFFSET 0x0u + +/* Control start/Reset register bits */ +#define CONTROL_SR_OFFSET 0x00u +#define CONTROL_SR_MASK 0x03u +#define CONTROL_SR_SHIFT 0u + +/* uDMA Control Start Transfer */ + +#define CTRL_START_TX_OFFSET 0x00u +#define CTRL_START_TX_MASK 0x01u +#define CTRL_START_TX_SHIFT 0u + +/* uDMA Control Reset Transfer */ +#define CTRL_RESET_TX_OFFSET 0x00u +#define CTRL_RESET_TX_MASK 0x02u +#define CTRL_RESET_TX_SHIFT 1u + +/**************************************************************************//** + * IRQ Configuration register details + */ +#define IRQ_CFG_REG_OFFSET 0x4u + +/* Control start/Reset register bits */ +#define IRQ_CFG_OFFSET 0x04u +#define IRQ_CFG_MASK 0x01u +#define IRQ_CFG_SHIFT 0u + +/***************************************************************************//** + * Transfer Status register details + */ +#define TX_STATUS_REG_OFFSET 0x08u + +/* Transfer status register bits */ +#define TX_STATUS_OFFSET 0x08u +#define TX_STATUS_MASK 0x03u +#define TX_STATUS_SHIFT 0u + +/***************************************************************************//** + * Source Memory Start Address Register + */ +#define SRC_START_ADDR_REG_OFFSET 0x0cu + +/* Source Memory Start Address Register bits */ +#define SRC_START_ADDR_OFFSET 0x0cu +#define SRC_START_ADDR_MASK 0xFFFFFFFFu +#define SRC_START_ADDR_SHIFT 0u + +/***************************************************************************//** + * Destination Memory Start Address register details + */ +#define DEST_START_ADDR_REG_OFFSET 0x10u + +/* Destination Memory Start Address register bits */ +#define DEST_START_ADDR_OFFSET 0x10u +#define DEST_START_ADDR_MASK 0xFFFFFFFFu +#define DEST_START_ADDR_SHIFT 0x0u + +/***************************************************************************//** + * Block Size register details + */ +#define BLK_SIZE_REG_OFFSET 0x14u + +/* Destination Memory Start Address register bits */ +#define BLK_SIZE_OFFSET 0x14u +#define BLK_SIZE_MASK 0xFFFFFFFFu +#define BLK_SIZE_SHIFT 0x0u + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_UDMA_APB_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c new file mode 100644 index 0000000..525928a --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Mi-V Watchdog Soft IP bare-metal driver. This module is delivered as part of + * Extended Sub System(ESS) MIV_ESS. + * Please refer to miv_watchdog.h file for more information. + */ + +#include "miv_watchdog.h" + +addr_t g_this_wdog; + +/***************************************************************************//* + * Please refer to miv_watchdog.h for more info about this function + */ +void +MIV_WDOG_init +( + addr_t base_addr +) +{ + /* Register the Mi-V Watchdog base address to the driver */ + g_this_wdog = base_addr; +} + +/***************************************************************************//* + * Please refer to miv_watchdog.h for more info about this function + */ +uint8_t MIV_WDOG_configure +( + const miv_wdog_config_t *config +) +{ + uint8_t error = 0u; + + /* check load value and trigger max value */ + if (config->timeout_val <= MIV_WDOG_TRIGGER_MAX) + { + HAL_set_32bit_reg(g_this_wdog, WDOGTRIG,(config->timeout_val)); + } + else + { + error = 1u; + } + + if (config->time_val <= MIV_WDOG_TIMER_MAX) + { + HAL_set_32bit_reg(g_this_wdog, WDOGMSVP,(config->mvrp_val)); + } + else + { + error = 1u; + } + + HAL_set_32bit_reg_field(g_this_wdog, WDOGCNTL_NEXT_ENFORBIDDEN, + config->forbidden_en); + + /* Reload watchdog with new load if it is not in forbidden window */ + if (!(WDOGSTAT_FORBIDDEN_MASK & (HAL_get_32bit_reg(g_this_wdog, WDOGSTAT)))) + { + HAL_set_32bit_reg(g_this_wdog, WDOGRFSH, MIV_WDOG_REFRESH_KEY); + } + else + { + error = 1u; + } + + return (error); +} + +/***************************************************************************//* + * Please refer to miv_watchdog.h for more info about this function + */ +void MIV_WDOG_get_config +( + miv_wdog_config_t *config +) +{ + if (0 != g_this_wdog) + { + + config->time_val = HAL_get_32bit_reg(g_this_wdog, WDOGTIME); + + config->timeout_val = HAL_get_32bit_reg(g_this_wdog, WDOGTRIG); + + config->mvrp_val = HAL_get_32bit_reg(g_this_wdog, WDOGMSVP); + + config->forbidden_en = HAL_get_32bit_reg_field(g_this_wdog, + WDOGCNTL_NEXT_ENFORBIDDEN); + } +} + diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h new file mode 100644 index 0000000..8877e55 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h @@ -0,0 +1,553 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * Watchdog module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(MIV_ESS). + */ +/*=========================================================================*//** + @mainpage MiV Watchdog Bare Metal Driver + + ============================================================================== + Introduction + ============================================================================== + The Mi-V Watchdog module in the MIV_ESS is used to generate a reset for the + system automatically if the software doesn't periodically update or refresh + the timer countdown register. This software driver provides set of functions + for controlling Mi-V Watchdog module as a part of bare metal system where no + operating system is available. The driver can be adapted for use as a part of + an operating system, but the implementation of the adaptation layer between + the driver and the operating system's driver model is outside the scope of the + driver. + + Mi-V Watchdog provides following features: + - Initializing the Mi-V Watchdog + - Reading current value and status of watchdog timer + - Refreshing the watchdog timer value + - Enabling, disabling and clearing timeout and Maximum Value up to which + Refresh is Permitted (MVRP) interrupts. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + The application software should initialize and configure the Mi-V Watchdog + module the the call to the MIV_WDOG_init() and MIV_WDOG_configure() functions. + + No MIV_WDOG hardware configuration parameter are used by the driver, apart + from the MIV_WDOG base address. Hence, no additional configuration files are + required to use the driver. + + ============================================================================== + Theory of Operation + ============================================================================== + The Mi-V Watchdog driver functions are grouped into the following categories: + - Initialization and configuration + - Reading the current value and status of the watchdog timer + - Refreshing the watchdog timer value + - Support for enabling, disabling and clearing time-out and MVRP interrupts. + + -------------------------------- + Initialization and Configuration + -------------------------------- + The MIV_WDOG_init() function stores the base of MIV_WDT module in the MIV_ESS. + This base address is used by rest of the functions to access the Mi-V Watchdog + registers. Please make call this function before calling any other function + from this driver. + Note: The Mi-V Watchdog driver supports only one instance of MIV_WDT in the + hardware. + The Mi-V Watchdog driver provides the MIV_WDOG_configure() function to + configure the MIV_WDOG module with desired configuration values. It also + provides the MIV_WDOG_get_config() to read back the current configuration of + the MIV_WDOG. You can use this function to retrieve the current configurations + and then overwrite them with the application specific values, such as initial + watchdog timer value, Maximum Value (up to which) Refresh (is) Permitted, + watchdog time-out value, enable/disable forbidden region, enable/disable + MVRP interrupt and interrupt type. + + -------------------------------------------- + Reading the Watchdog Timer Value and Status + -------------------------------------------- + Mi-V Watchdog is a down counter. A refresh forbidden window can be created by + configuring the watchdog Maximum Value up to which Refresh is Permitted (MVRP). + When the current value of the watchdog timer is greater than the MVRP value, + refreshing the watchdog is forbidden. Attempting to refresh the watchdog timer + in the forbidden window will assert a timeout interrupt. The + MIV_WDOG_forbidden_status() function can be used to know whether the watchdog + timer is in forbidden window or has crossed it. By default, the forbidden + window is disabled. It can be enabled by providing an appropriate value as + parameter to the MIV_WDOG_configure() function. When the forbidden window is + disabled, any attempt to refresh the watchdog timer is ignored and the counter + keeps on down counting. + + The current value of the watchdog timer can be read using the + MIV_WDOG_current_value() function. This function can be called at any time. + + -------------------------------------------- + Refreshing the Watchdog Timer Value + -------------------------------------------- + The watchdog timer value is refreshed using the MIV_WDOG_reload() function. + The value reloaded into the watchdog timer down-counter is specified at the + configuration time with an appropriate value as parameter to the + MIV_WDOG_get_config() function. + + -------------------------------------------- + Interrupt Control + -------------------------------------------- + The Mi-V Watchdog generates two interrupts, The MVRP interrupt and + the timeout interrupt. + The MVRP interrupt is generated when the watchdog down-counter crosses the + Maximum Value up to which Refresh is Permitted (MVRP). Following functions to + control MVRP interrupt: + - MIV_WDOG_enable_mvrp_irq + - MIV_WDOG_disable_mvrp_irq + - MIV_WDOG_clear_mvrp_irq + + The timeout interrupt is generated when the watchdog down-counter crosses the + watchdog timeout value. The timeout value is a non-zero value and it can be + set to a maximum of MIV_WDOG_TRIGGER_MAX. The non-maskable interrupt is + generated when the watchdog crosses this timeout value, the down counter + keeps on down counting and a reset signal is generated when reaches zero. + Following functions to control timeout interrupt: + - MIV_WDOG_enable_timeout_irq + - MIV_WDOG_disable_timeout_irq + - MIV_WDOG_clear_timeout_irq + +*//*=========================================================================*/ + +#ifndef MIV_WATCHDOG_H_ +#define MIV_WATCHDOG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "miv_watchdog_regs.h" + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#else +#include "hal.h" +#endif + +/****************************************************************************//* + * The following constants can be used to configure the Mi-V Watchdog where a + * zero or non-zero value such as enable or disable is to be provided as a input + * parameter as shown below: + */ +#define MIV_WDOG_ENABLE 1u +#define MIV_WDOG_DISABLE 0u + +/***************************************************************************//** + The miv_wdog_config_t type for the watchdog Configuration structure. This + type is used as a parameter for the MIV_WDOG_configure() and the + MIV_WDOG_get_config() functions. + + Following are the values as part of this structure +| Parameter | Description | +|------------------|-----------------------------------------------------------| +| time_val | The value from which the watchdog timer counts down | +| mvrp_val | The Watchdog MVRP value | +| timeout_val | The watchdog timeout value | +| forbidden_en | Enable/disable the forbidden window | +| | When set, if a refresh occurs in the forbidden window, | +| | the watchdog timeout interrupt will be generated. | + +Time calculation example: + + time_val = 0xFFFFF0u + mvrp_val = 0x989680u + timeout_val = 0x3e8u + + A prescaler = 256 is used. + Considering clock = 50Mhz + + The MVRP interrupt will happen after + (0xFFFFF0 - 0x989680) * ( 1/(50MHz/256)) + mvrp interrupt will happen after 34 sec. after system reset + + (0xFFFFF0 - 0x3e8) * ( 1/(50MHz/256)) + timeout interrupt will happen after 85 sec. after system reset + */ +typedef struct miv_wdog_config +{ + uint32_t time_val; + uint32_t mvrp_val; + uint32_t timeout_val; + uint32_t forbidden_en; + uint32_t intr_type; +}miv_wdog_config_t; + +extern addr_t g_this_wdog; + +/***************************************************************************//* + Internal constants and types +*******************************************************************************/ + +/// @cond private +#define MIV_WDOG_TRIGGER_MAX 4095u +#define MIV_WDOG_TIMER_MAX 16777200u +/// @endcond + +/*-------------------------------------------------------------------------*//* +MIV_WDOG_REFRESH_KEY +===================== + +The MIV_WDOG_REFRESH_KEY macro holds the magic value which will cause a +reload of the watchdog's down counter when written to the watchdog's +WDOGREFRESH register. +*/ +#define MIV_WDOG_REFRESH_KEY (uint32_t)0xDEADC0DEU + +/*-------------------------------------------------------------------------*//* +MIV_WDOG_FORCE_RESET_KEY +===================== +The MIV_WDOG_FORCE_RESET_KEY macro holds the magic value which will force a +reset if the watchdog is already timeout. Writing any other value or writing +TRIGGER register at other times will trigger the watchdog NMI sequence +(i.e raise a timeout interrupt) + */ +#define MIV_WDOG_FORCE_RESET_KEY (uint32_t)0xDEADU + +/***************************************************************************//** + * The MIV_WDOG_init() is used to register the Mi-V Watchdog module base + * address to the driver. + * + * Note: User should call this function before calling any other Mi-V watchdog + * driver function. + * + * @param base_addr + * The base address of the Mi-V watchdog module. This address is used by + * rest of the watchdog driver functions to access the registers. + * + * @return + * This function does not return any value. + */ +void +MIV_WDOG_init +( + addr_t base_addr +); + +/***************************************************************************//** + * The MIV_WDOG_get_config() function returns the current configurations of the + * Mi-V Watchdog. The Mi-V Watchdog is pre-initialized by the flash + * bits at the design time. When used for the first time before calling the + * MIV_WDOG_configure() function, this function will return the default + * configurations as configured at the design time. + * + * @param config + * The config parameter is used to store the current configuration of the Mi-V + * Watchdog. + * + * Please see the description of miv_wdog_config_t for details. + * + * @return + * This function does not return any value. + * + * Example: + */ +void +MIV_WDOG_get_config +( + miv_wdog_config_t* config +); + +/***************************************************************************//** + * The MIV_WDOG_configure() function configures the watchdog module. The + * Watchdog module is pre-initialized by the flash bits at the design time to the + * default values. You can reconfigure the Watchdog module using + * MIV_WDOG_configure() function. + * + * Note that the MIV_WDOG_configure() function can be used only once, as it + * writes into the TIME register. After a write into the TIME register, the TIME, + * TRIGGER and MSVP register values are frozen and can't be altered again unless + * a system reset happens. + * + * Note also that the Mi-V Watchdog is not enabled at reset, calling this function + * will start the watchdog, it cannot then be disabled and must be refreshed + * periodically. + * + * @param config + * The config parameter is the input parameter in which the configurations to + * be applied to the watchdog module are provided by the application. + * Please see the description of miv_wdog_config_t for details. + * + * @return + * This function returns a zero value when executed successfully. A non-zero + * value is returned when the configuration values are out of bound. + * + * Example: + */ +uint8_t +MIV_WDOG_configure +( + const miv_wdog_config_t * config +); + +/***************************************************************************//** + * The MIV_WDOG_reload() function causes the watchdog to reload its down-counter + * timer with the load value configured through interrupt handler. This function + * must be called regularly to avoid a system reset or a watchdog interrupt. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_reload +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg(g_this_wdog, WDOGRFSH, MIV_WDOG_REFRESH_KEY); + } +} + +/***************************************************************************//** + * The MIV_WDOG_current_value() function returns the current value of the + * watchdog's down-counter. + * + * @param + * Void + * + * @return + * This function returns the current value of the watchdog’s down-counter as + * a 32-bit unsigned integer. + */ +static inline uint32_t +MIV_WDOG_current_value +( + void +) +{ + return (HAL_get_32bit_reg(g_this_wdog, WDOGRFSH)); +} + +/***************************************************************************//** + * The MIV_WDOG_forbidden_status() function returns the refresh status of the + * Mi-V Watchdog. + * + * @param + * Void + * + * @return + * This function returns the refresh status of the watchdog. A value of 1 + * indicates that watchdog's down-counter is within the forbidden window and + * that a reload should not be done. A value of 0 indicates that the watchdog's + * down counter is within the permitted window and that a reload is allowed. + */ +static inline uint32_t +MIV_WDOG_forbidden_status +( + void +) +{ + return (HAL_get_32bit_reg_field(g_this_wdog, WDOGSTAT_FORBIDDEN)); +} + +/***************************************************************************//** + * The MIV_WDOG_enable_mvrp_irq() function enables the MVRP interrupt. + * This interrupt is asserted when the timer countdown register leaves the + * maximum value up to which refresh is permitted (MVRP) window. + * + * @param + * Void + * + * @return + * This function does not return a value. + * + * Example: + */ +static inline void +MIV_WDOG_enable_mvrp_irq +( + void +) +{ + + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGCNTL_NEXT_INTENT_MSVP, 0x01u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_disable_mvrp_irq() function disables the generation of the + * MVRP interrupt. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_disable_mvrp_irq +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGCNTL_NEXT_INTENT_MSVP, 0x0u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_clear_timeout_irq() function clears the watchdog’s timeout + * interrupt which is connected to the MIV-RV32 interrupt. Calling + * MIV_WDOG_clear_timeout_irq() results in clearing the MIV-RV32 interrupt. + * Note: You must call the MIV_WDOG_clear_timeout_irq() function as part of your + * implementation of the interrupt handler in order to prevent the same + * interrupt event re-triggering a call to the timeout ISR. + * + * @param + * Void + * + * @return + * This function does not return any value. + * + */ +static inline void +MIV_WDOG_clear_timeout_irq +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_WDOG_TRIPPED, 0x01u); + /* + * Perform a second write to ensure that the first write completed before + * returning from this function. This is to account for posted writes across + * the AHB matrix. The second write ensures that the first write has + * completed and that the interrupt line has been de-asserted by the time + * the function returns. Omitting the second write may result in a delay + * in the de-assertion of the interrupt line going to the RISC-V and a + * retriggering of the interrupt. + */ + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_WDOG_TRIPPED, 0x01u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_clear_mvrp_irq() function clears the mvrp interrupt. + * + * Note: You must call the MIV_WDOG_clear_mvrp_irq() function as part of your + * implementation of the interrupt service routine (ISR) in order to + * prevent the same interrupt event re-triggering a call to the mvrp ISR. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_clear_mvrp_irq +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_MSVP_TRIPPED, 0x01u); + /* + * Perform a second write to ensure that the first write completed before + * returning from this function. This is to account for posted writes across + * the AHB matrix. The second write ensures that the first write has + * completed and that the interrupt line has been de-asserted by the time + * the function returns. Omitting the second write may result in a delay + * in the de-assertion of the interrupt line going to the RISC-V and a + * re-triggering of the interrupt. + */ + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_MSVP_TRIPPED, 0x01u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_timeout_occured() function reports the occurrence of a timeout + * event. + * + * @param + * Void + * + * @return + * A zero value indicates no watchdog timeout event occurred. A value of 1 + * indicates that a timeout event occurred. + */ +static inline uint32_t +MIV_WDOG_timeout_occured +( + void +) +{ + return (HAL_get_32bit_reg_field(g_this_wdog, WDOGSTAT_TRIGGERED)); +} + +/***************************************************************************//** + * The MIV_WDOG_force_reset() function is used to force an immediate reset + * if the watchdog has already triggered. Writing any value in this condition + * will result in watchdog timeout. + * The time out interrupt WDOG_IRQ will be set to high and watchdog timer + * countdown register updated with watchdog trigger timeout register value. + * If the Watchdog has timed out, a special 16-bit value needs to be written + * to the register to force a reset on CPU_RESETN, 0xDEAD + * Then the Watchdog countdown is reset/updated with the top Watchdog Runtime + * register value. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_force_reset +( + void +) +{ + if (WDOGSTAT_TRIGGERED_MASK == + HAL_get_32bit_reg_field(g_this_wdog, WDOGSTAT_TRIGGERED)) + + { + HAL_set_32bit_reg(g_this_wdog, WDOGFORCE, MIV_WDOG_FORCE_RESET_KEY); + } + + else + { + HAL_set_32bit_reg(g_this_wdog, WDOGFORCE, 0x0u); + } +} + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_WATCHDOG_H_ */ diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h new file mode 100644 index 0000000..2fca983 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h @@ -0,0 +1,122 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP watchdog module driver. This module is delivered as a part of Mi-V + * extended Sub-System(ESS) MIV_ESS. + */ + +#ifndef MIV_WDOG_REGISTERS +#define MIV_WDOG_REGISTERS 1u + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * Refresh register details + */ +#define WDOGRFSH_REG_OFFSET 0x00u + +/* Refresh register bits */ +#define WDOGRFSH_OFFSET 0x00u +#define WDOGRFSH_MASK 0xFFFFFFFFu +#define WDOGRFSH_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Control register details + */ +#define WDOGCNTL_REG_OFFSET 0x04u + +/* Control register next intent msvp bit */ +#define WDOGCNTL_NEXT_INTENT_MSVP_OFFSET 0x04u +#define WDOGCNTL_NEXT_INTENT_MSVP_MASK 0x01u +#define WDOGCNTL_NEXT_INTENT_MSVP_SHIFT 0u + +/* Control register next intent wdog bit */ +#define WDOGCNTL_NEXT_INTENT_WDOG_OFFSET 0x04u +#define WDOGCNTL_NEXT_INTENT_WDOG_MASK 0x02u +#define WDOGCNTL_NEXT_INTENT_WDOG_SHIFT 1u + +/* Control register next enforbidden bit */ +#define WDOGCNTL_NEXT_ENFORBIDDEN_OFFSET 0x04u +#define WDOGCNTL_NEXT_ENFORBIDDEN_MASK 0x10u +#define WDOGCNTL_NEXT_ENFORBIDDEN_SHIFT 4u + +/*------------------------------------------------------------------------------ + * Watchdog status register + */ +#define WDOGSTAT_REG_OFFSET 0x08u + +/* msvp_tripped bit */ +#define WDOGSTAT_MSVP_TRIPPED_OFFSET 0x08u +#define WDOGSTAT_MSVP_TRIPPED_MASK 0x01u +#define WDOGSTAT_MSVP_TRIPPED_SHIFT 0u + +/* WDOG Tripped bit */ +#define WDOGSTAT_WDOG_TRIPPED_OFFSET 0x08u +#define WDOGSTAT_WDOG_TRIPPED_MASK 0x02u +#define WDOGSTAT_WDOG_TRIPPED_SHIFT 1u + +/* Forbidden bit */ +#define WDOGSTAT_FORBIDDEN_OFFSET 0x08u +#define WDOGSTAT_FORBIDDEN_MASK 0x04u +#define WDOGSTAT_FORBIDDEN_SHIFT 2u + +/* Triggered bit */ +#define WDOGSTAT_TRIGGERED_OFFSET 0x08u +#define WDOGSTAT_TRIGGERED_MASK 0x08u +#define WDOGSTAT_TRIGGERED_SHIFT 3u + +/* wdoglocked bit */ +#define WDOGSTAT_WDOGLOCKED_OFFSET 0x08u +#define WDOGSTAT_WDOGLOCKED_MASK 0x10u +#define WDOGSTAT_WDOGLOCKED_SHIFT 4u + +/*------------------------------------------------------------------------------ + * Watchdog runtime register + */ +#define WDOGTIME_REG_OFFSET 0x0Cu + +/* wdogmsvp bit */ +#define WDOGTIME_WDOGVALUE_OFFSET 0x0Cu +#define WDOGTIME_WDOGVALUE_MASK 0xFFFFFFu +#define WDOGTIME_WDOGVALUE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Watchdog MVRP register + */ +#define WDOGMSVP_REG_OFFSET 0x10u + +/* wdogmsvp bit */ +#define WDOGMSVP_OFFSET 0x10u +#define WDOGMSVP_MASK 0xFFFFFFu +#define WDOGMSVP_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Watchdog Trigger Timeout register + */ +#define WDOGTRIG_REG_OFFSET 0x14u + +/* wdogmsvp bit */ +#define WDOGTRIG_WDOGRST_OFFSET 0x14u +#define WDOGTRIG_WDOGRST_MASK 0xFFFFFFu +#define WDOGTRIG_WDOGRST_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Watchdog Force Reset register details + */ +#define WDOGFORCE_REG_OFFSET 0x18u + +/* Refresh register bits */ +#define WDOGFORCE_OFFSET 0x18u +#define WDOGFORCE_MASK 0xFFFFFFFFu +#define WDOGFORCE_SHIFT 0u + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_WATCHDOG_REGS_H_ */ diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/hal/cpu_types.h b/applications/user-crypto/miv-rv32-keytree-services/src/platform/hal/cpu_types.h new file mode 100644 index 0000000..ef8ab20 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/hal/cpu_types.h @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file cpu_types.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Type definitions which can be commonly used by the fabric-ip drivers. + * + */ +#ifndef __CPU_TYPES_H +#define __CPU_TYPES_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned int size_t; + +/*------------------------------------------------------------------------------ + * addr_t: address type. + * Used to specify the address of peripherals present in the processor's memory + * map. + */ +typedef unsigned int addr_t; + +/*------------------------------------------------------------------------------ + * psr_t: processor state register. + * Used by HAL_disable_interrupts() and HAL_restore_interrupts() to store the + * processor's state between disabling and restoring interrupts. + */ +typedef unsigned int psr_t; + +#ifdef __cplusplus +} +#endif + +#endif /* CPU_TYPES_H */ + diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/hal/hal.h b/applications/user-crypto/miv-rv32-keytree-services/src/platform/hal/hal.h new file mode 100644 index 0000000..7eec17a --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/hal/hal.h @@ -0,0 +1,235 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file hal.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware abstraction layer functions for peripheral register accesses. + * + */ +#ifndef __HAL_H +#define __HAL_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include "cpu_types.h" +#include "hw_reg_access.h" +#include "hal_assert.h" +/***************************************************************************//** + * Enable all interrupts at the processor level. + */ +void HAL_enable_interrupts( void ); + +/***************************************************************************//** + * Disable all interrupts at the processor core level. + * Return the interrupts enable state before disabling occurred so that it can + * later be restored. + */ +psr_t HAL_disable_interrupts( void ); + +/***************************************************************************//** + * Restore the interrupts enable state at the processor core level. + * This function is normally passed the value returned from a previous call to + * HAL_disable_interrupts(). + */ +void HAL_restore_interrupts( psr_t saved_psr ); + +/***************************************************************************//** + */ +#define FIELD_OFFSET(FIELD_NAME) (FIELD_NAME##_OFFSET) +#define FIELD_SHIFT(FIELD_NAME) (FIELD_NAME##_SHIFT) +#define FIELD_MASK(FIELD_NAME) (FIELD_NAME##_MASK) + +/***************************************************************************//** + * The macro HAL_set_32bit_reg() allows writing a 32 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint32_t containing the value to write. + */ +#define HAL_set_32bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_32bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_32bit_reg() is used to read the value of a 32 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint32_t value. + */ +#define HAL_get_32bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_32bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)) )) + +/***************************************************************************//** + * The macro HAL_set_32bit_reg_field() is used to write a field within a + * 32 bits wide register. The field written can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * VALUE: A variable of type uint32_t containing the field value to write. + */ +#define HAL_set_32bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_32bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_32bit_reg_field() is used to read a register field from + * within a 32 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint32_t value. + */ +#define HAL_get_32bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_32bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +/***************************************************************************//** + * The macro HAL_set_16bit_reg() allows writing a 16 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint_fast16_t containing the value to write. + */ +#define HAL_set_16bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_16bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_16bit_reg() is used to read the value of a 16 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint16_t value. + */ +#define HAL_get_16bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_16bit_reg( (BASE_ADDR) + (REG_NAME##_REG_OFFSET) )) + +/***************************************************************************//** + * The macro HAL_set_16bit_reg_field() is used to write a field within a + * 16 bits wide register. The field written can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * VALUE: A variable of type uint16_t containing the field value to write. + */ +#define HAL_set_16bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_16bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_16bit_reg_field() is used to read a register field from + * within a 8 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint16_t value. + */ +#define HAL_get_16bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_16bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +/***************************************************************************//** + * The macro HAL_set_8bit_reg() allows writing a 8 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint_fast8_t containing the value to write. + */ +#define HAL_set_8bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_8bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_8bit_reg() is used to read the value of a 8 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint8_t value. + */ +#define HAL_get_8bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_8bit_reg( (BASE_ADDR) + (REG_NAME##_REG_OFFSET) )) + +/***************************************************************************//** + */ +#define HAL_set_8bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_8bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_8bit_reg_field() is used to read a register field from + * within a 8 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint8_t value. + */ +#define HAL_get_8bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_8bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +#ifdef __cplusplus +} +#endif + +#endif /*HAL_H*/ + diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/hal/hal_assert.h b/applications/user-crypto/miv-rv32-keytree-services/src/platform/hal/hal_assert.h new file mode 100644 index 0000000..1e18b54 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/hal/hal_assert.h @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hal_assert.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief HAL assert functions + */ +#ifndef __HAL_ASSERT_HEADER +#define __HAL_ASSERT_HEADER 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Disable assertions if we do not recognize the compiler. */ +#if defined ( __GNUC__ ) +#if defined(NDEBUG) +/***************************************************************************//** + * HAL_ASSERT() is defined out when the NDEBUG symbol is used. + ******************************************************************************/ +#define HAL_ASSERT(CHECK) + +#else + +/***************************************************************************//** + * Default behavior for HAL_ASSERT() macro: + *------------------------------------------------------------------------------ + The behavior is toolchain specific and project setting specific. + ******************************************************************************/ +#define HAL_ASSERT(CHECK)\ + do { \ + if (!(CHECK)) \ + { \ + __asm__ volatile ("ebreak"); \ + }\ + } while(0); + +#endif /* NDEBUG */ +#endif /*__GNUC__*/ + +#ifdef __cplusplus +} +#endif +#endif /* __HAL_ASSERT_HEADER */ + diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/hal/hal_irq.c b/applications/user-crypto/miv-rv32-keytree-services/src/platform/hal/hal_irq.c new file mode 100644 index 0000000..95a0775 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/hal/hal_irq.c @@ -0,0 +1,45 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hal_irq.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Legacy interrupt control functions for the Microchip driver library + * hardware abstraction layer. + * + */ +#include "hal.h" +#include "miv_rv32_hal/miv_rv32_hal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * + */ +void HAL_enable_interrupts(void) { + MRV_enable_interrupts(); +} + +/*------------------------------------------------------------------------------ + * + */ +psr_t HAL_disable_interrupts(void) { + psr_t psr; + psr = read_csr(mstatus); + MRV_disable_interrupts(); + return(psr); +} + +/*------------------------------------------------------------------------------ + * + */ +void HAL_restore_interrupts(psr_t saved_psr) { + write_csr(mstatus, saved_psr); +} + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/hal/hw_macros.h b/applications/user-crypto/miv-rv32-keytree-services/src/platform/hal/hw_macros.h new file mode 100644 index 0000000..189609c --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/hal/hw_macros.h @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hw_macros.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware registers access macros. + * + * THE MACROS DEFINED IN THIS FILE ARE DEPRECATED. DO NOT USE FOR NEW + * DEVELOPMENT. + * + * These macros are used to access peripheral registers. They allow access to + * 8, 16 and 32 bit wide registers. All accesses to peripheral registers should + * be done through these macros in order to ease porting across different + * processors/bus architectures. + * + * Some of these macros also allow access to a specific register field. + * + */ +#ifndef __HW_REGISTER_MACROS_H +#define __HW_REGISTER_MACROS_H 1 +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * 32 bits registers access: + */ +#define HW_get_uint32_reg(BASE_ADDR, REG_OFFSET) (*((uint32_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint32_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint32_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint32_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint32_t) \ + ( \ + (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint32_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint32_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 32 bits memory access: + */ +#define HW_get_uint32(BASE_ADDR) (*((uint32_t volatile *)(BASE_ADDR))) + +#define HW_set_uint32(BASE_ADDR, VALUE) (*((uint32_t volatile *)(BASE_ADDR)) = (VALUE)) + +/*------------------------------------------------------------------------------ + * 16 bits registers access: + */ +#define HW_get_uint16_reg(BASE_ADDR, REG_OFFSET) (*((uint16_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint16_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint16_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint16_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint16_t) \ + ( \ + (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint16_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint16_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 8 bits registers access: + */ +#define HW_get_uint8_reg(BASE_ADDR, REG_OFFSET) (*((uint8_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint8_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint8_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint8_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint8_t) \ + ( \ + (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint8_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint8_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 8 bits memory access: + */ +#define HW_get_uint8(BASE_ADDR) (*((uint8_t volatile *)(BASE_ADDR))) + +#define HW_set_uint8(BASE_ADDR, VALUE) (*((uint8_t volatile *)(BASE_ADDR)) = (VALUE)) + +#ifdef __cplusplus +extern "C" { +#endif + +#endif /* __HW_REGISTER_MACROS_H */ + diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/hal/hw_reg_access.S b/applications/user-crypto/miv-rv32-keytree-services/src/platform/hal/hw_reg_access.S new file mode 100644 index 0000000..dd29223 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/hal/hw_reg_access.S @@ -0,0 +1,215 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hw_reg_access.S + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware registers access functions. + * The implementation of these function is platform and toolchain specific. + * The functions declared here are implemented using assembler as part of the + * processor/toolchain specific HAL. This implementation is for the combination + * of the 32 bit RISC-V processors and GNU tool chain. + * + */ + +.section .text + .globl HW_set_32bit_reg + .globl HW_get_32bit_reg + .globl HW_set_32bit_reg_field + .globl HW_get_32bit_reg_field + .globl HW_set_16bit_reg + .globl HW_get_16bit_reg + .globl HW_set_16bit_reg_field + .globl HW_get_16bit_reg_field + .globl HW_set_8bit_reg + .globl HW_get_8bit_reg + .globl HW_set_8bit_reg_field + .globl HW_get_8bit_reg_field + + +/***************************************************************************//** + * HW_set_32bit_reg is used to write the content of a 32 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint32_t value + */ +HW_set_32bit_reg: + sw a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_32bit_reg is used to read the content of a 32 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + + * @return 32 bits value read from the peripheral register. + */ +HW_get_32bit_reg: + lw a0, 0(a0) + ret + +/***************************************************************************//** + * HW_set_32bit_reg_field is used to set the content of a field in a 32 bits + * wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint32_t mask + * a3: uint32_t value + */ +HW_set_32bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lw t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sw t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_32bit_reg_field is used to read the content of a field out of a + * 32 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint32_t mask + * + * @return 32 bits value containing the register field value specified + * as parameter. + */ +HW_get_32bit_reg_field: + lw a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +/***************************************************************************//** + * HW_set_16bit_reg is used to write the content of a 16 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint_fast16_t value + */ +HW_set_16bit_reg: + sh a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_16bit_reg is used to read the content of a 16 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + + * @return 16 bits value read from the peripheral register. + */ +HW_get_16bit_reg: + lh a0, (a0) + ret + +/***************************************************************************//** + * HW_set_16bit_reg_field is used to set the content of a field in a 16 bits + * wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast16_t mask + * a3: uint_fast16_t value + * @param value Value to be written in the specified field. + */ +HW_set_16bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lh t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sh t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_16bit_reg_field is used to read the content of a field from a + * 16 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast16_t mask + * + * @return 16 bits value containing the register field value specified + * as parameter. + */ +HW_get_16bit_reg_field: + lh a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +/***************************************************************************//** + * HW_set_8bit_reg is used to write the content of a 8 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint_fast8_t value + */ +HW_set_8bit_reg: + sb a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_8bit_reg is used to read the content of a 8 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + + * @return 8 bits value read from the peripheral register. + */ +HW_get_8bit_reg: + lb a0, 0(a0) + ret + +/***************************************************************************//** + * HW_set_8bit_reg_field is used to set the content of a field in a 8 bits + * wide peripheral register. + * + * a0: addr_t reg_addr, + * a1: int_fast8_t shift + * a2: uint_fast8_t mask + * a3: uint_fast8_t value + */ +HW_set_8bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lb t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sb t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_8bit_reg_field is used to read the content of a field from a + * 8 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast8_t mask + * + * @return 8 bits value containing the register field value specified + * as parameter. + */ +HW_get_8bit_reg_field: + lb a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +.end diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/hal/hw_reg_access.h b/applications/user-crypto/miv-rv32-keytree-services/src/platform/hal/hw_reg_access.h new file mode 100644 index 0000000..1a24309 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/hal/hw_reg_access.h @@ -0,0 +1,239 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hw_reg_access.S + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware registers access functions. + * The implementation of these function is platform and tool-chain specific. + * The functions declared here are implemented using assembler as part of the + * processor/tool-chain specific HAL. This implementation is for the combination + * of the 32 bit RISC-V processors and GNU tool chain. + * + */ +#ifndef __HW_REG_ACCESS +#define __HW_REG_ACCESS +#ifdef __cplusplus +extern "C" { +#endif + +#include "cpu_types.h" +/***************************************************************************//** + * HW_set_32bit_reg is used to write the content of a 32 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_32bit_reg +( + addr_t reg_addr, + uint32_t value +); + +/***************************************************************************//** + * HW_get_32bit_reg is used to read the content of a 32 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 32 bits value read from the peripheral register. + */ +uint32_t +HW_get_32bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_32bit_reg_field is used to set the content of a field in a 32 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void +HW_set_32bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint32_t mask, + uint32_t value +); + +/***************************************************************************//** + * HW_get_32bit_reg_field is used to read the content of a field out of a + * 32 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 32 bits value containing the register field value specified + * as parameter. + */ +uint32_t +HW_get_32bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint32_t mask +); + +/***************************************************************************//** + * HW_set_16bit_reg is used to write the content of a 16 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_16bit_reg +( + addr_t reg_addr, + uint_fast16_t value +); + +/***************************************************************************//** + * HW_get_16bit_reg is used to read the content of a 16 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 16 bits value read from the peripheral register. + */ +uint16_t +HW_get_16bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_16bit_reg_field is used to set the content of a field in a 16 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void HW_set_16bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast16_t mask, + uint_fast16_t value +); + +/***************************************************************************//** + * HW_get_16bit_reg_field is used to read the content of a field from a + * 16 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 16 bits value containing the register field value specified + * as parameter. + */ +uint16_t HW_get_16bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast16_t mask +); + +/***************************************************************************//** + * HW_set_8bit_reg is used to write the content of a 8 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_8bit_reg +( + addr_t reg_addr, + uint_fast8_t value +); + +/***************************************************************************//** + * HW_get_8bit_reg is used to read the content of a 8 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 8 bits value read from the peripheral register. + */ +uint8_t +HW_get_8bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_8bit_reg_field is used to set the content of a field in a 8 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void HW_set_8bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast8_t mask, + uint_fast8_t value +); + +/***************************************************************************//** + * HW_get_8bit_reg_field is used to read the content of a field from a + * 8 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 8 bits value containing the register field value specified + * as parameter. + */ +uint8_t HW_get_8bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast8_t mask +); + +#ifdef __cplusplus +} +#endif + +#endif /* __HW_REG_ACCESS */ + diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld b/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld new file mode 100644 index 0000000..474eb43 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld @@ -0,0 +1,154 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-execute-in-place.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * image executing from a one address space whereas the data, sdata and stack + * sections are placed in another address space. This could be used in cases such + * as: + * 1) When using MIV_RV32, the reset vector points to the LSRAM at address + * 0x80000000 and the data, sdata, bss and stack sections are placed in the + * TCM region. + * + * 2) Executing from a Non Volatile memory. The actual memory will depend on + * the FPGA platform. For exameple, it could be the eNVM on SmartFusion2, + * Igloo2 or on-board non-volatile memory which supports code execution. + * + * NOTE: Modify the memory section addresses and the sizes according to your + * Libero design. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + + +MEMORY +{ + rom (rx) : ORIGIN = 0x80000000, LENGTH = 16k + ram (rwx) : ORIGIN = 0x80004000, LENGTH = 16k +} + +STACK_SIZE = 1k; /* needs to be calculated for your application */ +HEAP_SIZE = 1k; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > rom + + .text : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.text.entry))) + . = ALIGN(0x10); + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } >rom + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } >ram AT>rom + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } >ram AT>rom + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram +} + diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv-rv32-ram.ld b/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv-rv32-ram.ld new file mode 100644 index 0000000..53076a0 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv-rv32-ram.ld @@ -0,0 +1,150 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-ram.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * debug image executing in SRAM. + * + * This linker script assumes that a RAM is connected at on Mi-V soft processor + * memory space pointed by the reset vector address. + * + * NOTE : Modify the memory section address and the size according to your + * Libero design. + * For example: + * 1) If you want to download and step debug at a different RAM memory address in + * your design (For example TCM base address) than the one provided in this file. + * 2) The MIV_RV32, when used with MIV_ESS IP, provides ways to copy the executable + * HEX file from external Non-Volatile memory into the TCM at reset. In this + * case your executable must be linked to the TCM address. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +MEMORY +{ + ram (rwx) : ORIGIN = 0x80000000, LENGTH = 32k +} + +STACK_SIZE = 2k; /* needs to be calculated for your application */ +HEAP_SIZE = 1k; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > ram + + .text : ALIGN(0x10) + { + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } > ram + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } > ram + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } > ram + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram +} + diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv_rv32_assert.h b/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv_rv32_assert.h new file mode 100644 index 0000000..b3912ed --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv_rv32_assert.h @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * MIV_RV32 HAL Embedded Software + * + */ +#ifndef MIV_RV32_ASSERT_HEADER +#define MIV_RV32_ASSERT_HEADER + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + * ASSERT() implementation. + ******************************************************************************/ +/* Disable assertions if we do not recognize the compiler. */ +#if defined ( __GNUC__ ) +#if defined(NDEBUG) +#define ASSERT(CHECK) +#else +#define ASSERT(CHECK)\ + do { \ + if (!(CHECK)) \ + { \ + __asm__ volatile ("ebreak"); \ + }\ + } while(0); + +#endif /* NDEBUG check */ +#endif /* compiler check */ + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_RV32_ASSERT_HEADER */ + diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv_rv32_entry.S b/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv_rv32_entry.S new file mode 100644 index 0000000..0ea3172 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv_rv32_entry.S @@ -0,0 +1,590 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_entry.S + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor vectors, trap handling and startup code. + * + */ +#ifndef ENTRY_S +#define ENTRY_S + +#define A_EXTENSION_MASK 0x00000001u +#define MTVEC_MODE_BIT_MASK 0x00000003u +#define MTVEC_VECTORED_MODE_VAL 0x00000001u + +#define MTIMEH_ADDR 0x200BFFCu + + +#if __riscv_xlen == 64 +# define LREG ld +# define SREG sd +# define REGBYTES 8 +#else +# define LREG lw +# define SREG sw +# define REGBYTES 4 +#endif + +#if defined(MIV_FP_CONTEXT_SAVE) && defined(__riscv_flen) +#define SP_SHIFT_OFFSET 64 +#else +#define SP_SHIFT_OFFSET 32 +#endif + +.macro STORE_CONTEXT + addi sp, sp, -SP_SHIFT_OFFSET*REGBYTES + SREG x1, 0 * REGBYTES(sp) + SREG x1, 0 * REGBYTES(sp) + SREG x2, 1 * REGBYTES(sp) + SREG x3, 2 * REGBYTES(sp) + SREG x4, 3 * REGBYTES(sp) + SREG x5, 4 * REGBYTES(sp) + SREG x6, 5 * REGBYTES(sp) + SREG x7, 6 * REGBYTES(sp) + SREG x8, 7 * REGBYTES(sp) + SREG x9, 8 * REGBYTES(sp) + SREG x10, 9 * REGBYTES(sp) + SREG x11, 10 * REGBYTES(sp) + SREG x12, 11 * REGBYTES(sp) + SREG x13, 12 * REGBYTES(sp) + SREG x14, 13 * REGBYTES(sp) + SREG x15, 14 * REGBYTES(sp) + SREG x16, 15 * REGBYTES(sp) + SREG x17, 16 * REGBYTES(sp) + SREG x18, 17 * REGBYTES(sp) + SREG x19, 18 * REGBYTES(sp) + SREG x20, 19 * REGBYTES(sp) + SREG x21, 20 * REGBYTES(sp) + SREG x22, 21 * REGBYTES(sp) + SREG x23, 22 * REGBYTES(sp) + SREG x24, 23 * REGBYTES(sp) + SREG x25, 24 * REGBYTES(sp) + SREG x26, 25 * REGBYTES(sp) + SREG x27, 26 * REGBYTES(sp) + SREG x28, 27 * REGBYTES(sp) + SREG x29, 28 * REGBYTES(sp) + SREG x30, 29 * REGBYTES(sp) + SREG x31, 30 * REGBYTES(sp) + + #ifdef __riscv_flen + #ifdef MIV_FP_CONTEXT_SAVE + fsw f0, 31*REGBYTES(sp) + fsw f1, 32*REGBYTES(sp) + fsw f2, 33*REGBYTES(sp) + fsw f3, 34*REGBYTES(sp) + fsw f4, 35*REGBYTES(sp) + fsw f5, 36*REGBYTES(sp) + fsw f6, 37*REGBYTES(sp) + fsw f7, 38*REGBYTES(sp) + fsw f8, 39*REGBYTES(sp) + fsw f9, 40*REGBYTES(sp) + fsw f10, 41*REGBYTES(sp) + fsw f11, 42*REGBYTES(sp) + fsw f12, 43*REGBYTES(sp) + fsw f13, 44*REGBYTES(sp) + fsw f14, 45*REGBYTES(sp) + fsw f15, 46*REGBYTES(sp) + fsw f16, 47*REGBYTES(sp) + fsw f17, 48*REGBYTES(sp) + fsw f18, 49*REGBYTES(sp) + fsw f19, 50*REGBYTES(sp) + fsw f20, 51*REGBYTES(sp) + fsw f21, 52*REGBYTES(sp) + fsw f22, 53*REGBYTES(sp) + fsw f23, 54*REGBYTES(sp) + fsw f24, 55*REGBYTES(sp) + fsw f25, 56*REGBYTES(sp) + fsw f26, 57*REGBYTES(sp) + fsw f27, 58*REGBYTES(sp) + fsw f28, 59*REGBYTES(sp) + fsw f29, 60*REGBYTES(sp) + fsw f30, 61*REGBYTES(sp) + fsw f31, 62*REGBYTES(sp) + #endif /* __riscv_flen */ + #endif /* MIV_FP_CONTEXT_SAVE */ +.endm + + .section .entry, "ax" + .globl _start + +_start: + j handle_reset + +/* Some of the Mi-V soft IP cores support compressed 'C' extension. If the Mi-V + core in your design doesn't support 'C' extension and you enable 'C' extension + in firmware project compiler options, then it would result in a trap. For this + case, we are avoiding compressed instruction here so you can put a breakpoint + at the jump and you can at least look at mcause, mepc and get some hints + about the crash. */ +trap_entry: +.option push +.option norvc +j generic_trap_handler +.option pop + .word 0 + .word 0 + +sw_trap_entry: + j vector_sw_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + +tmr_trap_entry: + j vector_tmr_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + +ext_trap_entry: + j vector_ext_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + .word 0 + +#ifndef MIV_LEGACY_RV32 +MGEUI_trap_entry: + j vector_MGEUI_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MGECI_trap_entry: + j vector_MGECI_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + .word 0 + +#ifndef MIV_RV32_V3_0 +MSYS_MIE22_trap_entry: +#ifndef MIV_RV32_V3_0 + j vector_SUBSYSR_IRQHandler +#endif /*MIV_RV32_V3_0*/ +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE23_trap_entry: + j vector_SUBSYS_IRQHandler +#ifdef __riscv_compressed + .2byte 0 +#endif +#endif /*MIV_RV32_V3_0*/ + +MSYS_MIE24_trap_entry: + j vector_MSYS_EI0_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE25_trap_entry: + j vector_MSYS_EI1_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE26_trap_entry: + j vector_MSYS_EI2_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE27_trap_entry: + j vector_MSYS_EI3_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE28_trap_entry: + j vector_MSYS_EI4_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE29_trap_entry: + j vector_MSYS_EI5_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE30_trap_entry: +#ifndef MIV_RV32_V3_0 + j vector_MSYS_EI6_trap_handler +#else + j vector_SUBSYS_IRQHandler +#endif +#ifdef __riscv_compressed + .2byte 0 +#endif + +#ifndef MIV_RV32_V3_0 +MSYS_MIE31_trap_entry: + j vector_MSYS_EI7_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif +#endif /* MIV_RV32_V3_0 */ +#endif /* MIV_LEGACY_RV32 */ + +.align 4 +generic_trap_handler: + STORE_CONTEXT + csrr a0, mcause + csrr a1, mepc + jal handle_trap + j generic_restore + +vector_sw_trap_handler: + STORE_CONTEXT + jal handle_m_soft_interrupt + j generic_restore + +vector_tmr_trap_handler: + STORE_CONTEXT + jal handle_m_timer_interrupt + j generic_restore + +vector_ext_trap_handler: + STORE_CONTEXT +#ifdef MIV_LEGACY_RV32 + jal handle_m_ext_interrupt +#else + jal External_IRQHandler +#endif /* MIV_LEGACY_RV32 */ + j generic_restore + +#ifndef MIV_LEGACY_RV32 +vector_MGEUI_trap_handler: + STORE_CONTEXT + jal MGEUI_IRQHandler + j generic_restore + +vector_MGECI_trap_handler: + STORE_CONTEXT + jal MGECI_IRQHandler + j generic_restore + +vector_MSYS_EI0_trap_handler: + STORE_CONTEXT + jal MSYS_EI0_IRQHandler + j generic_restore + +vector_MSYS_EI1_trap_handler: + STORE_CONTEXT + jal MSYS_EI1_IRQHandler + j generic_restore + +vector_MSYS_EI2_trap_handler: + STORE_CONTEXT + jal MSYS_EI2_IRQHandler + j generic_restore + +vector_MSYS_EI3_trap_handler: + STORE_CONTEXT + jal MSYS_EI3_IRQHandler + j generic_restore + +vector_MSYS_EI4_trap_handler: + STORE_CONTEXT + jal MSYS_EI4_IRQHandler + j generic_restore + +vector_MSYS_EI5_trap_handler: + STORE_CONTEXT + jal MSYS_EI5_IRQHandler + j generic_restore + +vector_SUBSYS_IRQHandler: + STORE_CONTEXT + jal SUBSYS_IRQHandler + j generic_restore + +#ifndef MIV_RV32_V3_0 +vector_MSYS_EI6_trap_handler: + STORE_CONTEXT + jal MSYS_EI6_IRQHandler + j generic_restore + +vector_MSYS_EI7_trap_handler: + STORE_CONTEXT + jal MSYS_EI7_IRQHandler + j generic_restore + + +vector_SUBSYSR_IRQHandler: + STORE_CONTEXT + jal SUBSYSR_IRQHandler + j generic_restore + +#endif /*MIV_RV32_V3_0*/ +#endif /* MIV_LEGACY_RV32 */ + +generic_restore: + LREG x1, 0 * REGBYTES(sp) + LREG x2, 1 * REGBYTES(sp) + LREG x3, 2 * REGBYTES(sp) + LREG x4, 3 * REGBYTES(sp) + LREG x5, 4 * REGBYTES(sp) + LREG x6, 5 * REGBYTES(sp) + LREG x7, 6 * REGBYTES(sp) + LREG x8, 7 * REGBYTES(sp) + LREG x9, 8 * REGBYTES(sp) + LREG x10, 9 * REGBYTES(sp) + LREG x11, 10 * REGBYTES(sp) + LREG x12, 11 * REGBYTES(sp) + LREG x13, 12 * REGBYTES(sp) + LREG x14, 13 * REGBYTES(sp) + LREG x15, 14 * REGBYTES(sp) + LREG x16, 15 * REGBYTES(sp) + LREG x17, 16 * REGBYTES(sp) + LREG x18, 17 * REGBYTES(sp) + LREG x19, 18 * REGBYTES(sp) + LREG x20, 19 * REGBYTES(sp) + LREG x21, 20 * REGBYTES(sp) + LREG x22, 21 * REGBYTES(sp) + LREG x23, 22 * REGBYTES(sp) + LREG x24, 23 * REGBYTES(sp) + LREG x25, 24 * REGBYTES(sp) + LREG x26, 25 * REGBYTES(sp) + LREG x27, 26 * REGBYTES(sp) + LREG x28, 27 * REGBYTES(sp) + LREG x29, 28 * REGBYTES(sp) + LREG x30, 29 * REGBYTES(sp) + LREG x31, 30 * REGBYTES(sp) + + #ifdef __riscv_flen + #ifdef MIV_FP_CONTEXT_SAVE + flw f0, 0 * REGBYTES(sp) + flw f1, 1 * REGBYTES(sp) + flw f2, 2 * REGBYTES(sp) + flw f3, 3 * REGBYTES(sp) + flw f4, 4 * REGBYTES(sp) + flw f5, 5 * REGBYTES(sp) + flw f6, 6 * REGBYTES(sp) + flw f7, 7 * REGBYTES(sp) + flw f8, 8 * REGBYTES(sp) + flw f9, 9 * REGBYTES(sp) + flw f10, 10 * REGBYTES(sp) + flw f11, 11 * REGBYTES(sp) + flw f12, 12 * REGBYTES(sp) + flw f13, 13 * REGBYTES(sp) + flw f14, 14 * REGBYTES(sp) + flw f15, 15 * REGBYTES(sp) + flw f16, 16 * REGBYTES(sp) + flw f17, 17 * REGBYTES(sp) + flw f18, 18 * REGBYTES(sp) + flw f19, 19 * REGBYTES(sp) + flw f20, 20 * REGBYTES(sp) + flw f21, 21 * REGBYTES(sp) + flw f22, 22 * REGBYTES(sp) + flw f23, 23 * REGBYTES(sp) + flw f24, 24 * REGBYTES(sp) + flw f25, 25 * REGBYTES(sp) + flw f26, 26 * REGBYTES(sp) + flw f27, 27 * REGBYTES(sp) + flw f28, 28 * REGBYTES(sp) + flw f29, 29 * REGBYTES(sp) + flw f30, 30 * REGBYTES(sp) + flw f31, 31 * REGBYTES(sp) + #endif /* __riscv_flen */ + #endif /* MIV_FP_CONTEXT_SAVE */ + + addi sp, sp, SP_SHIFT_OFFSET*REGBYTES + mret + + .section .text, "ax" +handle_reset: +/* Ensure instructions are not relaxed, since gp is not yet set */ +.option push +.option norelax + +#ifndef MIV_RV32_V3_0 + csrwi mstatus, 0 + csrwi mie, 0 + la ra, _start + +/* Clearnig this to be on safer side as RTL doesnt seem to clear it on reset. */ +#ifndef MIV_LEGACY_RV32 + li t0, MTIMEH_ADDR + sw x0, 0(t0) +#endif + + csrr t0, misa + andi t0, t0, A_EXTENSION_MASK + bnez t0, ima_cores_setup /* Jump to IMA core handling */ + + +/* For MIV_RV32 cores the mtvec exception base address is fixed at Reset vector + address + 0x4. Check the mode bits. */ +/* In the MIV_RV32 v3.1, the MTVEC exception base address is WARL, and can be + configured by the user at runtime */ + + csrr t0, mtvec + andi t0, t0, MTVEC_MODE_BIT_MASK + li t1, MTVEC_VECTORED_MODE_VAL + bne t0, t1, ima_cores_setup /* Jump to IMA core handling */ + + /* When mode = 1 => this is vectored mode on MIV_RV32 core. + Verify that the trap_handler address matches the configuration in MTVEC */ + csrr t0, mtvec + andi t0, t0, 0xFFFFFFFC + la t1, trap_entry + bne t0, t1, vector_address_not_matching + j generic_reset_handling + +#else /* MIV_RV32_V3_0 */ + +/* Clearnig this to be on safer side as RTL doesnt seem to clear it on reset. */ +#ifndef MIV_LEGACY_RV32 + li t0, MTIMEH_ADDR + sw x0, 0(t0) +#endif + +/* In the MIV_RV32 v3.1, the MTVEC exception base address is WARL, and can be + configured by the user at runtime */ + csrr t0, mtvec + andi t0, t0, MTVEC_MODE_BIT_MASK + li t1, MTVEC_VECTORED_MODE_VAL + bne t0, t1, ima_cores_setup /* Jump to IMA core handling */ + +/* When mode = 1 => this is vectored mode on MIV_RV32 core. + Verify that the trap_handler address matches the configuration in MTVEC */ + csrr t0, mtvec + andi t0, t0, 0xFFFFFFFC + la t1, trap_entry + bne t0, t1, vector_address_not_matching + j generic_reset_handling +#endif /*MIV_RV32_V3_0*/ + +ima_cores_setup: + la t0, trap_entry + +#ifdef MIV_LEGACY_RV32_VECTORED_INTERRUPTS + addi t0, t0, 0x01 /* Set the mode bit for IMA cores. + For both MIV_RV32 v3.1 and v3.0 cores this is done by configurator. */ +#endif + csrw mtvec, t0 + +generic_reset_handling: +/* Copy sdata section first so that the gp is set and linker relaxation can be + used */ + la a4, __sdata_load + la a5, __sdata_start + la a6, __sdata_end + beq a4, a5, 1f /* Exit if source and dest are same */ + beq a5, a6, 1f /* Exit if section start and end addresses are same */ + call block_copy + +1: + /* initialize global pointer */ + la gp, __global_pointer$ + +.option pop + +/* Floating point support configuration */ +#ifdef __riscv_flen + csrr t0, mstatus + lui t1, 0xffffa + addi t1, t1, -1 + and t0, t0, t1 + lui t1, 0x4 + or t1, t0, t1 + csrw mstatus, t1 + + lui t0, 0x0 + fscsr t0 +#endif + call initializations + /* Initialize stack pointer */ + la sp, __stack_top + + /* Jump into C code */ + j _init + +/* Error: trap_entry is not at the expected address of reset_vector+mtvec offset + as configured in the MIV_RV32 core vectored mode */ +vector_address_not_matching: + ebreak + +initializations: +/* Initialize the .bss section */ + mv t0, ra /* Store ra for future use */ + la a5, __bss_start + la a6, __bss_end + beq a5, a6, 1f /* Section start and end address are the same */ + call zeroize_block + +1: +/* Initialize the .sbss section */ + la a5, __sbss_start + la a6, __sbss_end + beq a5, a6, 1f /* Section start and end address are the same */ + call zeroize_block + +/* Clear heap */ + la a5, __heap_start + la a6, __heap_end + beq a5, a6, 1f /* Section start and end address are the same */ + call zeroize_block + +1: +/* Copy data section */ + la a4, __data_load + la a5, __data_start + la a6, __data_end + beq a4, a5, 1f /* Exit early if source and dest are same */ + beq a5, a6, 1f /* Section start and end addresses are the same */ + call block_copy + +1: + mv ra, t0 /* Retrieve ra */ + ret + +zeroize_block: + bltu a6, a5, block_copy_error /* Error. End address is less than start */ + or a7, a6, a5 /* Check if start or end is unalined */ + andi a7, a7, 0x03u + bgtz a7, block_copy_error /* Unaligned addresses error*/ +zeroize_loop: + sw x0, 0(a5) + add a5, a5, __SIZEOF_POINTER__ + blt a5, a6, zeroize_loop + ret + +block_copy: + bltu a6, a5, block_copy_error /* Error. End address is less than start */ + or a7, a6, a5 /* Check if start or end is unalined */ + andi a7, a7, 0x03u + bgtz a7, block_copy_error /* Unaligned addresses error*/ +block_copy_loop: + lw a7, 0(a4) + sw a7, 0(a5) + addi a5, a5, 0x04 + addi a4, a4, 0x04 + blt a5, a6, block_copy_loop + j block_copy_exit + +block_copy_error: + j block_copy_error + +block_copy_exit: + ret + +#endif /*ENTRY_S*/ diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv_rv32_hal.c b/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv_rv32_hal.c new file mode 100644 index 0000000..a112821 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv_rv32_hal.c @@ -0,0 +1,410 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_hal.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Implementation of Hardware Abstraction Layer for Mi-V soft processors + * + */ +#include +#include "miv_rv32_hal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SUCCESS 0U +#define ERROR 1U +#define MASK_32BIT 0xFFFFFFFFu + +/*------------------------------------------------------------------------------ + * Write in a sequence recommended by privileged spec to avoid spurious + * interrupts + + # New comparand is in a1:a0. + li t0, -1 + sw t0, mtimecmp # No smaller than old value. + sw a1, mtimecmp+4 # No smaller than new value. + sw a0, mtimecmp # New value. + */ +#ifndef MIV_RV32_EXT_TIMECMP +#define WRITE_MTIMECMP(value) MTIMECMPH = MASK_32BIT; \ + MTIMECMP = value & MASK_32BIT;\ + MTIMECMPH = (value >> 32u) & MASK_32BIT; +#else +#define WRITE_MTIMECMP(value) +#endif + +#ifndef MIV_RV32_EXT_TIMER +#define WRITE_MTIME(value) MTIME = value & MASK_32BIT;\ + MTIMEH = (value >> 32u) & MASK_32BIT; +#else +#define WRITE_MTIME(value) +#endif + +extern void Software_IRQHandler(void); + +#ifdef MIV_LEGACY_RV32 +#define MTIME_PRESCALER 100UL +/*------------------------------------------------------------------------------ + * + */ +uint8_t Invalid_IRQHandler(void); +uint8_t External_1_IRQHandler(void); +uint8_t External_2_IRQHandler(void); +uint8_t External_3_IRQHandler(void); +uint8_t External_4_IRQHandler(void); +uint8_t External_5_IRQHandler(void); +uint8_t External_6_IRQHandler(void); +uint8_t External_7_IRQHandler(void); +uint8_t External_8_IRQHandler(void); +uint8_t External_9_IRQHandler(void); +uint8_t External_10_IRQHandler(void); +uint8_t External_11_IRQHandler(void); +uint8_t External_12_IRQHandler(void); +uint8_t External_13_IRQHandler(void); +uint8_t External_14_IRQHandler(void); +uint8_t External_15_IRQHandler(void); +uint8_t External_16_IRQHandler(void); +uint8_t External_17_IRQHandler(void); +uint8_t External_18_IRQHandler(void); +uint8_t External_19_IRQHandler(void); +uint8_t External_20_IRQHandler(void); +uint8_t External_21_IRQHandler(void); +uint8_t External_22_IRQHandler(void); +uint8_t External_23_IRQHandler(void); +uint8_t External_24_IRQHandler(void); +uint8_t External_25_IRQHandler(void); +uint8_t External_26_IRQHandler(void); +uint8_t External_27_IRQHandler(void); +uint8_t External_28_IRQHandler(void); +uint8_t External_29_IRQHandler(void); +uint8_t External_30_IRQHandler(void); +uint8_t External_31_IRQHandler(void); + + +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for external interrupts. + */ +uint8_t (* const mrv_ext_irq_handler_table[32])(void) = +{ + + Invalid_IRQHandler, + External_1_IRQHandler, + External_2_IRQHandler, + External_3_IRQHandler, + External_4_IRQHandler, + External_5_IRQHandler, + External_6_IRQHandler, + External_7_IRQHandler, + External_8_IRQHandler, + External_9_IRQHandler, + External_10_IRQHandler, + External_11_IRQHandler, + External_12_IRQHandler, + External_13_IRQHandler, + External_14_IRQHandler, + External_15_IRQHandler, + External_16_IRQHandler, + External_17_IRQHandler, + External_18_IRQHandler, + External_19_IRQHandler, + External_20_IRQHandler, + External_21_IRQHandler, + External_22_IRQHandler, + External_23_IRQHandler, + External_24_IRQHandler, + External_25_IRQHandler, + External_26_IRQHandler, + External_27_IRQHandler, + External_28_IRQHandler, + External_29_IRQHandler, + External_30_IRQHandler, + External_31_IRQHandler +}; + +#else +/*------------------------------------------------------------------------------ + * Interrupt handlers as mapped into the MIE register of the MIV_RV32 + */ +extern void Reserved_IRQHandler(void); +extern void External_IRQHandler(void); +extern void MGEUI_IRQHandler(void); +extern void MGECI_IRQHandler(void); +extern void MSYS_EI0_IRQHandler(void); +extern void MSYS_EI1_IRQHandler(void); +extern void MSYS_EI2_IRQHandler(void); +extern void MSYS_EI3_IRQHandler(void); +extern void MSYS_EI4_IRQHandler(void); +extern void MSYS_EI5_IRQHandler(void); +extern void SUBSYS_IRQHandler(void); + +#ifndef MIV_RV32_V3_0 /*For MIV_RV32 v3.1*/ +extern void MSYS_EI6_IRQHandler(void); +extern void MSYS_EI7_IRQHandler(void); +extern void SUBSYSR_IRQHandler(void); // @suppress("Unused function declaration") +#endif /*MIV_RV32_V3_0*/ + +#endif /* MIV_LEGACY_RV32 */ + +/*------------------------------------------------------------------------------ + * Increment value for the mtimecmp register in order to achieve a system tick + * interrupt as specified through the MRV_systick_config() function. + */ +static uint64_t g_systick_increment = 0U; +static uint64_t g_systick_cmp_value = 0U; + +/*------------------------------------------------------------------------------ + * Configure the machine timer to generate an interrupt. + */ +uint32_t MRV_systick_config(uint64_t ticks) +{ + uint32_t ret_val = ERROR; + uint64_t remainder = ticks; + g_systick_increment = 0U; + g_systick_cmp_value = 0U; + + while (remainder >= MTIME_PRESCALER) + { + remainder -= MTIME_PRESCALER; + g_systick_increment++; + } + + g_systick_cmp_value = g_systick_increment + MRV_read_mtime(); + + if (g_systick_increment > 0U) + { + WRITE_MTIMECMP(g_systick_cmp_value); + set_csr(mie, MIP_MTIP); + MRV_enable_interrupts(); + ret_val = SUCCESS; + } + + return ret_val; +} + +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for machine timer interrupts. + */ +void handle_m_timer_interrupt(void) +{ + clear_csr(mie, MIP_MTIP); + + uint64_t mtime_at_irq = MRV_read_mtime(); + +#ifndef NDEBUG + static volatile uint32_t d_tick = 0u; +#endif + + while(g_systick_cmp_value < (mtime_at_irq + MTIME_DELTA)) { + g_systick_cmp_value = g_systick_cmp_value + g_systick_increment; + +#ifndef NDEBUG + d_tick += 1; +#endif + } +/***************************************************************************//** + /* + * Note: If d_tick > 1 it means, that a system timer interrupt has been + * missed. + * Please ensure that interrupt handlers are as short as possible to prevent + * them stopping other interrupts from being handled. For example, if a + * system timer interrupt occurs during a software interrupt, the system + * timer interrupt will not be handled until the software interrupt handling + * is complete. If the software interrupt handling time is more than one + * systick interval, it will result in d_tick > 1. + * If you are running the program using the debugger and halt the CPU at a + * breakpoint, MTIME will continue to increment and interrupts will be + * missed; resulting in d_tick > 1. + */ + + WRITE_MTIMECMP(g_systick_cmp_value); + + SysTick_Handler(); + + set_csr(mie, MIP_MTIP); +} + +void handle_m_soft_interrupt(void) +{ + Software_IRQHandler(); + MRV_clear_soft_irq(); +} +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for software interrupts. + */ +#ifdef MIV_LEGACY_RV32 +void handle_m_ext_interrupt(void) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; + uint8_t disable = EXT_IRQ_KEEP_ENABLED; + + if (0u !=int_num) + { + disable = mrv_ext_irq_handler_table[int_num](); + + PLIC->TARGET[hart_id].CLAIM_COMPLETE = int_num; + + if(EXT_IRQ_DISABLE == disable) + { + MRV_PLIC_disable_irq((IRQn_Type)int_num); + } + } +} +#else + +/*------------------------------------------------------------------------------ + * MSYS local interrupts table + */ +void (* const local_irq_handler_table[16])(void) = +{ +#ifndef MIV_RV32_V3_0 + MGEUI_IRQHandler, + MGECI_IRQHandler, + SUBSYS_IRQHandler, + SUBSYSR_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + MSYS_EI0_IRQHandler, + MSYS_EI1_IRQHandler, + MSYS_EI2_IRQHandler, + MSYS_EI3_IRQHandler, + MSYS_EI4_IRQHandler, + MSYS_EI5_IRQHandler, + MSYS_EI6_IRQHandler, + MSYS_EI7_IRQHandler +#else + MGEUI_IRQHandler, + MGECI_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + MSYS_EI0_IRQHandler, + MSYS_EI1_IRQHandler, + MSYS_EI2_IRQHandler, + MSYS_EI3_IRQHandler, + MSYS_EI4_IRQHandler, + MSYS_EI5_IRQHandler, + SUBSYS_IRQHandler, + Reserved_IRQHandler, +#endif +}; + +/*------------------------------------------------------------------------------ + * Jump to interrupt table containing local interrupts + */ +void handle_local_ei_interrupts(uint8_t irq_no) +{ + uint64_t mhart_id = read_csr(mhartid); + ASSERT(irq_no <= MIV_LOCAL_IRQ_MAX) + ASSERT(irq_no >= MIV_LOCAL_IRQ_MIN) + + uint8_t ei_no = (uint8_t)(irq_no - MIV_LOCAL_IRQ_MIN); + (*local_irq_handler_table[ei_no])(); +} +#endif /* MIV_LEGACY_RV32 */ + + +/*------------------------------------------------------------------------------ + * Trap handler. This function is invoked in the non-vectored mode. + */ +void handle_trap(uintptr_t mcause, uintptr_t mepc) +{ + uint64_t is_interrupt = mcause & MCAUSE_INT; + + if (is_interrupt) + { +#ifndef MIV_LEGACY_RV32 + if (((mcause & MCAUSE_CAUSE) >= MIV_LOCAL_IRQ_MIN) && ((mcause & MCAUSE_CAUSE) <= MIV_LOCAL_IRQ_MAX)) + { + handle_local_ei_interrupts((uint8_t)(mcause & MCAUSE_CAUSE)); + } + else if ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT) +#else + if ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT) +#endif + { +#ifndef MIV_LEGACY_RV32 + External_IRQHandler(); +#else + handle_m_ext_interrupt(); +#endif + } + else if ((mcause & MCAUSE_CAUSE) == IRQ_M_SOFT) + { + handle_m_soft_interrupt(); + } + else if ((mcause & MCAUSE_CAUSE) == IRQ_M_TIMER) + { + handle_m_timer_interrupt(); + } + } + else + { +#ifndef NDEBUG + /* + Arguments supplied to this function are mcause, mepc (exception PC) and + stack pointer. + Based on privileged-isa specification mcause values and meanings are: + + 0 Instruction address misaligned (mtval/mtval is the address) + 1 Instruction access fault (mtval/mtval is the address) + 2 Illegal instruction (mtval/mtval contains the + offending instruction opcode) + 3 Breakpoint + 4 Load address misaligned (mtval/mtval is the address) + 5 Load address fault (mtval/mtval is the address) + 6 Store/AMO address fault (mtval/mtval is the address) + 7 Store/AMO access fault (mtval/mtval is the address) + 8 Environment call from U-mode + 9 Environment call from S-mode + A Environment call from M-mode + B Instruction page fault + C Load page fault (mtval/mtval is the address) + E Store page fault (mtval/mtval is the address) + + # Please note: mtval is the newer name for register mbadaddr + # If you get a compile failure here, use the older name. + # At this point, both are supported in latest compiler, older compiler + # versions only support mbadaddr. + # See: https://github.com/riscv/riscv-gcc/issues/133 + */ + + /* interrupt pending */ + uintptr_t mip = read_csr(mip); + + /* additional info and meaning depends on mcause */ + uintptr_t mtval = read_csr(mtval); + + /* trap vector */ + uintptr_t mtvec = read_csr(mtvec); + + /* temporary, sometimes might hold temporary value of a0 */ + uintptr_t mscratch = read_csr(mscratch); + + /* status contains many smaller fields: */ + uintptr_t mstatus = read_csr(mstatus); + + /* PC value when the exception was taken*/ + uintptr_t mmepc = read_csr(mepc); + + /* breakpoint */ + __asm__("ebreak"); +#else + _exit(1 + mcause); +#endif /* NDEBUG */ + } +} + +#ifdef __cplusplus +} +#endif + diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv_rv32_hal.h b/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv_rv32_hal.h new file mode 100644 index 0000000..9ce9ef6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv_rv32_hal.h @@ -0,0 +1,773 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_hal.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware Abstraction Layer functions for Mi-V soft processors + * + */ + +/*=========================================================================*//** + @mainpage MIV_RV32 Hardware Abstraction Layer + + ============================================================================== + Introduction + ============================================================================== + This document describes the Hardware Abstraction Layer (HAL) for the MIV_RV32 + Soft IP Core. This release of the HAL corresponds to the Soft IP core MIV_RV32 + v3.1 release. It also supports earlier versions of the MIV_RV32 as well as the + legacy RV32 IP cores. + The preprocessor macros provided with the MIV_RV32 HAL are used to customize + it to target the Soft Processor IP version being used in your project. + + The term "MIV_RV32" represents following two cores: + - MIV_RV32 v3.0 and later (the latest and greatest Mi-V soft processor) + - MIV_RV32IMC v2.1 (MIV_RV32 v3.0 is a drop in replacement for this core) + It is highly recommended to migrate your design to MIV_RV32 v3.1 + + The term, Legacy RV32 IP cores, represents following IP cores: + - MIV_RV32IMA_L1_AHB + - MIV_RV32IMA_L1_AXI + - MIV_RV32IMAF_L1_AHB + + These legacy RV32 IP cores are deprecated. It is highly recommended to migrate + your designs to MIV_RV32 v3.1 (and subsequent IP releases) for the latest + enhancements, bug fixes, and support. + + -------------------------------- + MIV_RV32 V3.1 + -------------------------------- + This is the latest release of the MIV_RV32 Soft IP core. For more details, + refer to the MIV_RV32 User [Guide](https://www.microchip.com/en-us/products/fpgas-and-plds/ip-core-tools/miv-rv32) + + The MIV_RV32 Core as well as this document use the terms defined below: + + -------------------------------- + - SUBSYS - Processor Subsystem for RISC-V + - OPSRV - Offload Processor Subsystem for RISC-V + - GPR - General Purpose Registers + - MGECIE - Machine GPR ECC Correctable Interrupt Enable + - MGEUIE - Machine GPR ECC Uncorrectable Interrupt Enable + - MTIE - Machine Timer Interrupt Enable + - MEIE - Machine External Interrupt Enable + - MSIE - Machine Software Interrupt Enable + - ISR - Interrupt Service Routine + + ============================================================================== + Customizing MIV_RV32 HAL + ============================================================================== + To use the HAL with older releases of MIV_RV32, preprocessor macros have been + provided. Using these macros, any of the IP version is targeted. + The HAL is used to target any of the mentioned platforms by adding the + following macros in the way : + Project Properties > C/C++ Build > Settings > Preprocessor in Assembler and + Compiler settings. + The table below shows the macros corresponding to the MIV Core being used in + your libero project. By default, the HAL targets v3.1 of the IP core and no + macros need to be set for this configutation. + + | Libero MI-V Soft IP Version | SoftConsole Macro | + |-----------------------------|-------------------| + | MIV_RV32 v3.1 | no macro required | + | MIV_RV32 v3.0 | MIV_CORE_V3_0 | + | Legacy RV32 Cores | MIV_LEGACY_RV32 | + + -------------------------------- + Interrupt Handling + -------------------------------- + The MIE Register is defined as a enum in the HAL, and the table below is used + as a reference when the vectored interrupts are enabled in the GUI core + configurator. + + The MIE register is a RISC-V Control and Status Register (CSR), which stands + for the Machine Interrupt Enable. This is used to enable the machine mode + interrupts in the MIV_RV32 hart. Refer to the RISC-V Priv spec for more details. + + The following table shows the trap entry addresses when an interrupt occurs and + the vectored interrupts are enabled in the GUI configurator. + + | MIE Register Bit | Interrupt Enable | Vector Address | + |-------------------|------------------|----------------| + | 31 | MSYS_IE7 | mtvec.BASE + 0x7C | + | 30 | MSYS_IE6 | mtvec.BASE + 0x78 | + | 29 | MSYS_IE5 | mtvec.BASE + 0x74 | + | 28 | MSYS_IE4 | mtvec.BASE + 0x70 | + | 27 | MSYS_IE3 | mtvec.BASE + 0x6C | + | 26 | MSYS_IE2 | mtvec.BASE + 0x68 | + | 25 | MSYS_IE1 | mtvec.BASE + 0x64 | + | 24 | MSYS_IE0 | mtvec.BASE + 0x60 | + | 23 | SUBSYS_EI | mtvec.BASE + 0x5C | + | 22 | SUBSYSR | mtvec.BASE + 0x58 | + | 17 | MGECIE | mtvec.BASE + 0x44 | + | 16 | MGEUIE | mtvec.BASE + 0x40 | + | 11 | MEIE | mtvec.BASE + 0x2C | + | 7 | MTIE | mtvec.BASE + 0x1C | + | 3 | MSIE | mtvec.BASE + 0x0C | + + + For changes in MIE register map, see the [MIE Register Map for MIV_RV32 v3.0] + (#mie-register-map-for-miv_rv32-v3.0) section. + + SUBSYSR is currently not being used by the core and is Reserved for future use. + + The mtvec.BASE field corresponds to the bits [31:2], where mtvec stands for + Machine Trap Vector, and all traps set the PC to the the value stored in the + mtvec.BASE field when in Non-Vectored mode. In this case, a generic trap + handler is as an interrupt service routine. + + When Vectored interrupts are enabled, use this formula to calculate the trap + address: (mtvec.BASE + 4*cause), where cause comes from the mcause CSR. The + mcause register is written with a code indicating the event that caused the trap. + For more details, see the RISC-V priv specification. + + The MIV_RV32 Soft IP core does not contain a Platfrom Level Interrup Controller + (PLIC). It is advised to use the PLIC contained within the MIV_ESS sub-system. + Connect the PLIC interrupt output of the MIV_ESS to the EXT_IRQ pin on the + MIV_RV32. + + The following table is the MIE register map for the MIV_RV32 Core V3.0. It only + highlights the differences between the V3.0 and V3.1 of the core. + + -------------------------------- + MIE Register Map for MIV_RV32 V3.0 + -------------------------------- + + | MIE Register Bit | Target Interrupt | Vector Address | + |-------------------|------------------|----------------| + | 31 | Not in use | top table | + | 30 | SUBSYS_EI | addr + 0x78 | + | 23 | Not in use | Not in use | + | 22 | Not in use | Not in use | + + Other interrupt bit postions like the MGEUIE and MSYS_IE5 to MSYS_IE0 remain + unchanged. + + -------------------------------- + Floating Point Interrupt Support + -------------------------------- + When an interrupt is taken and Floating Point instructions are used in the + ISR, the floating point register context must be saved to resume the application + correctly. To use this feature, enable the provided macro in the + Softconsole build settings. + This feature is turned off by default as it adds overhead which is not required + when the ISR does not used FP insturctions and saving the general purpose + register context is sufficient. + + | Macro Name | Definition | + |--------------------------|-------------------------------------------------| + | MIV_FP_CONTEXT_SAVE | Define to save the FP register file | + + + -------------------------------- + SUBSYS - SubSystem for RISC-V + -------------------------------- + SUBSYS stands for SubSystem for RISC-V. This was previously (MIV_RV32 v3.0) + known as OPSRV, which stands for "Offload Processor Subsystem + for RISC-V". See the earlier versions of the handbook for more details. + In the latest release of the MIV_RV32 IP core v3.1, OPSRV has been renamed to + SUBSYS. The MIV_RV32 HAL now uses SUBSYS instead of OPSRV. + + *//*=========================================================================*/ +#ifndef RISCV_HAL_H +#define RISCV_HAL_H + +#include "miv_rv32_regs.h" +#include "miv_rv32_plic.h" +#include "miv_rv32_assert.h" +#include "miv_rv32_subsys.h" + +#ifndef LEGACY_DIR_STRUCTURE +#include "fpga_design_config/fpga_design_config.h" +#else +#include "hw_platform.h" +#endif /*LEGACY_DIR_STRUCTURE*/ + +#ifdef __cplusplus +extern "C" { +#endif +/*-------------------------------------------------------------------------*//** + SUBSYS Backwards Compatibility + ======================================= + For application code using the older macro names and API functions, these macros + act as a compatibility layer and applications which use OPSRV API features work + due to these macro definitions. However, it is adviced to update your + application code to use the SUBSYS macros and API functions. + + | Macro Name | Now Called | + |-------------------------|--------------------------| + | OPSRV_TCM_ECC_CE_IRQ | SUBSYS_TCM_ECC_CE_IRQ | + | OPSRV_TCM_ECC_UCE_IRQ | SUBSYS_TCM_ECC_UCE_IRQ | + | OPSRV_AXI_WR_RESP_IRQ | SUBSYS_AXI_WR_RESP_IRQ | + | MRV32_MSYS_OPSRV_IRQn | MRV32_SUBSYS_IRQn | + | MRV32_opsrv_enable_irq | MRV32_subsys_enable_irq | + | MRV32_opsrv_disable_irq | MRV32_subsys_disable_irq | + | MRV32_opsrv_clear_irq | MRV32_subsys_clear_irq | + | OPSRV_IRQHandler | SUBSYS_IRQHandler | + */ + +/*-------------------------------------------------------------------------*//** + MTIME Timer Interrupt Constants + ======================================= + These values contain the register addresses for the registers used by the + machine timer interrupt + + MTIME_PRESCALER is not defined on the MIV_RV32IMC v2.0 and v2.1. By using this + definition the system crashes. For those core, use the following definition: + + #define MTIME_PRESCALER 100u + + MTIME and MTIMECMP + -------------------------------- + MIV_RV32 core offers flexibility in terms of generating MTIME and MTIMECMP + registers internal to the core or using external time reference. There four + possible combinations: + + - Internal MTIME and Internal MTIME IRQ enabled Generate the MTIME and MTIMECMP + registers internally. (The only combination available on legacy RV32 cores) + + - Internal MTIME enabled and Internal MTIME IRQ disabled Generate the MTIME + internally and have a timer interrupt input to the core as external pin. In + this case, 1 pin port will be available on MIV_RV32 for timer interrupt. + + - When the internal MTIME is disabled, and the Internal MTIME IRQ is enabled, the + system generates the time value externally and generates the mtimecmp and + interrupt internally (for example, a multiprocessor system with a shared time + between all cores). In this case, a 64-bit port is available on the MIV_RV32 + core as input. + + - Internal MTIME and Internal MTIME IRQ disabled Generate both the time and + timer interrupts externally. In this case a 64 bit port will be available on + the MIV_RV32 core as input, and a 1 pin port will be available for timer + interrupt. + + To handle all these combinations in the firmware, the following constants must + be defined in accordance with the configuration that you have made on your + MIV_RV32 core design. + + MIV_RV32_EXT_TIMER + -------------------------------- + When defined, it means that the MTIME register is not available internal to + the core. In this case, a 64 bit port will be available on the MIV_RV32 core as + input. When this macro is not defined, it means that the MTIME register is + available internally to the core. + + MIV_RV32_EXT_TIMECMP + -------------------------------- + When defined, it means the MTIMECMP register is not available internally to + the core and the Timer interrupt input to the core comes as an external pin. + When this macro is not defined it means the that MTIMECMP register exists + internal to the core and that the timer interrupt is generated internally. + +NOTE: All these macros must not be defined if you are using a MIV_RV32 core. + */ + +#define OPSRV_TCM_ECC_CE_IRQ SUBSYS_TCM_ECC_CE_IRQ +#define OPSRV_TCM_ECC_UCE_IRQ SUBSYS_TCM_ECC_UCE_IRQ +#define OPSRV_AXI_WR_RESP_IRQ SUBSYS_AXI_WR_RESP_IRQ +#define MRV32_MSYS_OPSRV_IRQn MRV32_SUBSYS_IRQn +#define MRV32_opsrv_enable_irq MRV32_subsys_enable_irq +#define MRV32_opsrv_disable_irq MRV32_subsys_disable_irq +#define MRV32_opsrv_clear_irq MRV32_subsys_clear_irq +#define OPSRV_IRQHandler SUBSYS_IRQHandler + +/*-------------------------------------------------------------------------*//** + External IRQ + ======================================= + Return value from External IRQ handler. This is used to disable the + External Interrupt. + + | Macro Name | Value | Description| + |-------------------|--------|----------------| + | EXT_IRQ_KEEP_ENABLED | 0 | Keep external interrupts enabled | + | EXT_IRQ_DISABLE | 1 | Disable external interrupts | + */ +#define EXT_IRQ_KEEP_ENABLED 0U +#define EXT_IRQ_DISABLE 1U + +#define MTIME_DELTA 5 +#ifdef MIV_LEGACY_RV32 +#define MSIP (*(uint32_t*)0x44000000UL) +#define MTIMECMP (*(uint32_t*)0x44004000UL) +#define MTIMECMPH (*(uint32_t*)0x44004004UL) +#define MTIME (*(uint32_t*)0x4400BFF8UL) +#define MTIMEH (*(uint32_t*)0x4400BFFCUL) + +/* To maintain backward compatibility with FreeRTOS config code */ +#define PRCI_BASE 0x44000000UL +#else /* MIV_LEGACY_RV32 */ + +/* To maintain backward compatibility with FreeRTOS config code */ +#define PRCI_BASE 0x02000000UL + +#ifndef MIV_RV32_EXT_TIMECMP +#define MTIMECMP (*(volatile uint32_t*)0x02004000UL) +#define MTIMECMPH (*(volatile uint32_t*)0x02004004UL) +#else +#define MTIMECMP (0u) +#define MTIMECMPH (0u) +#endif + +#define MTIME_PRESCALER (*(volatile uint32_t*)0x02005000UL) + +#ifndef MIV_RV32_EXT_TIMER +#define MTIME (*(volatile uint32_t*)0x0200BFF8UL) +#define MTIMEH (*(volatile uint32_t*)0x0200BFFCUL) + +/***************************************************************************//** + MIMPID Register + The MIMPID register is a RISC-V Control and Status Register In the v3.0 of + MIV_RV32, the value of `MIMPID = 0x000540AD`. In the v3.1 of MIV_RV32, the + value if `MIMPID = 0xE5010301` corresponding to (E)mbedded (5)ystem(01) core + version (03).(01) this terminology will be followed in the subsequent releases + of the core read the csr value and store it in a varible which may be used to + check the MIV_RV32 core version during runtime. + + Future releases of the core will increment the 03 and 01 as major and minor + releases respectively and the register can be read at runtime to find the + Soft IP core version. + + | Core Version | Register | Value | Notes | + |----------------|------------|---------|---------| + | MIV_RV32 V3.1 | mimpid | 0xE5010301 | implimentation ID | + | MIV_RV32 V3.0 | mimpid | 0x000540AD | implimentation ID | + */ +#define MIMPID read_csr(mimpid) + +/*Used as a mask to read and write to mte mtvec.BASE address*/ +#define MTVEC_BASE_ADDR_MASK 0xFFFFFFFC + +#else +#define MTIME (0u) +#define MTIMEH (0u) +#endif /*MIV_RV32_EXT_TIMER*/ + +/*-------------------------------------------------------------------------*//** + RISC-V Specification Interrupts + ======================================= + These definitions are provided for easy identification of the interrupt + in the MIE/MIP registers. + Apart from the standard software, timer, and external interrupts, the names + of the additional interrupts correspond to the names as used in the MIV_RV32 + handbook. Please refer the MIV_RV32 handbook for more details. + + All the interrups, provided by the MIV_RV32 core, follow the interrupt priority + order and register description as mentioned in the RISC-V spec. + + | Macro Name | Value | Description| + |-------------------|--------|----------------| + | MRV32_SOFT_IRQn | MIE_3_IRQn | Software interrupt enable | + | MRV32_TIMER_IRQn | MIE_7_IRQn | Timer interrupt enable | + | MRV32_EXT_IRQn | MIE_11_IRQn | External interrupt enable | + + */ +#define MRV32_SOFT_IRQn MIE_3_IRQn +#define MRV32_TIMER_IRQn MIE_7_IRQn +#define MRV32_EXT_IRQn MIE_11_IRQn + +/***************************************************************************//** + Interrupt numbers: + This enum represents the interrupt enable bits in the MIE register. + */ +enum +{ + MIE_0_IRQn = (0x01u), + MIE_1_IRQn = (0x01u<<1u), + MIE_2_IRQn = (0x01u<<2u), + MIE_3_IRQn = (0x01u<<3u), /*MSIE 0xC*/ + MIE_4_IRQn = (0x01u<<4u), + MIE_5_IRQn = (0x01u<<5u), + MIE_6_IRQn = (0x01u<<6u), + MIE_7_IRQn = (0x01u<<7u), /*MTIE 0x1C*/ + MIE_8_IRQn = (0x01u<<8u), + MIE_9_IRQn = (0x01u<<9u), + MIE_10_IRQn = (0x01u<<10u), + MIE_11_IRQn = (0x01u<<11u), /*MEIE 0x2C*/ + MIE_12_IRQn = (0x01u<<12u), + MIE_13_IRQn = (0x01u<<13u), + MIE_14_IRQn = (0x01u<<14u), + MIE_15_IRQn = (0x01u<<15u), + MIE_16_IRQn = (0x01u<<16u), /*MGEUIE ECC Uncorrectable 0x40*/ + MIE_17_IRQn = (0x01u<<17u), /*MGECIE ECC Correctable 0x44*/ + MIE_18_IRQn = (0x01u<<18u), + MIE_19_IRQn = (0x01u<<19u), + MIE_20_IRQn = (0x01u<<20u), + MIE_21_IRQn = (0x01u<<21u), + MIE_22_IRQn = (0x01u<<22u), /*SUBSYSR 0x58 (R)eserved*/ + MIE_23_IRQn = (0x01u<<23u), /*SUBSYS_IE 0x5C for MIV_RV32 v3.1*/ + MIE_24_IRQn = (0x01u<<24u), /*MSYS_IE0 0x60*/ + MIE_25_IRQn = (0x01u<<25u), /*MSYS_IE1 0x64*/ + MIE_26_IRQn = (0x01u<<26u), /*MSYS_IE2 0x68*/ + MIE_27_IRQn = (0x01u<<27u), /*MSYS_IE3 0x6C*/ + MIE_28_IRQn = (0x01u<<28u), /*MSYS_IE4 0x70*/ + MIE_29_IRQn = (0x01u<<29u), /*MSYS_IE5 0x74*/ + MIE_30_IRQn = (0x01u<<30u), /*MSYS_IE6 0x78, read comment below*/ + MIE_31_IRQn = (0x01u<<31u) /*MSYS_IE7 0x7C*/ +} MRV_LOCAL_IRQn_Type; + +#define MRV32_MGEUIE_IRQn MIE_16_IRQn +#define MRV32_MGECIE_IRQn MIE_17_IRQn +#define MRV32_MSYS_EIE0_IRQn MIE_24_IRQn +#define MRV32_MSYS_EIE1_IRQn MIE_25_IRQn +#define MRV32_MSYS_EIE2_IRQn MIE_26_IRQn +#define MRV32_MSYS_EIE3_IRQn MIE_27_IRQn +#define MRV32_MSYS_EIE4_IRQn MIE_28_IRQn +#define MRV32_MSYS_EIE5_IRQn MIE_29_IRQn +#ifndef MIV_RV32_V3_0 /*For MIV_RV32 v3.1*/ +#define MRV32_SUBSYSR_IRQn MIE_22_IRQn +#define MRV32_SUBSYS_IRQn MIE_23_IRQn +#define MRV32_MSYS_EIE6_IRQn MIE_30_IRQn +#define MRV32_MSYS_EIE7_IRQn MIE_31_IRQn +#else +#define MRV32_SUBSYS_IRQn MIE_30_IRQn +#endif /*MIV_RV32_V3_0*/ + +/*--------------------------------Public APIs---------------------------------*/ + +/***************************************************************************//** + The MRV32_clear_gpr_ecc_errors() function clears single bit ECC errors on the + GPRs. The ECC block does not write back corrected data to memory. Hence, when + ECC is enabled for the GPRs and if that data has a single bit error then the + data coming out of the ECC block is corrected and will not have the error, but + the data source will still have the error. Therefore, if data has a single bit + error, then the corrected data must be written back to prevent the single bit + error from becoming a double bit error. Clear the pending interrupt bit after + this using MRV32_mgeci_clear_irq() function to complete the ECC error handling. + + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline void MRV32_clear_gpr_ecc_errors(void) +{ + uint32_t temp; + + __asm__ __volatile__ ( + "sw x31, %0" + :"=m" (temp)); + + __asm__ volatile ( + "mv x31, x1;" + "mv x1, x31;" + + "mv x31, x2;" + "mv x2, x31;" + + "mv x31, x3;" + "mv x3, x31;" + + "mv x31, x4;" + "mv x4, x31;" + + "mv x31, x5;" + "mv x5, x31;" + + "mv x31, x6;" + "mv x6, x31;" + + "mv x31, x7;" + "mv x7, x31;" + + "mv x31, x8;" + "mv x8, x31;" + + "mv x31, x9;" + "mv x9, x31;" + + "mv x31, x10;" + "mv x10, x31;" + + "mv x31, x11;" + "mv x11, x31;" + + "mv x31, x12;" + "mv x12, x31;" + + "mv x31, x13;" + "mv x13, x31;" + + "mv x31, x14;" + "mv x14, x31;" + + "mv x31, x15;" + "mv x15, x31;" + + "mv x31, x16;" + "mv x16, x31;" + + "mv x31, x17;" + "mv x17, x31;" + + "mv x31, x18;" + "mv x18, x31;" + + "mv x31, x19;" + "mv x19, x31;" + + "mv x31, x20;" + "mv x20, x31;" + + "mv x31, x21;" + "mv x21, x31;" + + "mv x31, x22;" + "mv x22, x31;" + + "mv x31, x23;" + "mv x23, x31;" + + "mv x31, x24;" + "mv x24, x31;" + + "mv x31, x25;" + "mv x25, x31;" + + "mv x31, x26;" + "mv x26, x31;" + + "mv x31, x27;" + "mv x27, x31;" + + "mv x31, x28;" + "mv x28, x31;" + + "mv x31, x29;" + "mv x29, x31;" + + "mv x31, x30;" + "mv x30, x31;"); + + __asm__ __volatile__ ( + "lw x31, %0;" + : + :"m" (temp)); +} + + +/***************************************************************************//** + The MRV32_mgeui_clear_irq() function clears the GPR ECC Uncorrectable + Interrupt. MGEUI interrupt is available only when ECC is enabled in the MIV_RV32 + IP configurator. + + @return + This function does not return any value. + */ +static inline void MRV32_mgeui_clear_irq(void) +{ + clear_csr(mip, MRV32_MGEUIE_IRQn); +} + +/***************************************************************************//** + The MRV32_mgeci_clear_irq() function clears the GPR ECC Correctable Interrupt + MGECI interrupt is available only when ECC is enabled in the MIV_RV32 IP + configurator. + + @return + This function does not return any value. + */ +static inline void MRV32_mgeci_clear_irq(void) +{ + clear_csr(mip, MRV32_MGECIE_IRQn); +} + +/***************************************************************************//** + The MRV_enable_local_irq() function enables the local interrupts. It takes a + mask value as input. For each set bit in the mask value, the corresponding + interrupt bit in the MIE register is enabled. + + MRV_enable_local_irq( MRV32_SOFT_IRQn | MRV32_TIMER_IRQn | MRV32_EXT_IRQn | + MRV32_MSYS_EIE0_IRQn | + MRV32_MSYS_SUBSYS_IRQn); + */ +static inline void MRV_enable_local_irq(uint32_t mask) +{ + set_csr(mie, mask); +} + +/***************************************************************************//** + The MRV_disable_local_irq() function disables the local interrupts. It takes a + mask value as input. For each set bit in the mask value, the corresponding + interrupt bit in the MIE register is disabled. + + MRV_disable_local_irq( MRV32_SOFT_IRQn | MRV32_TIMER_IRQn | MRV32_EXT_IRQn | + MRV32_MSYS_EIE0_IRQn | + MRV32_MSYS_SUBSYS_IRQn); + */ +static inline void MRV_disable_local_irq(uint32_t mask) +{ + clear_csr(mie, mask); +} +#endif /* MIV_LEGACY_RV32 */ + +/***************************************************************************//** + The MRV_enable_interrupts() function enables all interrupts by setting the + machine mode interrupt enable bit in MSTATUS register. + + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline void MRV_enable_interrupts(void) +{ + set_csr(mstatus, MSTATUS_MIE); +} + +/***************************************************************************//** + The MRV_disable_interrupts() function disables all interrupts by clearing the + machine mode interrupt enable bit in MSTATUS register. + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline void MRV_disable_interrupts(void) +{ + clear_csr(mstatus, MSTATUS_MPIE); + clear_csr(mstatus, MSTATUS_MIE); +} + +/***************************************************************************//** + The MRV_read_mtvec_base() function reads the mtvec base value, which is the + addr used when an interrupt/trap occurs. In the mtvec register, [31:2] is the + BASE address. NOTE: The BASE address must be aligned on a 4B boundary. + + @param + The function does not take any parameters. + + @return + The function returns the value of the BASE field [31:2] as an unsigned 32-bit + value. + */ + +#ifndef MIV_LEGACY_RV32 +#ifndef MIV_RV32_v3_0 +static inline uint32_t MRV_read_mtvec_base (void) +{ + uint32_t mtvec_addr_base = read_csr(mtvec); + return mtvec_addr_base & MTVEC_BASE_ADDR_MASK; +} + +/***************************************************************************//** + The MRV_set_mtvec_base() function takes the mtvec_base address as a unsigned int + and writes the value into the BASE field [31:2] in the mtvec CSR, MODE[1:0] + is Read-only. BASE is 4B aligned, so the lowest 2 bits of mtvec_base are + ignored. + + @param mtvec_base + Any legal value is passed into the function, and it is used as the trap_entry + for interrupts. The PC jumps to this address provided when an interrupt occurs. + In case of vectored interrupts, the address value mentioned in the vector + table under the MIE Register Map is updated to the value passed to this + function parameter. + + @return + This function does not return any value. + */ +static inline void MRV_set_mtvec_base (uint32_t mtvec_base) +{ + mtvec_base = mtvec_base & MTVEC_BASE_ADDR_MASK; + write_csr(mtvec, mtvec_base); +} +#endif /*MIV_RV32_v3_0*/ +#endif /*MIV_LEGACY_RV32*/ + +/***************************************************************************//** + The MRV_read_mtime() function returns the current MTIME register value. + */ +static inline uint64_t MRV_read_mtime(void) +{ + volatile uint32_t hi = 0u; + volatile uint32_t lo = 0u; + + /* when mtime lower word is 0xFFFFFFFF, there will be rollover and + * returned value could be wrong. */ + do { + hi = MTIMEH; + lo = MTIME; + } while(hi != MTIMEH); + + return((((uint64_t)MTIMEH) << 32u) | lo); +} + +/***************************************************************************//** + The MRV_raise_soft_irq() function raises a synchronous software interrupt + by writing into the MSIP register. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV_raise_soft_irq(void) +{ + set_csr(mie, MIP_MSIP); /* Enable software interrupt bit */ + +#ifdef MIV_LEGACY_RV32 + /* You need to make sure that the global interrupt is enabled */ + MSIP = 0x01; /* raise soft interrupt */ +#else + /* Raise soft IRQ on MIV_RV32 processor */ + SUBSYS->soft_reg |= SUBSYS_SOFT_IRQ; +#endif +} + +/***************************************************************************//** + The MRV_clear_soft_irq() function clears a synchronous software interrupt + by clearing the MSIP register. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV_clear_soft_irq(void) +{ +#ifdef MIV_LEGACY_RV32 + MSIP = 0x00u; /* clear soft interrupt */ +#else + /* Clear soft IRQ on MIV_RV32 processor */ + SUBSYS->soft_reg &= ~SUBSYS_SOFT_IRQ; +#endif +} + +/***************************************************************************//** + System tick handler. This handler function gets called when the Machine + timer interrupt asserts. An implementation of this function must be provided + by the application to implement the application specific machine timer + interrupt handling. If application does not provide such implementation, the + weakly linked handler stub function implemented in riscv_hal_stubs.c gets + linked. + */ +void SysTick_Handler(void); + +/***************************************************************************//** + System timer tick configuration. + Configures the machine timer to generate a system tick interrupt at regular + intervals. Takes the number of system clock ticks between interrupts. + + Though this function can take any valid ticks value as parameter, we expect + that, for all practical purposes, a small tick value (to generate periodic + interrupts every few miliseconds) is passed. If you need to generate periodic + events in the range of seconds or more, you may use the SysTick_Handler() to + further count the number of interrupts and hence the larger time intervals. + + @param ticks + This is the number of ticks or clock cycles which are counted down from the + interrupt to be triggered. + + @return + Returns 0 if successful. + Returns 1 if the interrupt interval is not achieved. + */ +uint32_t MRV_systick_config(uint64_t ticks); + +#ifdef __cplusplus +} +#endif +#endif /* RISCV_HAL_H */ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv_rv32_hal_version.h b/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv_rv32_hal_version.h new file mode 100644 index 0000000..4922bf2 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv_rv32_hal_version.h @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_hal_version.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware Abstraction Layer functions for Mi-V soft processors + * + */ + +#ifndef MIV_RV32_HAL_VERSION_H +#define MIV_RV32_HAL_VERSION_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MIV_RV32_HAL_VERSION_MAJOR 4 +#define MIV_RV32_HAL_VERSION_MINOR 2 +#define MIV_RV32_HAL_VERSION_PATCH 100 + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv_rv32_init.c b/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv_rv32_init.c new file mode 100644 index 0000000..85f8aca --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv_rv32_init.c @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_init.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor memory section initializations and start-up code. + * + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern void main(void); + +void _init(void) +{ + /* This function is a placeholder for the case where some more hardware + * specific initializations are required before jumping into the application + * code. You can implement it here. */ + + /* Jump to the application code after all initializations are completed */ + main(); +} + +/* Function called after main() finishes */ +void +_fini(void) +{ +} + +#ifdef __cplusplus +} +#endif + diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv_rv32_plic.h b/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv_rv32_plic.h new file mode 100644 index 0000000..3fd4103 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv_rv32_plic.h @@ -0,0 +1,214 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_plic.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V legacy RV32 soft processor PLIC access data structures and + * functions. + * Legacy RV32 soft processors are DEPRICATED. + * Migrate to MIV_RV32 v3.0 or later. + * + */ +#ifndef RISCV_PLIC_H +#define RISCV_PLIC_H + +#include +#include "miv_rv32_regs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================== + * Interrupt numbers: + */ +#ifdef MIV_LEGACY_RV32 +typedef enum +{ + MRV_NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + External_3_IRQn = 3, + External_4_IRQn = 4, + External_5_IRQn = 5, + External_6_IRQn = 6, + External_7_IRQn = 7, + External_8_IRQn = 8, + External_9_IRQn = 9, + External_10_IRQn = 10, + External_11_IRQn = 11, + External_12_IRQn = 12, + External_13_IRQn = 13, + External_14_IRQn = 14, + External_15_IRQn = 15, + External_16_IRQn = 16, + External_17_IRQn = 17, + External_18_IRQn = 18, + External_19_IRQn = 19, + External_20_IRQn = 20, + External_21_IRQn = 21, + External_22_IRQn = 22, + External_23_IRQn = 23, + External_24_IRQn = 24, + External_25_IRQn = 25, + External_26_IRQn = 26, + External_27_IRQn = 27, + External_28_IRQn = 28, + External_29_IRQn = 29, + External_30_IRQn = 30, + External_31_IRQn = 31 +} IRQn_Type; + +#define EXT_INTR_SOURCES 31 + +/*============================================================================== + * PLIC: Platform Level Interrupt Controller + */ +#define PLIC_BASE_ADDR 0x40000000UL + +typedef struct +{ + volatile uint32_t PRIORITY_THRESHOLD; + volatile uint32_t CLAIM_COMPLETE; + volatile uint32_t reserved[1022]; +} MRV_IRQ_Target_Type; + +typedef struct +{ + volatile uint32_t ENABLES[32]; +} MRV_Target_Enables_Type; + +typedef struct +{ + /*-------------------- Source Priority --------------------*/ + volatile uint32_t SOURCE_PRIORITY[1024]; + + /*-------------------- Pending array --------------------*/ + volatile const uint32_t PENDING_ARRAY[32]; + volatile uint32_t RESERVED1[992]; + + /*-------------------- Target enables --------------------*/ + volatile MRV_Target_Enables_Type TARGET_ENABLES[15808]; + + volatile uint32_t RESERVED2[16384]; + + /*--- Target Priority threshold and claim/complete---------*/ + MRV_IRQ_Target_Type TARGET[15872]; + +} PLIC_Type; + +#define PLIC ((PLIC_Type *)PLIC_BASE_ADDR) + +/*============================================================================== + * The function MRV_PLIC_init() initializes the PLIC controller and enables + * the global external interrupt bit. + */ +static inline void MRV_PLIC_init(void) +{ + uint32_t inc; + unsigned long hart_id = read_csr(mhartid); + + /* Disable all interrupts for the current hart. */ + for(inc = 0; inc < ((EXT_INTR_SOURCES + 32u) / 32u); ++inc) + { + PLIC->TARGET_ENABLES[hart_id].ENABLES[inc] = 0; + } + + /* Set priorities to zero. */ + for(inc = 0; inc < EXT_INTR_SOURCES; ++inc) + { + PLIC->SOURCE_PRIORITY[inc] = 0; + } + + /* Set the threshold to zero. */ + PLIC->TARGET[hart_id].PRIORITY_THRESHOLD = 0; + + /* Enable machine external interrupts. */ + set_csr(mie, MIP_MEIP); +} + +/*============================================================================== + * The function MRV_PLIC_enable_irq() enables the external interrupt for the + * interrupt number indicated by the parameter IRQn. + */ +static inline void MRV_PLIC_enable_irq(IRQn_Type IRQn) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t current = PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32]; + current |= (uint32_t)1 << (IRQn % 32); + PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32] = current; +} + +/*============================================================================== + * The function MRV_PLIC_disable_irq() disables the external interrupt for + * the interrupt number indicated by the parameter IRQn. + + * NOTE: + * This function can be used to disable the external interrupt from outside + * external interrupt handler function. + * This function MUST NOT be used from within the External Interrupt handler. + * If you wish to disable the external interrupt while the interrupt handler + * for that external interrupt is executing then you must use the return value + * EXT_IRQ_DISABLE to return from the extern interrupt handler. + */ +static inline void MRV_PLIC_disable_irq(IRQn_Type IRQn) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t current = PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32]; + + current &= ~((uint32_t)1 << (IRQn % 32)); + + PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32] = current; +} + +/*============================================================================== + * The function MRV_PLIC_set_priority() sets the priority for the external + * interrupt for the interrupt number indicated by the parameter IRQn. + */ +static inline void MRV_PLIC_set_priority(IRQn_Type IRQn, uint32_t priority) +{ + PLIC->SOURCE_PRIORITY[IRQn] = priority; +} + +/*============================================================================== + * The function MRV_PLIC_get_priority() returns the priority for the external + * interrupt for the interrupt number indicated by the parameter IRQn. + */ +static inline uint32_t MRV_PLIC_get_priority(IRQn_Type IRQn) +{ + return PLIC->SOURCE_PRIORITY[IRQn]; +} + +/***************************************************************************//** + * MRV_PLIC_clear_pending_irq(void) + * This is only called by the startup hart and only once + * Clears any pending interrupts as PLIC can be in unknown state on startup + */ +static inline void MRV_PLIC_clear_pending_irq(void) +{ + unsigned long hart_id = read_csr(mhartid); + volatile uint32_t int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; + volatile int32_t wait_possible_int; + + while (MRV_NoInterrupt_IRQn != int_num) + { + PLIC->TARGET[hart_id].CLAIM_COMPLETE = int_num; + wait_possible_int = 0xFU; + while (wait_possible_int) + { + wait_possible_int--; + } + + int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; + } +} + +#endif /* MIV_LEGACY_RV32 */ + +#ifdef __cplusplus +} +#endif + +#endif /* RISCV_PLIC_H */ diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv_rv32_regs.h b/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv_rv32_regs.h new file mode 100644 index 0000000..07d58e7 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv_rv32_regs.h @@ -0,0 +1,520 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor register bit mask and shift constants encodings. + * + */ +#ifndef MIV_RV32_REGS_H +#define MIV_RV32_REGS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MSTATUS_UIE 0x00000001UL +#define MSTATUS_SIE 0x00000002UL +#define MSTATUS_HIE 0x00000004UL +#define MSTATUS_MIE 0x00000008UL +#define MSTATUS_UPIE 0x00000010UL +#define MSTATUS_SPIE 0x00000020UL +#define MSTATUS_HPIE 0x00000040UL +#define MSTATUS_MPIE 0x00000080UL +#define MSTATUS_SPP 0x00000100UL +#define MSTATUS_HPP 0x00000600UL +#define MSTATUS_MPP 0x00001800UL +#define MSTATUS_FS 0x00006000UL +#define MSTATUS_XS 0x00018000UL +#define MSTATUS_MPRV 0x00020000UL +#define MSTATUS_SUM 0x00040000UL +#define MSTATUS_MXR 0x00080000UL +#define MSTATUS_TVM 0x00100000UL +#define MSTATUS_TW 0x00200000UL +#define MSTATUS_TSR 0x00400000UL +#define MSTATUS_RES 0x7F800000UL +#define MSTATUS32_SD 0x80000000UL +#define MSTATUS64_SD 0x8000000000000000UL + +#define MCAUSE32_CAUSE 0x7FFFFFFFUL +#define MCAUSE64_CAUSE 0x7FFFFFFFFFFFFFFFUL +#define MCAUSE32_INT 0x80000000UL +#define MCAUSE64_INT 0x8000000000000000UL + +#define MIP_SSIP (1u << IRQ_S_SOFT) +#define MIP_HSIP (1u << IRQ_H_SOFT) +#define MIP_MSIP (1u << IRQ_M_SOFT) +#define MIP_STIP (1u << IRQ_S_TIMER) +#define MIP_HTIP (1u << IRQ_H_TIMER) +#define MIP_MTIP (1u << IRQ_M_TIMER) +#define MIP_SEIP (1u << IRQ_S_EXT) +#define MIP_HEIP (1u << IRQ_H_EXT) +#define MIP_MEIP (1u << IRQ_M_EXT) + +#define PRV_M 3U + +#define VM_MBARE 0U +#define VM_MBB 1U +#define VM_MBBID 2U +#define VM_SV32 8U +#define VM_SV39 9U +#define VM_SV48 10U + +#define IRQ_S_SOFT 1U +#define IRQ_H_SOFT 2U +#define IRQ_M_SOFT 3U +#define IRQ_S_TIMER 5U +#define IRQ_H_TIMER 6U +#define IRQ_M_TIMER 7U +#define IRQ_S_EXT 9U +#define IRQ_H_EXT 10U +#define IRQ_M_EXT 11U + +#define DEFAULT_RSTVEC 0x00001000 +#define DEFAULT_NMIVEC 0x00001004 +#define DEFAULT_MTVEC 0x00001010 +#define CONFIG_STRING_ADDR 0x0000100C +#define EXT_IO_BASE 0x40000000 +#define DRAM_BASE 0x80000000 + +#ifdef __riscv + +#if __riscv_xlen == 64 +# define MSTATUS_SD MSTATUS64_SD +# define SSTATUS_SD SSTATUS64_SD +# define MCAUSE_INT MCAUSE64_INT +# define MCAUSE_CAUSE MCAUSE64_CAUSE +# define RISCV_PGLEVEL_BITS 9 +#else +# define MSTATUS_SD MSTATUS32_SD +# define SSTATUS_SD SSTATUS32_SD +# define RISCV_PGLEVEL_BITS 10 +# define MCAUSE_INT MCAUSE32_INT +# define MCAUSE_CAUSE MCAUSE32_CAUSE +#endif + +#define RISCV_PGSHIFT 12U +#define RISCV_PGSIZE (1U << RISCV_PGSHIFT) + +#ifndef __ASSEMBLER__ + +#ifdef __GNUC__ + +#define read_csr(reg) ({ unsigned long __tmp; \ + __asm__ volatile ("csrr %0, " #reg : "=r"(__tmp)); \ + __tmp; }) + +#define write_csr(reg, val) ({ \ + __asm__ volatile ("csrw " #reg ", %0" :: "rK"(val)); }) + +#define swap_csr(reg, val) ({ unsigned long __tmp; \ + __asm__ volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "rK"(val)); \ + __tmp; }) + +#define set_csr(reg, bit) ({ unsigned long __tmp; \ + __asm__ volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ + __tmp; }) + +#define clear_csr(reg, bit) ({ unsigned long __tmp; \ + __asm__ volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ + __tmp; }) + +#ifdef __riscv_atomic + +#define MASK(nr) (1UL << nr) +#define MASK_NOT(nr) (~(1UL << nr)) + +/** + * atomic_read - read atomic variable + * @v: pointer of type int + * + * Atomically reads the value of @v. + */ +static inline int atomic_read(const int *v) +{ + return *((volatile int *)(v)); +} + +/** + * atomic_set - set atomic variable + * @v: pointer of type int + * @i: required value + * + * Atomically sets the value of @v to @i. + */ +static inline void atomic_set(int *v, int i) +{ + *v = i; +} + +/** + * atomic_add - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v. + */ +static inline void atomic_add(int i, int *v) +{ + __asm__ __volatile__ ( + "amoadd.w zero, %1, %0" + : "+A" (*v) + : "r" (i)); +} + +static inline int atomic_fetch_add(unsigned int mask, int *v) +{ + int out; + + __asm__ __volatile__ ( + "amoadd.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_sub - subtract integer from atomic variable + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v. + */ +static inline void atomic_sub(int i, int *v) +{ + atomic_add(-i, v); +} + +static inline int atomic_fetch_sub(unsigned int mask, int *v) +{ + int out; + + __asm__ __volatile__ ( + "amosub.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_add_return - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v and returns the result + */ +static inline int atomic_add_return(int i, int *v) +{ + register int c; + __asm__ __volatile__ ( + "amoadd.w %0, %2, %1" + : "=r" (c), "+A" (*v) + : "r" (i)); + return (c + i); +} + +/** + * atomic_sub_return - subtract integer from atomic variable + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v and returns the result + */ +static inline int atomic_sub_return(int i, int *v) +{ + return atomic_add_return(-i, v); +} + +/** + * atomic_inc - increment atomic variable + * @v: pointer of type int + * + * Atomically increments @v by 1. + */ +static inline void atomic_inc(int *v) +{ + atomic_add(1, v); +} + +/** + * atomic_dec - decrement atomic variable + * @v: pointer of type int + * + * Atomically decrements @v by 1. + */ +static inline void atomic_dec(int *v) +{ + atomic_add(-1, v); +} + +static inline int atomic_inc_return(int *v) +{ + return atomic_add_return(1, v); +} + +static inline int atomic_dec_return(int *v) +{ + return atomic_sub_return(1, v); +} + +/** + * atomic_sub_and_test - subtract value from variable and test result + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v and returns + * true if the result is zero, or false for all + * other cases. + */ +static inline int atomic_sub_and_test(int i, int *v) +{ + return (atomic_sub_return(i, v) == 0); +} + +/** + * atomic_inc_and_test - increment and test + * @v: pointer of type int + * + * Atomically increments @v by 1 + * and returns true if the result is zero, or false for all + * other cases. + */ +static inline int atomic_inc_and_test(int *v) +{ + return (atomic_inc_return(v) == 0); +} + +/** + * atomic_dec_and_test - decrement and test + * @v: pointer of type int + * + * Atomically decrements @v by 1 and + * returns true if the result is 0, or false for all other + * cases. + */ +static inline int atomic_dec_and_test(int *v) +{ + return (atomic_dec_return(v) == 0); +} + +/** + * atomic_add_negative - add and test if negative + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v and returns true + * if the result is negative, or false when + * result is greater than or equal to zero. + */ +static inline int atomic_add_negative(int i, int *v) +{ + return (atomic_add_return(i, v) < 0); +} + +static inline int atomic_xchg(int *v, int n) +{ + register int c; + __asm__ __volatile__ ( + "amoswap.w %0, %2, %1" + : "=r" (c), "+A" (*v) + : "r" (n)); + return c; +} + +/** + * atomic_and - Atomically clear bits in atomic variable + * @mask: Mask of the bits to be retained + * @v: pointer of type int + * + * Atomically retains the bits set in @mask from @v + */ +static inline void atomic_and(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoand.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_and(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoand.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_or - Atomically set bits in atomic variable + * @mask: Mask of the bits to be set + * @v: pointer of type int + * + * Atomically sets the bits set in @mask in @v + */ +static inline void atomic_or(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoor.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_or(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoor.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_xor - Atomically flips bits in atomic variable + * @mask: Mask of the bits to be flipped + * @v: pointer of type int + * + * Atomically flips the bits set in @mask in @v + */ +static inline void atomic_xor(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoxor.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_xor(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoxor.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * test_and_set_bit - Set a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_set_bit(int nr, volatile unsigned long *addr) +{ + unsigned long __res, __mask; + __mask = MASK(nr); + __asm__ __volatile__ ( \ + "amoor.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to clear + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_clear_bit(int nr, volatile unsigned long *addr) +{ + unsigned long __res, __mask; + __mask = MASK_NOT(nr); + __asm__ __volatile__ ( \ + "amoand.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * test_and_change_bit - Change a bit and return its old value + * @nr: Bit to change + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_change_bit(int nr, volatile unsigned long *addr) +{ + + unsigned long __res, __mask; + __mask = MASK(nr); + __asm__ __volatile__ ( \ + "amoxor.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * set_bit - Atomically set a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * This function is atomic and may not be reordered. + */ + +static inline void set_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOOR.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK(nr))); +} + +/** + * clear_bit - Clears a bit in memory + * @nr: Bit to clear + * @addr: Address to start counting from + * + * clear_bit() is atomic and may not be reordered. + */ +static inline void clear_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOAND.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK_NOT(nr))); +} + +/** + * change_bit - Toggle a bit in memory + * @nr: Bit to change + * @addr: Address to start counting from + * + * change_bit() is atomic and may not be reordered. + */ +static inline void change_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOXOR.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK(nr))); +} + +#endif /* __riscv_atomic */ + +#endif /* __GNUC__ */ + +#endif /* __ASSEMBLER__ */ + +#endif /* __riscv */ + +#ifdef __cplusplus +} +#endif + +#endif /* RISCV_REGS_H */ diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv_rv32_stubs.c b/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv_rv32_stubs.c new file mode 100644 index 0000000..e26ecfc --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv_rv32_stubs.c @@ -0,0 +1,243 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_stubs.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Stubs for the Mi-V soft processor Interrupt handler. + * + * The functions below will only be linked with the application code if the user + * does not provide an implementation for these functions. These functions are + * defined with weak linking so that they can be overridden by a function with + * same prototype in the user's application code. + * + */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +__attribute__((weak)) void Software_IRQHandler(void) +{ + _exit(10); +} + +__attribute__((weak)) void SysTick_Handler(void) +{ + /* Default handler */ +} + +#ifdef MIV_LEGACY_RV32 +__attribute__((weak)) uint8_t Invalid_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_1_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_2_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_3_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_4_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_5_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_6_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_7_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_8_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_9_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_10_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_11_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_12_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_13_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_14_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_15_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_16_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_17_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_18_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_19_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_20_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_21_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_22_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_23_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_24_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_25_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_26_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_27_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_28_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_29_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_30_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_31_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +#else +__attribute__((weak)) void External_IRQHandler(void) +{ +} +__attribute__((weak)) void MGECI_IRQHandler(void) +{ +} +__attribute__((weak)) void MGEUI_IRQHandler(void) +{ +} +__attribute__((weak)) void SUBSYS_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI0_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI1_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI2_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI3_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI4_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI5_IRQHandler(void) +{ +} +__attribute__((weak)) void Reserved_IRQHandler(void) +{ + _exit(10); +} +#ifndef MIV_RV32_V3_0 /* For MIV_RV32 v3.0 */ +__attribute__((weak)) void MSYS_EI6_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI7_IRQHandler(void) +{ +} +__attribute__((weak)) void SUBSYSR_IRQHandler(void) +{ +} +#endif /* MIV_RV32_V3_0 */ +#endif /* MIV_LEGACY_RV32 */ + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv_rv32_subsys.h b/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv_rv32_subsys.h new file mode 100644 index 0000000..509f13b --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv_rv32_subsys.h @@ -0,0 +1,293 @@ +/******************************************************************************* + * Copyright 2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_subsys.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor SUBSYS regsiter description and API fuctions. + * + */ +#ifndef MIV_RV32_SUBSYS_H +#define MIV_RV32_SUBSYS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef MIV_LEGACY_RV32 +#define MGEUI 16U +#define MGECI 17U +#define MSYS_EI0 24U +#define MSYS_EI1 25U +#define MSYS_EI2 26U +#define MSYS_EI3 27U +#define MSYS_EI4 28U +#define MSYS_EI5 29U + +#define MGEUI_MEIP (1u << MGEUI) +#define MGECI_MEIP (1u << MGECI) +#define MSYS_EI0IP (1u << MSYS_EI0) +#define MSYS_EI1IP (1u << MSYS_EI1) +#define MSYS_EI2IP (1u << MSYS_EI2) +#define MSYS_EI3IP (1u << MSYS_EI3) +#define MSYS_EI4IP (1u << MSYS_EI4) +#define MSYS_EI5IP (1u << MSYS_EI5) + +#define MIV_LOCAL_IRQ_MIN 16 +#ifndef MIV_RV32_V3_0 /*For MIV_RV32 v3.1*/ +#define SUBSYSR 22U +#define SUBSYS_EI 23U +#define MSYS_EI6 30U +#define MSYS_EI7 31U +#define MIV_SUBSYSR (1u << SUBSYSR) +#define MIV_SUBSYS (1u << SUBSYS_EI) +#define MSYS_EI6IP (1u << MSYS_EI6) +#define MSYS_EI7IP (1u << MSYS_EI7) +#define MIV_LOCAL_IRQ_MAX 31 + +#else /* MIV_RV32_V3_0 */ +#define MIV_LOCAL_IRQ_MAX 29 +#define SUBSYS_EI 30U +#define MIP_SUBSYS_REG (1u << SUBSYS_EI) + +#endif /* MIV_RV32_V3_0 */ +#endif /* MIV_LEGACY_RV32 */ + +#ifdef MIV_LEGACY_RV32 +#define MIV_LOCAL_IRQ_MAX 0U +#define MIV_LOCAL_IRQ_MIN 0U +#endif /* MIV_LEGACY_RV32 */ + +#ifdef __cplusplus +} +#endif + +/*-------------------------------------------------------------------------*//** + SUBSYS Register Configuration + ======================================= + For the SUBSYS registers configutation, the following definitions are used in + the SUBSUS API functions. For example, to raise soft interrupts, enable parity + checks, soft reset, and so on. + + | Configuration | Value | Description | + |--------------------------|-------|------------------------------------------------| + | SUBSYS_SOFT_REG_GRP_DED | 0x04 | Mask for the Core GPR DED Reset Register | + | SUBSYS_CFG_PARITY_CHECK | 0x01 | Use to set or clear the parity check on the TCM | + | SUBSYS_SOFT_RESET | 0x01 | Use the SUBSYS soft reset the MIV_RV32 IP core | + | SUBSYS_SOFT_IRQ | 0x02 | Use to raise a software interrupt through SUBSYS| + */ +/*Mask for the Core GPR DED Reset Register*/ +#define SUBSYS_SOFT_REG_GRP_DED 0x04U + +/*Use to set or clear the parity check on the TCM*/ +#define SUBSYS_CFG_PARITY_CHECK 0x01U + +/*Use the SUBSYS soft reset the MIV_RV32 IP core*/ +#define SUBSYS_SOFT_RESET 0x01U + +/*Use to raise a software interrupt through SUBSYS*/ +#define SUBSYS_SOFT_IRQ 0x02U + +/*-------------------------------------------------------------------------*//** + SUBSYS Interrupt Request Masks + ======================================= + The following values correspond to the bit value of the SUBSYS interrupt + enable and interrupt pending register. + + | Interrupt Mask | Value | Description | + |----------------------------|---------|-------------------------------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | TCM ECC controllable error irq enable | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | TCM ECC uncontrollable error irq enable | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | AXI write response error irq enable | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | Icache ECC Correctable error irq | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | Icache ECC Uncorrectable error irq | + | SUBSYS_BASE_ADDR | 0x6000u | Base address of the SUBSYS | + */ +/* TCM ECC correctable error irq enable mask value */ +#define SUBSYS_TCM_ECC_CE_IRQ 0x01u + +/* TCMECC uncorrectable error irq enable */ +#define SUBSYS_TCM_ECC_UCE_IRQ 0x02u + +/* AXI write response error irq enable */ +#define SUBSYS_AXI_WR_RESP_IRQ 0x10u + +/*Icache ECC Correctable error irq*/ +#define SUBSYS_ICACHE_ECC_CE_IRQ 0x40u + +/*Icache ECC Uncorrectable error irq*/ +#define SUBSYS_ICACHE_ECC_UCE_IRQ 0x80u + +/*Base address of the SUBSYS*/ +#define SUBSYS_BASE_ADDR 0x00006000UL + +/***************************************************************************//** + Subsys contains interrupt enable, interrupt pending and Subsys registers + which can be used to enable SUBSYS specific features such as ECC for vaious + memories. For more available features refer to the MIV_RV32 User Guide +*/ +typedef struct +{ + volatile uint32_t cfg; /*Parity is not supported by MIV_RV32 v3.1 and MIV_RV32 v3.0.100*/ + volatile uint32_t reserved0[3]; + volatile uint32_t irq_en; /*offset 0x10*/ + volatile uint32_t irq_pend; + volatile uint32_t reserved1[2]; + volatile uint32_t soft_reg; /*offset 0x20*/ +} SUBSYS_Type; + +#define SUBSYS ((SUBSYS_Type *)SUBSYS_BASE_ADDR) + +/***************************************************************************//** + The MRV32_subsys_enable_irq() function initializes the SUBSYS interrupts. It + takes the logical OR of the following defined IRQ masks as a parameter. + + @param irq_mask + | irq_mask | Value | + |------------------------|------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | + Use logical OR values of one or more interrupts to enable them in the SUBSYS + @return + This function does not return any value. + */ +static inline void MRV32_subsys_enable_irq(uint32_t irq_mask) +{ + SUBSYS->irq_en |= irq_mask; +} + +/***************************************************************************//** + The MRV32_subsys_disable_irq() function disables the SUBSYS interrupts. It + takes the logical OR of the following defined IRQ masks as a parameter. + + @param irq_mask + | irq_mask | Value | + |------------------------|------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | + Use logical OR values of one or more interrupts to disable them in the SUBSYS + @return + This function does not return any value. + */ +static inline void MRV32_subsys_disable_irq(uint32_t irq_mask) +{ + SUBSYS->irq_en &= ~irq_mask; +} + +/***************************************************************************//** + The MRV32_subsys_clear_irq() function clears the SUBSYS interrupts, which was + triggered. It takes the logical OR of the following defined IRQ masks as a + parameter. + @param irq_mask + | irq_mask | Value | + |------------------------|------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | + Use logical OR values of one or more interrupts to disable them in the SUBSYS + @return + This function does not return any value. + */ +static inline void MRV32_subsys_clear_irq(uint32_t irq_mask) +{ + SUBSYS->irq_pend |= irq_mask; +} + +/***************************************************************************//** + The MRV32_subsys_irq_cause() function returns the irq_pend register value which + is present in the SUBSYS. This is be used to check which irq_mask value + caused the SUBSYS interrupt to occur. + @param + This function does not take any parameters + + @return + This function returns the irq_pend regsiter value. +*/ +static inline uint32_t MRV32_subsys_irq_cause() +{ + return SUBSYS->irq_pend; +} + +/***************************************************************************//** + The MRV32_is_gpr_ded() function returns the core_gpr_ded_reset_reg bit value. + When ECC is enabled, the core_gpr_ded_reset_reg is set when the core was + reset due to GPR DED error. + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline uint32_t MRV32_is_gpr_ded(void) +{ + return((SUBSYS->soft_reg & SUBSYS_SOFT_REG_GRP_DED) >> 0x02u); +} + +/***************************************************************************//** + The MRV32_clear_gpr_ded() function must be used to clear the + core_gpr_ded_reset_reg bit. When ECC is enabled, the core_gpr_ded_reset_reg is + set when the core was previously reset due to GPR DED error. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV32_clear_gpr_ded(void) +{ + SUBSYS->soft_reg &= ~SUBSYS_SOFT_REG_GRP_DED; +} + +/***************************************************************************//** + The MRV32_enable_parity_check() function is used to enable parity check on + the TCM and it's interface transactions. This feature is not available on + MIV_RV32 v3.1 and MIV_RV32 v3.0.100 + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV32_enable_parity_check(void) +{ + SUBSYS->cfg |= SUBSYS_CFG_PARITY_CHECK; +} + +/***************************************************************************//** + The MRV32_disable_parity_check() function is used to disable parity check on + the TCM and it's interface transactions. + @param + This function does not take any parameters + + @return + This function does not return any value. + + */ +static inline void MRV32_disable_parity_check(void) +{ + SUBSYS->cfg &= ~SUBSYS_CFG_PARITY_CHECK; +} + +/***************************************************************************//** + The MRV32_cpu_soft_reset() function is used to cause a soft cpu reset on + the MIV_RV32 soft processor core. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV32_cpu_soft_reset(void) +{ + SUBSYS->soft_reg |= SUBSYS_SOFT_RESET; +} +#endif /* MIV_RV32_SUBSYS_H */ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv_rv32_syscall.c b/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv_rv32_syscall.c new file mode 100644 index 0000000..bd2f881 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/miv_rv32_syscall.c @@ -0,0 +1,364 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_syscall.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Stubs for system calls. + * + */ +#include +#include +#include +#include +#include "miv_rv32_hal.h" + +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +#include + +#ifndef LEGACY_DIR_STRUCTURE +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" +#else +#include "core_uart_apb.h" +#endif + +#endif /*MSCC_STDIO_THRU_CORE_UART_APB*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + +/*------------------------------------------------------------------------------ + * CoreUARTapb instance data for the CoreUARTapb instance used for standard + * output. + */ +static UART_instance_t g_stdio_uart; + +/*============================================================================== + * Flag used to indicate if the UART driver needs to be initialized. + */ +static int g_stdio_uart_init_done = 0; + +/* + * Disable semihosting apis + */ +#pragma import(__use_no_semihosting_swi) + +/*============================================================================== + * sendchar() + */ +int sendchar(int ch) +{ + /*-------------------------------------------------------------------------- + * Initialize the UART driver if it is the first time this function is + * called. + */ + if ( !g_stdio_uart_init_done ) + { + /****************************************************************************** + * Baud value: + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + UART_init( &g_stdio_uart, + MSCC_STDIO_UART_BASE_ADDR, + ((SYS_CLK_FREQ/(16 * MSCC_STDIO_BAUD_VALUE))-1), + (DATA_8_BITS | NO_PARITY)); + + g_stdio_uart_init_done = 1; + } + + /*-------------------------------------------------------------------------- + * Output text to the UART. + */ + UART_send( &g_stdio_uart, (uint8_t *)&ch, 1 ); + + return (ch); +} + +/*============================================================================== + * getachar() + */ +int getachar(void) +{ + uint8_t rx_size; + uint8_t rx_byte; + + if ( !g_stdio_uart_init_done ) + { + /****************************************************************************** + * Baud value: + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + UART_init( &g_stdio_uart, + MSCC_STDIO_UART_BASE_ADDR, + ((SYS_CLK_FREQ/(16 * MSCC_STDIO_BAUD_VALUE))-1), + (DATA_8_BITS | NO_PARITY)); + + g_stdio_uart_init_done = 1; + } + + do + { + rx_size = UART_get_rx(&g_stdio_uart, &rx_byte, 1); + } while(0u == rx_size); + + return rx_byte; +} + +#endif /*MSCC_STDIO_THRU_CORE_UART_APB*/ + +#undef errno +static int errno; + +static char *__env[1] = { 0 }; +char **environ = __env; + +void write_hex(int fd, uint32_t hex) +{ + char towrite; + + write( fd , "0x", 2U ); + + for (uint32_t ii = 8U ; ii > 0U; ii--) + { + uint32_t jj = ii-1U; + uint8_t digit = ((hex & (0xFU << (jj*4U))) >> (jj*4U)); + towrite = digit < 0xAU ? (0x48U + digit) : (0x65U + (digit - 0xAU)); + write( fd, &towrite, 1U); + } +} + + +#ifdef GDB_TESTING +void __attribute__((optimize("O0"))) _exit(int code) +#else +void _exit(int code) +#endif +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + const char * message = "\nProgam has exited with code:"; + + write(STDERR_FILENO, message, strlen(message)); + write_hex(STDERR_FILENO, code); +#endif + + while (1){}; +} + +void *_sbrk(ptrdiff_t incr) +{ + extern char _end; + extern char _heap_end; + extern char __heap_start; + extern char __heap_end; + static char *curbrk = &_end; + void * ret = NULL; + + /* + * Did we allocated memory for the heap in the linker script? + * You need to set HEAP_SIZE to a non-zero value in your linker script if + * the following assertion fires. + */ + ASSERT(&__heap_end > &__heap_start); + + if (((curbrk + incr) < &_end) || ((curbrk + incr) > &_heap_end)) + { + errno = ENOMEM; + ret = ((char *) - 1); + } + else + { + curbrk += incr; + ret = curbrk - incr; + } + + /* + * Did we run out of heap? + * You need to increase the heap size in the linker script if the following + * assertion fires. + * */ + ASSERT(curbrk <= &__heap_end); + + return(ret); +} + +int _isatty(int fd) +{ + int ret = 0; + + if (fd <= 2) /* one of stdin, stdout, stderr */ + { + ret = 1; + } + else + { + errno = EBADF; + ret = 0; + } + + return(ret); +} + +static int stub(int err) +{ + errno = err; + return -1; +} + +int _open(const char* name, int flags, int mode) +{ + return stub(ENOENT); +} + +int _openat(int dirfd, const char* name, int flags, int mode) +{ + return stub(ENOENT); +} + +int _close(int fd) +{ + return stub(EBADF); +} + +int _execve(const char* name, char* const argv[], char* const env[]) +{ + return stub(ENOMEM); +} + +int _fork(void) +{ + return stub(EAGAIN); +} + +int _fstat(int fd, struct stat *st) +{ + int ret = 0; + + if (isatty(fd)) + { + st->st_mode = S_IFCHR; + ret = 0; + } + else + { + ret = stub(EBADF); + } + + return ret; +} + +int _getpid(void) +{ + return 1; +} + +int _kill(int pid, int sig) +{ + return stub(EINVAL); +} + +int _link(const char *old_name, const char *new_name) +{ + return stub(EMLINK); +} + +off_t _lseek(int fd, off_t ptr, int dir) +{ + off_t ret = 0; + if (_isatty(fd)) + { + ret = 0; + } + else + { + ret = stub(EBADF); + } + + return ret; +} + +ssize_t _read(int fd, void* ptr, size_t len) +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + + char* ptr1 = (char*)ptr; + + if (_isatty(fd)) + { + int count; + + for (count = 0; count < len; count++) + { + ptr1[count] = getachar(); + sendchar(ptr1[count]); + + /* Return partial buffer if we get EOL */ + if (('\r' == ptr1[count])||('\n' == ptr1[count])) + { + ptr1[count] = '\n'; + return count; + } + } + + return count; /* Filled the buffer */ + } +#endif + + return stub(EBADF); +} + +int _stat(const char* file, struct stat* st) +{ + return stub(EACCES); +} + +clock_t _times(struct tms* buf) +{ + return stub(EACCES); +} + +int _unlink(const char* name) +{ + return stub(ENOENT); +} + +int _wait(int* status) +{ + return stub(ECHILD); +} + +ssize_t _write(int fd, const void* ptr, size_t len) +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + int count_out; + char* ptr1 = (char*)ptr; + + /*-------------------------------------------------------------------------- + * Output text to the UART. + */ + count_out = 0; + while(len--) + { + sendchar(ptr1[count_out]); + count_out++; + } + + errno = 0; + return count_out; + +#else /* MSCC_STDIO_THRU_CORE_UART_APB */ + + return stub(EBADF); + +#endif /* MSCC_STDIO_THRU_CORE_UART_APB */ + +} + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/sample_fpga_design_config.h b/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/sample_fpga_design_config.h new file mode 100644 index 0000000..a380d96 --- /dev/null +++ b/applications/user-crypto/miv-rv32-keytree-services/src/platform/miv_rv32_hal/sample_fpga_design_config.h @@ -0,0 +1,167 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file sample_fpga_design_config.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Sample design configuration settings + * + */ + /*========================================================================*//** + @mainpage + Example file detailing how the fpga_design_config.h should be constructed + for the SoftConsole project targeted for Mi-V processors. + + @section intro_sec Introduction + The SoftConsole project targeted for Mi-V processors now have an improved + folder structure. Detailed description of the folder structure is available + at https://github.com/Mi-V-Soft-RISC-V/miv-rv32-documentation. + + The fpga_design_config.h must be stored as shown below + /boards//fpga_design_config.h + + Currently this file must be hand crafted when using the Mi-V Soft Processor. + In future, all the design and soft IP configurations will be automatically + generated from the Libero design description data. + + You can use this sample file as an example. + Rename this file from sample_fpga_design_config.h to fpga_design_config.h + and then customize it per your hardware design. + + @section Project configuration Instructions + 1. Change SYS_CLK_FREQ define to frequency of Mi-V Soft processor clock + 2 Add all the soft IP core BASE addresses + 3. Add the peripheral Core Interrupts to Mi-V Soft processor IRQ number + mappings + 4. Define MSCC_STDIO_UART_BASE_ADDR if you want a CoreUARTapb mapped to + STDIO + + **NOTE** + In the legacy folder structures, the file hw_config.h as was used at the + root of the project folder. This file is now depricated. + +*//*=========================================================================*/ + +#ifndef FPGA_DESIGN_CONFIG_H_ +#define FPGA_DESIGN_CONFIG_H_ + +/***************************************************************************//** + * Soft-processor clock definition + * This is the only clock brought over from the Mi-V Libero design. + */ +#ifndef SYS_CLK_FREQ +#define SYS_CLK_FREQ 50000000UL +#endif + +/***************************************************************************//** + * Peripheral base addresses. + * Format of define is: + * __BASE_ADDR + * The field is optional if there is only one instance of the core + * in the design + * MIV_ESS is an extended peripheral subsystem IP core with peripherals + * connections as defined below. + * The system can be further extended by attaching APB peripherals to the + * empty APB slots. + */ +#define MIV_ESS_PLIC_BASE_ADDR 0x70000000UL +#define COREUARTAPB0_BASE_ADDR 0x71000000UL +#define MIV_MTIMER_BASE_ADDR 0x72000000UL +#define MIV_ESS_APBSLOT3_BASE_ADDR 0x73000000UL +#define MIV_ESS_APBSLOT4_BASE_ADDR 0x74000000UL +#define COREGPIO_OUT_BASE_ADDR 0x75000000UL +#define CORESPI_BASE_ADDR 0x76000000UL +#define MIV_ESS_uDMA_BASE_ADDR 0x78000000UL +#define MIV_ESS_WDOG_BASE_ADDR 0x79000000UL +#define MIV_ESS_I2C_BASE_ADDR 0x7A000000UL +#define MIV_ESS_APBSLOTB_BASE_ADDR 0x7B000000UL +#define MIV_ESS_APBSLOTC_BASE_ADDR 0x7C000000UL +#define MIV_ESS_APBSLOTD_BASE_ADDR 0x7D000000UL +#define MIV_ESS_APBSLOTE_BASE_ADDR 0x7E000000UL +#define MIV_ESS_APBSLOTF_BASE_ADDR 0x7F000000UL + +/***************************************************************************//** + * Peripheral Interrupts are mapped to the corresponding Mi-V Soft processor + * interrupt in the Libero design. + * + * On the legacy RV32 cores, there can be up to 31 external interrupts (IRQ[30:0] + * pins). The legacy RV32 Soft processor external interrupts are defined in the + miv_rv32_plic.h + * + * These are of the form + * typedef enum +{ + NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + . + . + . + External_31_IRQn = 31 +} IRQn_Type; + + On the legacy RV32 processors, the PLIC identifies the interrupt and passes it + on to the processor core. The interrupt 0 is not used. The pin IRQ[0] should + map to External_1_IRQn likewise IRQ[30] should map to External_31_IRQn + +e.g + +#define TIMER0_IRQn External_30_IRQn +#define TIMER1_IRQn External_31_IRQn + + The MIV_RV32 soft processor has up to six optional system interrupts, MSYS_EI[n] + in addition to one EXT_IRQ. + The MIV_RV32 does not have an inbuilt PLIC and all the interrupts are directly + delivered to the processor core, hence unlike legacy RV32 cores, no interrupt + number mapping is necessary on MIV_RV32 core. + */ + +/**************************************************************************** + * Baud value to achieve a 115200 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ +#define BAUD_VALUE_115200 ((SYS_CLK_FREQ / (16 * 115200)) - 1) + +/****************************************************************************** + * Baud value to achieve a 57600 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + #define BAUD_VALUE_57600 ((SYS_CLK_FREQ / (16 * 57600)) - 1) + +/***************************************************************************//** + * Define MSCC_STDIO_THRU_CORE_UART_APB in the project settings if you want the + * standard IOs to be redirected to a terminal via UART. + */ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +/* + * A base address mapping for the STDIO printf/scanf mapping to CortUARTapb + * must be provided if it is being used + * + * e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR + */ +#define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB0_BASE_ADDR + +#ifndef MSCC_STDIO_UART_BASE_ADDR +#error MSCC_STDIO_UART_BASE_ADDR not defined- e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR +#endif + +#ifndef MSCC_STDIO_BAUD_VALUE +/* + * The MSCC_STDIO_BAUD_VALUE define should be set in your project's settings to + * specify the baud value used by the standard output CoreUARTapb instance for + * generating the UART's baud rate if you want a different baud rate from the + * default of 115200 baud + */ +#define MSCC_STDIO_BAUD_VALUE 115200 +#endif /*MSCC_STDIO_BAUD_VALUE*/ + +#endif /* end of MSCC_STDIO_THRU_CORE_UART_APB */ +/******************************************************************************* + * End of user edit section + */ +#endif /* FPGA_DESIGN_CONFIG_H_ */ diff --git a/applications/user-crypto/miv-rv32-message-authentication/.cproject b/applications/user-crypto/miv-rv32-message-authentication/.cproject new file mode 100644 index 0000000..ba31722 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/.cproject @@ -0,0 +1,333 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-message-authentication/.gitignore b/applications/user-crypto/miv-rv32-message-authentication/.gitignore new file mode 100644 index 0000000..f1b6b72 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/.gitignore @@ -0,0 +1,3 @@ +/.settings/ +/*miv-rv32-imc-debug*/ +/*miv-rv32-imc-release*/ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-message-authentication/.project b/applications/user-crypto/miv-rv32-message-authentication/.project new file mode 100644 index 0000000..b7a2b33 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/.project @@ -0,0 +1,26 @@ + + + miv-rv32-message-authentication + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/applications/user-crypto/miv-rv32-message-authentication/README.md b/applications/user-crypto/miv-rv32-message-authentication/README.md new file mode 100644 index 0000000..2620ff3 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/README.md @@ -0,0 +1,195 @@ +PolarFire User Crypto - Message Authentication And Hash Service Example +================================================================================ +This example project demonstrates the use of the following PolarFire User Crypto +Services functions: + + - CALSymEncAuth() + - CALSymEncAuthDMA() + - CALMAC() + - CALMACDMA() + - CALHash() + - CALHashDMA() + +The User Crypto message authentication service provides a way to ensure the +message integrity and to confirm that the message came from the stated sender +(its authenticity). This example project demonstrate the use of MAC services +to generate message authenticate code, authenticated encryption (the input +message), and hash service to covert data of arbitrary length to a fixed length. + +There are two different build configurations provided with this project which +configure this SoftConsole project for RISC-V IMC instruction extension. +The following configurations are provided with the example: + + - miv-rv32-imc-debug + - miv-rv32-imc-release + +Mi-V Soft Processor +-------------------------------------------------------------------------------- +This example uses Mi-V SoftProcessor MiV_RV32.The design is built for debugging +MiV_RV32 through the PolarFire FPGA programming JTAG port using a FlashPro5. +To achieve this the CoreJTAGDebug IP is used to connect to the JTAG port of the +MiV_RV32. + +All the platform/design specific definitions such as peripheral base addresses, +system clock frequency etc. are included in fpga_design_config.h. The +fpga_design_config.h is located at the root folder of this project. + +The Mi-V Soft Processor MiV_RV32 firmware projects needs the miv_rv32_hal and +the hal firmware(RISC-V HAL). + +The RISC-V HAL is available at GitHub [Mi-V-Soft-RISC-V](https://mi-v-ecosystem.github.io/redirects/platform). + +How to use this example +-------------------------------------------------------------------------------- +This example project is targeted at a MIV_RV32 design running on a PolarFire-Eval-Kit +connected via a USB-UART serial cable to a host PC running a terminal emulator +such as TeraTerm or Putty configured as follows: + + - 115200 baud + - 8 data bits + - 1 stop bit + - no parity + - no flow control. + +Run the example project using a debugger. A greeting message will appear over the +UART terminal followed by a menu system and instructions. + +This program displays the return data from User Crypto processor for message +authentication and hash service. + +fpga_design_config (formerly known as hw_config.h) +-------------------------------------------------------------------------------- +The SoftConsole project targeted for Mi-V processors now use an improved +directory structure. The fpga_design_config.h must be stored as shown below + +` + /boards//fpga_design_config/fpga_design_config.h +` + +Currently, this file must be hand crafted when using the Mi-V Soft Processor. +In future, all the design and soft IP configurations will be automatically +generated from the Libero design description data. + +You can use the sample file provided with MIV_RV32 HAL as an example. Rename it +from sample_fpga_design_config.h to fpga_design_config.h and then customize it +per your hardware design such as SYS_CLK_FREQ, peripheral BASE addresses, +interrupt numbers, definition of MSCC_STDIO_UART_BASE_ADDR if you want a +CoreUARTapb mapped to STDIO, etc. + +### Data Authenticated Encryption Using AES 256-bit key + +Select option '1' to perform authenticated encryption using Galois/counter mode (GCM) +algorithm. This example project reads the 256 bit key, IV, 16 bytes plain text, +and additional authentication data (AAD) from UART terminal and calls the +**CALSymEncAuth()** or **CALSymEncAuthDMA()** function. This function performs +authenticated encryption with associated data for confidentiality and integrity. +The plain text is both encrypted and used in computation of message +authentication code according to the **SATSYMTYPE_AES256** encryption algorithm and +GCM mode. Both the encrypted data and tag are displayed on UART terminal. + +**NOTE** -: + In Case of GCM, in place of IV paramter user has to pass JO value which is calculated + according to the algorithm + mentioned in the following document. + [document](http://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf) + +Generate MAC Using **HMACSHA-256** Algorithms +Press 2 to calculate message authentication code using HMAC SHA-256 algorithms. +This example project reads the key and message from UART terminal and calls the +**CALMAC()** or **CALMACDMA()** function. The **CALMAC()** and **CALMACDMA()** functions +calculate the MAC for the message based on SHA256 algorithm and the secret key. +The calculated MAC is also displayed on UART terminal. + +Generate MAC Using AES-CMAC-256 Algorithms +Press 3 to calculated message authentication code using AES-CMAC-256 algorithms. +This example project reads the key and message from UART terminal and calls +the CALMAC function. The **CALMAC()** functions calculates the MAC for the message +based on AES CMAC 256 algorithm and the secret key. The calculated MAC is also +displayed on UART terminal. +NOTE: + MAC computation using DMA (i.e. **CALMACDMA** function) doesn’t support + **AES-CMAC-256** Algorithm. + +Hashing +Press 4 to perform hashing. This service reads 64 bytes of message value and +performs the hash operation using SHA-256 hash algorithm on the stored data. +The hash results are stored at user memory location and also displayed on UART +terminal. + +### Configurations + +The CAL library needs a config_user.h containing the configuration data. +This application provides following settings as per CAL requirement + 1. A variable which provides the base address of the User Crypto hardware block + is defined in main.c + + `uint32_t g_user_crypto_base_addr = 0x62000000UL;` + + 2. A symbol INC_STDINT_H is defined in project preprocessor setting. + For more detail, please refer to caltypes.h file present in CAL folder. + +**NOTE**: + 1. If you try to enter data values other than 0 - 9, a - f, A - F, an error + message will be displayed on the serial terminal. + 2. You must enter all input data as whole bytes. If you enter the 128-bit key + {1230...0} as 0x12 0x3 and press return, this will be treated as + byte0 = 0x12, byte1 = 0x30, byte2-127 = 0x00. + +### Test script + +A test script is provided with this example which automatically enters the NIST +vectors and associated data to verify the functionality. + +The following Tera Term macro scripts are present in "script" folder present. +You can use these script for testing Message Authentication and Hashing +services. +1. MAC-gcm_msg_auth.ttl - Data Authenticated Encryption +2. MAC-hmac_aes_cmac_256.ttl - Generate MAC Using AES-CMAC-256 Algorithms +3. MAC-hmac_sha_256.ttl - Generate MAC Using HMAC SHA-256 Algorithms +4. SHA-256.ttl - Hashing + +**NOTE:** +1. Tera Term Macros don’t work with Windows 10 build 14393.0. You should update + to Windows 10 build 14393.0.105 or [later.](https://osdn.net/ticket/browse.php?group_id=1412&tid=36526) +2. Before running Tera Term Macro script, set language as English + (Setup->General->Language). Also setup transmit delay in (Setup->Serial port) + to 5msec/char and 5msec/line. +3. By default, Tera Term log will be stored in Tera Term installation Directory. + +## Target hardware + +This project was tested on PolarFire-Eval-Kit with CFG4 configuration of the +MIV_RV32 design available [here](https://github.com/Mi-V-Soft-RISC-V/PolarFire-Eval-Kit/tree/main/Libero_Projects) + +All the design specific definitions such as peripheral base addresses, system +clock frequency etc. are included in fpga_design_config.h. + +The firmware projects needs the HAL and the MIV_RV32 HAL firmware components. + +This example project can be used with another design using a different hardware +configurations. This can be achieved by overwriting the content of this example +project's "fpga_design_config.h" file with the correct data per your Libero design. + +### Booting the system + +Currently the example project is configured to use FlashPro debugger to execute +from LSRAM in both Debug and Release mode. + +In the release mode build configuration, following setting is used +`--change-section-lma *-0x80000000` under +Tool Settings > Cross RISCV GNU Create Flash Image > General > Other flags. + +This will allow you to attach the release mode executable as the memory +initialization client in Libero when you want to execute it from non-volatile memory. + +## Silicon revision dependencies + +This example is tested on PolarFire MPF300TS device. + +### CAL library src + +To obtain the CAL source code and a SoftConsole project to generate the CAL +library archive file (*.a) refer [SoftConsole Documentation](https://mi-v-ecosystem.github.io/SoftConsole-Documentation/SoftConsole-v2021.3/using_softconsole/other.html#crypto-application-library). +The CAL source code is bound by license agreement and it will be available as +part of the SoftConsole installation if the CAL specific license was agreed +while installing it. \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-message-authentication/miv-rv32-message-authentication hw Debug.launch b/applications/user-crypto/miv-rv32-message-authentication/miv-rv32-message-authentication hw Debug.launch new file mode 100644 index 0000000..bd7b1a5 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/miv-rv32-message-authentication hw Debug.launch @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/user-crypto/miv-rv32-message-authentication/miv-rv32-message-authentication hw attach.launch b/applications/user-crypto/miv-rv32-message-authentication/miv-rv32-message-authentication hw attach.launch new file mode 100644 index 0000000..f16d645 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/miv-rv32-message-authentication hw attach.launch @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/user-crypto/miv-rv32-message-authentication/scripts/MAC-gcm_msg_auth.ttl b/applications/user-crypto/miv-rv32-message-authentication/scripts/MAC-gcm_msg_auth.ttl new file mode 100644 index 0000000..b2c8ce6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/scripts/MAC-gcm_msg_auth.ttl @@ -0,0 +1,97 @@ +; Tera Term Setting: +; 1. Before running Tera Term Macro script, you should set language as English +; and transmit delay in Serial port setup to 5msec/char and 5msec/line. +; 2. By default, Tera Term log will be stored in Tera Term installation Directory. +changedir '.' +logopen "MAC_gcm_msg_auth.log" 0 0 0 1 + +settitle 'PolarFire User Crypto MAC service' + +setsync 1 + +; Set baud rate to 115200 +setbaud 115200 + +; local echo off +setecho 0 + +;press any key +send '5' +pause 1 + +; ------------------------------------------------------------------------------- +; INPUT +; Key = 96ac126b5b0ed0890b893657afa4c274ce300cb480cce961c27ddbc61e30783c +; IV = ee9e54a316ced1374a13ca2e00000001 +; PT = b4786d6bda2dd17690f5b0df362f539c54e7e1cd2cd0ac1f0acfaa51d673095729f88db1b6dd54be0b62d349e56557aa4e4980 +; AAD = 396d0892aff3212995e8f564083a0972 +; OUTPUT +; CT = df5af7ef15164d9faf062ab23356f7c4313bb9b05612de9e051ec31af83d7ff9f34e51143dfd43ab84a38f8950208653f1ff54 +; Tag = 9516b2653b1b06562bfca914 +; ----------------------------------------------------------------------------- + +;DMA enabled Test case 1 +send '1' +pause 2 + +;key +send '96ac126b5b0ed0890b893657afa4c274ce300cb480cce961c27ddbc61e30783c' +pause 2 + +;IV +send 'ee9e54a316ced1374a13ca2e00000001' +pause 1 + +;PT +send 'b4786d6bda2dd17690f5b0df362f539c54e7e1cd2cd0ac1f0acfaa51d673095729f88db1b6dd54be0b62d349e56557aa4e4980' +pause 1 +send 13 +pause 1 + +;AAD +send '396d0892aff3212995e8f564083a0972' +pause 1 +send 13 +pause 1 + +;Enable DMA +send '1' +pause 5 + +;Press any key to continue +send '6' + +; ----------------------------------------------------------------------------- +;DMA disabled Test case 2 +send '1' +pause 2 + +;key +send '96ac126b5b0ed0890b893657afa4c274ce300cb480cce961c27ddbc61e30783c' +pause 2 + +;IV +send 'ee9e54a316ced1374a13ca2e00000001' +pause 1 + +;PT +send 'b4786d6bda2dd17690f5b0df362f539c54e7e1cd2cd0ac1f0acfaa51d673095729f88db1b6dd54be0b62d349e56557aa4e4980' +pause 1 +send 13 +pause 1 + +;AAD +send '396d0892aff3212995e8f564083a0972' +pause 1 +send 13 +pause 1 + +;Disable DMA +send '0' +pause 5 + +;Press any key to continue +send '6' + +; ----------------------------------------------------------------------------- +logclose \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-message-authentication/scripts/MAC-hmac_aes_cmac_256.ttl b/applications/user-crypto/miv-rv32-message-authentication/scripts/MAC-hmac_aes_cmac_256.ttl new file mode 100644 index 0000000..b1f01df --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/scripts/MAC-hmac_aes_cmac_256.ttl @@ -0,0 +1,47 @@ +; Tera Term Setting: +; 1. Before running Tera Term Macro script, you should set language as English +; and transmit delay in Serial port setup to 5msec/char and 5msec/line. +; 2. By default, Tera Term log will be stored in Tera Term installation Directory. +changedir '.' +logopen "MAC_hmac_aes_cmac_256.log" 0 0 0 1 + +settitle 'PolarFire User Crypto MAC service' + +setsync 1 + +; Set baud rate to 115200 +setbaud 115200 + +; local echo off +setecho 0 + +; ---------------------------------------------------------------------------------------------------------------------------------------------------------- +; Test Case 1 +; INPUT +; Key = f70b8a4eee3518bba071af55f25f7b698a5b7dc8865cdaca6d1c7993657acc95 +; Msg = 795ee1af7504621aac329f5081912de545fa11174f3979b14f11aa30df813a235b467fd8f3a14734fe5ac9e39105dcb25184673885cd19bc70ee5a53dd4e8149 +; OUTPUT +; Mac = 93542734d6cd43de +; ---------------------------------------------------------------------------------------------------------------------------------------------------------- +send '3' +pause 2 + +;key +send 'f70b8a4eee3518bba071af55f25f7b69' +send '8a5b7dc8865cdaca6d1c7993657acc95' +pause 1 + +;Msg +send '795ee1af7504621aac329f5081912de545fa11174f39' +send '79b14f11aa30df813a235b467fd8f3a14734fe5ac9e3' +send '9105dcb25184673885cd19bc70ee5a53dd4e8149' +pause 1 +send 13 +pause 1 + +;press any key +send '5' +pause 1 + + +logclose \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-message-authentication/scripts/MAC-hmac_sha_256.ttl b/applications/user-crypto/miv-rv32-message-authentication/scripts/MAC-hmac_sha_256.ttl new file mode 100644 index 0000000..0381201 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/scripts/MAC-hmac_sha_256.ttl @@ -0,0 +1,93 @@ +; Tera Term Setting: +; 1. Before running Tera Term Macro script, you should set language as English +; and transmit delay in Serial port setup to 5msec/char and 5msec/line. +; 2. By default, Tera Term log will be stored in Tera Term installation Directory. +changedir '.' +logopen "MAC_hmac_sha_256.log" 0 0 0 1 + +settitle 'PolarFire User Crypto MAC HMAC SHA 256 service' + +setsync 1 + +; Set baud rate to 115200 +setbaud 115200 + +; local echo off +setecho 0 + +send 13 + +; ---------------------------------------------------------------------------------------------------------------------------------------------------------- +; Test Case 1 - DMA disabled +; INPUT +; Input Date: "Sample message for keylen= '0') && (*src <= '9')) + { + *dest = (*src - '0'); + } + else if((*src >= 'a') && (*src <= 'f')) + { + *dest = (*src - 'a') + 10u; + } + else if((*src >= 'A') && (*src <= 'F')) + { + *dest = (*src - 'A') + 10u; + } + else if(*src != 0x00u) + { + UART_send(&g_uart, (const uint8_t *)"\r\n Invalid data.", sizeof("\r\n Invalid data.")); + error_flag = 1u; + } + return error_flag; +} + +/*============================================================================== + Validate the input hex value . + */ +uint8_t validate_input(uint8_t ascii_input) +{ + uint8_t valid_key = 0u; + + if(((ascii_input >= 'A') && (ascii_input <= 'F')) || \ + ((ascii_input >= 'a') && (ascii_input <= 'f')) || \ + ((ascii_input >= '0') && (ascii_input <= '9'))) + { + valid_key = 1u; + } + else + { + valid_key = 0u; + } + return valid_key; +} + +const uint8_t hex_chars[16] = { '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + +/*============================================================================== + Display content of buffer passed as parameter as hex values. + */ +void display_output +( + uint8_t* in_buffer, + uint32_t byte_length +) +{ + uint32_t inc; + uint8_t byte = 0; + + UART_send(&g_uart, (const uint8_t*)" ", sizeof(" ")); + for(inc = 0; inc < byte_length; ++inc) + { + if((inc > 1u) &&(0u == (inc % 16u))) + { + UART_send(&g_uart, (const uint8_t*)"\r\n ", sizeof("\r\n ")); + } + + byte = in_buffer[inc]; + UART_send(&g_uart, &hex_chars[((byte & 0xF0) >> 4) ], 1); + UART_send(&g_uart, &hex_chars[(byte & 0x0F)], 1); + } + +} + +/*============================================================================== + Function to read data from UART terminal and stored it. + */ +uint16_t get_data_from_uart +( + uint8_t* src_ptr, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +) +{ + uint8_t complete = 0u; + uint8_t rx_buff[1]; + uint8_t rx_size = 0u; + uint16_t count = 0u; + uint16_t ret_size = 0u; + uint8_t first = 0u; + uint16_t src_ind = 0u; + uint8_t prev = 0; + uint8_t curr = 0; + uint8_t temp = 0; + uint8_t next_byte = 0; + uint16_t read_data_size = 0; + + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, msg, msg_size); + + if(size != 1) + { + read_data_size = size * 2; + } + else + { + read_data_size = size; + } + + /* Read the key size sent by user and store it. */ + count = 0u; + while(!complete) + { + rx_size = UART_get_rx(&g_uart, rx_buff, sizeof(rx_buff)); + if(rx_size > 0u) + { + /* Is it to terminate from the loop */ + if(ENTER == rx_buff[0]) + { + complete = 1u; + } + /* Is entered key valid */ + else if(validate_input(rx_buff[0]) != 1u) + { + UART_send(&g_uart, rx_buff, sizeof(rx_buff)); + UART_send(&g_uart, (const uint8_t *)"\r\n Invalid input.", + sizeof("\r\n Invalid input.")); + UART_send(&g_uart, msg, msg_size); + complete = 0u; + count = 0u; + first = 0u; + clear_variable(src_ptr, 4); + } + else + { + if(next_byte == 0) + { + convert_ascii_to_hex(&src_ptr[src_ind], &rx_buff[0]); + prev = src_ptr[src_ind]; + next_byte = 1; + } + else + { + convert_ascii_to_hex(&curr, &rx_buff[0]); + temp = ((prev << 4) & 0xF0); + src_ptr[src_ind] = (temp | curr); + next_byte = 0; + src_ind++; + } + + + /* Switching to next line after every 8 bytes */ + if(((count % 32u) == 0x00u) && (count > 0x00u) && (complete != 0x01u)) + { + UART_send(&g_uart, (const uint8_t *)"\n\r", sizeof("\n\r")); + first = 0u; + } + + if(first == 0u) + { + UART_send(&g_uart, (const uint8_t *)" ", sizeof(" ")); + first++; + } + UART_send(&g_uart, rx_buff, sizeof(rx_buff)); + count++; + if(read_data_size == count) + { + complete = 1u; + } + } + } + } + + if((count%2) == 0) + { + ret_size = count/2; + } + else + { + if(size!=1) + { + temp = src_ptr[src_ind]; + src_ptr[src_ind] = ((temp << 4) & 0xF0); + + ret_size = (count/2)+1; + } + else + { + ret_size = 1; + } + } + + return ret_size; +} + +/*============================================================================== + Function to get the key from user. + */ +uint8_t enable_dma +( + const uint8_t* msg, + uint8_t msg_size +) +{ + volatile uint8_t invalid_ip = 1u; + uint8_t dma_enable = 0; + + const uint8_t invalid_ms[] = "\r\n Invalid input. "; + + while(invalid_ip != 0) + { + /* Read the 16 bytes of input data from UART terminal. */ + get_input_data(&dma_enable, 1, msg, msg_size); + + if(dma_enable >= 2) + { + UART_send(&g_uart, invalid_ms, sizeof( invalid_ms)); + } + else + { + invalid_ip = 0; + } + } + + return dma_enable; +} diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/application/helper.h b/applications/user-crypto/miv-rv32-message-authentication/src/application/helper.h new file mode 100644 index 0000000..6c586a6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/application/helper.h @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file helper.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Helper function public API. + * + */ +#ifndef __HELPER_H_ +#define __HELPER_H_ 1 + +/****************************************************************************** + * Maximum buffer size. + *****************************************************************************/ +#define MAX_RX_DATA_SIZE 256 +#define MASTER_TX_BUFFER 10 + +/*============================================================================== + Macro + */ +#define VALID 0U +#define INVALID 1U +#define ENTER 13U +/****************************************************************************** + * CoreUARTapb instance data. + *****************************************************************************/ +extern UART_instance_t g_uart; + +uint16_t get_input_data +( + uint8_t* location, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +); +void get_key +( + uint8_t key_type, + uint8_t* location, + uint8_t size, + const uint8_t* msg, + uint8_t msg_size +); +uint16_t get_data_from_uart +( + uint8_t* src_ptr, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +); +uint8_t enable_dma +( + const uint8_t* msg, + uint8_t msg_size +); +void display_output +( + uint8_t* in_buffer, + uint32_t byte_length +); +#endif /* __HELPER_H_ */ diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/application/main.c b/applications/user-crypto/miv-rv32-message-authentication/src/application/main.c new file mode 100644 index 0000000..e787166 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/application/main.c @@ -0,0 +1,522 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file main.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief This Example Project demonstrates the usage of PolarFire User Crypto + * services for message authentication and hashing. + * + */ +#include "hal/hal.h" +#include "fpga_design_config/fpga_design_config.h" +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" +#include +#include +#include "stdint.h" +#include +#include + +#include "helper.h" +#include "cal/calpolicy.h" +#include "cal/pk.h" +#include "cal/pkx.h" +#include "cal/pkxlib.h" +#include "cal/calini.h" +#include "cal/utils.h" +#include "cal/hash.h" +#include "cal/drbgf5200.h" +#include "cal/drbg.h" +#include "cal/nrbg.h" +#include "cal/sym.h" +#include "cal/shaf5200.h" +#include "cal/calenum.h" +#include "cal/mac.h" + + +/****************************************************************************** + * CoreUARTapb instance data. + *****************************************************************************/ +UART_instance_t g_uart; + +uint32_t g_user_crypto_base_addr = 0x62000000UL; +/****************************************************************************** + * Instruction message. + *****************************************************************************/ +const uint8_t read_dma_enable_ip[] = +"\r\n Enter 1 to perform Symmetric encryption with DMA or \r\n\ + 0 to perform Symmetric encryption without DMA: \r\n"; + +/*============================================================================== + Messages displayed over the UART. + */ +const uint8_t g_greeting_msg[] = +"\r\n\r\n\ +******************************************************************************\r\n\ +************* PolarFire User Crypto Example Project **************************\r\n\ +******************************************************************************\r\n\ + This example project demonstrates the use of the User Crypto Message \r\n\ + authentication services and hash services. The following User Crypto service\r\n\ + are demonstrated:\r\n\ + 1 - Galois/Counter Mode, GCM Message Authentication.\r\n\ + 2 - Message authentication code - HMAC-SHA-256.\r\n\ + 3 - Message authentication code - AES-CMAC-256.\r\n\ + 4 - SHA-256 service.\r\n"; +const uint8_t g_select_operation_msg[] = +"\r\n\ +------------------------------------------------------------------------------\r\n\ + Select the Cryptographic operation to perform:\r\n\ + Press Key '1' to perform AES-GCM-256 encryption \r\n\ + Press Key '2' to perform HMAC SHA 256 \r\n\ + Press Key '3' to perform HMAC AES-CMAC-256 \r\n\ + Press Key '4' to perform hash operation \r\n\ +------------------------------------------------------------------------------\r\n"; +static const uint8_t g_separator[] = +"\r\n\ +------------------------------------------------------------------------------"; + +/*============================================================================== + Global Variables. + */ +/* AES-128 encryption/decryption. */ + uint8_t __attribute__ ((section (".crypto_data"))) g_iv[16]; + uint8_t __attribute__ ((section (".crypto_data"))) g_plain_text[128]; + + + uint8_t __attribute__ ((section (".crypto_data"))) g_key_256bit[32]; + uint8_t __attribute__ ((section (".crypto_data"))) g_auth_data[128]; + uint8_t __attribute__ ((section (".crypto_data"))) tag[32]; + + + uint8_t __attribute__ ((section (".crypto_data"))) g_mac[32]; + uint8_t __attribute__ ((section (".crypto_data"))) g_encrypted_text[128]; + + + uint8_t __attribute__ ((section (".crypto_data"))) g_hash_msg[128] = {0x00}; + uint8_t __attribute__ ((section (".crypto_data"))) g_hash_result[32]; + +/* Helper function.*/ +static void clr_hmac_sha_var(void); +static void clr_hmac_aes_cmac_var(void); +static void clr_gcm_msg_auth_var(void); +static void clear_sha256_var(void); + +/*============================================================================== + Hash operation using SHA-256 + */ +void sha_256bit_hash() +{ + uint16_t count = 0u; + uint8_t status; + uint8_t use_dma = 0; + + const uint8_t sha_msg[] = + "\r\n Enter message to perform hashing (max 128 Bytes): \r\n"; + + /* Clear input and output variables */ + clear_sha256_var(); + + /* Get the input Text/Data from the user and store it for Hashing. */ + count = get_input_data(&g_hash_msg[0],sizeof(g_hash_msg), sha_msg, + sizeof(sha_msg)); + + /* Use dma or not */ + use_dma = enable_dma(read_dma_enable_ip, sizeof(read_dma_enable_ip)); + + if(use_dma != 1) + { + /* Without DMA */ + status = CALHash(SATHASHTYPE_SHA256, g_hash_msg, count, g_hash_result); + } + else + { + /* With DMA */ + status = CALHashDMA(SATHASHTYPE_SHA256, g_hash_msg, count, g_hash_result, + X52CCR_DEFAULT); + } + + if(SATR_SUCCESS == status) + { + if(use_dma == 1) + { + CALPKTrfRes(SAT_TRUE); + } + /* Display the calculated Hash value */ + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, (const uint8_t*)"\r\n Calculated hash value for the input data:\r\n", + sizeof("\r\n Calculated hash value for the input data:\r\n")); + display_output(g_hash_result, sizeof(g_hash_result)); + } + else + { + UART_send(&g_uart, g_separator, sizeof(g_separator)); + /* Display the error information */ + UART_send(&g_uart, (const uint8_t *)"\r\n SHA-256 service fail\r\n", + sizeof("\r\n SHA-256 service fail\r\n")); + } +} + +/*============================================================================== + Message authentication code - AES-CMAC-256 + */ +static void hmac_aes_cmac_256(void) +{ + uint8_t status = 0u; + uint16_t msg_len = 0; + + const uint8_t read_key_msg[] = + "\r\n Enter the 256-bit/32-byte key: \r\n"; + const uint8_t read_data_msg[] = + "\r\n Enter the input data (max 128 bytes):\r\n"; + + /* Clear all global variable. */ + clr_hmac_aes_cmac_var(); + + /* Get key. key size 256 bit*/ + get_input_data(&g_key_256bit[0], sizeof(g_key_256bit), read_key_msg, sizeof(read_key_msg)); + + /* Read the 128 bytes of input data from UART terminal. */ + msg_len = get_input_data(&g_plain_text[0], sizeof(g_plain_text), read_data_msg, sizeof(read_data_msg)); + + /* Without DMA */ + status = CALMAC(SATMACTYPE_AESCMAC256,(uint32_t*)&g_key_256bit, sizeof(g_key_256bit), + g_plain_text, msg_len, g_mac); + + /* Display the encrypted data in hex format. */ + if(SATR_SUCCESS == status) + { + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, (const uint8_t *)"\r\n Message Authentication successful \r\n Generated MAC:\r\n", + sizeof("\r\n Message Authentication successful \r\n Generated MAC:\r\n")); + display_output(g_mac, 8); + } + else + { + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, (const uint8_t *)"\r\n Message Authentication fail\r\n", + sizeof("\r\n Message Authentication fail\r\n")); + } +} + +/*============================================================================== + Message authentication code - HMAC-SHA-256 + */ +static void hmac_sha_256(void) +{ + uint8_t status = 0u; + uint16_t msg_len = 0; + uint8_t use_dma = 0; + + const uint8_t read_key_msg[] = + "\r\n Enter the 256 bit key to be used: \r\n"; + const uint8_t read_data_msg[] = + "\r\n Enter input data(max 128 Bytes):\r\n"; + const uint8_t read_dma_enable_ip[] = + "\r\n Enter 1 to perform Symmetric encryption with DMA or \r\n\ + 0 to perform Symmetric encryption without DMA: \r\n"; + + /* Clear Global variables. */ + clr_hmac_sha_var(); + + /* Get key. key size 256 bit*/ + get_input_data(&g_key_256bit[0], sizeof(g_key_256bit), read_key_msg, + sizeof(read_key_msg)); + + /* Read the 32 bytes of input data from UART terminal. */ + msg_len = get_input_data(&g_plain_text[0],sizeof(g_plain_text), + read_data_msg, sizeof(read_data_msg)); + + /* Use dma or not */ + use_dma = enable_dma(read_dma_enable_ip, sizeof(read_dma_enable_ip)); + + if(use_dma != 1) + { + /* Without DMA */ + status = CALMAC(SATMACTYPE_SHA256, (uint32_t*)&g_key_256bit, sizeof(g_key_256bit), + g_plain_text, msg_len, g_encrypted_text); + } + else + { + /* With DMA */ + status = CALMACDMA(SATMACTYPE_SHA256, (uint32_t*)&g_key_256bit, sizeof(g_key_256bit), + g_plain_text, msg_len, g_encrypted_text, X52CCR_DEFAULT); + } + + /* Display the encrypted data in hex format. */ + if(SATR_SUCCESS == status) + { + if(use_dma == 1) + { + CALPKTrfRes(SAT_TRUE); + } + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, + (const uint8_t *)"\r\n Message Authentication successful \r\n Output data:\r\n", + sizeof("\r\n Message Authentication successful \r\n Output data:\r\n")); + display_output(g_encrypted_text, 32u); + } + else + { + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, (const uint8_t *)"\r\n Error\r\n", sizeof("\r\n Error\r\n")); + } +} + +/*============================================================================== + GCM Message Authentication - AES-GCM-256 + */ + +static void gcm_msg_auth(void) +{ + uint8_t status = 0u; + uint8_t use_dma = 0; + uint16_t msg_len = 0; + uint16_t aad_len = 0; + uint32_t g_tag_len = 0; + + const uint8_t read_dma_enable_ip[] = + "\r\n Enter 1 to perform Symmetric encryption with DMA or \r\n\ + 0 to perform Symmetric encryption without DMA: \r\n"; + const uint8_t read_key_msg[] = + "\r\n Enter the 256-bit/32-byte key: \r\n"; + const uint8_t read_data_msg[] = + "\r\n Enter the input data to encrypt(PT) (max: 128 Bytes):\r\n"; + const uint8_t read_iv_msg[] = + "\r\n Enter the 16 bytes(128 bit) initialization vector(IV): \r\n"; + const uint8_t read_auth_data_msg[] = + "\r\n Enter the 16 bytes of authentication data(AAD): \r\n"; + + /* Clear all global variable related to AES GCM */ + clr_gcm_msg_auth_var(); + + /* Get key used for encryption. key size 256 bit*/ + get_input_data(&g_key_256bit[0], sizeof(g_key_256bit), read_key_msg, + sizeof(read_key_msg)); + + /* Get the Initialization Vector value. IV size is 128 bit */ + get_input_data(g_iv, sizeof(g_iv), read_iv_msg, sizeof(read_iv_msg)); + + /* Get the data to be encrypted. Data size is 16 bytes*/ + msg_len = get_input_data(&g_plain_text[0], sizeof(g_plain_text), + read_data_msg, sizeof(read_data_msg)); + + /* Get additional authentication data (AAD). AAD size is 16 bytes*/ + aad_len = get_input_data(&g_auth_data[0], sizeof(g_auth_data), read_auth_data_msg, + sizeof(read_auth_data_msg)); + + /* Use dma or not */ + use_dma = enable_dma(read_dma_enable_ip, sizeof(read_dma_enable_ip)); + + if(use_dma != 1) + { + /* Without DMA */ + status = CALSymEncAuth(SATSYMTYPE_AES256, (uint32_t*)&g_key_256bit[0], + SATSYMMODE_GCM, g_iv, g_plain_text, + g_encrypted_text, msg_len, g_auth_data, aad_len, + tag, 12); + } + else + { + /* With DMA */ + status = CALSymEncAuthDMA(SATSYMTYPE_AES256, (uint32_t*)&g_key_256bit[0], + SATSYMMODE_GCM, g_iv, g_plain_text, + g_encrypted_text, msg_len, g_auth_data, + aad_len, tag, 12, X52CCR_DEFAULT); + } + + /* Display the encrypted data in hex format. */ + if(SATR_SUCCESS == status) + { + CALPKTrfRes(SAT_TRUE); + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, (const uint8_t *)"\r\n Encrypted data(CT):\r\n", + sizeof("\r\n Encrypted data(CT):\r\n")); + display_output(g_encrypted_text, sizeof(g_encrypted_text)/2); + UART_send(&g_uart, (const uint8_t *)"\r\n\n Message Authentication Code(Tag):\r\n", + sizeof("\r\n\n Message Authentication Code(Tag):\r\n")); + display_output(tag, sizeof(tag)); + } + else + { + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, (const uint8_t *)"\r\n Error\r\n", sizeof("\r\n Error\r\n")); + } + /* GCM verification */ + + /* clear the plaintext buffer */ + uint16_t bc ; + for(bc = 0 ; bc < sizeof(g_plain_text) ; bc++) + { + g_plain_text[bc] = 0 ; + } + + status = CALSymDecVerify(SATSYMTYPE_AES256, (uint32_t*)&g_key_256bit[0], SATSYMMODE_GCM, g_iv + , g_encrypted_text, g_plain_text, msg_len, g_auth_data, aad_len, tag, 12); + if(SATR_SUCCESS == status) + { + status = CALSymTrfRes(SAT_TRUE); + if(SATR_SUCCESS == status) + { + + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, (const uint8_t *)"\r\n Decrypted data(CT):\r\n", + sizeof("\r\n Decrypted data(CT):\r\n")); + display_output(g_plain_text, sizeof(g_plain_text)/2); + UART_send(&g_uart, (const uint8_t *)"\r\n\n Message Authentication successful(Tag):\r\n", + sizeof("\r\n\n Message Authentication successful(Tag):\r\n")); + display_output(tag, sizeof(tag)); + } + } + +} +/*============================================================================== + Display greeting message when application is started. + */ +static void display_greeting(void) +{ + UART_send(&g_uart, g_greeting_msg,sizeof(g_greeting_msg)); +} + +/*============================================================================== + Display the choice of cryptographic operation to perform. + */ +static void display_operation_choices(void) +{ + UART_send(&g_uart, g_select_operation_msg, sizeof(g_select_operation_msg)); +} + +/*============================================================================== + Display the Option to continue or exit. + */ +static void display_option(void) +{ + uint8_t rx_size; + uint8_t rx_buff[1]; + + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, (const uint8_t*)"\r\n Press any key to continue.\r\n", + sizeof("\r\n Press any key to continue.\r\n")); + do + { + rx_size = UART_get_rx(&g_uart, rx_buff, sizeof(rx_buff)); + } while(0u == rx_size); +} + +/****************************************************************************** + * main function. + *****************************************************************************/ +int main( void ) +{ + uint8_t rx_buff[1]; + size_t rx_size = 0; + + + /* Initialize CoreUARTapb with its base address, baud value, and line + configuration. */ + UART_init(&g_uart, COREUARTAPB0_BASE_ADDR, BAUD_VALUE_115200, + (DATA_8_BITS | NO_PARITY)); + + /* Initializes the Athena Processor. */ + CALIni(); + + /* Display greeting message. */ + display_greeting(); + + /* Select cryptographic operation to perform */ + display_operation_choices(); + + for(;;) + { + /* Read input from UART terminal. */ + rx_size = UART_get_rx(&g_uart, rx_buff, sizeof(rx_buff)); + if(rx_size > 0) + { + switch(rx_buff[0]) + { + case '1': + /* Galois/Counter Mode, GCM Message Authentication */ + gcm_msg_auth(); + display_option(); + display_operation_choices(); + break; + + case '2': + /* Perform HMAC SHA 256 */ + hmac_sha_256(); + display_option(); + display_operation_choices(); + break; + + case '3': + /* Perform HMAC AES-CMAC-256 */ + hmac_aes_cmac_256(); + display_option(); + display_operation_choices(); + break; + + case '4': + /* Perform SHA-256*/ + sha_256bit_hash(); + display_option(); + display_operation_choices(); + break; + + default: + break; + } + } + } +} + +static void clr_hmac_sha_var(void) +{ + uint16_t var = 0; + + for(var = 0; var < sizeof(g_key_256bit); var++) + { + g_key_256bit[var] = 0; + } + for(var = 0; var < sizeof(g_plain_text); var++) + { + g_plain_text[var] = 0; + } +} + +static void clr_gcm_msg_auth_var(void) +{ + uint16_t index = 0; + + clr_hmac_sha_var(); + + for(index = 0; index < sizeof(g_iv); index++) + { + g_iv[index] = 0; + } + for(index = 0; index < sizeof(g_auth_data); index++) + { + g_auth_data[index] = 0; + } +} + +static void clr_hmac_aes_cmac_var(void) +{ + uint16_t var = 0; + + clr_hmac_sha_var(); + + for(var = 0; var < sizeof(g_mac); var++) + { + g_mac[var] = 0; + } +} + +static void clear_sha256_var(void) +{ + volatile uint32_t index; + + for(index = 0u; index < sizeof(g_hash_msg); index++) + { + g_hash_msg[index] = 0u; + } +} diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h b/applications/user-crypto/miv-rv32-message-authentication/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h new file mode 100644 index 0000000..3fd1438 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h @@ -0,0 +1,156 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file fpga_design_config.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Sample design configuration settings. + * + */ + /*========================================================================*//** + @mainpage + Example file detailing how the fpga_design_config.h should be constructed + for the SoftConsole project targeted for Mi-V processors. + + @section intro_sec Introduction + The SoftConsole project targeted for Mi-V processors now have an improved + folder structure. Detailed description of the folder structure is available + at https://github.com/Mi-V-Soft-RISC-V/miv-rv32-documentation. + + The fpga_design_config.h must be stored as shown below + /boards//fpga_design_config.h + + Currently this file must be hand crafted when using the Mi-V Soft Processor. + In future, all the design and soft IP configurations will be automatically + generated from the Libero design description data. + + You can use this sample file as an example. + Rename this file from sample_fpga_design_config.h to fpga_design_config.h + and then customize it per your hardware design. + + @section Project configuration Instructions + 1. Change SYS_CLK_FREQ define to frequency of Mi-V Soft processor clock + 2 Add all the soft IP core BASE addresses + 3. Add the peripheral Core Interrupts to Mi-V Soft processor IRQ number + mappings + 4. Define MSCC_STDIO_UART_BASE_ADDR if you want a CoreUARTapb mapped to + STDIO + + **NOTE** + In the legacy folder structures, the file hw_config.h as was used at the + root of the project folder. This file is now depricated. + +*//*=========================================================================*/ + +#ifndef FPGA_DESIGN_CONFIG_H_ +#define FPGA_DESIGN_CONFIG_H_ + +/***************************************************************************//** + * Soft-processor clock definition + * This is the only clock brought over from the Mi-V Libero design. + */ +#ifndef SYS_CLK_FREQ +#define SYS_CLK_FREQ 83000000UL +#endif + +/***************************************************************************//** + * Peripheral base addresses. + * Format of define is: + * __BASE_ADDR + * The field is optional if there is only one instance of the core + * in the design + * MIV_ESS is an extended peripheral subsystem IP core with peripherals + * connections as defined below. + * The system can be further extended by attaching APB peripherals to the + * empty APB slots. + */ +#define COREUARTAPB0_BASE_ADDR 0x70000000UL +#define COREGPIO_OUT_BASE_ADDR 0x70001000UL +#define CORESPI_BASE_ADDR 0x70002000UL +#define CORESYS_SERV_BASE_ADDR 0x70003000UL + +/***************************************************************************//** + * Peripheral Interrupts are mapped to the corresponding Mi-V Soft processor + * interrupt in the Libero design. + * + * On the legacy RV32 cores, there can be up to 31 external interrupts (IRQ[30:0] + * pins). The legacy RV32 Soft processor external interrupts are defined in the + miv_rv32_plic.h + * + * These are of the form + * typedef enum +{ + NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + . + . + . + External_31_IRQn = 31 +} IRQn_Type; + + On the legacy RV32 processors, the PLIC identifies the interrupt and passes it + on to the processor core. The interrupt 0 is not used. The pin IRQ[0] should + map to External_1_IRQn likewise IRQ[30] should map to External_31_IRQn + +e.g + +#define TIMER0_IRQn External_30_IRQn +#define TIMER1_IRQn External_31_IRQn + + The MIV_RV32 soft processor has up to six optional system interrupts, MSYS_EI[n] + in addition to one EXT_IRQ. + The MIV_RV32 does not have an inbuilt PLIC and all the interrupts are directly + delivered to the processor core, hence unlike legacy RV32 cores, no interrupt + number mapping is necessary on MIV_RV32 core. + */ + +/**************************************************************************** + * Baud value to achieve a 115200 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ +#define BAUD_VALUE_115200 ((SYS_CLK_FREQ / (16 * 115200)) - 1) + +/****************************************************************************** + * Baud value to achieve a 57600 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + #define BAUD_VALUE_57600 ((SYS_CLK_FREQ / (16 * 57600)) - 1) + +/***************************************************************************//** + * Define MSCC_STDIO_THRU_CORE_UART_APB in the project settings if you want the + * standard IOs to be redirected to a terminal via UART. + */ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +/* + * A base address mapping for the STDIO printf/scanf mapping to CortUARTapb + * must be provided if it is being used + * + * e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR + */ +#define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB0_BASE_ADDR + +#ifndef MSCC_STDIO_UART_BASE_ADDR +#error MSCC_STDIO_UART_BASE_ADDR not defined- e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR +#endif + +#ifndef MSCC_STDIO_BAUD_VALUE +/* + * The MSCC_STDIO_BAUD_VALUE define should be set in your project's settings to + * specify the baud value used by the standard output CoreUARTapb instance for + * generating the UART's baud rate if you want a different baud rate from the + * default of 115200 baud + */ +#define MSCC_STDIO_BAUD_VALUE 115200 +#endif /*MSCC_STDIO_BAUD_VALUE*/ + +#endif /* end of MSCC_STDIO_THRU_CORE_UART_APB */ +/******************************************************************************* + * End of user edit section + */ +#endif /* FPGA_DESIGN_CONFIG_H_ */ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld b/applications/user-crypto/miv-rv32-message-authentication/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld new file mode 100644 index 0000000..8541db6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld @@ -0,0 +1,160 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-ram.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * debug image executing in SRAM. + * + * This linker script assumes that a RAM is connected at on Mi-V soft processor + * memory space pointed by the reset vector address. + * + * NOTE : Modify the memory section address and the size according to your + * Libero design. + * For example: + * 1) If you want to download and step debug at a different RAM memory address in + * your design (For example TCM base address) than the one provided in this file. + * 2) The MIV_RV32, when used with MIV_ESS IP, provides ways to copy the executable + * HEX file from external Non-Volatile memory into the TCM at reset. In this + * case your executable must be linked to the TCM address. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +MEMORY +{ + ram (rwx) : ORIGIN = 0x80000000, LENGTH = 64k + crypto_ram (rw) : ORIGIN = 0x61000000, LENGTH = 32k +} + +RAM_START_ADDRESS = 0x80000000; /* Must be the same value MEMORY region ram ORIGIN above. */ +RAM_SIZE = 64k; /* Must be the same value MEMORY region ram LENGTH above. */ +STACK_SIZE = 2k; /* needs to be calculated for your application */ +HEAP_SIZE = 0k; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > ram + + .text : ALIGN(0x10) + { + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } > ram + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } > ram + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } > ram + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram + + . = 0x61000000; + .crypto_data : ALIGN(0x10) + { + . = ALIGN(0x10); + *(.crypto_data) + } > crypto_ram +} + diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/aesf5200.h b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/aesf5200.h new file mode 100644 index 0000000..889dddd --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/aesf5200.h @@ -0,0 +1,104 @@ +/* ------------------------------------------------------------------- + $Rev: 1293 $ $Date: 2017-07-27 14:09:14 -0400 (Thu, 27 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for F5200 AES function hardware implementation for + CAL. + ------------------------------------------------------------------- */ + +#ifndef AESF5200_H +#define AESF5200_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef AESF5200_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATR aesf5200aes (SATSYMTYPE eSymType, SATSYMMODE eMode, + void *pIV, SATBOOL bLoadIV, const void *pSrc, void *pDest, SATUINT32_t uiLen, + SATBOOL bDecrypt); + +extern SATR aesf5200aesk (SATSYMTYPE eSymType, const SATUINT32_t *puiKey); + +extern SATR aesf5200gcm (SATSYMTYPE eSymType, SATSYMMODE eMode, void *pIV, + const void *pSrc, void *pDest, SATUINT32_t uiEncLen, + const void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, SATUINT32_t uiMACLen, + SATBOOL bDecrypt); + +extern SATR aesf5200gcmdma(SATSYMTYPE eSymType, SATSYMMODE eMode, void *pIV, + const void *pSrc, void *pDest, SATUINT32_t uiEncLen, const void *pAuth, + SATUINT32_t uiAuthLen, void *pMAC, SATUINT32_t uiMACLen, SATBOOL bDecrypt, + SATUINT32_t uiDMAChConfig); + +extern SATR aesf5200kw(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR aesf5200kwp(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR aesf5200kr(SATSYMTYPE eSymType, SATSYMMODE eMode, + const SATUINT32_t *puiKey, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKrf, SATBOOL bDecrypt); + +extern SATR aesf5200dma(SATSYMTYPE eSymType, SATSYMMODE eMode, void *pIV, + SATBOOL bLoadIV, const void *pExtSrc, void *pExtDest, SATUINT32_t uiLen, + SATUINT32_t uiDMAChConfig, SATBOOL bDecrypt); + +extern SATR aesf5200krdma(SATSYMTYPE eSymType, SATSYMMODE eMode, + const SATUINT32_t *puiKey, void *pIV, SATBOOL bLoadIV, const void *pExtSrc, + void *pExtDest, SATUINT32_t uiLen, SATUINT32_t uiKrf, + SATUINT32_t uiDMAChConfig, SATBOOL bDecrypt); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/calcontext.h b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/calcontext.h new file mode 100644 index 0000000..fc408c2 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/calcontext.h @@ -0,0 +1,88 @@ +/* ------------------------------------------------------------------- + $Rev: 1298 $ $Date: 2017-08-04 13:04:19 -0400 (Fri, 04 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL context management functions. + ------------------------------------------------------------------- */ + +#ifndef CALCONTEXT_H +#define CALCONTEXT_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* Function resource handle. */ +/* ----- ------ ------- ---- */ +#define SATRES_DEFAULT (SATRESHANDLE)0U +#define SATRES_CALSW (SATRESHANDLE)1U + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ +typedef struct{ + SATUINT32_t uiBase; + SATRESCONTEXTPTR pContext; + }SATRESHANDLESTRUCT; + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALCONTEXT_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATRESCONTEXTPTR CALContextCurrent(const SATRESHANDLE hResource); + +extern SATR CALContextLoad(const SATRESHANDLE hResource, + const SATRESCONTEXTPTR pContext); + +extern SATR CALContextRemove(const SATRESHANDLE hResource); + +extern SATR CALContextUnload(const SATRESHANDLE hResource); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern void init_reshandles(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/calenum.h b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/calenum.h new file mode 100644 index 0000000..6281f3f --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/calenum.h @@ -0,0 +1,289 @@ +/* ------------------------------------------------------------------- + $Rev: 1566 $ $Date: 2018-09-14 11:04:30 -0400 (Fri, 14 Sep 2018) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + This file defines common types in the CAL. + + Most CAL types and constants are defined with the "SAT" prefix to + reduce the chance of name space collisions with other users. + ------------------------------------------------------------------- */ + +#ifndef CALENUM_H +#define CALENUM_H + +/* -------- */ +/* Includes */ +/* -------- */ + +/* CAL base types. */ +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ +/* NULL definitions. */ +#define SAT_NULL 0 + +/* Boolean definitions. */ +#define SAT_TRUE ((SATBOOL)1) +#define SAT_FALSE ((SATBOOL)0) + + +/* Major cipher key/SSP type. */ +/* ----- ------ ------- ----- */ +#define SATSSPTYPE_NULL (SATSSPTYPE)0 +#define SATSSPTYPE_SYMKEY (SATSSPTYPE)1 +#define SATSSPTYPE_ASYMKEY (SATSSPTYPE)2 +/* Special marker for end of list. */ +#define SATSSPTYPE_LAST (SATSSPTYPE)3 + + +/* Asymmetric Ciphers */ +/* ---------- ------- */ +#define SATASYMTYPE_NULL (SATASYMTYPE)0U +#define SATASYMTYPE_DSA_SIGN (SATASYMTYPE)1U +#define SATASYMTYPE_DSA_VERIFY (SATASYMTYPE)2U +#define SATASYMTYPE_RSA_ENCRYPT (SATASYMTYPE)3U +#define SATASYMTYPE_RSA_DECRYPT (SATASYMTYPE)4U +#define SATASYMTYPE_DH (SATASYMTYPE)5U +#define SATASYMTYPE_ECDSA_SIGN (SATASYMTYPE)6U +#define SATASYMTYPE_ECDSA_VERIFY (SATASYMTYPE)7U +#define SATASYMTYPE_ECDH (SATASYMTYPE)8U +#define SATASYMTYPE_RSA_SIGN (SATASYMTYPE)9U +#define SATASYMTYPE_RSA_VERIFY (SATASYMTYPE)10U +/* Special marker for end of list. */ +#define SATASYMTYPE_LAST (SATASYMTYPE)11U + + +/* Encoding Types */ +/* -------- ----- */ +#define SATRSAENCTYPE_NULL (SATRSAENCTYPE)0U +#define SATRSAENCTYPE_PKCS (SATRSAENCTYPE)1U +#define SATRSAENCTYPE_ANSI (SATRSAENCTYPE)2U +#define SATRSAENCTYPE_PSS (SATRSAENCTYPE)3U +/* Special marker for end of list. */ +#define SATRSAENCTYPE_LAST (SATRSAENCTYPE)4U + + +/* Symmetric Ciphers */ +/* --------- ------- */ + +/* Cipher Type. */ +#define SATSYMTYPE_NULL (SATSYMTYPE)0U +#define SATSYMTYPE_AES128 (SATSYMTYPE)1U +#define SATSYMTYPE_AES192 (SATSYMTYPE)2U +#define SATSYMTYPE_AES256 (SATSYMTYPE)3U +#define SATSYMTYPE_AESKS128 (SATSYMTYPE)4U +#define SATSYMTYPE_AESKS192 (SATSYMTYPE)5U +#define SATSYMTYPE_AESKS256 (SATSYMTYPE)6U +/* Special marker for end of list. */ +#define SATSYMTYPE_LAST (SATSYMTYPE)7U + +/* Names for common cipher key lengths, in bits. */ +#define SATSYMKEYSIZE_AES128 (SATSYMKEYSIZE)128U +#define SATSYMKEYSIZE_AES192 (SATSYMKEYSIZE)192U +#define SATSYMKEYSIZE_AES256 (SATSYMKEYSIZE)256U +#define SATSYMKEYSIZE_AESKS128 (SATSYMKEYSIZE)256U +#define SATSYMKEYSIZE_AESKS192 (SATSYMKEYSIZE)384U +#define SATSYMKEYSIZE_AESKS256 (SATSYMKEYSIZE)512U + +/* Cipher Mode. */ +#define SATSYMMODE_NULL (SATSYMMODE)0U +#define SATSYMMODE_ECB (SATSYMMODE)1U +#define SATSYMMODE_CBC (SATSYMMODE)2U +#define SATSYMMODE_CFB (SATSYMMODE)3U +#define SATSYMMODE_OFB (SATSYMMODE)4U +#define SATSYMMODE_CTR (SATSYMMODE)5U +#define SATSYMMODE_GCM (SATSYMMODE)6U +#define SATSYMMODE_GHASH (SATSYMMODE)8U +/* Special marker for end of list. */ +#define SATSYMMODE_LAST (SATSYMMODE)9U + + +/* Hashes */ +/* ------ */ +#define SATHASHTYPE_NULL (SATHASHTYPE)0U +#define SATHASHTYPE_SHA1 (SATHASHTYPE)1U +#define SATHASHTYPE_SHA224 (SATHASHTYPE)2U +#define SATHASHTYPE_SHA256 (SATHASHTYPE)3U +#define SATHASHTYPE_SHA384 (SATHASHTYPE)4U +#define SATHASHTYPE_SHA512 (SATHASHTYPE)5U +#define SATHASHTYPE_SHA512_224 (SATHASHTYPE)6U +#define SATHASHTYPE_SHA512_256 (SATHASHTYPE)7U +/* Special marker for end of list. */ +#define SATHASHTYPE_LAST (SATHASHTYPE)8U + +/* Hash sizes defined in bits */ +#define SATHASHSIZE_NULL (SATHASHSIZE)0U +#define SATHASHSIZE_SHA1 (SATHASHSIZE)160U +#define SATHASHSIZE_SHA224 (SATHASHSIZE)224U +#define SATHASHSIZE_SHA256 (SATHASHSIZE)256U +#define SATHASHSIZE_SHA384 (SATHASHSIZE)384U +#define SATHASHSIZE_SHA512 (SATHASHSIZE)512U +#define SATHASHSIZE_SHA512_224 (SATHASHSIZE)224U +#define SATHASHSIZE_SHA512_256 (SATHASHSIZE)256U + +#define SATHASHSIZE_HASH160 (SATHASHSIZE)160U +#define SATHASHSIZE_HASH192 (SATHASHSIZE)192U +#define SATHASHSIZE_HASH224 (SATHASHSIZE)224U +#define SATHASHSIZE_HASH256 (SATHASHSIZE)256U +#define SATHASHSIZE_HASH320 (SATHASHSIZE)320U +#define SATHASHSIZE_HASH384 (SATHASHSIZE)384U +#define SATHASHSIZE_HASH512 (SATHASHSIZE)512U +#define SATHASHSIZE_HASH521 (SATHASHSIZE)521U + + +/* Message Authentication Codes */ +/* ------- -------------- ----- */ + +/* Message Authentication Types */ +#define SATMACTYPE_NULL (SATMACTYPE)0U +#define SATMACTYPE_SHA1 (SATMACTYPE)1U +#define SATMACTYPE_SHA224 (SATMACTYPE)2U +#define SATMACTYPE_SHA256 (SATMACTYPE)3U +#define SATMACTYPE_SHA384 (SATMACTYPE)4U +#define SATMACTYPE_SHA512 (SATMACTYPE)5U +#define SATMACTYPE_SHA512_224 (SATMACTYPE)6U +#define SATMACTYPE_SHA512_256 (SATMACTYPE)7U +#define SATMACTYPE_AESCMAC128 (SATMACTYPE)10U +#define SATMACTYPE_AESCMAC192 (SATMACTYPE)11U +#define SATMACTYPE_AESCMAC256 (SATMACTYPE)12U +#define SATMACTYPE_AESGMAC (SATMACTYPE)13U +/* Special marker for end of list. */ +#define SATMACTYPE_LAST (SATMACTYPE)14U + + +/* Message Authentication Flags */ +#define SATMACFLAG_OP (SATMACTYPEFLAG)0U +#define SATMACFLAG_FIRSTPASS (SATMACTYPEFLAG)1U +#define SATMACFLAG_FINALPASS (SATMACTYPEFLAG)2U +#define SATMACFLAG_IKEYFINAL (SATMACTYPEFLAG)4U +#define SATMACFLAG_OKEYFINAL (SATMACTYPEFLAG)8U + + +/* Non-deterministic Random Bit Generator */ +/* ------- -------------- ----- */ + +/* NRBG register write enables */ +#define SATNRBGCONFIG_NONE 0x0 +#define SATNRBGCONFIG_RNG_CSR 0x1 +#define SATNRBGCONFIG_RNG_CNTLIM 0x2 +#define SATNRBGCONFIG_RNG_VOTIMER 0X4 +#define SATNRBGCONFIG_RNG_FMSK 0X8 + +/* RNG_CSR access defines */ +#define SATNRBGCONFIG_CSR_RODIS 0x0 +#define SATNRBGCONFIG_CSR_ROEN 0x1 +#define SATNRBGCONFIG_CSR_ROFATAL 0x2 +#define SATNRBGCONFIG_CSR_ROFATALCLR 0X4 + +/* RNG_FMSK mask values */ +#define SATNRBGCONFIG_FMSK_ROOSCF 0xFF +#define SATNRBGCONFIG_FMSK_MONOBITF 0x10000 +#define SATNRBGCONFIG_FMSK_POKERF 0x20000 +#define SATNRBGCONFIG_FMSK_RUNSF 0x40000 +#define SATNRBGCONFIG_FMSK_LRUNSF 0x80000 +#define SATNRBGCONFIG_FMSK_F1401 0xF0000 +#define SATNRBGCONFIG_FMSK_REPCNTF 0x100000 +#define SATNRBGCONFIG_FMSK_APROPF 0x200000 +#define SATNRBGCONFIG_FMSK_SP800 0x300000 + +/* RNG_ROHEALTH mask values */ +#define SATNRBGCONFIG_HLTH_ROOSCF 0x3FC0 +#define SATNRBGCONFIG_HLTH_APROPF 0x20 +#define SATNRBGCONFIG_HLTH_REPCNTF 0x10 +#define SATNRBGCONFIG_HLTH_LRUNSF 0x8 +#define SATNRBGCONFIG_HLTH_RUNSF 0x4 +#define SATNRBGCONFIG_HLTH_POKERF 0x2 +#define SATNRBGCONFIG_HLTH_MONOBITF 0x1 + + +/* Return Codes */ +/* ------ ----- */ +#define SATR_SUCCESS (SATR)0U +#define SATR_FAIL (SATR)1U +#define SATR_BADPARAM (SATR)2U +#define SATR_VERIFYFAIL (SATR)3U +#define SATR_KEYSFULL (SATR)4U +#define SATR_BUSY (SATR)5U +#define SATR_ROFATAL (SATR)6U +#define SATR_PARITYFLUSH (SATR)7U +#define SATR_SIGNFAIL (SATR)8U +#define SATR_VALIDATEFAIL (SATR)9U +#define SATR_PAF (SATR)10U +#define SATR_VALPARMX (SATR)11U +#define SATR_VALPARMY (SATR)12U +#define SATR_VALPARMB (SATR)13U +#define SATR_DCMPPARMX (SATR)14U +#define SATR_DCMPPARMB (SATR)15U +#define SATR_DCMPPARMP (SATR)16U +#define SATR_SIGNPARMD (SATR)17U +#define SATR_SIGNPARMK (SATR)18U +#define SATR_VERPARMR (SATR)19U +#define SATR_VERPARMS (SATR)20U +#define SATR_MSBICV1 (SATR)21U +#define SATR_MSBICV2 (SATR)22U +#define SATR_PADLEN (SATR)23U +#define SATR_LSB0PAD (SATR)24U +#define SATR_BADLEN (SATR)25U +#define SATR_BADHASHTYPE (SATR)26U +#define SATR_BADTYPE (SATR)27U +#define SATR_BADMODE (SATR)28U +#define SATR_BADCONTEXT (SATR)29U +#define SATR_BADHASHLEN (SATR)30U +#define SATR_BADMACTYPE (SATR)31U +#define SATR_BADMACLEN (SATR)32U +#define SATR_BADHANDLE (SATR)33U +#define SATR_FNP (SATR)34U +#define SATR_HFAULT (SATR)35U +#define SATR_NOPEND (SATR)36U +#define SATR_BADRSAENC (SATR)37U +#define SATR_BADMOD (SATR)38U +/* Special marker for end of list. */ +#define SATR_LAST (SATR)39U + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* See caltypes.h for type definitions associated with defines above. */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALENUM_C +#ifdef __cplusplus +extern "C" { +#endif + +/* NOTE: this header file does not have an associated C file. */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/calini.h b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/calini.h new file mode 100644 index 0000000..62461d1 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/calini.h @@ -0,0 +1,69 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL initialization + ------------------------------------------------------------------- */ + +#ifndef CALINI_H +#define CALINI_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALINI_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALIni(void); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/calpolicy.h b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/calpolicy.h new file mode 100644 index 0000000..2a43445 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/calpolicy.h @@ -0,0 +1,183 @@ +/* ------------------------------------------------------------------- + $Rev: 1293 $ $Date: 2017-07-27 14:09:14 -0400 (Thu, 27 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file defining CAL policy for endianess, HW/SW, etc. + ------------------------------------------------------------------- */ + +#ifndef CALPOLICY_H +#define CALPOLICY_H + +/* -------- */ +/* Includes */ +/* -------- */ + +/* The following include provides a custom configuration header file when + CALCONFIGH is defined +*/ +#ifdef CALCONFIGH +# include CALCONFIGH +#else +# error "CALCONFIGH not defined. CAL requires a custom configuration header \ +defined by CALCONFIGH. Review CAL README." +#endif + +/* ------- */ +/* Defines */ +/* ------- */ + +/* Context switching */ +#ifndef MAXRESHANDLES +# define MAXRESHANDLES 1 +#endif + +/* Little Endian (default) / Big Endian */ +#ifndef SAT_LITTLE_ENDIAN +# define SAT_LITTLE_ENDIAN 1 +#endif + +/* PK SW Point Validate Checking */ +#ifndef PKSWCHKVALPT +# define PKSWCHKVALPT 1 +#endif + +/* DMA */ +#ifndef USE_X52EXEC_DMA +# define USE_X52EXEC_DMA 0 +#endif + +/* SHA */ +#define MAXHASHLEN 512 +#define MAXHMACKEYLEN 512 + +/* RNG */ +#define NRBGSIMNUMRO 16 +#define ENTROPYMEMBLOCKS 7 +#define BUFMEMBLOCKS 3 +#ifndef RNXBLKLEN +#define RNXBLKLEN 32 +#endif +#ifndef RNXBLKOUTLEN +#define RNXBLKOUTLEN 4 +#endif + +#ifndef USENRBGSW +# define USENRBGSW 0 +#endif + +/* PK */ +#ifndef PKX0_BASE +# define PKX0_BASE 0xE0000000u +#endif + +#if USEPKSW +# ifndef MAXMODSIZE +# define MAXMODSIZE 8192 +# endif +# ifndef PKSWBUFSIZE +# define PKSWBUFSIZE 15*(MAXMODSIZE/32) +# endif +#else +# define USEPKSW 0 +#endif + +/* Set default values for X52 configuration defines. */ +#ifndef X52_CFG_OPT +# define X52_CFG_OPT 0 +#endif +#ifndef X52_LIR_LEN +# define X52_LIR_LEN 0x800 +#endif +#ifndef X52_BER_LEN +# define X52_BER_LEN 0x400 +#endif +#ifndef X52_MMR_LEN +# define X52_MMR_LEN 0x400 +#endif +#ifndef X52_TSR_LEN +# define X52_TSR_LEN 0x400 +#endif +#ifndef X52_FPR_LEN +# define X52_FPR_LEN 0x400 +#endif +#if X52_LIR_ROM_LEN>0 && X52_LIR_LEN>X52_LIR_ROM_LEN +# define PKX_OFFSET 2048 +#else +# define PKX_OFFSET 0 +#endif + +/* X52 Configuration Options */ +#define AESPKX (X52_CFG_OPT&0x00000001u) +#define AESPKXGCM (X52_CFG_OPT&0x00000008u) +#define AESPKXFASTKEY (X52_CFG_OPT&0x01000000u) +#define SHAPKXOPT1 (X52_CFG_OPT&0x00000020u) +#define SHAPKXOPT224 (X52_CFG_OPT&0x00000040u) +#define SHAPKXOPT256 (X52_CFG_OPT&0x00000080u) +#define SHAPKXOPT384 (X52_CFG_OPT&0x00000100u) +#define SHAPKXOPT512 (X52_CFG_OPT&0x00000200u) +#define SHAPKXOPT5124 (X52_CFG_OPT&0x00400000u) +#define SHAPKXOPT5126 (X52_CFG_OPT&0x00800000u) + +/* Define the maximum number of return values that may be handled using + CAL*TrfRes() function(s). +*/ +#define CAL_MAXTRFS 4 + +/* Volatile pointer operations */ +/* These access macros are designed so that they may be redefined by a + user compiling CAL. +*/ +#ifndef CALREAD32 +# define CALREAD32(ptr) ( *(ptr) ) +#endif +#ifndef CALWRITE32 +# define CALWRITE32(ptr, val) ( *(ptr)=val ) +#endif +#ifndef CALPOLL32 +# define CALPOLL32(ptr, val, mask) while ((*(ptr) & (mask)) != (val)); +#endif + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +#ifndef CALPOLICY_C +#ifdef __cplusplus +extern "C" { +#endif + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +/* NOTE: this header file does not have an associated C file. */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/caltypes.h b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/caltypes.h new file mode 100644 index 0000000..3b2fe0b --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/caltypes.h @@ -0,0 +1,328 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + This file defines common types in the CAL. + + Since support for the C99 stdint.h integer types is not universal, + these are defined herein and may require customization from compiler + to compiler, or use of the stdint.h header, if present (recommended). + + C99 supports 64-bit types; however, support in older compilers is + spotty. For those that do not support it, the macro NO64BITINT may be + defined by the user to prevent defintion of 64-bit types. This is + generally safe with CAL-PK and CAL-SYM; however, this is incompatible + with CAL-SW. + + Most CAL types and constants are defined with the "SAT" prefix to + reduce the chance of name space collisions with other users. + ------------------------------------------------------------------- */ + +#ifndef CALTYPES_H +#define CALTYPES_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* Base Types */ +/* ---- ----- */ + +/* The user may compile using stdint.h instead of the definitions below + by defining the macro INC_STDINT_H. */ +#ifdef INC_STDINT_H +#include +#endif + +/* Integer type abstraction layer. */ +#ifndef INC_STDINT_H + +typedef unsigned char uint8_t; +typedef signed char int8_t; + +typedef unsigned short uint16_t; +typedef signed short int16_t; + +typedef unsigned int uint32_t; +typedef int int32_t; + +/* stdint.h is a C99 feature, and C99 supports 64-bit ints, so this is + immune to the macro used to disable 64-bit int support. +*/ +typedef unsigned long long uint64_t; +typedef long long int64_t; + +typedef long uintptr_t; + +#endif + +/* Boolean type. */ +typedef uint8_t SATBOOL; + +/* Unsigned integer type */ +typedef uint8_t SATUINT8_t; +typedef uint16_t SATUINT16_t; +typedef uint32_t SATUINT32_t; +#ifdef INC_STDINT_H +typedef uint64_t SATUINT64_t; +#else +#ifndef NO64BITINT +typedef uint64_t SATUINT64_t; +#endif +#endif + +/* Integer type */ +typedef int8_t SATINT8_t; +typedef int16_t SATINT16_t; +typedef int32_t SATINT32_t; +#ifdef INC_STDINT_H +typedef int64_t SATINT64_t; +#else +#ifndef NO64BITINT +typedef int64_t SATINT64_t; +#endif +#endif + +typedef uintptr_t SATUINTPTR_t; + +/* Major cipher key/SSP type. */ +/* ----- ------ ------- ----- */ +typedef uint8_t SATSSPTYPE; +typedef SATSSPTYPE * SATSSPTYPEPTR; + + +/* Asymmetric Ciphers */ +/* ---------- ------- */ + +/* Cipher type. */ +typedef uint8_t SATASYMTYPE; +typedef SATASYMTYPE * SATASYMTYPEPTR; + +/* Cipher size type. */ +typedef uint16_t SATASYMSIZE; +typedef SATASYMSIZE * SATASYMSIZEPTR; + +/* Cipher encoding */ +typedef uint8_t SATRSAENCTYPE; +typedef SATRSAENCTYPE * SATRSAENCTYPEPTR; + +/* DSA public/private key. */ +typedef struct { + uint16_t ui16PLen; /* Length of modulus p. */ + uint16_t ui16QLen; /* Length of prime divisor q. */ + uint32_t *pui32P; /* Prime modulus p. */ + uint32_t *pui32Q; /* Prime divisor q. */ + uint32_t *pui32G; /* Generator g, length==p. */ + uint32_t *pui32X; /* Private key x, length==p. */ + uint32_t *pui32Y; /* Private key y, length==q. */ +} SATASYMDSADOMAIN; +typedef SATASYMDSADOMAIN * SATASYMDSADOMAINPTR; + + +/* Symmetric Ciphers */ +/* --------- ------- */ + +/* Cipher type. */ +typedef uint8_t SATSYMTYPE; +typedef SATSYMTYPE * SATSYMTYPEPTR; + +/* Cipher key size type (in bits). */ +typedef uint16_t SATSYMKEYSIZE; +typedef SATSYMKEYSIZE * SATSYMKEYSIZEPTR; + +/* Cipher mode type. */ +typedef uint8_t SATSYMMODE; +typedef SATSYMMODE * SATSYMMODEPTR; + +/* Cipher key object. */ +/* Other fields are only valid when sstCipher!=SATSYMTYPE_NULL. */ +typedef struct { + SATSYMTYPE sstCipher; + SATSYMKEYSIZE ssksKeyLen; + uint32_t *pui32Key; +} SATSYMKEY; +typedef SATSYMKEY * SATSYMKEYPTR; + + +/* Hashes */ +/* ------ */ + +/* Hash type. */ +typedef uint8_t SATHASHTYPE; +typedef SATHASHTYPE * SATHASHTYPEPTR; + +/* Hash size type (in bits). */ +typedef uint16_t SATHASHSIZE; +typedef SATHASHSIZE * SATHASHSIZEPTR; + + +/* Context switching. */ +/* ----- ------ ------- ----- */ + +typedef uint32_t SATRESHANDLE; +typedef SATRESHANDLE * SATRESHANDLEPTR; + +typedef struct { + SATHASHTYPE sshashtype; + uint32_t uiRunLen; + uint32_t uiHash[MAXHASHLEN/32]; /* holds intermed hash */ +} SHACTX; + +typedef struct { + SATHASHTYPE sshashtype; + uint32_t uiRunLen; + uint32_t uiKeyLen; + uint32_t uiHash[MAXHASHLEN/32]; /* holds intermed hash */ + uint32_t uiKey[MAXHMACKEYLEN/32]; /* holds intermed key */ +} SHAHMACCTX; + +typedef struct { + uint8_t uiContextType; + union{ + SHACTX ctxSHA; + SHAHMACCTX ctxMAC; + }CTXUNION; +} SATRESCONTEXT; +typedef SATRESCONTEXT * SATRESCONTEXTPTR; + + +/* Message Authentication Codes */ +/* ------- -------------- ----- */ + +/* MAC type. */ +typedef uint8_t SATMACTYPE; +typedef SATMACTYPE * SATMACTYPEPTR; +typedef uint8_t SATMACTYPEFLAG; + + +/* Random Number Generator */ +/* ------ ------ --------- */ +typedef union { + uint32_t u32[4]; + uint8_t u8[16]; +} uint128_t; + +typedef struct { + uint128_t ui128V; + uint128_t ui128K[2]; + uint32_t uiReseedCnt; + uint32_t uiReseedLim; + uint32_t uiEntropyFactor; + SATSYMKEYSIZE eStrength; + SATBOOL bTesting; + +} DRBGCTX; + +typedef DRBGCTX * DRBGCTXPTR; + + +/* Function Return Code */ +/* -------- ------ ---- */ +typedef uint16_t SATR ; +typedef SATR * SATRPTR ; + + +/* Transfer Results */ +/* -------- ------- */ +typedef struct { + SATUINT32_t uiLen; + volatile SATUINT32_t* vpuiSrc; + void* pDest; +} SATDATATRF; + +typedef struct { + SATUINT32_t uiResType; + SATUINT32_t uiNumDataTrf; + SATDATATRF dtrfArray[CAL_MAXTRFS]; +} SATRESULT; + + +/* EC Ultra Structs */ +/* -- ----- ------- */ +typedef uint32_t SATECTYPE; + +typedef struct { + SATUINT32_t uiLen; + SATUINT32_t* puiX; + SATUINT32_t* puiY; +} SATECPOINT; + +typedef struct { + SATUINT32_t uiLen; + SATUINT32_t* puiMod; + SATUINT32_t* puiMontPrecompute; + SATUINT32_t* puiRSqd; +} SATECMONTMOD; + +typedef struct { + SATUINT32_t uiCurveSize; + SATECTYPE eCurveType; + SATECPOINT* pBasePoint; + SATECMONTMOD* pModP; + SATECMONTMOD* pModN; + SATUINT32_t* puiA; + SATUINT32_t* puiB; +} SATECCURVE; + +typedef struct { + SATUINT32_t uiLen; + SATUINT32_t* puiSigR; + SATUINT32_t* puiSigS; + SATUINT32_t* puiSigX; + SATUINT32_t* puiSigY; +} SATECDSASIG; + +typedef struct { + SATHASHSIZE sHashLen; + SATUINT32_t* puiHash; +} SATHASH; + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALTYPES_C +#ifdef __cplusplus +extern "C" { +#endif + +/* NOTE: this header file does not have an associated C file. */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/config_user.h b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/config_user.h new file mode 100644 index 0000000..3728565 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/config_user.h @@ -0,0 +1,44 @@ +/* ------------------------------------------------------------------- + $Rev: 727 $ $Date: 2017-10-20 16:50:53 -0400 (Fri, 20 Oct 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + + User configuration file to include/exclude CAL components. + ------------------------------------------------------------------- */ + +#ifndef CALCONFIG_F5200_H +#define CALCONFIG_F5200_H + +#include "x52cfg_user.h" +#include + +extern uint32_t g_user_crypto_base_addr; + +#define SAT_LITTLE_ENDIAN 1 +#define PKX0_BASE (g_user_crypto_base_addr) +#define USEPKX 1 +#define USEAESPKX 1 +#define USESHAPKX 1 +#define USEDRBGPKX 1 +#define USENRBGPKX 1 +#define USECALCTX 1 + +#endif diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/drbg.h b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/drbg.h new file mode 100644 index 0000000..dba16f7 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/drbg.h @@ -0,0 +1,91 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for DRBG functions for CAL + ------------------------------------------------------------------- */ + +#ifndef DRBG_H +#define DRBG_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ +#define CALDRBGENTROPYFACTOR 2 + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef DRBG_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALDRBGInstantiate(const SATUINT32_t *puiNonce, + SATUINT32_t uiNonceLen, const SATUINT32_t *puiPzStr, + SATUINT32_t uiPzStrLen, SATSYMKEYSIZE eStrength, + SATUINT32_t uiEntropyFactor, SATUINT32_t uiReseedLim, SATBOOL bTesting); + +extern SATR CALDRBGReseed(const SATUINT32_t *puiAddIn, SATUINT32_t uiAddInLen); + +extern SATR CALDRBGGenerate(const SATUINT32_t *puiAddIn, SATUINT32_t uiAddInLen, + SATBOOL bPredResist, SATUINT32_t *puiOut, SATUINT32_t uiOutBlocks); + +extern SATR CALDRBGUninstantiate(void); + +extern SATR CALDRBGGetCtx(DRBGCTXPTR drbgCtxExt); + +extern SATR CALDRBGLoadCtx(DRBGCTXPTR drbgCtxExt); + +extern SATR CALDRBGGetbInst(void); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +extern SATR CALDrbgTrfRes(SATBOOL bBlock); + +extern void CALDrbgIni(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/drbgf5200.h b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/drbgf5200.h new file mode 100644 index 0000000..d7f6c4c --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/drbgf5200.h @@ -0,0 +1,120 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for F5200 DRBG function hardware implementations + in CAL. + ------------------------------------------------------------------- */ + +#ifndef DRBGF5200_H +#define DRBGF5200_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ +#define RNXEFACTOR (X52BER+2) +#define RNXIRLEN (X52BER+2) +#define RNXKEYORD (X52BER+3) +#define RNXRESPRED (X52BER+4) +#define RNXTESTSEL (X52BER+5) +#define RNXBADDIN (X52BER+6) +#define RNXPPSTR (X52BER+7) +#define RNXPCTX (X52BER+8) +#define RNXPRENT (X52BER+13) +#define RNXITMP3 (X52BER+20) +#define RNXPCTX2 (X52BER+22) +/* These use same locs as tb generator, but can change */ +#define RNXRDATA (X52BER_ENDIAN+0x24) +#define RNXAIDATAOFF 0x0062 +#define RNXAIDATA (X52BER_ENDIAN+RNXAIDATAOFF) +#define RNXCTXOFF 0x0094 +#define RNXCTX (X52FPR+RNXCTXOFF) +#define RNXCTXV (X52FPR_ENDIAN+RNXCTXOFF+6) +#define RNXCTXVMMR (X52MMR_ENDIAN+RNXCTXOFF+6) +#define RNXTESTENT (X52TSR_ENDIAN+8) + +#define RNXCTXWORDS 18 +#define RNXBLENLOC (RNXCTX+RNXCTXWORDS) +#define RNXBOUTLENLOC (RNXCTX+RNXCTXWORDS+1) + +#define RNXMAXTESTENT32 512 +#define CALDRBGMAXADDINLEN X52_BER_LEN-RNXAIDATAOFF-4 +#define CALDRBGMAXPSNONCELEN X52_BER_LEN-RNXAIDATAOFF-4 + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef DRBGF5200_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATR drbgf5200Ini(void); + +extern SATR drbgf5200TrfRes(SATBOOL bBlock); + +extern SATR drbgf5200instantiate(const SATUINT32_t *puiNonce, + SATUINT32_t uiNonceLen, const SATUINT32_t *puiPzStr, SATUINT32_t uiPzStrLen, + SATSYMKEYSIZE eStrength, SATUINT32_t uiEntropyFactor, + SATUINT32_t uiReseedLim, SATBOOL bTesting); + +extern SATR drbgf5200reseed(const SATUINT32_t *puiAddIn, + SATUINT32_t uiAddInLen); + +extern SATR drbgf5200generate(const SATUINT32_t *puiAddIn, + SATUINT32_t uiAddInLen, SATBOOL bPredResist, SATUINT32_t uiReqLen, + SATUINT32_t *puiOut); + +extern SATR drbgf5200uninstantiate(void); + +extern SATR drbgf5200getctx(DRBGCTXPTR drbgCtxExt); + +extern SATR drbgf5200loadctx(DRBGCTXPTR drbgCtxExt); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/hash.h b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/hash.h new file mode 100644 index 0000000..f3fd6d4 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/hash.h @@ -0,0 +1,102 @@ +/* ------------------------------------------------------------------- + $Rev: 1293 $ $Date: 2017-07-27 14:09:14 -0400 (Thu, 27 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL hash functions. + ------------------------------------------------------------------- */ + +#ifndef HASH_H +#define HASH_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ +extern const SATHASHSIZE uiHashWordLen[SATHASHTYPE_LAST]; + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef HASH_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALHash(SATHASHTYPE eHashType, const void *pMsg, + SATUINT32_t uiMsgLen, void *pHash); + +extern SATR CALHashDMA(SATHASHTYPE eHashType, const void *pMsg, + SATUINT32_t uiMsgLen, void *pHash, SATUINT32_t uiDMAChConfig); + +extern SATR CALHashCtx(const SATRESHANDLE hResource, + const SATRESCONTEXTPTR pContext, const void *pMsg, SATUINT32_t uiMsgLen, + void *pHash, const SATBOOL bFinal); + +extern SATR CALHashCtxIni(const SATRESCONTEXTPTR pContext, + const SATHASHTYPE eHashType); + +extern SATR CALHashIni(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen); + +extern SATR CALHashWrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR CALHashRead(void *pHash); + +extern SATR CALKeyTree(SATBOOL bPathSizeSel, const SATUINT32_t* puiKey, + SATUINT8_t uiOpType, const SATUINT32_t* puiPath, SATUINT32_t* puiKeyOut); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATUINT32_t iGetHashLen(SATHASHTYPE eHashType); + +extern SATUINT32_t iGetBlockLen(SATHASHTYPE eHashType); + +extern SATR CALHashCtxLoad(const SATRESHANDLE hResource, + SATRESCONTEXTPTR const pContext, SATUINT32_t uiRunLen); + +extern SATUINT32_t iGetRunLen(SATRESCONTEXTPTR const pContext); + +extern SATR CALHashTypeIni(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/mac.h b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/mac.h new file mode 100644 index 0000000..acdc767 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/mac.h @@ -0,0 +1,95 @@ +/* ------------------------------------------------------------------- + $Rev: 1296 $ $Date: 2017-08-01 13:54:48 -0400 (Tue, 01 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL MAC functions. + ------------------------------------------------------------------- */ + +#ifndef MAC_H +#define MAC_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef MAC_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALMAC(SATMACTYPE eMACType, const SATUINT32_t *pKey, SATUINT32_t uiKeyLen, + const void *pMsg, SATUINT32_t uiMsgLen, void *pMAC); + +extern SATR CALMACDMA(SATMACTYPE eMACType, const SATUINT32_t *pKey, + SATUINT32_t uiKeyLen, const void *pMsg, SATUINT32_t uiMsgLen, + const void *pMAC, SATUINT32_t uiDMAChConfig); + +extern SATR CALMACIni(SATMACTYPE eMACType, const SATUINT32_t *pKey, + SATUINT32_t uiKeyLen, SATUINT32_t uiMsgLen); + +extern SATR CALMACCtx(const SATRESHANDLE hResource, + const SATRESCONTEXTPTR pContext, const void *pMsg, SATUINT32_t uiMsgLen, + void *pHash, const SATUINT8_t uiFlag); + +extern SATR CALMACCtxIni(const SATRESCONTEXTPTR pContext, const SATHASHTYPE eHashType, + const SATUINT32_t *pKey, SATUINT32_t uiKeyLen); + +extern SATR CALMACWrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR CALMACRead(void *pMAC); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATUINT32_t iGetMACKeyLen(SATMACTYPE eMACType); + +extern SATR CALMACCtxLoad(const SATRESHANDLE hResource, + SATRESCONTEXTPTR const pContext, SATUINT32_t uiRunLen); + +extern SATUINT32_t iGetMACRunLen(SATRESCONTEXTPTR const pContext); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/miv-rv32i-user-crypto-lib.a b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/miv-rv32i-user-crypto-lib.a new file mode 100644 index 0000000..5fda638 Binary files /dev/null and b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/miv-rv32i-user-crypto-lib.a differ diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/miv-rv32imc-user-crypto-lib.a b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/miv-rv32imc-user-crypto-lib.a new file mode 100644 index 0000000..ee7bcf4 Binary files /dev/null and b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/miv-rv32imc-user-crypto-lib.a differ diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/nrbg.h b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/nrbg.h new file mode 100644 index 0000000..d517065 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/nrbg.h @@ -0,0 +1,83 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for NRBG functions for CAL. + ------------------------------------------------------------------- */ + +#ifndef NRBG_H +#define NRBG_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef NRBG_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALNRBGSetTestEntropy(SATUINT32_t * puiEntropy, + SATUINT32_t uiEntLen32); + +extern SATR CALNRBGGetEntropy(SATUINT32_t * puiEntropy, SATUINT32_t uiEntLen32, + SATBOOL bTesting); + +extern SATR CALNRBGConfig(SATUINT32_t uiWriteEn, SATUINT32_t uiCSR, + SATUINT32_t uiCntLim, SATUINT32_t uiVoTimer, SATUINT32_t uiFMsk, + SATUINT32_t* puiStatus); + +extern SATUINT32_t CALNRBGHealthStatus(void); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATUINT32_t CALNRBGGetTestEntLen(void); + +extern SATR nrbgpkxgetentropy(SATUINT32_t * puiEntropy, + SATUINT32_t uiEntLen32); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/pk.h b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/pk.h new file mode 100644 index 0000000..5983d9a --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/pk.h @@ -0,0 +1,302 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for for CAL PK. + ------------------------------------------------------------------- */ + +#ifndef PK_H +#define PK_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef PK_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALPKTrfRes(SATBOOL bBlock); + +extern SATR CALDSASign(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALDSASignCM(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALDSASignHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, const SATUINT32_t* puiK, + const SATUINT32_t* puiX, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, SATUINT32_t uiN, + SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALDSASignHashCM(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, const SATUINT32_t* puiK, + const SATUINT32_t* puiX, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, SATUINT32_t uiN, + SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALDSAVerify(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiY, const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, + const SATUINT32_t* puiQMu, SATUINT32_t uiN, SATUINT32_t uiL); + +extern SATR CALDSAVerifyHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, const SATUINT32_t* puiY, + const SATUINT32_t* puiR, const SATUINT32_t* puiS, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALECDHC(const SATUINT32_t* puiS, const SATUINT32_t* puiWx, + const SATUINT32_t* puiWy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t* puiK, const SATUINT32_t* puiR, + const SATUINT32_t* puiRMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiZ); + +extern SATR CALECDSASign(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALECDSASignTwist(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALECDSASignCM(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALECDSASignTwistCM(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALECDSASignHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiK, const SATUINT32_t* puiD, const SATUINT32_t* puiB, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSASignHashCM(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiK, const SATUINT32_t* puiD, const SATUINT32_t* puiB, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSASignTwistHash(const SATUINT32_t* puiMsg, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSAVerify(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS,const + SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress); + +extern SATR CALECDSAVerifyTwist(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALECDSAVerifyHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSAVerifyTwistHash(const SATUINT32_t* puiMsg, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALECMult(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECMultCM(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t* puiN, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress, SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECMultTwist(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiLen, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECMultTwistCM(const SATUINT32_t* puiMul, + const SATUINT32_t* puiPx, const SATUINT32_t* puiPy, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiMod,const SATUINT32_t* puiMu, + const SATUINT32_t* puiN, SATUINT32_t uiLen, SATUINT32_t* puiRx, + SATUINT32_t* puiRy); + +extern SATR CALECMultAdd(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiB, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen, SATUINT32_t uiPtPCompress, SATUINT32_t uiPtQCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECPtValidate(const SATUINT32_t* puiPx, const SATUINT32_t* puiPy, + const SATUINT32_t* puiB, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen); + +extern SATR CALECKeyPairGen(const SATUINT32_t* puiC, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + const SATUINT32_t* puiNM1, const SATUINT32_t* puiNM1Mu, const SATUINT32_t* puiB, + SATUINT32_t* puiD, SATUINT32_t* puiQx, SATUINT32_t* puiQy, SATUINT32_t uiLen); + +extern SATR CALExpo(const SATUINT32_t* puiBase, const SATUINT32_t* puiExpo, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALExpoCM(const SATUINT32_t* puiBase, const SATUINT32_t* puiExpo, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALMMult(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALMMultAdd(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiC, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALModRed(const SATUINT32_t* puiA, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiALen, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPreCompute(const SATUINT32_t* puiMod, SATUINT32_t* puiMu, + SATUINT32_t uiModLen); + +extern SATR CALRSACRT(const SATUINT32_t* puiCipher, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ,const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiLen, SATUINT32_t* puiPlain); + +extern SATR CALRSACRTCM(const SATUINT32_t* puiCipher, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t * puiE, const SATUINT32_t* puiP, + const SATUINT32_t* puiQ, const SATUINT32_t * puiN, + const SATUINT32_t * puiNMu, SATUINT32_t uiLen, SATUINT32_t uiELen, + SATUINT32_t* puiPlain); + +extern SATR CALRSACRTSign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + const SATUINT32_t* puiN, SATUINT32_t uiLen, SATUINT32_t* puiSig); + +extern SATR CALRSACRTSignCM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, const SATUINT32_t* puiQ, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSig); + +extern SATR CALRSACRTSignHash(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ,const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + const SATUINT32_t* puiN, SATUINT32_t uiMsgLen, SATUINT32_t uiModLen, + SATUINT32_t* puiSig, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALRSACRTSignHashCM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, const SATUINT32_t* puiQ, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, SATUINT32_t* puiSig, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALRSASign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiD, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, SATUINT32_t* puiSig); + +extern SATR CALRSASignHash(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiD, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, SATUINT32_t uiModLen, + SATUINT32_t* puiSig, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALRSAVerify(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, + const SATUINT32_t* puiSig); + +extern SATR CALRSAVerifyHash(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiE, SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, const SATUINT32_t* puiSig, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPurge52(SATBOOL bVerify); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/pkx.h b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/pkx.h new file mode 100644 index 0000000..c23dda4 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/pkx.h @@ -0,0 +1,409 @@ +/* ------------------------------------------------------------------- + $Rev: 1298 $ $Date: 2017-08-04 13:04:19 -0400 (Fri, 04 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for for CAL PK. + ------------------------------------------------------------------- */ + +#ifndef PKX_H +#define PKX_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* X5200 Addressing */ +#define X52BER ((volatile SATUINT32_t *) (PKX0_BASE + 0x00000000u)) +#define X52MMR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00001000u)) +#define X52TSR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00002000u)) +#define X52FPR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00003000u)) +#define X52LIR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00004000u)) +#define X52CSR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00007F80u)) +#define X52CSRMERRS ((volatile SATUINT32_t *) (PKX0_BASE + 0x00007F8Cu)) +#define X52CSRMERRT0 ((volatile SATUINT32_t *) (PKX0_BASE + 0x00007F94u)) + +#if SAT_LITTLE_ENDIAN +#define X52BER_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00008000u)) +#define X52MMR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00009000u)) +#define X52TSR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x0000A000u)) +#define X52FPR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x0000B000u)) +#define X52DMACONFIG_ENDIAN 0x8 +#else +#define X52BER_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00000000u)) +#define X52MMR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00001000u)) +#define X52TSR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00002000u)) +#define X52FPR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00003000u)) +#define X52DMACONFIG_ENDIAN 0x0 +#endif + +/* X5200 Macros */ +#define X52GO(x) (0x10 | ((x)<<8)) + +/* Counter Measures */ +#define RANDLEN 4 + +/* X5200 CSRMAIN bit field masks. */ +#define X52CSRMAINRST 1 +#define X52CSRMAINCCMPLT 2 +#define X52CSRMAINCMPLT 4 +#define X52CSRMAINBUSY 8 +#define X52CSRMAINGO 0x10 +#define X52CSRMAINPURGE 0x20 +#define X52CSRMAINECDIS 0x40 +#define X52CSRMAINALARM 0x80 +#define X52CSRMAINLIRA ((0xFFF) << 8) +#define X52CSRMERRSSEC ((0x2) << 24) +#define X52CSRMERRSA 0x1FFF + +/* Address pointers for ROM'd P-curve moduli */ +#define P192_MOD (&uiROMMods[0]) +#define P224_MOD (&uiROMMods[1]) +#define P256_MOD (&uiROMMods[2]) +#define P384_MOD (&uiROMMods[3]) +#define P521_MOD (&uiROMMods[4]) + +/* X5200 Addressing Flags */ +#define X52BYTEREVERSE_FLAG 1 +#define X52WORDREVERSE_FLAG 2 +#define X52BYTEREVERSE 0x00002000 +#define X52WORDREVERSE 0x00004000 +#define X52ADDRESSRANGE 0x2000 + +/* X5200 DMA channel configuration constants. */ +#define X52CCR_DEFAULT 0 /* BSIZE=auto, ESWP=none, PROT=user, INC=inc */ +#define X52CCR_BSIZEAUTO 0 /* BSIZE=auto */ +#define X52CCR_BSIZEBYTE 0x10 /* BSIZE=byte */ +#define X52CCR_BSIZEHWORD 0x20 /* BSIZE=half word */ +#define X52CCR_BSIZEWORD 0x30 /* BSIZE=word */ +#define X52CCR_ESWPNONE 0 /* ESWP=none */ +#define X52CCR_ESWPWORD 0x8 /* ESWP=swap bytes in word [0123]->[3210] */ +#define X52CCR_PROTUSER 0 /* PROT=user */ +#define X52CCR_PROTPRIV 0x2 /* PROT=priv */ +#define X52CCR_INCADDR 0 /* INC=inc */ +#define X52CCR_NOINCADDR 0x1 /* INC=non-inc */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef PKX_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern void CALPKXIni(void); + +extern void CALPKMem32Load(volatile SATUINT32_t * puiDst, + const SATUINT32_t * puiSrc, SATUINT32_t uiNum ); + +extern SATR CALPKXTrfRes(SATBOOL bBlock); + +extern SATR CALPKXPreCompute(const SATUINT32_t* puiMod, SATUINT32_t* puiMu, + SATUINT32_t uiModLen); + +extern SATR CALPKXExpo(const SATUINT32_t* puiBase, const SATUINT32_t* puiExpo, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALPKXExpoCM(const SATUINT32_t* puiBase, + const SATUINT32_t* puiExpo, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPKXDSASign(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXDSASignCM(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXDSASHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATUINT32_t uiDMAChConfig, const SATBOOL bCM); + +extern SATR CALPKXDSAVerify(const SATUINT32_t *puiHash, + const SATUINT32_t *puiG, const SATUINT32_t *puiY, + const SATUINT32_t *puiSigR, const SATUINT32_t *puiSigS, + const SATUINT32_t *puiP, const SATUINT32_t *puiPMu, + const SATUINT32_t *puiQ, const SATUINT32_t *puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL); + +extern SATR CALPKXDSAVHDMA(const SATUINT32_t *puiExtInput, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t *puiG, const SATUINT32_t *puiY, + const SATUINT32_t *puiSigR, const SATUINT32_t *puiSigS, + const SATUINT32_t *puiP, const SATUINT32_t *puiPMu, const SATUINT32_t *puiQ, + const SATUINT32_t *puiQMu, SATUINT32_t uiN, SATUINT32_t uiL, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXModRed(const SATUINT32_t* puiA, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiALen, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPKXMMult(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPKXMMultAdd(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiC, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALPKXECMult(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECMultTwist(const SATUINT32_t* puiMul, + const SATUINT32_t* puiPx,const SATUINT32_t* puiPy, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen, SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECMultCM(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t * puiN, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress, SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECMultTwistCM(const SATUINT32_t* puiMul, + const SATUINT32_t* puiPx, const SATUINT32_t* puiPy, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + const SATUINT32_t * puiN, SATUINT32_t uiLen, SATUINT32_t* puiRx, + SATUINT32_t* puiRy); + +extern SATR CALPKXECMultAdd(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiB, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen, SATUINT32_t uiPtPCompress, SATUINT32_t uiPtQCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECDSASign(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASignTwist(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx,const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASignCM(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASignTwistCM(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASH(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + const SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASHCM(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + const SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, SATUINT32_t uiDMAChConfig, + const SATBOOL bCM); + +extern SATR CALPKXECDSASTwistH(const SATUINT32_t* puiHash, + const SATHASHTYPE eHashType, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiK, const SATUINT32_t* puiD, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, const SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASTwistHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECDSAVerify(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVerifyTwist(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVH(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB,const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + const SATUINT32_t uiLen, const SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB,const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECDSAVTwistH(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, const SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVTwistHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECDHC(const SATUINT32_t* puiS, const SATUINT32_t* puiWx, + const SATUINT32_t* puiWy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t* puiK, const SATUINT32_t* puiR, + const SATUINT32_t* puiRMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiZ); + +extern SATR CALPKXRSACRT(const SATUINT32_t* puiCipher, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, SATUINT32_t uiLen, + SATUINT32_t* puiPlain); + +extern SATR CALPKXRSACRTCM(const SATUINT32_t* puiCipher, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiE, + const SATUINT32_t* puiP, const SATUINT32_t* puiQ, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, const SATUINT32_t uiLen, const SATUINT32_t uiELen, + SATUINT32_t* puiPlain); + +extern SATR CALPKXRSACRTSign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiCipher, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, + const SATUINT32_t* puiQMu, const SATUINT32_t* puiN, SATUINT32_t uiLen, + SATUINT32_t* puiS); + +extern SATR CALPKXRSACRTSignCM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, + const SATUINT32_t* puiP, const SATUINT32_t* puiQ, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSig); + +extern SATR CALPKXRSACRTSHDMA(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + const SATUINT32_t* puiN, SATUINT32_t uiMsgLen, SATUINT32_t uiModLen, + SATUINT32_t* puiSig, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXRSACRTSHDMACM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, + const SATUINT32_t* puiP, const SATUINT32_t* puiQ, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, SATUINT32_t uiLen, + SATUINT32_t* puiSig, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXRSASign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiD, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, SATUINT32_t* puiSig); + +extern SATR CALPKXRSASHDMA(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiD, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, SATUINT32_t* puiSig, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXRSAVerify(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, + const SATUINT32_t* puiS); + +extern SATR CALPKXRSAVHDMA(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiE,SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, const SATUINT32_t* puiS, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECPtValidate(const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiLen); + +extern SATR CALPKXECKeyPairGen(const SATUINT32_t* puiC, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + const SATUINT32_t* puiNM1, const SATUINT32_t* puiNM1Mu, const SATUINT32_t* puiB, + SATUINT32_t* puiD, SATUINT32_t* puiQx, SATUINT32_t* puiQy, SATUINT32_t uiLen); + +extern SATR CALPKXPurge52(SATBOOL bVerify); + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ +extern SATRESULT SATResults; + +/* -------- ------ --------- */ +/* External Global Constants */ +/* -------- ------ --------- */ +extern const SATUINT32_t uiROMMods[]; + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/pkxlib.h b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/pkxlib.h new file mode 100644 index 0000000..fb4c0fc --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/pkxlib.h @@ -0,0 +1,95 @@ +/* ------------------------------------------------------------------- + $Rev: 1434 $ $Date: 2017-10-20 16:46:16 -0400 (Fri, 20 Oct 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for PKX-5200 Library. + ------------------------------------------------------------------- */ + +#ifndef PKXLIB_H +#define PKXLIB_H + +#include "caltypes.h" +#include "calpolicy.h" + +#define PKX_JMP_NONE (0xFFFFu + PKX_OFFSET) + +/* jump table entry points: starting PC value */ +#define PKX_JMP_RECIP_PRECOMPUTE (0x0000 + PKX_OFFSET) +#define PKX_JMP_MOD_EXP (0x0002 + PKX_OFFSET) +#define PKX_JMP_RSA_CRT (0x0004 + PKX_OFFSET) +#define PKX_JMP_EC_PTMUL (0x0006 + PKX_OFFSET) +#define PKX_JMP_EC_DSA_SIGN (0x0008 + PKX_OFFSET) +#define PKX_JMP_EC_DSA_VERIFY (0x000A + PKX_OFFSET) +#define PKX_JMP_DSA_SIGN (0x000C + PKX_OFFSET) +#define PKX_JMP_DSA_VERIFY (0x000E + PKX_OFFSET) +#define PKX_JMP_MOD_MULT (0x0010 + PKX_OFFSET) +#define PKX_JMP_MOD_RED (0x0012 + PKX_OFFSET) +#define PKX_JMP_EC_PTDECOMP (0x0014 + PKX_OFFSET) +#define PKX_JMP_EC_DHC (0x0016 + PKX_OFFSET) +#define PKX_JMP_MOD_MULT_ADD (0x0018 + PKX_OFFSET) +#define PKX_JMP_EC_PTMUL_ADD (0x001A + PKX_OFFSET) +#define PKX_JMP_EC_PTVALIDATE (0x001C + PKX_OFFSET) +#define PKX_JMP_F5200_SHA (0x001E + PKX_OFFSET) +#define PKX_JMP_F5200_AES (0x0020 + PKX_OFFSET) +#define PKX_JMP_F5200_AESK (0x0022 + PKX_OFFSET) +#define PKX_JMP_F5200_GCM (0x0024 + PKX_OFFSET) +#define PKX_JMP_F5200_GHA (0x0026 + PKX_OFFSET) +#define PKX_JMP_F5200_AESKW (0x0028 + PKX_OFFSET) +#define PKX_JMP_F5200_AESKWP (0x002A + PKX_OFFSET) +#define PKX_JMP_RNG_INSTANTIATE (0x002C + PKX_OFFSET) +#define PKX_JMP_RNG_RESEED (0x002E + PKX_OFFSET) +#define PKX_JMP_RNG_GENERATE (0x0030 + PKX_OFFSET) +#define PKX_JMP_RNG_UNINSTANTIATE (0x0032 + PKX_OFFSET) +#define PKX_JMP_RNG_GETENTROPY (0x0034 + PKX_OFFSET) +#define PKX_JMP_F5200_SHA_HMAC (0x0036 + PKX_OFFSET) +#define PKX_JMP_F5200_AES_DMA (0x0038 + PKX_OFFSET) +#define PKX_JMP_RNG_CTRLSTATUS (0x003A + PKX_OFFSET) +#define PKX_JMP_F5200_SHA_DMA (0x003C + PKX_OFFSET) +#define PKX_JMP_SHX_KEYTREE (0x003E + PKX_OFFSET) +#define PKX_JMP_PKX_DSA_DMA (0x0040 + PKX_OFFSET) +#define PKX_JMP_PKX_RSACRT_SIGN (0x0042 + PKX_OFFSET) +#define PKX_JMP_PKX_RSA_SIGN (0x0044 + PKX_OFFSET) +#define PKX_JMP_PKX_RSA_VERIFY (0x0046 + PKX_OFFSET) +#define PKX_JMP_PKX_EC_DSA_DMA (0x0048 + PKX_OFFSET) +#define PKX_JMP_F5200_AES_KEYROLL (0x004A + PKX_OFFSET) +#define PKX_JMP_EXPM (0x004C + PKX_OFFSET) +#define PKX_JMP_RSACRTM (0x004E + PKX_OFFSET) +#define PKX_JMP_EC_PTMULM (0x0050 + PKX_OFFSET) +#define PKX_JMP_DSA_SIGN_M (0x0052 + PKX_OFFSET) +#define PKX_JMP_EC_DSA_SIGN_M (0x0054 + PKX_OFFSET) +#define PKX_JMP_EC_KEYPAIRGEN (0x0056 + PKX_OFFSET) +#define PKX_JMP_RSACRTCM_SIGN (0x0058 + PKX_OFFSET) +#define PKX_JMP_F5200_GCM_NEW (0x005A + PKX_OFFSET) +/* PKX PKRev 2180 */ +/* PKX SHARev 2160 */ +/* PKX AESRev 2135 */ +/* Hex Checksum: 0xd0d79866 */ + +extern const SATUINT32_t uiPKX_Flags; +extern const SATUINT32_t uiPKX_BERWords; +extern const SATUINT32_t uiPKX_LIRWords; +extern const SATUINT32_t uiPKX_Rev; +extern const SATUINT32_t uiPKX_LibSize; +extern const SATUINT32_t uiPKX_LibChksum; +extern const SATUINT32_t uiPKX_Lib[]; +extern SATBOOL bMPF300TS_ES; + +#endif diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/shaf5200.h b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/shaf5200.h new file mode 100644 index 0000000..da598d1 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/shaf5200.h @@ -0,0 +1,101 @@ +/* ------------------------------------------------------------------- + $Rev: 1296 $ $Date: 2017-08-01 13:54:48 -0400 (Tue, 01 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for SHA function hardware implementation for CAL. + ------------------------------------------------------------------- */ + +#ifndef SHAF5200_H +#define SHAF5200_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef SHAF5200_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATR shapkxctx(SATRESCONTEXTPTR const pContext, const void *pBuffer, + SATUINT32_t uiBufLen,void *pHash, const SATBOOL bFinal); + +extern SATR shapkxhmacctx(SATRESCONTEXTPTR const pContext, const void *pBuffer, + SATUINT32_t uiBufLen, void *pHash, const SATUINT8_t uiFlag); + +extern SATR shapkxctxload(SATRESCONTEXTPTR const pContext); + +extern void shapkxctxunload(SATRESCONTEXTPTR const pContext); + +extern SATR shapkxini(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen); + +extern SATR shapkxhmacini(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, + const void *pKey, SATUINT32_t uiKeyLen); + +extern SATR shapkxwrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR shapkxhmacwrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR shapkxread(void *pHash, SATUINT32_t uiRevFlag); + +extern SATR shapkxkeytree(SATBOOL bPathSizeSel, const SATUINT32_t* puiKey, + SATUINT8_t uiOpType, const SATUINT32_t* puiPath, SATUINT32_t* puiKeyOut); + +extern SATR shapkxdma(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, + const void *pExtSrc, const void *pExtDest, SATUINT32_t uiDMAChConfig); + +extern SATR shapkxhmacdma(SATMACTYPE eMACType, const SATUINT32_t *pKey, + SATUINT32_t uiKeyLen, const void *pMsg, SATUINT32_t uiMsgLen, + const void *pMAC, SATUINT32_t uiDMAChConfig); + +extern SATR shapkxhashtypeini(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/sym.h b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/sym.h new file mode 100644 index 0000000..2e07faa --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/sym.h @@ -0,0 +1,129 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for Symmetric Key Cryptography in CAL. + ------------------------------------------------------------------- */ + +#ifndef SYM_H +#define SYM_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef SYM_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALSymTrfRes(SATBOOL bBlock); + +extern SATR CALSymEncrypt(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen); + +extern SATR CALSymDecrypt(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen); + +extern SATR CALSymEncryptDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymDecryptDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymEncryptKR(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF); + +extern SATR CALSymDecryptKR(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF); + +extern SATR CALSymEncryptKRDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymDecryptKRDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymEncAuth(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen); + +extern SATR CALSymDecVerify(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen); + +extern SATR CALSymKw(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR CALSymKwp(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR CALSymEncAuthDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymDecVerifyDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen, SATUINT32_t uiDMAChConfig); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/utils.h b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/utils.h new file mode 100644 index 0000000..91474f0 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/utils.h @@ -0,0 +1,93 @@ +/* ------------------------------------------------------------------- + $Rev: 1300 $ $Date: 2017-08-07 11:36:02 -0400 (Mon, 07 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL utility functions. + ------------------------------------------------------------------- */ + +#ifndef UTILS_H +#define UTILS_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef UTILS_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern void CALMemCopy(void *pDst, const void *pSrc, SATUINT32_t uiNum8); + +extern void CALMemClear( void * pLoc, SATUINT32_t uiNum ); + +extern void CALMemClear32( SATUINT32_t* puiLoc, SATUINT32_t uiLen32 ); + +extern SATBOOL CALMemCmp(const void *pA, const void *pB, SATUINT32_t uiNum); + +extern void CALVol32MemLoad(volatile SATUINT32_t * puiDst, const void * pSrc, + SATUINT32_t uiNum32); + +extern void CALVol32MemRead(void * pDst, volatile SATUINT32_t * puiSrc, + SATUINT32_t uiNum32); + +extern void CALByteReverse(SATUINT32_t* puiArray, SATINT32_t iNumberBytes); + +extern void CALByteReverseWord(SATUINT32_t* puiArray, SATINT32_t iNumberWords); + +extern void CALWordReverse(SATUINT32_t *puiArray, SATINT32_t iNumberWords); + +extern void vAppendNonzero(void *puiArray, SATUINT32_t uiLen, + SATUINT32_t uiBlockSize); + +extern void vAppendZero(void *puiArray, SATUINT32_t uiLen, + SATUINT32_t uiBlockSize); + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/x52cfg_user.h b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/x52cfg_user.h new file mode 100644 index 0000000..c8d8648 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/middleware/cal/x52cfg_user.h @@ -0,0 +1,72 @@ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ +/* X5200 configuration */ +/* $Date: 2015-07-23 14:30:19 -0400 (Thu, 23 Jul 2015) $ $Rev: 2093 $ */ +/* ------------------------------------------------------------------- + Options: + * LIR ROM size : 4096 + * LIR RAM size : 2048 + * BER size : 1024 + * MMR size : 1024 + * TSR size : 1024 + * FPR size : 1024 + * Single error correct, dual error detect (SECDED) memory parity + * DMA enabled + * FPGA multipliers disabled + * AES enabled + - Fast key schedule generation + - GCM/GHASH enabled + - AES countermeasures enabled + * RNG enabled + * External PRNG disabled + * SHA enabled + - Fast SHA enabled + - SHA-1 enabled + - SHA-224 enabled + - SHA-256 enabled + - SHA-384 enabled + - SHA-512 enabled + - SHA-512/224 enabled + - SHA-512/256 enabled + - SHA countermeasures enabled + * P-curves populated in FCR: + - P-192 populated + - P-224 populated + - P-256 populated + - P-384 populated + - P-521 populated + * Data memory scrambling enabled + + ------------------------------------------------------------------- */ + +#ifndef X52CFG_H +#define X52CFG_H + +#define X52_CFG_MODEL 0xf5200 +#define X52_CFG_DATE 0x15072720 +#define X52_CFG_REV 0x0000082e +#define X52_CFG_OPT 0x0fd87ff9 +#define X52_CFG_OPT2 0xc0000000 +#define X52_LIR_LEN 0x1800 +#define X52_LIR_ROM_LEN 0x1000 +#define X52_LIR_RAM_LEN 0x0800 +#define X52_BER_LEN 0x400 +#define X52_MMR_LEN 0x400 +#define X52_TSR_LEN 0x400 +#define X52_FPR_LEN 0x400 + +#endif diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/README.md b/applications/user-crypto/miv-rv32-message-authentication/src/platform/README.md new file mode 100644 index 0000000..f7f6030 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/README.md @@ -0,0 +1,27 @@ +# Mi-V soft processor platform source code + +## Repo organization + +``` + + | + |-- drivers + | |- fpga_ip + | | | CoreGPIO + | | | CoreSysServices_PF + | | | CoreUARTapb + | | + | |- off_chip + | | | . + | | | . + | | + |-- hal + | | + |-- miv_rv32_hal + + +``` + +The drivers published here are compatible with the improved SoftConsole project folder structure being used in the latest [example projects](https://github.com/Mi-V-Soft-RISC-V/miv-rv32-bare-metal-examples). +These drivers can also be used with the legacy folder structure (projects released via Firmware Catalog) by defining the **LEGACY_DIR_STRUCTURE** macro in the SoftConsole project settings. + diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c new file mode 100644 index 0000000..1a0073f --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c @@ -0,0 +1,533 @@ +/******************************************************************************* + * (c) Copyright 2008-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file core_gpio.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreGPIO bare metal driver implementation. + * + */ +#include "coregpio_regs.h" +#include "core_gpio.h" + +/*-------------------------------------------------------------------------*//** + * + */ +#define GPIO_INT_ENABLE_MASK (uint32_t)0x00000008UL +#define OUTPUT_BUFFER_ENABLE_MASK 0x00000004UL + + +#define NB_OF_GPIO 32 + +#define CLEAR_ALL_IRQ32 (uint32_t)0xFFFFFFFF +#define CLEAR_ALL_IRQ16 (uint16_t)0xFFFF +#define CLEAR_ALL_IRQ8 (uint8_t)0xFF + +/*-------------------------------------------------------------------------*//** + * GPIO_init() + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_init +( + gpio_instance_t * this_gpio, + addr_t base_addr, + gpio_apb_width_t bus_width +) +{ + uint8_t i = 0; + addr_t cfg_reg_addr = base_addr; + + this_gpio->base_addr = base_addr; + this_gpio->apb_bus_width = bus_width; + + /* Clear configuration. */ + for( i = 0, cfg_reg_addr = base_addr; i < NB_OF_GPIO; ++i ) + { + HW_set_8bit_reg( cfg_reg_addr, 0 ); + cfg_reg_addr += 4; + } + /* Clear any pending interrupts */ + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, CLEAR_ALL_IRQ32 ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, (uint16_t)CLEAR_ALL_IRQ16 ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, (uint16_t)CLEAR_ALL_IRQ16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, (uint8_t)CLEAR_ALL_IRQ8 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_config + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_config +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint32_t config +) +{ + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + uint32_t cfg_reg_addr = this_gpio->base_addr; + cfg_reg_addr += (port_id * 4); + HW_set_32bit_reg( cfg_reg_addr, config ); + + /* + * Verify that the configuration was correctly written. Failure to read + * back the expected value may indicate that the GPIO port was configured + * as part of the hardware flow and cannot be modified through software. + * It may also indicate that the base address passed as parameter to + * GPIO_init() was incorrect. + */ + HAL_ASSERT( HW_get_32bit_reg( cfg_reg_addr ) == config ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_set_outputs + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_set_outputs +( + gpio_instance_t * this_gpio, + uint32_t value +) +{ + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, GPIO_OUT, value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, GPIO_OUT0, (uint16_t)value ); + HAL_set_16bit_reg( this_gpio->base_addr, GPIO_OUT1, (uint16_t)(value >> 16) ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT0, (uint8_t)value ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT1, (uint8_t)(value >> 8) ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT2, (uint8_t)(value >> 16) ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT3, (uint8_t)(value >> 24) ); + break; + + default: + HAL_ASSERT(0); + break; + } + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( GPIO_get_outputs( this_gpio ) == value ); +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_inputs + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_inputs +( + gpio_instance_t * this_gpio +) +{ + uint32_t gpio_in = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + gpio_in = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_IN ); + break; + + case GPIO_APB_16_BITS_BUS: + gpio_in |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_IN0 ); + gpio_in |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_IN1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + gpio_in |= HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN0 ); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN1 ) << 8); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN2 ) << 16); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return gpio_in; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_outputs + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_outputs +( + gpio_instance_t * this_gpio +) +{ + uint32_t gpio_out = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + gpio_out = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ); + break; + + case GPIO_APB_16_BITS_BUS: + gpio_out |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT0 ); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + gpio_out |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT0 ); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT1 ) << 8); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT2 ) << 16); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return gpio_out; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_set_output + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_set_output +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint8_t value +) +{ + HAL_ASSERT( port_id < NB_OF_GPIO ); + + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + { + uint32_t outputs_state; + + outputs_state = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ); + if ( 0 == value ) + { + outputs_state &= ~(1 << port_id); + } + else + { + outputs_state |= 1 << port_id; + } + HAL_set_32bit_reg( this_gpio->base_addr, GPIO_OUT, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ) == outputs_state ); + } + break; + + case GPIO_APB_16_BITS_BUS: + { + uint16_t outputs_state; + uint32_t gpio_out_reg_addr = this_gpio->base_addr + GPIO_OUT_REG_OFFSET + ((port_id >> 4) * 4); + + outputs_state = HW_get_16bit_reg( gpio_out_reg_addr ); + if ( 0 == value ) + { + outputs_state &= ~(1 << (port_id & 0x0F)); + } + else + { + outputs_state |= 1 << (port_id & 0x0F); + } + HW_set_16bit_reg( gpio_out_reg_addr, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HW_get_16bit_reg( gpio_out_reg_addr ) == outputs_state ); + } + break; + + case GPIO_APB_8_BITS_BUS: + { + uint8_t outputs_state; + uint32_t gpio_out_reg_addr = this_gpio->base_addr + GPIO_OUT_REG_OFFSET + ((port_id >> 3) * 4); + + outputs_state = HW_get_8bit_reg( gpio_out_reg_addr ); + if ( 0 == value ) + { + outputs_state &= ~(1 << (port_id & 0x07)); + } + else + { + outputs_state |= 1 << (port_id & 0x07); + } + HW_set_8bit_reg( gpio_out_reg_addr, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HW_get_8bit_reg( gpio_out_reg_addr ) == outputs_state ); + } + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_drive_inout + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_drive_inout +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + gpio_inout_state_t inout_state +) +{ + uint32_t config; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + switch( inout_state ) + { + case GPIO_DRIVE_HIGH: + /* Set output high */ + GPIO_set_output( this_gpio, port_id, 1 ); + + /* Enable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config |= OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + case GPIO_DRIVE_LOW: + /* Set output low */ + GPIO_set_output( this_gpio, port_id, 0 ); + + /* Enable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config |= OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + case GPIO_HIGH_Z: + /* Disable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config &= ~OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_enable_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_enable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t cfg_value; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + cfg_reg_addr += (port_id * 4); + cfg_value = HW_get_8bit_reg( cfg_reg_addr ); + cfg_value |= GPIO_INT_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, cfg_value ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_disable_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_disable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t cfg_value; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + cfg_reg_addr += (port_id * 4); + cfg_value = HW_get_8bit_reg( cfg_reg_addr ); + cfg_value &= ~GPIO_INT_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, cfg_value ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_clear_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_clear_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t irq_clr_value = ((uint32_t)1) << ((uint32_t)port_id); + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, irq_clr_value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, irq_clr_value >> 16 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, irq_clr_value >> 24 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_irq_sources + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_irq_sources +( + gpio_instance_t * this_gpio +) +{ + uint32_t intr_src = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + intr_src = HAL_get_32bit_reg( this_gpio->base_addr, IRQ ); + break; + + case GPIO_APB_16_BITS_BUS: + intr_src |= HAL_get_16bit_reg( this_gpio->base_addr, IRQ0 ); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + intr_src |= HAL_get_16bit_reg( this_gpio->base_addr, IRQ0 ); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ1 ) << 8); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ2 ) << 16); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return intr_src; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_clear_all_irq_sources + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_clear_all_irq_sources +( + gpio_instance_t * this_gpio, + uint32_t bitmask +) +{ + uint32_t irq_clr_value = bitmask; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, irq_clr_value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, irq_clr_value >> 16 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, irq_clr_value >> 24 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h new file mode 100644 index 0000000..88ba178 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h @@ -0,0 +1,722 @@ +/******************************************************************************* + * (c) Copyright 2008-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file core_gpio.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreGPIO bare metal driver public API. + * + */ + +/*=========================================================================*//** + @mainpage CoreGPIO Bare Metal Driver. + + @section intro_sec Introduction + The CoreGPIO hardware IP includes up to 32 general-purpose input/output GPIOs. + This driver provides a set of functions for controlling the GPIOs as part of a + bare-metal system where no operating system is available. These drivers + can be adapted for use as part of an operating system, but the implementation + of the adaptation layer between this driver and the operating system's driver + model is outside the scope of this driver. + + @section driver_configuration Driver Configuration + The individual IOs of CoreGPIO can be configured either in the hardware flow + or as part of the software application through calls to the GPIO_config() + function. GPIOs configured as part of the hardware are fixed and cannot be + modified using a call to the GPI_config() function. + + @section theory_op Theory of Operation + The CoreGPIO driver uses the Actel Hardware Abstraction Layer (HAL) to access + hardware registers. You must ensure that the Actel HAL is included as part of + your software project. The Actel HAL is available through the Actel Firmware + Catalog. + + The CoreGPIO driver functions are logically grouped into the following groups: + - Initialization + - Configuration + - Reading and writing GPIO state + - Interrupt control + + The CoreGPIO driver is initialized through a call to the GPIO_init() function. + The GPIO_init() function must be called before any other GPIO driver functions + can be called. + + Each GPIO port is individually configured through a call to the + GPIO_config() function. Configuration includes deciding if a GPIO port is + going to be used as input, output, or both. GPIO ports configured as inputs + are further configured to generate interrupts based on the state of input. + Interrupts is either level- or edge-sensitive. + Note that a CoreGPIO hardware instance is generated as part of the hardware + flow with a fixed configuration for some or all of its IOs. + Attempting to modify the configuration of such a hardware-configured IO using + the GPIO_config() function has no effect. + + The state of the GPIO ports can be read and written using the following + functions: + - GPIO_get_inputs() + - GPIO_get_outputs() + - GPIO_set_outputs() + - GPIO_drive_inout() + + Interrupts generated by GPIO ports configured as inputs are controlled using + the following functions: + - GPIO_enable_irq() + - GPIO_disable_irq() + - GPIO_clear_irq() + - GPIO_get_irq_sources() + - GPIO_clear_all_irq_sources() + + *//*=========================================================================*/ +#ifndef CORE_GPIO_H_ +#define CORE_GPIO_H_ + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + The gpio_id_t enumeration is used to identify GPIOs as part of the + parameter to functions: + - GPIO_config(), + - GPIO_drive_inout(), + - GPIO_enable_int(), + - GPIO_disable_int(), + - GPIO_clear_int() + */ +typedef enum __gpio_id_t +{ + GPIO_0 = 0, + GPIO_1 = 1, + GPIO_2 = 2, + GPIO_3 = 3, + GPIO_4 = 4, + GPIO_5 = 5, + GPIO_6 = 6, + GPIO_7 = 7, + GPIO_8 = 8, + GPIO_9 = 9, + GPIO_10 = 10, + GPIO_11 = 11, + GPIO_12 = 12, + GPIO_13 = 13, + GPIO_14 = 14, + GPIO_15 = 15, + GPIO_16 = 16, + GPIO_17 = 17, + GPIO_18 = 18, + GPIO_19 = 19, + GPIO_20 = 20, + GPIO_21 = 21, + GPIO_22 = 22, + GPIO_23 = 23, + GPIO_24 = 24, + GPIO_25 = 25, + GPIO_26 = 26, + GPIO_27 = 27, + GPIO_28 = 28, + GPIO_29 = 29, + GPIO_30 = 30, + GPIO_31 = 31 +} gpio_id_t; + +/*-------------------------------------------------------------------------*//** + Possible width of the APB bus + */ +typedef enum __gpio_apb_width_t +{ + GPIO_APB_8_BITS_BUS = 0, + GPIO_APB_16_BITS_BUS = 1, + GPIO_APB_32_BITS_BUS = 2, + GPIO_APB_UNKNOWN_BUS_WIDTH = 3 +} gpio_apb_width_t; + +/*-------------------------------------------------------------------------*//** + Structure instance holding all data regarding the CoreGPIO + */ +typedef struct __gpio_instance_t +{ + addr_t base_addr; + gpio_apb_width_t apb_bus_width; +} gpio_instance_t; + +/*-------------------------------------------------------------------------*//** + GPIO ports definitions used to identify GPIOs as part of the parameter to + function GPIO_set_outputs(). + These definitions are also be used to identity GPIO through logical operations + on the return value of function GPIO_get_inputs(). + # GPIO_0_MASK + # GPIO_1_MASK + # GPIO_2_MASK + # GPIO_3_MASK + # GPIO_4_MASK + # GPIO_5_MASK + # GPIO_6_MASK + # GPIO_7_MASK + # GPIO_8_MASK + # GPIO_9_MASK + # GPIO_10_MASK + # GPIO_11_MASK + # GPIO_12_MASK + # GPIO_13_MASK + # GPIO_14_MASK + # GPIO_15_MASK + # GPIO_16_MASK + # GPIO_17_MASK + # GPIO_18_MASK + # GPIO_19_MASK + # GPIO_20_MASK + # GPIO_21_MASK + # GPIO_22_MASK + # GPIO_23_MASK + # GPIO_24_MASK + # GPIO_25_MASK + # GPIO_26_MASK + # GPIO_27_MASK + # GPIO_28_MASK + # GPIO_29_MASK + # GPIO_30_MASK + # GPIO_31_MASK + */ +#define GPIO_0_MASK 0x00000001UL +#define GPIO_1_MASK 0x00000002UL +#define GPIO_2_MASK 0x00000004UL +#define GPIO_3_MASK 0x00000008UL +#define GPIO_4_MASK 0x00000010UL +#define GPIO_5_MASK 0x00000020UL +#define GPIO_6_MASK 0x00000040UL +#define GPIO_7_MASK 0x00000080UL +#define GPIO_8_MASK 0x00000100UL +#define GPIO_9_MASK 0x00000200UL +#define GPIO_10_MASK 0x00000400UL +#define GPIO_11_MASK 0x00000800UL +#define GPIO_12_MASK 0x00001000UL +#define GPIO_13_MASK 0x00002000UL +#define GPIO_14_MASK 0x00004000UL +#define GPIO_15_MASK 0x00008000UL +#define GPIO_16_MASK 0x00010000UL +#define GPIO_17_MASK 0x00020000UL +#define GPIO_18_MASK 0x00040000UL +#define GPIO_19_MASK 0x00080000UL +#define GPIO_20_MASK 0x00100000UL +#define GPIO_21_MASK 0x00200000UL +#define GPIO_22_MASK 0x00400000UL +#define GPIO_23_MASK 0x00800000UL +#define GPIO_24_MASK 0x01000000UL +#define GPIO_25_MASK 0x02000000UL +#define GPIO_26_MASK 0x04000000UL +#define GPIO_27_MASK 0x08000000UL +#define GPIO_28_MASK 0x10000000UL +#define GPIO_29_MASK 0x20000000UL +#define GPIO_30_MASK 0x40000000UL +#define GPIO_31_MASK 0x80000000UL + +/*-------------------------------------------------------------------------*//** + * GPIO modes + * # GPIO_INPUT_MODE + * # GPIO_OUTPUT_MODE + * # GPIO_INOUT_MODE + */ +#define GPIO_INPUT_MODE 0x0000000002UL +#define GPIO_OUTPUT_MODE 0x0000000005UL +#define GPIO_INOUT_MODE 0x0000000003UL + +/*-------------------------------------------------------------------------*//** + * Possible GPIO inputs interrupt configurations. + * # GPIO_IRQ_LEVEL_HIGH + * # GPIO_IRQ_LEVEL_LOW + * # GPIO_IRQ_EDGE_POSITIVE + * # GPIO_IRQ_EDGE_NEGATIVE + * # GPIO_IRQ_EDGE_BOTH + */ +#define GPIO_IRQ_LEVEL_HIGH 0x0000000000UL +#define GPIO_IRQ_LEVEL_LOW 0x0000000020UL +#define GPIO_IRQ_EDGE_POSITIVE 0x0000000040UL +#define GPIO_IRQ_EDGE_NEGATIVE 0x0000000060UL +#define GPIO_IRQ_EDGE_BOTH 0x0000000080UL + +/*-------------------------------------------------------------------------*//** + * Possible states for GPIO configured as INOUT + */ +typedef enum gpio_inout_state +{ + GPIO_DRIVE_LOW = 0, + GPIO_DRIVE_HIGH, + GPIO_HIGH_Z +} gpio_inout_state_t; + +/*-------------------------------------------------------------------------*//** + The GPIO_init() function initializes a CoreGPIO hardware instance and the data + structure associated with the CoreGPIO hardware instance. + Note that a CoreGPIO hardware instance is generated with a fixed configuration + for some or all of its IOs as part of the hardware flow. + Attempting to modify the configuration of such a hardware-configured IO using + the GPIO_config() function has no effect. + + @param this_gpio + Pointer to the gpio_instance_t data structure instance holding all data + regarding the CoreGPIO hardware instance being initialized. A pointer to the + same data structure is used in subsequent calls to the CoreGPIO driver + functions in order to identify the CoreGPIO instance that must perform the + operation implemented by the called driver function. + + @param base_addr + The base_addr parameter is the base address in the memory map of the + processor for the registers of the GPIO instance being initialized. + + @param bus_width + The bus_width parameter informs the driver of the APB bus width selected + during the hardware flow configuration of the CoreGPIO hardware instance. It + indicates to the driver whether the CoreGPIO hardware registers are visible + as 8, 16, or 32-bits registers. Allowed values are: + - GPIO_APB_8_BITS_BUS + - GPIO_APB_16_BITS_BUS + - GPIO_APB_32_BITS_BUS + + @return + none. + + @example + @code + #define COREGPIO_BASE_ADDR 0xC2000000 + + gpio_instance_t g_gpio; + + void system_init( void ) + { + GPIO_init( &g_gpio, COREGPIO_BASE_ADDR, GPIO_APB_32_BITS_BUS ); + } + @endcode + */ +void GPIO_init +( + gpio_instance_t * this_gpio, + addr_t base_addr, + gpio_apb_width_t bus_width +); + +/*-------------------------------------------------------------------------*//** + The GPIO_config() function is used to configure an individual GPIO port. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO port to be configured. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @param config + The config parameter specifies the configuration to be applied to the GPIO + port identified by the first parameter. It is a logical OR of GPIO mode and + interrupt mode. The interrupt mode is only relevant if the GPIO is + configured as an input. + - Possible modes are: + - GPIO_INPUT_MODE, + - GPIO_OUTPUT_MODE, + - GPIO_INOUT_MODE. + - Possible interrupt modes are: + - GPIO_IRQ_LEVEL_HIGH, + - GPIO_IRQ_LEVEL_LOW, + - GPIO_IRQ_EDGE_POSITIVE, + - GPIO_IRQ_EDGE_NEGATIVE, + - GPIO_IRQ_EDGE_BOTH + + @return + none. + + @example + For example, the following call configures GPIO 4 as an input that generates + interrupts on a low-to-high transition of the input: + @code + GPIO_config( &g_gpio, GPIO_4, GPIO_INPUT_MODE | GPIO_IRQ_EDGE_POSITIVE ); + @endcode + */ +void GPIO_config +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint32_t config +); + +/*-------------------------------------------------------------------------*//** + The GPIO_set_outputs() function is used to set the state of the GPIO ports + configured as outputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param value + The value parameter specifies the state of the GPIO ports configured as + outputs. It is a bit mask of the form (GPIO_n_MASK | GPIO_m_MASK), where n + and m are numbers identifying GPIOs. + For example, (GPIO_0_MASK | GPIO_1_MASK | GPIO_2_MASK ) specifies that the + first, second, and third GPIO must be set high and all other outputs set + low. + + @return + none. + + @example + Set GPIO 0 and 8 outputs high and all other GPIO outputs low. + @code + GPIO_set_outputs( &g_gpio, GPIO_0_MASK | GPIO_8_MASK ); + @endcode + + @example + Set GPIO 2 and 4 outputs low without affecting the other GPIO outputs. + @code + uint32_t gpio_outputs; + gpio_outputs = GPIO_get_outputs( &g_gpio ); + gpio_outputs &= ~( GPIO_2_MASK | GPIO_4_MASK ); + GPIO_set_outputs( &g_gpio, gpio_outputs ); + @endcode + + @see GPIO_get_outputs() + */ +void GPIO_set_outputs +( + gpio_instance_t * this_gpio, + uint32_t value +); + +/*-------------------------------------------------------------------------*//** + The GPIO_set_output() function is used to set the state of a single GPIO port + configured as an output. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter specifies the GPIO port that has its output set by a + call to this function. + + @param value + The value parameter specifies the desired state for the GPIO output. A value + of 0 sets the output low, and a value of 1 sets the port high. + + @return + none. + */ +void GPIO_set_output +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint8_t value +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_inputs() function is used to read the state of all GPIOs + configured as inputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @return + This function returns a 32-bit unsigned integer, where each bit represents + the state of an input. The least significant bit represents the state of + GPIO 0, and the most significant bit represents the state of GPIO 31. + */ +uint32_t GPIO_get_inputs +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_outputs() function is used to read the current state of all + GPIO outputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @return + This function returns a 32-bit unsigned integer where each bit represents + the state of an output. The least significant bit represents the state + of GPIO 0, and the most significant bit represents the state of GPIO 31. + */ +uint32_t GPIO_get_outputs +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_drive_inout() function is used to set the output state of a + GPIO configured as INOUT. An INOUT GPIO is in one of three states: + - high + - low + - high impedance + + An INOUT output is typically be used where several devices drive the state of + a signal. The high and low states are equivalent to the high and low states of + a GPIO configured as an output. The high impedance state is used to prevent + the GPIO from driving the state of the output and therefore allow reading the + state of the GPIO as an input. + Note that the GPIO port you wish to use as INOUT through this function + must be configurable through software. Therefore, the GPIO ports used as INOUT + must not have a fixed configuration selected as part of the hardware flow. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO for which this function will + change the output state. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @param inout_state + The inout_state parameter specifies the state of the I/O identified by the + first parameter. Possible states are: + - GPIO_DRIVE_HIGH, + - GPIO_DRIVE_LOW, + - GPIO_HIGH_Z (high impedance) + + @return + none. + + @example + The call to GPIO_drive_inout() below will set the GPIO 7 output to + high impedance state. + @code + GPIO_drive_inout( &g_gpio, GPIO_7, GPIO_HIGH_Z ); + @endcode + */ +void GPIO_drive_inout +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + gpio_inout_state_t inout_state +); + +/*-------------------------------------------------------------------------*//** + The GPIO_enable_irq() function is used to enable an interrupt to be + generated based on the state of the input identified as a parameter. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO input that the call to + GPIO_enable_irq() enables to generate interrupts. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + @example + The call to GPIO_enable_irq() below allows GPIO 8 to generate interrupts. + + @code + GPIO_enable_irq( &g_gpio, GPIO_8 ); + @endcode + */ +void GPIO_enable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_disable_irq() function is used to disable interrupts from being + generated based on the state of the input specified as a parameter. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO input that the call to + GPIO_disable_irq() disables from generating interrupts. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + @example + The call to GPIO_disable_irq() below prevents GPIO 8 from generating + interrupts. + @code + GPIO_disable_irq( &g_gpio, GPIO_8 ); + @endcode + */ +void GPIO_disable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_clear_irq() function is used to clear the interrupt generated by + the GPIO specified as a parameter. The GPIO_clear_irq() function must be + called as part of a GPIO interrupt service routine (ISR) in order to prevent + the same interrupt event from re-triggering a call to the GPIO ISR. + Note that interrupts may also need to be cleared in the processor's + interrupt controller. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO input for which to clear the + interrupt. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + @example + The example below demonstrates the use of the GPIO_clear_irq() function as + part of the GPIO-9 interrupt service routine. + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + GPIO_clear_irq( &g_gpio, GPIO_9 ); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +void GPIO_clear_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_irq_sources() function is used to identify the source of the + interrupt. i.e. to That is the GPIO input line, whose state change triggered + the interrupt. The GPIO_get_irq_sources() function must be called as part of + a GPIO interrupt service routine (ISR) in order to determine the interrupt + source. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @return + This function returns a 32-bit unsigned integer, where each bit represents + the pin number of a GPIO. + + @example + The example below demonstrates the use of the GPIO_get_irq_sources() + function as part of the GPIO-9 interrupt service routine. + + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + GPIO_clear_all_irq_sources(g_p_mygpio, GPIO_get_irq_sources(g_p_mygpio)); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +uint32_t GPIO_get_irq_sources +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_clear_all_irq_sources() function is used to clear all the active + interrupts generated by the GPIO specified as a parameter. The + GPIO_clear_all_irq_sources() function must be called as part of a GPIO + interrupt service routine (ISR) in order to prevent the same interrupt event + from re-triggering a call to the GPIO ISR. + Note that interrupts may also need to be cleared in the processor's + interrupt controller. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param bitmask + This bitmask parameter is a 32-bit unsigned integer where each bit + represents the GPIO pin used to clear the interrupt bit register of the + corresponding GPIO bit. The least significant bit represents the status of + GPIO 0, and the most significant bit represents the status of GPIO 31. + + @return + none. + + @example + The example below demonstrates the use of the GPIO_clear_all_irq_sources() + function as part of the GPIO-9 interrupt service routine. + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + do_interrupt_processing(); + + GPIO_clear_all_irq_sources(g_p_mygpio, GPIO_get_irq_sources(g_p_mygpio)); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +void GPIO_clear_all_irq_sources +( + gpio_instance_t * this_gpio, + uint32_t bitmask +); + +#ifdef __cplusplus +} +#endif + +#endif /* CORE_GPIO_H_ */ diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h new file mode 100644 index 0000000..41f5b7c --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h @@ -0,0 +1,45 @@ +/******************************************************************************* + * (c) Copyright 2008-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file coregpio_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreGPIO register definitions + * + */ + +#ifndef __CORE_GPIO_REGISTERS_H +#define __CORE_GPIO_REGISTERS_H 1 + +/*------------------------------------------------------------------------------ + * + */ +#define IRQ_REG_OFFSET 0x80 + +#define IRQ0_REG_OFFSET 0x80 +#define IRQ1_REG_OFFSET 0x84 +#define IRQ2_REG_OFFSET 0x88 +#define IRQ3_REG_OFFSET 0x8C + +/*------------------------------------------------------------------------------ + * + */ +#define GPIO_IN_REG_OFFSET 0x90 + +#define GPIO_IN0_REG_OFFSET 0x90 +#define GPIO_IN1_REG_OFFSET 0x94 +#define GPIO_IN2_REG_OFFSET 0x98 +#define GPIO_IN3_REG_OFFSET 0x9C + +/*------------------------------------------------------------------------------ + * + */ +#define GPIO_OUT_REG_OFFSET 0xA0 + +#define GPIO_OUT0_REG_OFFSET 0xA0 +#define GPIO_OUT1_REG_OFFSET 0xA4 +#define GPIO_OUT2_REG_OFFSET 0xA8 +#define GPIO_OUT3_REG_OFFSET 0xAC + +#endif /* __CORE_GPIO_REGISTERS_H */ diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c new file mode 100644 index 0000000..1fd3dd6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c @@ -0,0 +1,1495 @@ +/******************************************************************************* + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * CoreI2C software driver implementation. + * + */ + +#include "core_smbus_regs.h" +#include "core_i2c.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * I2C transaction direction. + */ +#define WRITE_DIR 0u +#define READ_DIR 1u + +/* -- TRANSACTIONS TYPES -- */ +#define NO_TRANSACTION 0u +#define MASTER_WRITE_TRANSACTION 1u +#define MASTER_READ_TRANSACTION 2u +#define MASTER_RANDOM_READ_TRANSACTION 3u +#define WRITE_SLAVE_TRANSACTION 4u +#define READ_SLAVE_TRANSACTION 5u + +/* -- SMBUS H/W STATES -- */ +/* -- MASTER STATES -- */ +#define ST_BUS_ERROR 0x00u /* Bus error during MST or selected slave modes */ +#define ST_I2C_IDLE 0xF8u /* No activity and no interrupt either... */ +#define ST_START 0x08u /* start condition sent */ +#define ST_RESTART 0x10u /* repeated start */ +#define ST_SLAW_ACK 0x18u /* SLA+W sent, ack received */ +#define ST_SLAW_NACK 0x20u /* SLA+W sent, nack received */ +#define ST_TX_DATA_ACK 0x28u /* Data sent, ACK'ed */ +#define ST_TX_DATA_NACK 0x30u /* Data sent, NACK'ed */ +#define ST_LOST_ARB 0x38u /* Master lost arbitration */ +#define ST_SLAR_ACK 0x40u /* SLA+R sent, ACK'ed */ +#define ST_SLAR_NACK 0x48u /* SLA+R sent, NACK'ed */ +#define ST_RX_DATA_ACK 0x50u /* Data received, ACK sent */ +#define ST_RX_DATA_NACK 0x58u /* Data received, NACK sent */ +#define ST_RESET_ACTIVATED 0xD0u /* Master reset is activated */ +#define ST_STOP_TRANSMIT 0xE0u /* Stop has been transmitted */ + +/* -- SLAVE STATES -- */ +#define ST_SLAVE_SLAW 0x60u /* SLA+W received */ +#define ST_SLAVE_SLAR_ACK 0xA8u /* SLA+R received, ACK returned */ +#define ST_SLV_LA 0x68u /* Slave lost arbitration */ +#define ST_GCA 0x70u /* GCA received */ +#define ST_GCA_LA 0x78u /* GCA lost arbitration */ +#define ST_RDATA 0x80u /* Data received */ +#define ST_SLA_NACK 0x88u /* Slave addressed, NACK returned */ +#define ST_GCA_ACK 0x90u /* Previously addresses with GCA, data ACKed */ +#define ST_GCA_NACK 0x98u /* GCA addressed, NACK returned */ +#define ST_RSTOP 0xA0u /* Stop received */ +#define ST_SLARW_LA 0xB0u /* Arbitration lost */ +#define ST_RACK 0xB8u /* Byte sent, ACK received */ +#define ST_SLAVE_RNACK 0xC0u /* Byte sent, NACK received */ +#define ST_FINAL 0xC8u /* Final byte sent, ACK received */ +#define ST_SLV_RST 0xD8u /* Slave reset state */ + + +/* I2C Channel base offset */ +#define CHANNEL_BASE_SHIFT 5u +#define CHANNEL_MASK 0x1E0u + +/* + * Maximum address offset length in slave write-read transactions. + * A maximum of two bytes will be interpreted as address offset within the slave + * tx buffer. + */ +#define MAX_OFFSET_LENGTH 2u + +/*------------------------------------------------------------------------------ + * I2C interrupts control functions implemented "i2c_interrupt.c". + * the implementation of these functions depend on the underlying hardware + * design and how the CoreI2C interrupt line is connected to the system's + * interrupt controller. + */ +void I2C_enable_irq( i2c_instance_t * this_i2c ); +void I2C_disable_irq( i2c_instance_t * this_i2c ); +static void enable_slave_if_required(i2c_instance_t * this_i2c); + +/*------------------------------------------------------------------------------ + * I2C_init() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_init +( + i2c_instance_t * this_i2c, + addr_t base_address, + uint8_t ser_address, + i2c_clock_divider_t ser_clock_speed +) +{ + psr_t saved_psr; + uint_fast16_t clock_speed = (uint_fast16_t)ser_clock_speed; + + /* + * We need to disable ints while doing this as there is no guarantee we + * have not been called already and the ISR is active. + */ + saved_psr = HAL_disable_interrupts(); + + /* + * Initialize all items of the this_i2c data structure to zero. This + * initializes all state variables to their init value. It relies on + * the fact that NO_TRANSACTION, I2C_SUCCESS and I2C_RELEASE_BUS all + * have an actual value of zero. + */ + memset(this_i2c, 0, sizeof(i2c_instance_t)); + + /* + * Set base address of I2C hardware used by this instance. + */ + this_i2c->base_address = base_address; + + /* + * Update Serial address of the device + */ + this_i2c->ser_address = ((uint_fast8_t)ser_address << 1u); + + /* + * Configure hardware. + */ + HAL_set_8bit_reg_field(this_i2c->base_address, ENS1, 0x00); /* Reset I2C hardware. */ + HAL_set_8bit_reg_field(this_i2c->base_address, ENS1, 0x01); /* set enable bit */ + HAL_set_8bit_reg_field(this_i2c->base_address, CR2, ( (clock_speed >> 2) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c->base_address, CR1, ( (clock_speed >> 1) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c->base_address, CR0, ( clock_speed & 0x01) ); + + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS, this_i2c->ser_address); + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, this_i2c->ser_address); + + /* + * Finally safe to enable interrupts. + */ + HAL_restore_interrupts( saved_psr ); +} +/*------------------------------------------------------------------------------ + * I2C_channel_init() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_channel_init +( + i2c_instance_t * this_i2c_channel, + i2c_instance_t * this_i2c, + i2c_channel_number_t channel_number, + i2c_clock_divider_t ser_clock_speed +) +{ + psr_t saved_psr; + uint_fast16_t clock_speed = (uint_fast16_t)ser_clock_speed; + + HAL_ASSERT(channel_number < I2C_MAX_CHANNELS); + HAL_ASSERT(I2C_CHANNEL_0 != channel_number); + + /* + * Cannot allow channel 0 in this function as we will trash the hardware + * base address and slave address. + */ + if ((channel_number < I2C_MAX_CHANNELS) && + (I2C_CHANNEL_0 != channel_number)) + { + /* + * We need to disable ints while doing this as the hardware should already + * be active at this stage. + */ + saved_psr = HAL_disable_interrupts(); + + /* + * Initialize channel data. + */ + memset(this_i2c_channel, 0, sizeof(i2c_instance_t)); + + this_i2c_channel->base_address = + ((this_i2c->base_address) & ~((addr_t)CHANNEL_MASK)) + | (((addr_t)channel_number) << CHANNEL_BASE_SHIFT); + + this_i2c_channel->ser_address = this_i2c->ser_address; + + HAL_set_8bit_reg_field(this_i2c_channel->base_address, ENS1, 0x00); /* Reset I2C channel hardware. */ + HAL_set_8bit_reg_field(this_i2c_channel->base_address, ENS1, 0x01); /* set enable bit */ + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR2, ( (clock_speed >> 2) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR1, ( (clock_speed >> 1) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR0, ( clock_speed & 0x01) ); + /* + * Finally safe to enable interrupts. + */ + HAL_restore_interrupts( saved_psr ); + } +} + +/*------------------------------------------------------------------------------ + * I2C_write() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_write +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * write_buffer, + uint16_t write_size, + uint8_t options +) +{ + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + saved_psr = HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_WRITE_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_WRITE_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + this_i2c->dir = WRITE_DIR; + this_i2c->master_tx_buffer = write_buffer; + this_i2c->master_tx_size = write_size; + this_i2c->master_tx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_read() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +) +{ + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + saved_psr = HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_READ_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_READ_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + + this_i2c->dir = READ_DIR; + + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_write_read() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_write_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * addr_offset, + uint16_t offset_size, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +) +{ + HAL_ASSERT(offset_size > 0u); + HAL_ASSERT(addr_offset != (uint8_t *)0); + HAL_ASSERT(read_size > 0u); + HAL_ASSERT(read_buffer != (uint8_t *)0); + + this_i2c->master_status = I2C_FAILED; + + if((read_size > 0u) && (offset_size > 0u)) + { + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + saved_psr = HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_RANDOM_READ_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_RANDOM_READ_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + + this_i2c->dir = WRITE_DIR; + + this_i2c->master_tx_buffer = addr_offset; + this_i2c->master_tx_size = offset_size; + this_i2c->master_tx_idx = 0u; + + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + + HAL_restore_interrupts( saved_psr ); + } +} + +/*------------------------------------------------------------------------------ + * I2C_get_status() + * See "core_i2c.h" for details of how to use this function. + */ +i2c_status_t I2C_get_status +( + i2c_instance_t * this_i2c +) +{ + i2c_status_t i2c_status ; + + i2c_status = this_i2c->master_status ; + + return i2c_status; +} + +/*------------------------------------------------------------------------------ + * I2C_wait_complete() + * See "core_i2c.h" for details of how to use this function. + */ +i2c_status_t I2C_wait_complete +( + i2c_instance_t * this_i2c, + uint32_t timeout_ms +) +{ + i2c_status_t i2c_status; + psr_t saved_psr; + /* + * Because we have no idea of what CPU we are supposed to be running on + * we need to guard this write to the timeout value to avoid ISR/user code + * interaction issues. Checking the status below should be fine as only a + * single byte should change in that. + */ + saved_psr = HAL_disable_interrupts(); + this_i2c->master_timeout_ms = timeout_ms; + HAL_restore_interrupts( saved_psr ); + + /* Run the loop until state returns I2C_FAILED or I2C_SUCESS*/ + do { + i2c_status = this_i2c->master_status; + } while(I2C_IN_PROGRESS == i2c_status); + return i2c_status; +} + +/*------------------------------------------------------------------------------ + * I2C_system_tick() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_system_tick +( + i2c_instance_t * this_i2c, + uint32_t ms_since_last_tick +) +{ + if(this_i2c->master_timeout_ms != I2C_NO_TIMEOUT) + { + if(this_i2c->master_timeout_ms > ms_since_last_tick) + { + this_i2c->master_timeout_ms -= ms_since_last_tick; + } + else + { + psr_t saved_psr; + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + /* + * Mark current transaction as having timed out. + */ + this_i2c->master_status = I2C_TIMED_OUT; + this_i2c->transaction = NO_TRANSACTION; + this_i2c->is_transaction_pending = 0; + + HAL_restore_interrupts( saved_psr ); + + /* + * Make sure we do not incorrectly signal a timeout for subsequent + * transactions. + */ + this_i2c->master_timeout_ms = I2C_NO_TIMEOUT; + } + } +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_tx_buffer() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_tx_buffer +( + i2c_instance_t * this_i2c, + const uint8_t * tx_buffer, + uint16_t tx_size +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + this_i2c->slave_tx_buffer = tx_buffer; + this_i2c->slave_tx_size = tx_size; + this_i2c->slave_tx_idx = 0u; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_rx_buffer() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_rx_buffer +( + i2c_instance_t * this_i2c, + uint8_t * rx_buffer, + uint16_t rx_size +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + this_i2c->slave_rx_buffer = rx_buffer; + this_i2c->slave_rx_size = rx_size; + this_i2c->slave_rx_idx = 0u; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_mem_offset_length() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_mem_offset_length +( + i2c_instance_t * this_i2c, + uint8_t offset_length +) +{ + HAL_ASSERT(offset_length <= MAX_OFFSET_LENGTH); + + /* + * Single byte update, should be interrupt safe + */ + if(offset_length > MAX_OFFSET_LENGTH) + { + this_i2c->slave_mem_offset_length = MAX_OFFSET_LENGTH; + } + else + { + this_i2c->slave_mem_offset_length = offset_length; + } +} + +/*------------------------------------------------------------------------------ + * I2C_register_write_handler() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_register_write_handler +( + i2c_instance_t * this_i2c, + i2c_slave_wr_handler_t handler +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + this_i2c->slave_write_handler = handler; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_enable_slave() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_enable_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register and slave mode flag without the I2C ISR interrupting + * us. + */ + saved_psr = HAL_disable_interrupts(); + + /* Set the Assert Acknowledge bit. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + /* Enable slave mode */ + this_i2c->is_slave_enabled = 1u; + + HAL_restore_interrupts( saved_psr ); + + /* Enable I2C IRQ*/ + I2C_enable_irq( this_i2c ); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_slave() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_disable_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + /* Reset the assert acknowledge bit. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + + /* Disable slave mode with IRQ blocked to make whole change atomic */ + this_i2c->is_slave_enabled = 0u; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * + */ +static void enable_slave_if_required +( + i2c_instance_t * this_i2c +) +{ + /* + * This function is only called from within the ISR and so does not need + * guarding on the register access. + */ + if( 0 != this_i2c->is_slave_enabled ) + { + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x01u ); + } +} +/*------------------------------------------------------------------------------ + * I2C_set_slave_second_addr() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_slave_second_addr +( + i2c_instance_t * this_i2c, + uint8_t second_slave_addr +) +{ + uint8_t second_slave_address; + + /* + This function does not support CoreI2C hardware configured with a fixed + second slave address. The current implementation of the ADDR1[0] register + bit makes it difficult for the driver to support both programmable and + fixed second slave address, so we choose to support programmable only. + With the programmable configuration, ADDR1[0] and ADDR0[0] both control + enable/disable of GCA recognition, as an effective OR of the 2 bit fields. + Therefore we set ADDR1[0] to 0 here, so that only ADDR0[0] controls GCA. + */ + second_slave_address = (uint8_t)((second_slave_addr << 1u) & (~SLAVE1_EN_MASK)); + + /* + * Single byte register write, should be interrupt safe + */ + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, second_slave_address); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_slave_second_addr() + * See "i2c.h" for details of how to use this function. + */ +void I2C_disable_slave_second_addr +( + i2c_instance_t * this_i2c +) +{ + /* + We are disabling the second slave address by setting the value of the 2nd + slave address to the primary slave address. The reason for using this method + of disabling 2nd slave address is that ADDRESS1[0] has different meaning + depending on hardware configuration. Its use would likely interfere with + the intended GCA setting. + */ + /* + * Single byte register write, should be interrupt safe + */ + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, this_i2c->ser_address); +} + +/*------------------------------------------------------------------------------ + * i2C_set_gca() + * See "i2c.h" for details of how to use this function. + */ + +void I2C_set_gca +( + i2c_instance_t * this_i2c +) +{ + /* + * This read modify write access should be interrupt safe as the address + * register is not written to in the ISR. + */ + /* accept GC addressing. */ + HAL_set_8bit_reg_field(this_i2c->base_address, GC, 0x01u); +} + +/*------------------------------------------------------------------------------ + * I2C_clear_gca() + * See "i2c.h" for details of how to use this function. + */ +void I2C_clear_gca +( + i2c_instance_t * this_i2c +) +{ + /* + * This read modify write access should be interrupt safe as the address + * register is not written to in the ISR. + */ + /* Clear GC addressing. */ + HAL_set_8bit_reg_field(this_i2c->base_address, GC, 0x00u); +} + +/*------------------------------------------------------------------------------ + * I2C_isr() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_isr +( + i2c_instance_t * this_i2c +) +{ + volatile uint8_t status; + uint8_t data; + uint8_t hold_bus; + uint8_t clear_irq = 1u; + + status = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + + switch( status ) + { + /************** MASTER TRANSMITTER / RECEIVER *******************/ + + case ST_START: /* start has been xmt'd */ + case ST_RESTART: /* repeated start has been xmt'd */ + HAL_set_8bit_reg_field( this_i2c->base_address, STA, 0x00u); + HAL_set_8bit_reg( this_i2c->base_address, DATA, this_i2c->target_addr); /* write call address */ + HAL_set_8bit_reg_field( this_i2c->base_address, DIR, this_i2c->dir); /* set direction bit */ + if(this_i2c->dir == WRITE_DIR) + { + this_i2c->master_tx_idx = 0u; + } + else + { + this_i2c->master_rx_idx = 0u; + } + + /* + * Clear the pending transaction. This condition will be true if the slave + * has acquired the bus to carry out pending master transaction which + * it had received during its slave transmission or reception mode. + */ + if(this_i2c->is_transaction_pending) + { + this_i2c->is_transaction_pending = 0u; + } + + /* + * Make sure to update proper transaction after master START + * or RESTART + */ + if(this_i2c->transaction != this_i2c->pending_transaction) + { + this_i2c->transaction = this_i2c->pending_transaction; + } + break; + + case ST_LOST_ARB: + /* Set start bit. Let's keep trying! Don't give up! */ + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + break; + + case ST_STOP_TRANSMIT: + /* Stop has been transmitted. Do nothing */ + break; + + /******************* MASTER TRANSMITTER *************************/ + case ST_SLAW_NACK: + /* SLA+W has been transmitted; not ACK has been received - let's stop. */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_FAILED; + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + case ST_SLAW_ACK: + case ST_TX_DATA_ACK: + /* data byte has been xmt'd with ACK, time to send stop bit or repeated start. */ + if (this_i2c->master_tx_idx < this_i2c->master_tx_size) + { + HAL_set_8bit_reg(this_i2c->base_address, DATA, (uint_fast8_t)this_i2c->master_tx_buffer[this_i2c->master_tx_idx++]); + } + else if ( this_i2c->transaction == MASTER_RANDOM_READ_TRANSACTION ) + { + /* We are finished sending the address offset part of a random read transaction. + * It is is time to send a restart in order to change direction. */ + this_i2c->dir = READ_DIR; + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + else /* done sending. let's stop */ + { + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + hold_bus = this_i2c->options & I2C_HOLD_BUS; + + /* Store the information of current I2C bus status in the bus_status*/ + this_i2c->bus_status = hold_bus; + if ( hold_bus == 0u ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); /*xmt stop condition */ + enable_slave_if_required(this_i2c); + } + else + { + I2C_disable_irq( this_i2c ); + clear_irq = 0u; + } + this_i2c->master_status = I2C_SUCCESS; + } + break; + + case ST_TX_DATA_NACK: + /* data byte SENT, ACK to be received + * In fact, this means we've received a NACK (This may not be + * obvious, but if we've rec'd an ACK then we would be in state + * 0x28!) hence, let's send a stop bit + */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u);/* xmt stop condition */ + this_i2c->master_status = I2C_FAILED; + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + /********************* MASTER (or slave?) RECEIVER *************************/ + + /* STATUS codes 08H, 10H, 38H are all covered in MTX mode */ + case ST_SLAR_ACK: /* SLA+R tx'ed. */ + /* Let's make sure we ACK the first data byte received (set AA bit in CTRL) unless + * the next byte is the last byte of the read transaction. + */ + if(this_i2c->master_rx_size > 1u) + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + } + else if(1u == this_i2c->master_rx_size) + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + else /* this_i2c->master_rx_size == 0u */ + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_SUCCESS; + this_i2c->transaction = NO_TRANSACTION; + } + break; + + case ST_SLAR_NACK: /* SLA+R tx'ed; let's release the bus (send a stop condition) */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_FAILED; + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + case ST_RX_DATA_ACK: /* Data byte received, ACK returned */ + /* First, get the data */ + this_i2c->master_rx_buffer[this_i2c->master_rx_idx++] = HAL_get_8bit_reg(this_i2c->base_address, DATA); + if( this_i2c->master_rx_idx >= (this_i2c->master_rx_size - 1u)) + { + /* If we're at the second last byte, let's set AA to 0 so + * we return a NACK at the last byte. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + break; + + case ST_RX_DATA_NACK: /* Data byte received, NACK returned */ + /* Get the data, then send a stop condition */ + this_i2c->master_rx_buffer[this_i2c->master_rx_idx] = HAL_get_8bit_reg(this_i2c->base_address, DATA); + + hold_bus = this_i2c->options & I2C_HOLD_BUS; + + /* Store the information of current I2C bus status in the bus_status*/ + this_i2c->bus_status = hold_bus; + if ( hold_bus == 0u ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); /*xmt stop condition */ + + /* Bus is released, now we can start listening to bus, if it is slave */ + enable_slave_if_required(this_i2c); + } + else + { + I2C_disable_irq( this_i2c ); + clear_irq = 0u; + } + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + this_i2c->master_status = I2C_SUCCESS; + break; + + /******************** SLAVE RECEIVER **************************/ + case ST_GCA_NACK: /* NACK after, GCA addressing */ + case ST_SLA_NACK: /* Re-enable AA (assert ack) bit for future transmissions */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + this_i2c->transaction = NO_TRANSACTION; + this_i2c->slave_status = I2C_SUCCESS; + + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + break; + + case ST_GCA_LA: /* Arbitr. lost (GCA rec'd) */ + case ST_SLV_LA: /* Arbitr. lost (SLA rec'd) */ + /* + * We lost arbitration and either the GCE or our address was the + * one received so pend the master operation we were starting. + */ + this_i2c->is_transaction_pending = 1u; + /* Fall through to normal ST processing as we are now in slave mode */ + + case ST_GCA: /* General call address received, ACK returned */ + case ST_SLAVE_SLAW: /* SLA+W received, ACK returned */ + this_i2c->transaction = WRITE_SLAVE_TRANSACTION; + this_i2c->slave_rx_idx = 0u; + this_i2c->random_read_addr = 0u; + /* + * If Start Bit is set clear it, but store that information since it is because of + * pending transaction + */ + if(HAL_get_8bit_reg_field(this_i2c->base_address, STA)) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + this_i2c->is_transaction_pending = 1u; + } + this_i2c->slave_status = I2C_IN_PROGRESS; +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + /* Fall through to put address as first byte in payload buffer */ +#else + /* Only break from this case if the slave address must NOT be included at the + * beginning of the received write data. */ + break; +#endif + case ST_GCA_ACK: /* DATA received; ACK sent after GCA */ + case ST_RDATA: /* DATA received; must clear DATA register */ + if((this_i2c->slave_rx_buffer != (uint8_t *)0) + && (this_i2c->slave_rx_idx < this_i2c->slave_rx_size)) + { + data = HAL_get_8bit_reg(this_i2c->base_address, DATA); + this_i2c->slave_rx_buffer[this_i2c->slave_rx_idx++] = data; + +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + if((ST_RDATA == status) || (ST_GCA_ACK == status)) + { + /* Ignore the slave address byte in the random read address + computation in the case where INCLUDE_SLA_IN_RX_PAYLOAD + is defined. */ +#endif + this_i2c->random_read_addr = (this_i2c->random_read_addr << 8) + data; +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + } +#endif + } + + if(this_i2c->slave_rx_idx >= this_i2c->slave_rx_size) + { + /* Rx buffer is full. NACK next received byte. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + break; + + case ST_RSTOP: + /* STOP or repeated START occurred. */ + /* We cannot be sure if the transaction has actually completed as + * this hardware state reports that either a STOP or repeated START + * condition has occurred. We assume that this is a repeated START + * if the transaction was a write from the master to this point.*/ + if ( this_i2c->transaction == WRITE_SLAVE_TRANSACTION ) + { + if ( this_i2c->slave_rx_idx == this_i2c->slave_mem_offset_length ) + { + this_i2c->slave_tx_idx = this_i2c->random_read_addr; + } + /* Call the slave's write transaction handler if it exists. */ + if ( this_i2c->slave_write_handler != 0u ) + { + i2c_slave_handler_ret_t h_ret; + h_ret = this_i2c->slave_write_handler( this_i2c, this_i2c->slave_rx_buffer, (uint16_t)this_i2c->slave_rx_idx ); + if ( I2C_REENABLE_SLAVE_RX == h_ret ) + { + /* There is a small risk that the write handler could + * call I2C_disable_slave() but return + * I2C_REENABLE_SLAVE_RX in error so we only enable + * ACKs if still in slave mode. */ + enable_slave_if_required(this_i2c); + } + else + { + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x0u ); + /* Clear slave mode flag as well otherwise in mixed + * master/slave applications, the AA bit will get set by + * subsequent master operations. */ + this_i2c->is_slave_enabled = 0u; + } + } + else + { + /* Re-enable address acknowledge in case we were ready to nack the next received byte. */ + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x01u ); + } + } + else /* A stop or repeated start outside a write/read operation */ + { + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * See if we need to re-enable acknowledgement as some error conditions, such + * as a master prematurely ending a transfer, can see us get here with AA set + * to 0 which will disable slave operation if we are not careful. + */ + enable_slave_if_required(this_i2c); + } + + /* Mark any previous master write transaction as complete. */ + this_i2c->slave_status = I2C_SUCCESS; + + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + + break; + + case ST_SLV_RST: /* SMBUS ONLY: timeout state. must clear interrupt */ + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction. + */ + this_i2c->transaction = NO_TRANSACTION; + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * Clear status to I2C_FAILED only if there was an operation in progress. + */ + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->slave_status = I2C_FAILED; + } + + enable_slave_if_required(this_i2c); /* Make sure AA is set correctly */ + + break; + + /****************** SLAVE TRANSMITTER **************************/ + case ST_SLAVE_SLAR_ACK: /* SLA+R received, ACK returned */ + case ST_SLARW_LA: /* Arbitration lost, and: */ + case ST_RACK: /* Data tx'ed, ACK received */ + if ( status == ST_SLAVE_SLAR_ACK ) + { + this_i2c->transaction = READ_SLAVE_TRANSACTION; + this_i2c->random_read_addr = 0u; + this_i2c->slave_status = I2C_IN_PROGRESS; + /* If Start Bit is set clear it, but store that information since it is because of + * pending transaction + */ + if(HAL_get_8bit_reg_field(this_i2c->base_address, STA)) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + this_i2c->is_transaction_pending = 1u; + } + } + if (this_i2c->slave_tx_idx >= this_i2c->slave_tx_size) + { + /* Ensure 0xFF is returned to the master when the slave specifies + * an empty transmit buffer. */ + HAL_set_8bit_reg(this_i2c->base_address, DATA, 0xFFu); + } + else + { + /* Load the data the data byte to be sent to the master. */ + HAL_set_8bit_reg(this_i2c->base_address, DATA, (uint_fast8_t)this_i2c->slave_tx_buffer[this_i2c->slave_tx_idx++]); + } + /* Determine if this is the last data byte to send to the master. */ + if (this_i2c->slave_tx_idx >= this_i2c->slave_tx_size) /* last byte? */ + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + /* Next read transaction will result in slave's transmit buffer + * being sent from the first byte. */ + this_i2c->slave_tx_idx = 0u; + } + break; + + case ST_SLAVE_RNACK: /* Data byte has been transmitted; not-ACK has been received. */ + case ST_FINAL: /* Last Data byte tx'ed, ACK received */ + /* We assume that the transaction will be stopped by the master. + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. */ + this_i2c->slave_tx_idx = 0u; + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + /* Mark previous state as complete */ + this_i2c->slave_status = I2C_SUCCESS; + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + + break; + + /* Master Reset has been activated Wait 35 ms for interrupt to be set, + * clear interrupt and proceed to 0xF8 state. */ + case ST_RESET_ACTIVATED: + case ST_BUS_ERROR: /* Bus error during MST or selected slave modes */ + default: + /* Some undefined state has encountered. Clear Start bit to make + * sure, next good transaction happen */ + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction. + */ + this_i2c->transaction = NO_TRANSACTION; + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * Clear statuses to I2C_FAILED only if there was an operation in progress. + */ + if(I2C_IN_PROGRESS == this_i2c->master_status) + { + this_i2c->master_status = I2C_FAILED; + } + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->slave_status = I2C_FAILED; + } + + break; + } + + if ( clear_irq ) + { + /* clear interrupt. */ + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + /* Read the status register to ensure the last I2C registers write took place + * in a system built around a bus making use of posted writes. */ + status = HAL_get_8bit_reg( this_i2c->base_address, STATUS); +} + +/*------------------------------------------------------------------------------ + * I2C_smbus_init() + * See "i2c.h" for details of how to use this function. + */ + +/* + * SMBSUS_NO = 1 + * SMBALERT_NO = 1 + * SMBus enable = 1 + */ +#define INIT_AND_ENABLE_SMBUS 0x54u +void I2C_smbus_init +( + i2c_instance_t * this_i2c +) +{ + /* + * Single byte register write, should be interrupt safe + */ + /* Enable SMBUS */ + HAL_set_8bit_reg(this_i2c->base_address, SMBUS, INIT_AND_ENABLE_SMBUS); +} + +/*------------------------------------------------------------------------------ + * I2C_enable_smbus_irq() + * See "i2c.h" for details of how to use this function. + */ +void I2C_enable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + if ( irq_type & I2C_SMBALERT_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_IE, 0x01u); + } + if ( irq_type & I2C_SMBSUS_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_IE, 0x01u); + } + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_smbus_irq() + * See "i2c.h" for details of how to use this function. + */ +void I2C_disable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + if ( irq_type & I2C_SMBALERT_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_IE, 0x00u); + } + if (irq_type & I2C_SMBSUS_IRQ ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_IE, 0x00u); + } + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_suspend_smbus_slave() + * See "i2c.h" for details of how to use this function. + */ +void I2C_suspend_smbus_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_NO_CONTROL, 0x00u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_resume_smbus_slave() + * See "i2c.h" for details of how to use this function. + */ +void I2C_resume_smbus_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_NO_CONTROL, 0x01u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_reset_smbus() + * See "i2c.h" for details of how to use this function. + */ +void I2C_reset_smbus +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + HAL_set_8bit_reg_field(this_i2c->base_address, SMBUS_MST_RESET, 0x01u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_smbus_alert() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_smbus_alert +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_NO_CONTROL, 0x00u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_clear_smbus_alert() + * See "i2c.h" for details of how to use this function. + */ +void I2C_clear_smbus_alert +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_NO_CONTROL, 0x01u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_get_irq_status() + * See "i2c.h" for details of how to use this function. + */ +uint8_t I2C_get_irq_status +( + i2c_instance_t * this_i2c +) +{ + uint8_t status ; + uint8_t irq_type = I2C_NO_IRQ ; + + status = HAL_get_8bit_reg(this_i2c->base_address, SMBUS); + + if( status & (uint8_t)SMBALERT_NI_STATUS_MASK ) + { + irq_type |= I2C_SMBALERT_IRQ ; + } + + if( status & (uint8_t)SMBSUS_NI_STATUS_MASK ) + { + irq_type |= I2C_SMBSUS_IRQ ; + } + + status = HAL_get_8bit_reg(this_i2c->base_address, CONTROL); + + if( status & (uint8_t)SI_MASK ) + { + irq_type |= I2C_INTR_IRQ ; + } + return(irq_type); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_addr2() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_user_data +( + i2c_instance_t * this_i2c, + void * p_user_data +) +{ + this_i2c->p_user_data = p_user_data ; +} + +/*------------------------------------------------------------------------------ + * I2C_get_user_data() + * See "i2c.h" for details of how to use this function. + */ +void * I2C_get_user_data +( + i2c_instance_t * this_i2c +) +{ + return( this_i2c->p_user_data); +} + +#ifdef __cplusplus +} +#endif + diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h new file mode 100644 index 0000000..3891ce0 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h @@ -0,0 +1,2306 @@ +/***************************************************************************//** + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * CoreI2C software driver Application Programming Interface. + * This file contains defines and function declarations allowing to interface + * with the CoreI2C software driver. + * + */ +/*=========================================================================*//** + @mainpage CoreI2C Bare Metal Driver. + The CoreI2C bare metal software driver supports I2C master and slave + operations. + + ============================================================================== + Introduction + ============================================================================== + The CoreI2C driver provides a set of functions for controlling the Microchip + CoreI2C hardware IP. The driver supports up to 16 separate I2C channels per + CoreI2C instance, with common slave address settings shared between channels + on a device. + + Optional features of the CoreI2C allow it to operate with I2C based protocols + such as System Management Bus (SMBus), Power Management Bus (PMBus), and + Intelligent Platform Management Interface (IPMI). This driver provides support + for these features when enabled in the CoreI2C IP. + + The major features provided by CoreI2C driver: + - Provides support to configuring the I2C channels of each CoreI2C peripheral device. + - I2C master operations. + - I2C slave operations. + - SMBus related operations. + + This driver is used as part of a bare metal system where no operating + system is available. The driver gets adapted as a part of an operating system, + but the implementation of the adaptation layer between the driver and the operating + system's driver model is outside the scope of this driver. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + Your application software should configure the CoreI2C driver through + calls to the I2C_init() function for each CoreI2C instance in the + hardware design. The configuration parameters include the CoreI2C hardware + instance base address and other runtime parameters, such as the I2C serial + clock frequency and the I2C device address. + + Once channel 0 of a CoreI2C peripheral has been initialized by I2C_init(), + any additional channels present should be configured by calling + I2C_channel_init() for each of the remaining channels. + + Apart from the CoreI2C hardware instance base address, no CoreI2C hardware configuration + parameters are used by the driver. Hence, no additional configuration files are required + to use the driver. + + -------------------------------- + Interrupt Control + -------------------------------- + The CoreI2C driver has to enable and disable the generation of interrupts by + CoreI2C at various times when it is operating. This enabling and disabling of + interrupts must be done through the system’s interrupt controller. For that + reason, the method of controlling the CoreI2C interrupt is system specific + and it is necessary to customize the I2C_enable_irq() and I2C_disable_irq() + functions. These functions are available in the i2c_interrupt.c file. + The default implementation calls HAL_ASSERT(0) to indicate to the application + developer that a suitable implementations for these functions must be provided. + + The implementation of the I2C_enable_irq() function should permit interrupts + generated by a CoreI2C instance to interrupt the processor. The implementation + of the I2C_disable_irq() function should prevent interrupts generated by a + CoreI2C instance from interrupting the processor. See the provided example + projects for a working implementation of these functions. + + The I2C_register_write_handler() function registers a write handler + function with the CoreI2C driver that calls on completion of an I2C write + transaction by the CoreI2C slave. It is your responsibility to create and + register the implementation of this handler function that processes or + trigger the processing of the received data. + + The SMBSUS and SMBALERT interrupts are related to the SMBus interface and are + enabled and disabled through I2C_enable_smbus_irq() and + I2C_disable_smbus_irq() respectively. It is your responsibility to create + interrupt handler functions in your application to get the desired response + for the SMBus interrupts. + + Note: You must include the path to any application header files that are + included in the i2c_interrupt.c file, as an include path in your + project's compiler settings. The details of how to do this will depend + on your development software. + + -------------------------------- + SMBus Logic Options + -------------------------------- + SMBus related APIs does not have any effect if the "Generate SMBus Logic" + is not enabled in the CoreI2C hardware configuration. Following are API's + that does not give the desired results if SMBus Logic is disabled. + + - I2C_smbus_init() + - I2C_reset_smbus() + - I2C_enable_smbus_irq() + - I2C_disable_smbus_irq() + - I2C_suspend_smbus_slave() + - I2C_resume_smbus_slave() + - I2C_set_smsbus_alert() + - I2C_clear_smsbus_alert() + - I2C_get_irq_status() + + -------------------------------- + Fixed Baud Rate Values + -------------------------------- + The serial clock frequency parameter passed to the I2C_init() and + I2C_channel_init() functions may not have any effect if fixed values were + selected for Baud rate in the hardware configuration of CoreI2C. When fixed + values are selected for these baud rates, the driver cannot overwrite + the fixed values. + + ----------------------------------- + Fixed Slave Address Options Values + ----------------------------------- + The primary slave address parameter passed to the I2C_init() function and + secondary address value passed to the I2C_set_slave_second_addr() function, + may not have the desired effect if fixed values were selected for the slave 0 + address and slave 1 address respectively. Proper operation of this version of + the driver requires the slave addresses to be programmable. + + ============================================================================== + Theory of Operation + ============================================================================== + The CoreI2C software driver is designed to allow the control of multiple + instances of CoreI2C with one or more I2C channels. Each channel in an + instance of CoreI2C in the hardware design is associated with a single + instance of the i2c_instance_t structure in the software. You must allocate + memory for one unique i2c_instance_t structure instance for each channel of + each CoreI2C hardware instance. The contents of these data structures are + initialised by calling I2C_init() and if necessary I2C_channel_init(). + A pointer to the structure is passed to the subsequent driver functions in order + to identify the CoreI2C hardware instance and channel to perform the + requested operation. + + Note: Do not attempt to directly manipulate the contents of i2c_instance_t + structures. These structures are only intended to be modified by the driver + functions. + + The CoreI2C driver functions are grouped into the following categories: + - Initialization and configuration functions + - Interrupt control + - I2C slave addressing functions + - I2C master operations functions to handle write, read, and write-read + transactions + - I2C slave operations functions to handle write, read, and write-read + transactions + - Mixed master-slave operations + - SMBus interface configuration and control + + -------------------------------- + Initialization and Configuration + -------------------------------- + The CoreI2C device is first initialized by calling the I2C_init() + function. Since each CoreI2C peripheral supports up to 16 channels, an + additional function, I2C_channel_init(), is required to initialize the + remaining channels with their own data structures. + + I2C_init() function initializes channel 0 of a CoreI2C and the i2c_instance_t + for channel 0 acts as the basis for further channel initialization as the + hardware base address and I2C serial address are same across all the channels. + Ensure to call I2C_init() function before calling any other I2C driver function + calls. The I2C_init() call for each CoreI2C takes the I2C serial address assigned + to the I2C and the serial clock divider to generate its I2C clock as configuration + parameters. + + I2C_channel_init() function takes as input parameters a pointer to the CoreI2C + i2c_instance_t which has been initialized by calling the I2C_init() and a pointer + to a separate i2c_instance_t which represents this new channel. Another input + parameter which is required by this function is serial clock divider which generates + its I2C clock. + + -------------------------------- + Interrupt Control + -------------------------------- + The CoreI2C driver is interrupt driven and it uses each channels INT + interrupt to drive the state machine which is at the heart of the driver. + The application is responsible for providing the link between the interrupt + generating hardware and the CoreI2C interrupt handler and must ensure that + the I2C_isr() function is called with the correct i2c_instance_t structure + pointer for the CoreI2C channel initiating the interrupt. + + The driver enables and disables the generation of INT interrupts by CoreI2C + at various times when it is operating through the user supplied + I2C_enable_irq() and I2C_disable_irq() functions. + + The I2C_register_write_handler() function is used to register a write + handler function with the CoreI2C driver which is called on completion + of an I2C write transaction by the CoreI2C slave. It is the user + applications responsibility to create and register the implementation of + this handler function that processes or triggers the processing of the + received data. + + The other two interrupt sources in the CoreI2C are related to SMBus + operation and are enabled and disabled through I2C_enable_smbus_irq() and + I2C_disable_smbus_irq() respectively. Due to the application specific + nature of the response to SMBus interrupts, you must design interrupt + handler functions in the application to get the desired behaviour for + SMBus related interrupts. + + If enabled, the SMBA_INT signal from the CoreI2C is asserted if an + SMBALERT condition is signalled on the SMBALERT_NI input for the channel. + + If enabled, the SMBS_INT signal from the CoreI2C is asserted if an + SMBSUSPEND condition is signalled on the SMBSUS_NI input for the channel. + + ## I2C Slave Addressing Functions + A CoreI2C peripheral responds to the following three slave addresses: + - Slave address 0 - This is the primary slave address that accesses + a CoreI2C channel when it acts as a slave in + I2C transactions. You must configure the primary slave + address using I2C_init(). + + - Slave address 1 - This is the secondary slave address which might be + required in certain application specific scenarios. + The secondary slave address is configured by + I2C_set_slave_second_addr() and is disabled by + I2C_disable_slave_second_addr(). + + - General call address - A CoreI2C slave can be configured to respond to + a broadcast command by a master transmitting the + general call address of 0x00. Use the I2C_set_gca() + function to enable the slave to respond to the general + call address. If the CoreI2C slave is not required to + respond to the general call address, disable this + address by calling I2C_clear_gca(). + + Note: All channels on a CoreI2C instance share the same slave address logic. + This means that they cannot have separate slave addresses and rely on + the separate physical I2C bus connections to distinguish them. + + -------------------------------- + Transaction Types + -------------------------------- + The I2C driver is designed to handle three types of I2C transaction: + - Write transactions + - Read transactions + - Write-read transactions + + ## Write Transaction + The master I2C device initiates a write transaction by sending a START bit + as soon as the bus becomes free. The START bit is followed by the 7-bit + serial address of the target slave device followed by the read/write bit + indicating the direction of the transaction. The slave acknowledges the + receipt of it's address with an acknowledge bit. The master sends data one + byte at a time to the slave, which must acknowledge the receipt of each byte + for the next byte to be sent. The master sends a STOP bit to complete the + transaction. The slave can abort the transaction by replying with a + non-acknowledge bit instead of an acknowledge bit. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ## Read Transaction + The master I2C device initiates a read transaction by sending a START bit + as soon as the bus becomes free. The START bit is followed by the 7-bit + serial address of the target slave device followed by the read/write bit + indicating the direction of the transaction. The slave acknowledges the + receipt of it's slave address with an acknowledge bit. The slave sends + data one byte at a time to the master, which must acknowledge the receipt of + each byte for the next byte to be sent. The master sends a non-acknowledge + bit following the last byte it wishes to read followed by a STOP bit. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ## Write-Read Transaction + The write-read transaction is a combination of a write transaction + immediately followed by a read transaction. There is no STOP bit in between + the write and read phases of a write-read transaction. A repeated START + bit is sent between the write and read phases. + + Whilst the write handler is being executed, the slave holds the clock line + low to stretch the clock until the response is ready. + + The write-read transaction is typically used to send a command or offset + in the write transaction specifying the logical data to be transferred + during the read phase. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ## Master Operations + The application can use the I2C_write(), I2C_read(), and I2C_write_read() + functions to initiate an I2C bus transaction. The application can then wait + for the transaction to complete using the I2C_wait_complete() function + or poll the status of the I2C transaction using the I2C_get_status() + function until it returns a value different from I2C_IN_PROGRESS. The + I2C_system_tick() function is used to set a time base for the + I2C_wait_complete() function's time out delay. + + ## Slave Operations + To configure the I2C driver to operate as an I2C slave requires the use + of the following functions: + - I2C_set_slave_tx_buffer() + - I2C_set_slave_rx_buffer() + - I2C_set_slave_mem_offset_length() + - I2C_register_write_handler() + - I2C_enable_slave() + + Use of all functions is not required if the slave I2C does not need to support + all types of I2C read transactions. The subsequent sections list the functions + that must be used to support each transaction type. + + ## Responding to Read Transactions + The following functions are used to configure the CoreI2C driver to + respond to I2C read transactions: + • I2C_set_slave_tx_buffer() + • I2C_enable_slave() + + The I2C_set_slave_tx_buffer() function specifies the data buffer that + is transmitted when the I2C slave is the target of an I2C read + transaction. It is then up to the application to manage the content of + that buffer to control the data that will be transmitted to the I2C + master as a result of the read transaction. + + The I2C_enable_slave() function enables the I2C hardware instance + to respond to the I2C transactions. It must be called after the I2C driver + has been configured to respond to the required transaction types. + + ## Responding to Write Transactions + The following functions are used to configure the I2C driver to respond + to I2C write transactions: + • I2C_set_slave_rx_buffer() + • I2C_register_write_handler() + • I2C_enable_slave() + + The I2C_set_slave_rx_buffer() function specifies the data buffer that + stored the data received by the I2C slave when it targets an I2C write + transaction. + + The I2C_register_write_handler() function specifies the handler function + that must be called on completion of the I2C write transaction. It is this + handler function that processes or triggers the processing of the received + data. + + The I2C_enable_slave() function enables the I2C hardware instance + to respond to I2C transactions. It must be called after the I2C driver + has been configured to respond to the required transaction types. + + ## Responding to Write-Read Transactions + The following functions are used to configure the CoreI2C driver to + respond to write-read transactions: + - I2C_set_slave_mem_offset_length() + - I2C_set_slave_tx_buffer() + - I2C_set_slave_rx_buffer() + - I2C_register_write_handler() + - I2C_enable_slave() + + The I2C_set_slave_mem_offset_length() function specifies the number of + bytes expected by the I2C slave during the write phase of the write-read + transaction. + + The I2C_set_slave_tx_buffer() function specifies the data that is + transmitted to the I2C master during the read phase of the write-read + transaction. The value received by the I2C slave during the write phase of + the transaction will be used as an index into the transmit buffer + specified by this function. It decides which part of the transmit buffer + will be transmitted to the I2C master as part of the read phase of the + write-read transaction. + + The I2C_set_slave_rx_buffer() function specifies the data buffer that + stores the data received by the I2C slave during the write phase of + the write-read transaction. This buffer must be large enough to accommodate + the number of bytes specified through the I2C_set_slave_mem_offset_length() + function. + + The I2C_register_write_handler() function can optionally be used to + specify a handler function that is called on completion of the write phase + of the I2C write-read transaction. If a handler function is registered, it + is responsible for processing the received data in the slave receive + buffer and populating the slave transmit buffer with the data that will be + transmitted to the I2C master as part of the read phase of the write-read + transaction. + + The I2C_enable_slave() function enables the CoreI2C hardware instance to + respond to the I2C transactions. It must be called after configuring the + CoreI2C driver to respond to the required transaction types. + + ## Mixed Master-Slave Operations + The CoreI2C device supports mixed master and slave operations. If the + CoreI2C slave has a transaction in progress and your application attempts to + begin a master mode transaction, the CoreI2C driver queues the master mode + transaction until the bus is released and the CoreI2C can switch to master + mode and acquire the bus. The CoreI2C master then starts the previously + queued master transaction. + + ## SMBus Control + The CoreI2C driver enables the CoreI2C peripheral’s SMBus functionality + using the I2C_smbus_init() function. + + The I2C_suspend_smbus_slave() function is used with a master mode CoreI2C + to force slave devices on the SMBus to enter their Power-Down/Suspend mode. + The I2C_resume_smbus_slave() function is used to end the suspend operation + on the SMBus. + + The I2C_reset_smbus() function is used with a master mode CoreI2C to force + all devices on the SMBus to reset their SMBUs interface. + + The I2C_set_smsbus_alert() function is used by a slave mode CoreI2C to + force communication with the SMBus master. Once communications with the + master is initiated, the I2C_clear_smsbus_alert() function clears the alert + condition. + + The I2C_enable_smbus_irq() and I2C_disable_smbus_irq() functions are used to + enable and disable the SMBSUS and SMBALERT SMBus interrupts. + + *//*=========================================================================*/ + +#ifndef CORE_I2C_H_ +#define CORE_I2C_H_ + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#include "hal_assert.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + I2C_RELEASE_BUS + ======================================= + The I2C_RELEASE_BUS constant is used to specify the options parameter to + functions I2C_read(), I2C_write() and I2C_write_read() to indicate + that a STOP bit must be generated at the end of the I2C transaction to release + the bus. + */ +#define I2C_RELEASE_BUS 0x00u + +/*-------------------------------------------------------------------------*//** + I2C_HOLD_BUS + ======================================= + The I2C_HOLD_BUS constant specify the options parameter to functions I2C_read(), + I2C_write(), and I2C_write_read() to indicate that a STOP bit must not be + generated at the end of the I2C transaction in order to retain the bus ownership. + This causes the next transaction to begin with a repeated START bit and no STOP + bit between the transactions. + */ +#define I2C_HOLD_BUS 0x01u + +/*-------------------------------------------------------------------------*//** + Interrupt Identifier Number + ======================================= + The following constants specify the interrupt identifier number which is + solely used by the driver API. This has nothing to do with hardware interrupt + line. I2C_INTR_IRQ is the primary interrupt signal which drives the state machine + of the CoreI2C driver. The I2C_SMBALERT_IRQ and I2C_SMBSUS_IRQ are used by + SMBus interrupt enable and disable functions. These IRQ numbers are also used + by I2C_get_irq_status(). + + | Constant | Description | + |--------------------|--------------------------------------------------------| + | I2C_NO_IRQ | No interrupt | + | I2C_SMBALERT_IRQ | Used by SMBus interrupt enable functions | + | I2C_SMBSUS_IRQ | Used by SMBus interrupt disable functions | + | I2C_INTR_IRQ | Primary interrupt signal which drives the state machine| + + */ +#define I2C_NO_IRQ 0x00u +#define I2C_SMBALERT_IRQ 0x01u +#define I2C_SMBSUS_IRQ 0x02u +#define I2C_INTR_IRQ 0x04u + +/*-------------------------------------------------------------------------*//** + I2C_NO_TIMEOUT + ======================================= + The I2C_wait_complete() function uses I2C_NO_TIMEOUT constant as a parameter + to indicate that the wait for completion of the transaction should not time out. + */ +#define I2C_NO_TIMEOUT 0u + +/***************************************************************************//** + The i2c_channel_number_t type is used to specify the channel number of a + CoreI2C instance. + */ +typedef enum i2c_channel_number { + I2C_CHANNEL_0 = 0u, + I2C_CHANNEL_1, + I2C_CHANNEL_2, + I2C_CHANNEL_3, + I2C_CHANNEL_4, + I2C_CHANNEL_5, + I2C_CHANNEL_6, + I2C_CHANNEL_7, + I2C_CHANNEL_8, + I2C_CHANNEL_9, + I2C_CHANNEL_10, + I2C_CHANNEL_11, + I2C_CHANNEL_12, + I2C_CHANNEL_13, + I2C_CHANNEL_14, + I2C_CHANNEL_15, + I2C_MAX_CHANNELS = 16u +} i2c_channel_number_t; + +/***************************************************************************//** + The i2c_clock_divider_t type specifies the divider to be applied + to the I2C PCLK or BCLK signal in order to generate the I2C clock. + The I2C_BCLK_DIV_8 value selects a clock frequency based on division of BCLK, + all other values select a clock frequency based on division of PCLK. + */ +typedef enum i2c_clock_divider { + I2C_PCLK_DIV_256 = 0u, + I2C_PCLK_DIV_224, + I2C_PCLK_DIV_192, + I2C_PCLK_DIV_160, + I2C_PCLK_DIV_960, + I2C_PCLK_DIV_120, + I2C_PCLK_DIV_60, + I2C_BCLK_DIV_8 +} i2c_clock_divider_t; + +/***************************************************************************//** + The i2c_status_t type is used to report the status of I2C transactions. + */ +typedef enum i2c_status +{ + I2C_SUCCESS = 0u, + I2C_IN_PROGRESS, + I2C_FAILED, + I2C_TIMED_OUT +} i2c_status_t; + +/***************************************************************************//** + The i2c_slave_handler_ret_t type is used by slave write handler functions + to indicate whether or not the received data buffer should be released. + */ +typedef enum i2c_slave_handler_ret { + I2C_REENABLE_SLAVE_RX = 0u, + I2C_PAUSE_SLAVE_RX = 1u +} i2c_slave_handler_ret_t; + +/***************************************************************************//** + This structure identifies various CoreI2C hardware instances in the system + and the I2C channels within them. The application software should declare + one instance of this structure for each channel of each instance of CoreI2C + in your system. I2C_init() and I2C_channel_init() functions initialize this + structure depending on whether it is channel 0 or one of the additional + channels, respectively. A pointer to an initialized instance of the + structure should be passed as the first parameter to the CoreI2C driver + functions, to identify which CoreI2C hardware instance and channel should + perform the requested operation. + + The contents of this data structure should not be modified or used outside of + the CoreI2C driver. Software using the CoreI2C driver should only need to + create one single instance of this data structure for each channel of each + CoreI2C hardware instance in the system then pass a pointer to these data + structures with each call to the CoreI2C driver in order to identify which + CoreI2C hardware instance to use. + */ +typedef struct i2c_instance i2c_instance_t ; +/***************************************************************************//* + Slave write handler functions prototype +/***************************************************************************//** + This defines the function prototype that must be followed by I2C slave write + handler functions. These functions are registered with the CoreI2C driver + through the I2C_register_write_handler() function. + + Declaring and Implementing Slave Write Handler Functions: + + Slave write handler functions should follow the following prototype: + @code + i2c_slave_handler_ret_t write_handler + ( + i2c_instance_t *instance, uint8_t * data, uint16_t size + ); + @endcode + + The instance parameter is a pointer to the i2c_instance_t for which this + slave write handler has been declared. + + The data parameter is a pointer to a buffer (received data buffer) holding + the data written to the I2C slave. + + Define the INCLUDE_SLA_IN_RX_PAYLOAD macro for the driver to insert the + actual address used to access the slave as the first byte in the buffer. + This allows the applications to tailor their response based on the actual + address used to access the slave (primary address, secondary address, or GCA). + + The size parameter is the number of bytes held in the received data buffer. + Handler functions must return one of the following values: + - I2C_REENABLE_SLAVE_RX + - I2C_PAUSE_SLAVE_RX + + If the handler function returns I2C_REENABLE_SLAVE_RX, the driver releases + the received data buffer and allows further I2C write transactions to the + I2C slave. + + If the handler function returns I2C_PAUSE_SLAVE_RX, the I2C slave responds + to subsequent write requests with a non-acknowledge bit (NACK), until the + received data buffer content gets processed by some other part of the + software application. + + Call the I2C_enable_slave() after returning the I2C_PAUSE_SLAVE_RX to release + the received data buffer in order to store the data received by the subsequent + I2C write transactions. + */ +typedef i2c_slave_handler_ret_t (*i2c_slave_wr_handler_t)(i2c_instance_t *instance, uint8_t *, uint16_t ); + +/***************************************************************************//** + This structure is used to identify the various CoreI2C hardware instances in + your system and the I2C channels within them. Your application software should + declare one instance of this structure for each channel of each instance of + CoreI2C in your system. The functions I2C_init() and I2C_channel_init() + initialize this structure depending on whether it is channel 0 or one of the + additional channels respectively. A pointer to an initialized instance of the + structure should be passed as the first parameter to the CoreI2C driver + functions, to identify which CoreI2C hardware instance and channel should + perform the requested operation. + + The contents of this data structure should not be modified or used outside of + the CoreI2C driver. Software using the CoreI2C driver should only need to + create one single instance of this data structure for each channel of each + CoreI2C hardware instance in the system then pass a pointer to these data + structures with each call to the CoreI2C driver in order to identify the + CoreI2C hardware instance it wishes to use. + */ +struct i2c_instance +{ + addr_t base_address; + uint_fast8_t ser_address; + + /* Transmit related info:*/ + uint_fast8_t target_addr; + + /* Current transaction type (WRITE, READ, RANDOM_READ)*/ + uint8_t transaction; + + uint_fast16_t random_read_addr; + + uint8_t options; + + /* Master TX INFO: */ + const uint8_t * master_tx_buffer; + uint_fast16_t master_tx_size; + uint_fast16_t master_tx_idx; + uint_fast8_t dir; + + /* Master RX INFO: */ + uint8_t * master_rx_buffer; + uint_fast16_t master_rx_size; + uint_fast16_t master_rx_idx; + + /* Master Status */ + volatile i2c_status_t master_status; + uint32_t master_timeout_ms; + + /* Slave TX INFO */ + const uint8_t * slave_tx_buffer; + uint_fast16_t slave_tx_size; + uint_fast16_t slave_tx_idx; + + /* Slave RX INFO */ + uint8_t * slave_rx_buffer; + uint_fast16_t slave_rx_size; + uint_fast16_t slave_rx_idx; + /* Slave Status */ + volatile i2c_status_t slave_status; + + /* Slave data: */ + uint_fast8_t slave_mem_offset_length; + i2c_slave_wr_handler_t slave_write_handler; + uint8_t is_slave_enabled; + + /* user specific data */ + void *p_user_data ; + + /* I2C bus status */ + uint8_t bus_status; + + /* Is transaction pending flag */ + uint8_t is_transaction_pending; + + /* I2C Pending transaction */ + uint8_t pending_transaction; +}; + +/*------------------------Public Function-------------------------------------*/ + +/***************************************************************************//** + The I2C_init() function configures channel 0 of a CoreI2C instance. It sets + the base hardware address which is used to locate the CoreI2C instance + in memory and also used internally by I2C_channel_init() to calculate the + register addresses for any additional channels. The slave serial address set + is shared by all channels on a CoreI2C instance. + + If only one channel is configured in a CoreI2C, the address of the + i2c_instance_t used in I2C_Init() will also be used in subsequent calls to the + CoreI2C driver functions. If more than one channel is configured in the + CoreI2C, I2C_channel_init() will be called after I2C_init(), which initializes + the i2c_instance_t data structure for a specific channel. + + @param this_i2c + Pointer to the i2c_instance_t data structure that holds all the data + related to channel 0 of the CoreI2C instance is initialized. A pointer + to this structure is used in all subsequent calls to the CoreI2C driver + functions which operates on channel 0 of this CoreI2C instance. + + @param base_address + Base address in the processor's memory map of the registers of the CoreI2C + instance being initialized. + + @param ser_address + This parameter sets the primary I2C serial address (SLAVE0 address) for the + CoreI2C to initialize. It is the principal I2C bus address to which the + CoreI2C instance will respond. CoreI2C can operate in master mode or slave + mode and the serial address is significant only in the case of I2C slave + mode. In master mode, CoreI2C does not require a serial address and the + value of this parameter is not important. If you do not intend to use the + CoreI2C device in slave mode, then provide any dummy slave address value + to this parameter. However, in systems where the CoreI2C is expected to + switch from master mode to slave mode, it is advisable to initialize the + CoreI2C device with a valid serial slave address. Call the I2C_init() + function whenever it is required to change the primary slave address as + there is no separate function to set the primary slave address of the + I2C device. The serial address initialized through this function is + basically the primary slave address or slave address0. + I2C_set_slave_second_addr() is used to set the secondary slave address + or slave address 1. + Note : ser_address parameter does not have any affect if fixed slave + address is enabled in CoreI2C hardware design. CoreI2C will + be always addressed with the hardware configured fixed slave + address. + Note : ser_address parameter will not have any affect if the CoreI2C + instance is only used in master mode. + + @param ser_clock_speed + This parameter sets the I2C serial clock frequency. It selects the divider + that generates the serial clock from the APB PCLK or from the BCLK. + It can be one of the following: + - I2C_PCLK_DIV_256 + - I2C_PCLK_DIV_224 + - I2C_PCLK_DIV_192 + - I2C_PCLK_DIV_160 + - I2C_PCLK_DIV_960 + - I2C_PCLK_DIV_120 + - I2C_PCLK_DIV_60 + - I2C_BCLK_DIV_8 + Note: serial_clock_speed value does not have any affect if the fixed baud + rate is enabled in CoreI2C hardware instance configuration dialogue + window. The fixed baud rate divider value overrides the value passed + as parameter in this function. + Note: serial_clock_speed value is not critical for devices that only operate + as slaves and can be set to any of the above values. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void system_init( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + } + @endcode + */ +void I2C_init +( + i2c_instance_t * this_i2c, + addr_t base_address, + uint8_t ser_address, + i2c_clock_divider_t ser_clock_speed +); + +/***************************************************************************//** + The I2C_channel_init() function initializes and configures hardware and data + structures of one of the additional channels of a CoreI2C instance. + I2C_init() must be called before calling this function to set the CoreI2C + instance hardware base address and I2C serial address. I2C_channel_init() also + initializes I2C serial clock divider to set the serial clock baud rate. + The pointer to data structure i2c_instance_t used for a particular channel + is used as an input parameter to subsequent CoreI2C driver functions + which operate on this channel. + + @param this_i2c_channel + Pointer to the i2c_instance_t data structure that holds all data related to + the CoreI2C channel gets initialized. A pointer to the same data structure + is used in subsequent calls to the CoreI2C driver functions in order to + identify the CoreI2C channel instance that should perform the operation + implemented by the called driver function. + + @param this_i2c + This is a pointer to an i2c_instance_t structure, previously initialized by + I2C_init(). It holds information regarding the hardware base address and + I2C serial address for the CoreI2C containing the channel to be + initialized. This information is required by I2C_channel_init() to + initialize the i2c_instance_t structure pointed by this_i2c_channel as + all channels in a CoreI2C instance share the same base address and serial + address. It is very important that the i2c_instance_t structure pointed + by this_i2c must be previously initialized by calling I2C_init(). + + @param channel_number + This parameter of type i2c_channel_number_t identifies the channel to be + initialized. + + @param ser_clock_speed + This parameter sets the I2C serial clock frequency. It selects the divider + that is used to generate the serial clock from the APB PCLK or from + the BCLK. It can be one of the following: + - I2C_PCLK_DIV_256 + - I2C_PCLK_DIV_224 + - I2C_PCLK_DIV_192 + - I2C_PCLK_DIV_160 + - I2C_PCLK_DIV_960 + - I2C_PCLK_DIV_120 + - I2C_PCLK_DIV_60 + - I2C_BCLK_DIV_8 + Note: serial_clock_speed value does not have any affect if the fixed baud + rate is enabled in CoreI2C hardware instance configuration dialogue + window. The fixed baud rate divider value will supersede the value + passed as parameter in this function. + Note: ser_clock_speed value is not critical for devices that only operate + as slaves and can be set to any of the above values. + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_SER_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + i2c_instance_t g_i2c_channel_1_inst; + + uint8_t tx_buffer[DATA_LENGTH]; + uint8_t write_length = DATA_LENGTH; + + void system_init( void ) + { + uint8_t target_slave_addr = 0x12; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize CoreI2C channel 1 with different clock speed + I2C_channel_init( &g_i2c_channel_1_inst, &g_i2c_inst, I2C_CHANNEL_1, + I2C_PCLK_DIV_224 ); + + // Write data to Channel 1 of CoreI2C instance. + I2C_write( &g_i2c_channel_1_inst, target_slave_addr, tx_buffer, + write_length, I2C_RELEASE_BUS ); + } + @endcode + +*/ +void I2C_channel_init +( + i2c_instance_t * this_i2c_channel, + i2c_instance_t * this_i2c, + i2c_channel_number_t channel_number, + i2c_clock_divider_t ser_clock_speed +); + +/***************************************************************************//** + The I2C_isr function is the CoreI2C interrupt service routine. User must + call this function from their application level CoreI2C interrupt handler + function. This function runs the I2C state machine based on previous and + current status. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREINTERRUPT_BASE_ADDR 0xCC000000u + #define COREI2C_SER_ADDR 0x10u + #define I2C_IRQ_NB 2u + + i2c_instance_t g_i2c_inst; + + void core_i2c_isr( void ) + { + I2C_isr( &g_i2c_inst ); + } + + void main( void ) + { + CIC_init( COREINTERRUPT_BASE_ADDR ); + NVIC_init(); + CIC_set_irq_handler( I2C_IRQ_NB, core_i2c_isr ); + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + NVIC_enable_interrupt( NVIC_IRQ_0 ); + } + @endcode + */ +void I2C_isr +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//* + #Master Specific Functions + + The following functions are only used within an I2C master's implementation. +/***************************************************************************//** + This function initiates an I2C master write transaction. This function returns + immediately after initiating the transaction. The content of the write buffer + passed as parameter should not be modified until the write transaction + completes. It also means that the memory allocated for the write buffer should + not be freed or should not go out of scope before the write completes. You can + check for the write transaction completion using the I2C_status() function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr + This parameter specifies the serial address of the target I2C device. + + @param write_buffer + This parameter is a pointer to a buffer holding the data to be written to + the target I2C device. Do not to release the memory used by this buffer + before the write transaction completes. For example, it is not appropriate + to return from a function allocating this buffer as an auto array variable + before the write transaction completes as this would result in the buffer's + memory being de-allocated from the stack when the function returns. This + memory could then be subsequently reused and modified causing unexpected + data to be written to the target I2C device. + + @param write_size + Number of bytes held in the write_buffer to be written to the target I2C + device. + + @param options + The options parameter is used to indicate if the I2C bus should be released + on completion of the write transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the write transaction causing the bus to be released for other I2C + devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the write + transaction, preventing other I2C devices from initiating a bus transaction. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t tx_buffer[DATA_LENGTH]; + uint8_t write_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Write data to Channel 0 of CoreI2C instance. + I2C_write( &g_i2c_inst, target_slave_addr, tx_buffer, write_length, + I2C_RELEASE_BUS ); + + // Wait for completion and record the outcome + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_write +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * write_buffer, + uint16_t write_size, + uint8_t options +); + +/***************************************************************************//** + This function initiates an I2C master read transaction. This function returns + immediately after initiating the transaction. + The contents of the read buffer passed as parameter should not be modified + until the read transaction completes. It also means that the memory allocated + for the read buffer should not be freed or should not go out of scope before + the read completes. You can check for the read transaction completion using + the I2C_status() function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr + This parameter specifies the serial address of the target I2C device. + + @param read_buffer + This is a pointer to a buffer where the data received from the target device + gets stored. Do not to release the memory used by this buffer before the read + transaction completes. For example, it is not appropriate to return from a + function allocating this buffer as an auto array variable before the read + transaction completes as this would result in the buffer's memory being + de-allocated from the stack when the function returns. This memory could + then be subsequently reallocated resulting in the read transaction + corrupting the newly allocated memory. + + @param read_size + This parameter specifies the number of bytes to read from the target device. + This size must not exceed the size of the read_buffer buffer. + + @param options + The options parameter is used to indicate if the I2C bus should be released + on completion of the read transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the read transaction causing the bus to be released for other I2C + devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the read transaction, + preventing other I2C devices from initiating a bus transaction. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t rx_buffer[DATA_LENGTH]; + uint8_t read_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Read data from target slave Channel 0 of CoreI2C instance. + I2C_read( &g_i2c_inst, target_slave_addr, rx_buffer, read_length, + I2C_RELEASE_BUS ); + + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +); + +/***************************************************************************//** + This function initiates an I2C write-read transaction where data is first + written to the target device before issuing a restart condition and changing + the direction of the I2C transaction in order to read from the target device. + + The same warnings about buffer allocation in I2C_write() and I2C_read() + applies to this function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr + This parameter specifies the serial address of the target I2C device. + + @param addr_offset + This parameter is a pointer to the buffer containing the data that is sent + to the slave during the write phase of the write-read transaction. This + data is typically used to specify an address offset specifying to the I2C + slave device what data it must return during the read phase of the + write-read transaction. + + @param offset_size + This parameter specifies the number of offset bytes to be written during the + write phase of the write-read transaction. This is typically the size of the + buffer pointed by the addr_offset parameter. + + @param read_buffer + This parameter is a pointer to the buffer where the data read from the I2C + slave will be stored. + + @param read_size + This parameter specifies the number of bytes to read from the target I2C + slave device. This size must not exceed the size of the buffer pointed by + the read_buffer parameter. + + @param options + The options parameter is used to indicate if the I2C bus should be released + on completion of the write-read transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the write-read transaction causing the bus to be released for other + I2C devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the write-read + transaction, preventing other I2C devices from initiating a bus transaction. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define TX_LENGTH 16u + #define RX_LENGTH 8u + + i2c_instance_t g_i2c_inst; + uint8_t rx_buffer[RX_LENGTH]; + uint8_t read_length = RX_LENGTH; + uint8_t tx_buffer[TX_LENGTH]; + uint8_t write_length = TX_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + I2C_write_read( &g_i2c_inst, target_slave_addr, tx_buffer, write_length, + rx_buffer, read_length, I2C_RELEASE_BUS ); + + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_write_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * addr_offset, + uint16_t offset_size, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +); + +/***************************************************************************//** + This function indicates the current state of a CoreI2C channel. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + The return value indicates the current state of a CoreI2C channel or the + outcome of the previous transaction if no transaction is in progress. + Following are the return values are: + - I2C_SUCCESS + The last I2C transaction has completed successfully. + - I2C_IN_PROGRESS + There is an I2C transaction in progress. + - I2C_FAILED + The last I2C transaction failed. + - I2C_TIMED_OUT + The request has failed to complete in the allotted time. + + @example + @code + i2c_instance_t g_i2c_inst; + + while( I2C_IN_PROGRESS == I2C_get_status( &g_i2c_inst ) ) + { + // Do something useful while waiting for I2C operation to complete + our_i2c_busy_task(); + } + + if( I2C_SUCCESS != I2C_get_status( &g_i2c_inst ) ) + { + // Something went wrong... + our_i2c_error_recovery( &g_i2c_inst ); + } + @endcode + */ +i2c_status_t I2C_get_status +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + This function waits for the current I2C transaction to complete. The return + value indicates whether the last I2C transaction was successful or not. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + @param timeout_ms + The timeout_ms parameter specifies the delay within which the current I2C + transaction should complete. The time out delay is given in + milliseconds. I2C_wait_complete() will return I2C_TIMED_OUT if the current + transaction has not completed after the time out delay has expired. This + parameter can be set to I2C_NO_TIMEOUT to indicate that I2C_wait_complete() + must not time out. + + @return + The return value indicates the outcome of the last I2C transaction. It can + be one of the following: + - I2C_SUCCESS + The last I2C transaction has completed successfully. + - I2C_FAILED + The last I2C transaction failed. + - I2C_TIMED_OUT + The last transaction failed to complete within the time out delay given + as second parameter. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t rx_buffer[DATA_LENGTH]; + uint8_t read_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Read data from Channel 0 of CoreI2C instance. + I2C_read( &g_i2c_inst, target_slave_addr, rx_buffer, read_length, + I2C_RELEASE_BUS ); + + // Wait for completion and record the outcome + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +i2c_status_t I2C_wait_complete +( + i2c_instance_t * this_i2c, + uint32_t timeout_ms +); + +/***************************************************************************//** + This function is used to control the expiration of the time out delay + specified as a parameter to the I2C_wait_complete() function. It must be + called from the interrupt service routine of a periodic interrupt source such + as the SysTick timer interrupt. It takes the period of the interrupt + source as its ms_since_last_tick parameter and uses it as the time base for + the I2C_wait_complete() function's time out delay. + + Note: This function does not need to be called if the I2C_wait_complete() + function is called with a timeout_ms value of I2C_NO_TIMEOUT. + + Note: If this function is not called then the I2C_wait_complete() function + will behave as if its timeout_ms was specified as I2C_NO_TIMEOUT and it + will not time out. + + Note: If this function is being called from an interrupt handler (for example, + SysTick) it is important that the calling interrupt have a lower priority + than the CoreI2C interrupt(s) to ensure any updates to the shared data are + protected. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + @param ms_since_last_tick + The ms_since_last_tick parameter specifies the number of milliseconds that + elapsed since the last call to I2C_system_tick(). This parameter would + typically be a constant specifying the interrupt rate of a timer used to + generate system ticks. + + @return None. + + @example + The following example shows how the I2C_system_tick() function. I2C_system_tick() + is called for each I2C channel from the SysTick timer interrupt service routine. + The following example shows how the SysTick is configured to generate an interrupt + in every 10 milliseconds. + @code + #define SYSTICK_INTERVAL_MS 10 + + void SysTick_Handler(void) + { + I2C_system_tick(&g_core_i2c0, SYSTICK_INTERVAL_MS); + I2C_system_tick(&g_core_i2c2, SYSTICK_INTERVAL_MS); + } + @endcode + */ +void I2C_system_tick +( + i2c_instance_t * this_i2c, + uint32_t ms_since_last_tick +); + +/***************************************************************************//* + #Slave Specific Functions + + The following functions are only used within the implementation of an I2C slave device. + +/***************************************************************************//** + This function specifies the memory buffer holding the data that will be sent + to the I2C master when this CoreI2C channel is the target of an I2C read or + write-read transaction. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param tx_buffer + This parameter is a pointer to the memory buffer holding the data to be + returned to the I2C master when this CoreI2C channel is the target of an + I2C read or write-read transaction. + + @param tx_size + Size of the transmit buffer pointed by the tx_buffer parameter. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Specify the transmit buffer containing the data that will be + // returned to the master during read and write-read transactions. + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + } + @endcode + */ +void I2C_set_slave_tx_buffer +( + i2c_instance_t * this_i2c, + const uint8_t * tx_buffer, + uint16_t tx_size +); + +/***************************************************************************//** + This function specifies the memory buffer that is used by the CoreI2C channel + to receive data when it is a slave. This buffer is the memory where data gets + stored when the CoreI2C channel is the target of an I2C master write + transaction (that is, when it is the slave). + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param rx_buffer + This parameter is a pointer to the memory buffer allocated by the caller + software to be used as a slave receive buffer. + + @param rx_size + Size of the slave receive buffer. This is the amount of memory allocated + to the buffer pointed by rx_buffer. + Note: Indirectly, this buffer size specifies the maximum I2C write + transaction length this CoreI2C channel targets. This is because + this CoreI2C channel responds to further received bytes with + a non-acknowledge bit (NACK) as soon as its receive buffer is + full. This causes the write transaction to fail. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_RX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_rx_buffer[SLAVE_RX_BUFFER_SIZE]; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Specify the buffer used to store the data written by the I2C master. + I2C_set_slave_rx_buffer( &g_i2c_inst, g_slave_rx_buffer, + sizeof(g_slave_rx_buffer) ); + } + @endcode + */ +void I2C_set_slave_rx_buffer +( + i2c_instance_t * this_i2c, + uint8_t * rx_buffer, + uint16_t rx_size +); + +/***************************************************************************//** + This function is used as part of the configuration of a CoreI2C channel to + operate as a slave supporting write-read transactions. It specifies the + number of bytes expected as part of the write phase of a write-read + transaction. The bytes received during the write phase of a write-read + transaction will be interpreted as an offset into the slave's transmit buffer. + This allows random access into the I2C slave transmit buffer from a remote + I2C master. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param offset_length + The offset_length parameter configures the number of bytes to be interpreted + by the CoreI2C slave as a memory offset value during the write phase of + write-read transactions. The maximum value for the offset_length parameter + is two. The value of offset_length has the following effect on the + interpretation of the received data. + • If offset_length is 0, the offset into the transmit buffer is fixed at 0. + • If offset_length is 1, a single byte of received data is interpreted as an + unsigned 8-bit offset value in the range 0 to 255. + • If offset_length is 2, 2 bytes of received data are interpreted as an + unsigned 16-bit offset value in the range 0 to 65535. The first byte + received in this case provides the high order bits of the offset and + the second byte provides the low order bits. + If the number of bytes received does not match the non 0 value of + offset_length, the transmit buffer offset is set to 0. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + I2C_set_slave_mem_offset_length( &g_i2c_inst, 1 ); + } + @endcode + */ +void I2C_set_slave_mem_offset_length +( + i2c_instance_t * this_i2c, + uint8_t offset_length +); + +/***************************************************************************//** + Register the function that is called to process the data written to this + CoreI2C channel when it is the slave in an I2C write transaction. + + Note: If a write handler is registered, it is called on completion of the + write phase of a write-read transaction and responsible for processing + the received data in the slave receive buffer and populating the slave + transmit buffer with the data that is transmitted to the I2C master + as part of the read phase of the write-read transaction. If a write + handler is not registered, the write data of a write-read transaction is + interpreted as an offset into the slave’s transmit buffer and handled by + the driver. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param handler + Pointer to the function that processes the I2C write request. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + // local function prototype + void slave_write_handler + ( + i2c_instance_t * this_i2c, + uint8_t * p_rx_data, + uint16_t rx_size + ); + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + I2C_set_slave_mem_offset_length( &g_i2c_inst, 1 ); + I2C_register_write_handler( &g_i2c_inst, slave_write_handler ); + } + @endcode +*/ +void I2C_register_write_handler +( + i2c_instance_t * this_i2c, + i2c_slave_wr_handler_t handler +); + +/***************************************************************************//** + This function enables slave mode operation for a CoreI2C channel. It enables + the CoreI2C slave to receive data when it is the target of an I2C read, write, + or write-read transaction. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + // Enable I2C slave + I2C_enable_slave( &g_i2c_inst ); + @endcode + */ +void I2C_enable_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + This function disables the slave mode operation for a CoreI2C channel. It stops + the CoreI2C slave that acknowledges the I2C read, write, or write-read + transactions targeted at it. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + // Disable I2C slave + I2C_disable_slave( &g_i2c_inst ); + @endcode + */ +void I2C_disable_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_slave_second_addr() function sets the secondary slave address for + a CoreI2C slave device. This is an additional slave address required in certain + applications, for example, to enable fail-safe operation in a system. As the + CoreI2C device supports 7-bit addressing, the highest value assigned to second + slave address is 127 (0x7F). + + Note: This function does not support CoreI2C hardware configured with a fixed + second slave address. The current implementation of the ADDR1[0] register + bit makes it difficult for the driver to support both programmable and + fixed second slave address, so we choose to support programmable only. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param second_slave_addr + The second_slave_addr parameter is the secondary slave address of the I2C + device. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SECOND_SLAVE_ADDR 0x20u + + i2c_instance_t g_i2c_inst; + void main( void ) + { + // Initialize the CoreI2C driver with its base address, primary I2C + // serial address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_second_addr( &g_i2c_inst, SECOND_SLAVE_ADDR ); + } + @endcode + */ +void I2C_set_slave_second_addr +( + i2c_instance_t * this_i2c, + uint8_t second_slave_addr +); + +/***************************************************************************//** + The I2C_disable_slave_second_addr() function disables the secondary slave + address of the CoreI2C slave device. + + Note: This version of the driver only supports CoreI2C hardware configured + with a programmable second slave address. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + i2c_instance_t g_i2c_inst; + I2C_disable_slave_second_addr( &g_i2c_inst); + @endcode + */ +void I2C_disable_slave_second_addr +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_gca() function is used to set the general call acknowledgement bit + of a CoreI2C slave device. This allows all channels of the CoreI2C slave + device to respond to a general call or broadcast message from an I2C master. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + i2c_instance_t g_i2c_inst; + + // Enable recognition of the General Call Address + I2C_set_gca( &g_i2c_inst ); + @endcode + */ +void I2C_set_gca +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_clear_gca() function is used to clear the general call acknowledgement + bit of a CoreI2C slave device. This will stop all channels of the I2C slave + device responding to any general call or broadcast message from the master. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + i2c_instance_t g_i2c_inst; + + // Disable recognition of the General Call Address + I2C_clear_gca( &g_i2c_inst ); + @endcode + */ + +void I2C_clear_gca +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//* + #I2C SMBUS Specific APIs + +/***************************************************************************//** + The I2C_smbus_init() function enables SMBus timeouts and status logic for a + CoreI2C channel. + + Note: This and any of the other SMBus related functionality will only have an + effect if the CoreI2C was instantiated with the Generate SMBus Logic + option checked. + + Note: If the CoreI2C was instantiated with the Generate IPMI Logic option + checked this function then enables the IPMI 3mS SCL low timeout but + none of the other SMBus functions will have any effect. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void system_init( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst); + } + @endcode + */ +void I2C_smbus_init +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_enable_smbus_irq() function is used to enable the CoreI2C channel’s + SMBSUS and SMBALERT SMBus interrupts. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param irq_type + The irq_type specify the SMBUS interrupt(s) which will be enabled. + The two possible interrupts are: + - I2C_SMBALERT_IRQ + - I2C_SMBSUS_IRQ + To enable both interrupts in one call, use I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ. + + @return + None + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both I2C_SMBALERT_IRQ & I2C_SMBSUS_IRQ interrupts + I2C_enable_smbus_irq( &g_i2c_inst, + (uint8_t)(I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ) ); + } + @endcode + */ +void I2C_enable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +); + +/***************************************************************************//** + The I2C_disable_smbus_irq() function disable the CoreI2C channel’s SMBSUS and + SMBALERT SMBus interrupts. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param irq_type + The irq_type specifies the SMBUS interrupt(s) which are disabled. + The two possible interrupts are: + • I2C_SMBALERT_IRQ + • I2C_SMBSUS_IRQ + To disable both ints in one call, use I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both SMBALERT & SMBSUS interrupts + I2C_enable_smbus_irq( &g_i2c_inst, + (uint8_t)(I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ)); + + ... + + // Disable the SMBALERT interrupt + I2C_disable_smbus_irq( &g_i2c_inst, I2C_SMBALERT_IRQ ); + } + @endcode + */ +void I2C_disable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +); + +/***************************************************************************//** + The I2C_suspend_smbus_slave() function forces any SMBUS slave devices + connected to a CoreI2C channel into Power-Down or Suspend mode by asserting + the channel's SMBSUS signal. The CoreI2C channel is the SMBus master in this + case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // suspend SMBus slaves + I2C_suspend_smbus_slave( &g_i2c_inst ); + + ... + + // Re-enable SMBus slaves + I2C_resume_smbus_slave( &g_i2c_inst ); + } + @endcode + */ +void I2C_suspend_smbus_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_resume_smbus_slave() function de-asserts the CoreI2C channel's SMBSUS + signal to take any connected slave devices out of the Suspend mode. The CoreI2C + channel is the SMBus master in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // suspend SMBus slaves + I2C_suspend_smbus_slave( &g_i2c_inst ); + + ... + + // Re-enable SMBus slaves + I2C_resume_smbus_slave( &g_i2c_inst ); + } + @endcode + */ +void I2C_resume_smbus_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_reset_smbus() function resets the CoreI2C channel's SMBus connection + by forcing SCLK low for 35 mS. The reset that automatically cleares after 35 ms + gets elapsed. The CoreI2C channel is the SMBus master in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Make sure the SMBus channel is in a known state by resetting it + I2C_reset_smbus( &g_i2c_inst ); + } + @endcode + */ +void I2C_reset_smbus +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_smbus_alert() function is used to force master communication with + an I2C slave device by asserting the CoreI2C channel's SMBALERT signal. The + CoreI2C channel is the SMBus slave in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Get the SMBus masters attention + I2C_set_smbus_alert( &g_i2c_inst ); + + ... + + // Once we are happy, drop the alert + I2C_clear_smbus_alert( &g_i2c_inst ); + } + @endcode + */ +void I2C_set_smbus_alert +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_clear_smbus_alert() function is used to de-assert the CoreI2C channel's + SMBALERT signal once a slave device gets a response from the master. The + CoreI2C channel is the SMBus slave in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Get the SMBus masters attention + I2C_set_smbus_alert( &g_i2c_inst ); + + ... + + // Once we are happy, drop the alert + I2C_clear_smbus_alert( &g_i2c_inst ); + } + @endcode + */ +void I2C_clear_smbus_alert +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_get_irq_status function returns information about which interrupts are + currently pending in a CoreI2C channel. + The interrupts supported by CoreI2C are: + • SMBUSALERT + • SMBSUS + • INTR + + The macros I2C_NO_IRQ, I2C_SMBALERT_IRQ, I2C_SMBSUS_IRQ, and I2C_INTR_IRQ are + provided to use with this function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + This function returns the status of the CoreI2C channel's interrupts as a + single byte bitmap where a bit is set to indicate a pending interrupt. + The following are the bit positions associated with each interrupt type: + Bit 0 - SMBUS_ALERT_IRQ + Bit 1 - SMBSUS_IRQ + Bit 2 - INTR_IRQ + It returns 0, if there are no pending interrupts. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + uint8_t irq_to_enable = I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ; + uint8_t pending_irq = 0u; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both I2C_SMBALERT_IRQ & I2C_SMBSUS_IRQ irq + I2C_enable_smbus_irq( &g_i2c_inst, irq_to_enable ); + + // Get I2C IRQ type + pending_irq = I2C_get_irq_status( &g_i2c_inst ); + + // Let's assume, in system, INTR and SMBALERT IRQ is pending. + // So pending_irq will return status of both the IRQs + + if( pending_irq & I2C_SMBALERT_IRQ ) + { + // if true, it means SMBALERT_IRQ is there in pending IRQ list + } + if( pending_irq & I2C_INTR_IRQ ) + { + // if true, it means I2C_INTR_IRQ is there in pending IRQ list + } + } + @endcode + */ +uint8_t I2C_get_irq_status +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_user_data() function allows the association of a block of application + specific data with a CoreI2C channel. The composition of the data block is an + application matter and the driver simply provides the means for the application + to set and retrieve the pointer. For example, this is used to provide additional + channel specific information to the slave write handler. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param p_user_data + The p_user_data parameter is a pointer to the user specific data block for + this channel. It is defined as void * as the driver does not know the actual + type of data being pointed to and simply stores the pointer for later + retrieval by the application. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + app_data_t channel_xdata; + + void main( void ) + { + app_data_t *p_xdata; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Store location of user data in instance structure + I2C_set_user_data( &g_i2c_inst, (void *)&channel_xdata ); + + ... + + // Retrieve location of user data and do some work on it + p_xdata = (app_data_t *)I2C_get_user_data( &g_i2c_inst ); + if( NULL != p_xdata ) + { + p_xdata->foo = 123; + } + } + @endcode + */ +void I2C_set_user_data +( + i2c_instance_t * this_i2c, + void * p_user_data +); + +/***************************************************************************//** + The I2C_get_user_data() function is used to allows the retrieval of the address + of a block of application specific data associated with a CoreI2C channel. + The composition of the data block is an application matter and the driver + simply provides the means for the application to set and retrieve the pointer. + For example, this is used to provide additional channel specific information + to the slave write handler. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + This function returns a pointer to the user specific data block for this + channel. It is defined as void * as the driver does not know the actual type + of data being pointed. If no user data has been registered for this channel + a NULL pointer is returned. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + app_data_t channel_xdata; + + void main( void ) + { + app_data_t *p_xdata; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Store location of user data in instance structure + I2C_set_user_data( &g_i2c_inst, (void *)&channel_xdata ); + + ... + + // Retrieve location of user data and do some work on it + p_xdata = (app_data_t *)I2C_get_user_data( &g_i2c_inst ); + if( NULL != p_xdata ) + { + p_xdata->foo = 123; + } + } + @endcode + */ +void * I2C_get_user_data +( + i2c_instance_t * this_i2c +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h new file mode 100644 index 0000000..b1d872d --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h @@ -0,0 +1,190 @@ +/******************************************************************************* + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + */ + +#ifndef __CORE_SMBUS_REGISTERS +#define __CORE_SMBUS_REGISTERS 1 + +/*------------------------------------------------------------------------------ + * CONTROL register details + */ +#define CONTROL_REG_OFFSET 0x00u + +/* + * CR0 bits. + */ +#define CR0_OFFSET 0x00u +#define CR0_MASK 0x01u +#define CR0_SHIFT 0u + +/* + * CR1 bits. + */ +#define CR1_OFFSET 0x00u +#define CR1_MASK 0x02u +#define CR1_SHIFT 1u + +/* + * AA bits. + */ +#define AA_OFFSET 0x00u +#define AA_MASK 0x04u +#define AA_SHIFT 2u + +/* + * SI bits. + */ +#define SI_OFFSET 0x00u +#define SI_MASK 0x08u +#define SI_SHIFT 3u + +/* + * STO bits. + */ +#define STO_OFFSET 0x00u +#define STO_MASK 0x10u +#define STO_SHIFT 4u + +/* + * STA bits. + */ +#define STA_OFFSET 0x00u +#define STA_MASK 0x20u +#define STA_SHIFT 5u + +/* + * ENS1 bits. + */ +#define ENS1_OFFSET 0x00u +#define ENS1_MASK 0x40u +#define ENS1_SHIFT 6u + +/* + * CR2 bits. + */ +#define CR2_OFFSET 0x00u +#define CR2_MASK 0x80u +#define CR2_SHIFT 7u + +/*------------------------------------------------------------------------------ + * STATUS register details + */ +#define STATUS_REG_OFFSET 0x04u + +/*------------------------------------------------------------------------------ + * DATA register details + */ +#define DATA_REG_OFFSET 0x08u + +/* + * TARGET_ADDR bits. + */ +#define TARGET_ADDR_OFFSET 0x08u +#define TARGET_ADDR_MASK 0xFEu +#define TARGET_ADDR_SHIFT 1u + +/* + * DIR bit. + */ +#define DIR_OFFSET 0x08u +#define DIR_MASK 0x01u +#define DIR_SHIFT 0u + + +/*------------------------------------------------------------------------------ + * ADDRESS register details + */ +#define ADDRESS_REG_OFFSET 0x0Cu + +/* + * GC bits. + */ +#define GC_OFFSET 0x0Cu +#define GC_MASK 0x01u +#define GC_SHIFT 0u + +/* + * ADR bits. + */ +#define OWN_SLAVE_ADDR_OFFSET 0x0Cu +#define OWN_SLAVE_ADDR_MASK 0xFEu +#define OWN_SLAVE_ADDR_SHIFT 1u + +/*------------------------------------------------------------------------------ + * SMBUS register details + */ +#define SMBUS_REG_OFFSET 0x10u + +/* + * SMBALERT_IE bits. + */ +#define SMBALERT_IE_OFFSET 0x10u +#define SMBALERT_IE_MASK 0x01u +#define SMBALERT_IE_SHIFT 0u + +/* + * SMBSUS_IE bits. + */ +#define SMBSUS_IE_OFFSET 0x10u +#define SMBSUS_IE_MASK 0x02u +#define SMBSUS_IE_SHIFT 1u + +/* + * SMB_IPMI_EN bits. + */ +#define SMB_IPMI_EN_OFFSET 0x10u +#define SMB_IPMI_EN_MASK 0x04u +#define SMB_IPMI_EN_SHIFT 2u + +/* + * SMBALERT_NI_STATUS bits. + */ +#define SMBALERT_NI_STATUS_OFFSET 0x10u +#define SMBALERT_NI_STATUS_MASK 0x08u +#define SMBALERT_NI_STATUS_SHIFT 3u + +/* + * SMBALERT_NO_CONTROL bits. + */ +#define SMBALERT_NO_CONTROL_OFFSET 0x10u +#define SMBALERT_NO_CONTROL_MASK 0x10u +#define SMBALERT_NO_CONTROL_SHIFT 4u + +/* + * SMBSUS_NI_STATUS bits. + */ +#define SMBSUS_NI_STATUS_OFFSET 0x10u +#define SMBSUS_NI_STATUS_MASK 0x20u +#define SMBSUS_NI_STATUS_SHIFT 5u + +/* + * SMBSUS_NO_CONTROL bits. + */ +#define SMBSUS_NO_CONTROL_OFFSET 0x10u +#define SMBSUS_NO_CONTROL_MASK 0x40u +#define SMBSUS_NO_CONTROL_SHIFT 6u + +/* + * SMBUS_MST_RESET bits. + */ +#define SMBUS_MST_RESET_OFFSET 0x10u +#define SMBUS_MST_RESET_MASK 0x80u +#define SMBUS_MST_RESET_SHIFT 7u + +/*------------------------------------------------------------------------------ + * SLAVE ADDRESS 1 register details + */ + +#define ADDRESS1_REG_OFFSET 0x1Cu + +/* + * SLAVE1_EN bit of Slave Address 1 . + */ +#define SLAVE1_EN_OFFSET 0x1Cu +#define SLAVE1_EN_MASK 0x01u +#define SLAVE1_EN_SHIFT 0u + +#endif /* __CORE_SMBUS_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c new file mode 100644 index 0000000..12e352d --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * CoreI2C driver interrupt control. + * + */ +#include "core_i2c.h" + +/*------------------------------------------------------------------------------ + * This function must be modified to enable interrupts generated from the + * CoreI2C instance identified as parameter. + */ +void I2C_enable_irq( i2c_instance_t * this_i2c ) +{ + HAL_ASSERT(0) +} + +/*------------------------------------------------------------------------------ + * This function must be modified to disable interrupts generated from the + * CoreI2C instance identified as parameter. + */ +void I2C_disable_irq( i2c_instance_t * this_i2c ) +{ + HAL_ASSERT(0) +} diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreSPI/core_spi.c b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreSPI/core_spi.c new file mode 100644 index 0000000..2e11750 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreSPI/core_spi.c @@ -0,0 +1,1345 @@ +/***************************************************************************//** + * Copyright 2013-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * CoreSPI bare metal driver implementation for CoreSPI. + * + * This Core SPI driver provides functions for implementing SPI master or + * SPI slave operations with the CoreSPI version 4.2.xxx It is not compatible + * with CoreSPI version 3.0.xxx. + * + * @file core_spi.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreSPI software configuration + * + */ + +#include "core_spi.h" +#include "corespi_regs.h" +#include + +/******************************************************************************* + * Null parameters with appropriate type definitions + */ +#define NULL_ADDR ( ( addr_t ) 0u ) +#define NULL_INSTANCE ( ( spi_instance_t * ) 0u ) +#define NULL_BUFF ( ( uint8_t * ) 0u ) +#define NULL_FRAME_HANDLER ( ( spi_frame_rx_handler_t ) 0u ) +#define NULL_BLOCK_HANDLER ( ( spi_block_rx_handler_t ) 0u ) +#define NULL_SLAVE_TX_UPDATE_HANDLER ( ( spi_slave_frame_tx_handler_t ) 0u ) +#define NULL_SLAVE_CMD_HANDLER NULL_BLOCK_HANDLER + +#define SPI_ALL_INTS (0xFFu) /* For clearing all active interrupts */ + +/******************************************************************************* + * Possible states for different register bit fields + */ + +#define DISABLE 0u +#define ENABLE 1u + + +/******************************************************************************* + * Function return values + */ +enum { + FAILURE = 0u, + SUCCESS = 1u +}; + +/******************************************************************************* + * Local function declarations + */ +static void fill_slave_tx_fifo( spi_instance_t * this_spi ); +static void read_slave_rx_fifo( spi_instance_t * this_spi ); +static void recover_from_rx_overflow( const spi_instance_t * this_spi ); + +/******************************************************************************* + * SPI_init() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_init +( + spi_instance_t * this_spi, + addr_t base_addr, + uint16_t fifo_depth +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( NULL_ADDR != base_addr ); + HAL_ASSERT( SPI_MAX_FIFO_DEPTH >= fifo_depth ); + HAL_ASSERT( SPI_MIN_FIFO_DEPTH <= fifo_depth ); + + if( ( NULL_INSTANCE != this_spi ) && ( base_addr != NULL_ADDR ) ) + { + /* + * Initialize all transmit / receive buffers and handlers + * + * Relies on the fact that byte filling with 0x00 will equate + * to 0 for any non byte sized items too. + */ + + /* First fill struct with 0s */ + memset( this_spi, 0, sizeof(spi_instance_t) ); + + /* Configure CoreSPI instance attributes */ + this_spi->base_addr = (addr_t)base_addr; + + /* Store FIFO depth or fall back to minimum if out of range */ + if( ( SPI_MAX_FIFO_DEPTH >= fifo_depth ) && ( SPI_MIN_FIFO_DEPTH <= fifo_depth ) ) + { + this_spi->fifo_depth = fifo_depth; + } + else + { + this_spi->fifo_depth = SPI_MIN_FIFO_DEPTH; + } + /* Make sure the CoreSPI is disabled while we configure it */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Ensure all slaves are deselected */ + HAL_set_8bit_reg( this_spi->base_addr, SSEL, 0u ); + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Ensure RXAVAIL, TXRFM, SSEND and CMDINT are disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, 0u ); + /* + * Enable the CoreSPI in the reset default of master mode + * with TXUNDERRUN, RXOVFLOW and TXDONE interrupts disabled. + * The driver does not currently use interrupts in master mode. + */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL1, ENABLE | CTRL1_MASTER_MASK ); + } +} + +/***************************************************************************//** + * SPI_configure_slave_mode() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_configure_slave_mode +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Don't yet know what slave transfer mode will be used */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_NONE; + + /* Make sure the CoreSPI is disabled while we configure it */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Ensure RXAVAIL, TXRFM, SSEND and CMDINT are disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, 0u ); + /* + * Enable the CoreSPI in slave mode with TXUNDERRUN, RXOVFLOW and TXDONE + * interrupts disabled. The appropriate interrupts will be enabled later + * on when the transfer mode is configured. + */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL1, ENABLE ); + } +} + +/***************************************************************************//** + * SPI_configure_master_mode() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_configure_master_mode +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Disable the CoreSPI for a little while, while we configure the CoreSPI */ + HAL_set_8bit_reg_field(this_spi->base_addr, CTRL1_ENABLE, DISABLE); + + /* Reset slave transfer mode to unknown in case it has been set previously */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_NONE; + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Ensure RXAVAIL, TXRFM, SSEND and CMDINT are disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, 0u ); + + /* Enable the CoreSPI in master mode with TXUNDERRUN, RXOVFLOW and TXDONE interrupts disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL1, ENABLE | CTRL1_MASTER_MASK ); + } +} + +/***************************************************************************//** + * SPI_set_slave_select() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +) +{ + spi_slave_t temp = (spi_slave_t)(0x00u) ; + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( SPI_MAX_NB_OF_SLAVES > slave ); + + if( ( NULL_INSTANCE != this_spi ) && ( SPI_MAX_NB_OF_SLAVES > slave ) ) + { + /* This function is only intended to be used with an SPI master */ + if( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW ) ) + { + recover_from_rx_overflow( this_spi ); + } + /* Set the correct slave select bit */ + temp = (spi_slave_t)( HAL_get_8bit_reg( this_spi->base_addr, SSEL ) | ((uint32_t)1u << (uint32_t)slave) ); + HAL_set_8bit_reg( this_spi->base_addr, SSEL, (uint_fast8_t)temp ); + } + } +} + +/***************************************************************************//** + * SPI_clear_slave_select() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_clear_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +) +{ + spi_slave_t temp = (spi_slave_t) (0x00u) ; + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( SPI_MAX_NB_OF_SLAVES > slave ); + + if( ( NULL_INSTANCE != this_spi ) && ( SPI_MAX_NB_OF_SLAVES > slave ) ) + { + /* This function is only intended to be used with an SPI master. */ + if( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW) ) + { + recover_from_rx_overflow( this_spi ); + } + /* Clear the correct slave select bit */ + temp = (spi_slave_t)( HAL_get_8bit_reg( this_spi->base_addr, SSEL ) & ~((uint32_t)1u << (uint32_t)slave) ); + HAL_set_8bit_reg( this_spi->base_addr, SSEL, (uint_fast8_t)temp ) ; + } + } +} + +/***************************************************************************//** + * SPI_transfer_frame() + * See "core_spi.h" for details of how to use this function. + */ +uint32_t SPI_transfer_frame +( + spi_instance_t * this_spi, + uint32_t tx_bits +) +{ + volatile uint32_t rx_data = 0u; /* Ensure consistent return value if in slave mode */ + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI master. */ + if( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Flush the receive and transmit FIFOs by resetting both */ + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK); + + /* Send frame. */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, tx_bits ); + + /* Wait for frame Tx to complete. */ + while ( ENABLE != HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_DONE ) ) + { + ; + } + + /* Read received frame. */ + rx_data = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + } + } + + /* Finally, return the frame we received from the slave or 0 */ + return( rx_data ); +} + + +/***************************************************************************//** + * SPI_transfer_block() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_transfer_block +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_buffer, + uint16_t rx_byte_size +) +{ + uint32_t transfer_size = 0U; /* Total number of bytes to transfer. */ + uint16_t transfer_idx = 0U; /* Number of bytes transferred so far */ + uint16_t tx_idx = 0u; /* Number of valid data bytes sent */ + uint16_t rx_idx = 0u; /* Number of valid response bytes received */ + uint16_t transit = 0U; /* Number of bytes "in flight" to avoid FIFO errors */ + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI master. */ + if( ( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) && + /* Check for empty transfer as well */ + ( 0u != ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) ) ) + { + /* + * tansfer_size is one less than the real amount as we have to write + * the last frame separately to trigger the slave deselect in case + * the SPS option is in place. + */ + transfer_size = ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) - 1u; + /* Flush the receive and transmit FIFOs */ + HAL_set_8bit_reg(this_spi->base_addr, CMD, (uint32_t)(CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK )); + + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW) ) + { + recover_from_rx_overflow( this_spi ); + } + + /* Disable the Core SPI for a little bit, while we load the TX FIFO */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + while( ( tx_idx < transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out 0s to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + } + ++transit; + ++tx_idx; + } + + /* If room left to put last frame in before the off, then do it */ + if( ( tx_idx == transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data, not expecting any reply this time */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out last 0 to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + } + + ++transit; + ++tx_idx; + } + + /* FIFO is all loaded up so enable Core SPI to start transfer */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + + /* Perform the remainder of the transfer by sending a byte every time a byte + * has been received. This should ensure that no Rx overflow can happen in + * case of an interrupt occurring during this function. + * + * We break the transfer down into stages to minimise the processing in + * each loop as the SPI interface is very demanding at higher clock rates. + * This works well with FIFOs but might be less efficient if there is only + * a single frame buffer. + * + * First stage transfers remaining command bytes (if any). + * At this stage anything in the RX FIFO can be discarded as it is + * not part of a valid response. + */ + while( tx_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + /* Send another byte. */ + if( tx_idx == transfer_size ) /* Last frame is special... */ + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Read and discard. */ + HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now, we are writing dummy bytes to push through the response from + * the slave but we still have to keep discarding any read data that + * corresponds with one of our command bytes. + */ + while( transfer_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + if( tx_idx < transfer_size ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Read and discard. */ + HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now we are now only sending dummy data to push through the + * valid response data which we store in the response buffer. + */ + while( tx_idx < transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received byte. */ + rx_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* If we still need to send the last frame */ + while( tx_idx == transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received byte. */ + rx_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* + * Finally, we are now finished sending data and are only reading + * valid response data which we store in the response buffer. + */ + while( transfer_idx <= transfer_size ) + { + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received byte. */ + rx_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + } + } + } + } +} + +/***************************************************************************//** + * SPI_transfer_block_store_all_resp() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_transfer_block_store_all_resp +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_data_buffer, + uint16_t rx_byte_size, + uint8_t * cmd_response_buffer +) +{ + uint32_t transfer_size = 0U; /* Total number of bytes to transfer. */ + uint16_t transfer_idx = 0U; /* Number of bytes transferred so far */ + uint16_t tx_idx = 0u; /* Number of valid data bytes sent */ + uint16_t rx_idx = 0u; /* Number of valid response bytes received */ + uint16_t transit = 0U; /* Number of bytes "in flight" to avoid FIFO errors */ + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI master. */ + if( ( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) && + /* Check for empty transfer as well */ + ( 0u != ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) ) ) + { + /* + * tansfer_size is one less than the real amount as we have to write + * the last frame separately to trigger the slave deselect in case + * the SPS option is in place. + */ + transfer_size = ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) - 1u; + /* Flush the receive and transmit FIFOs */ + HAL_set_8bit_reg(this_spi->base_addr, CMD, (uint32_t)(CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK )); + + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW) ) + { + recover_from_rx_overflow( this_spi ); + } + + /* Disable the Core SPI for a little bit, while we load the TX FIFO */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + while( ( tx_idx < transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out 0s to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + } + ++transit; + ++tx_idx; + } + + /* If room left to put last frame in before the off, then do it */ + if( ( tx_idx == transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data, not expecting any reply this time */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out last 0 to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + } + + ++transit; + ++tx_idx; + } + + /* FIFO is all loaded up so enable Core SPI to start transfer */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + + /* Perform the remainder of the transfer by sending a byte every time a byte + * has been received. This should ensure that no Rx overflow can happen in + * case of an interrupt occurring during this function. + * + * We break the transfer down into stages to minimise the processing in + * each loop as the SPI interface is very demanding at higher clock rates. + * This works well with FIFOs but might be less efficient if there is only + * a single frame buffer. + * + * First stage transfers remaining command bytes (if any). + * At this stage anything in the RX FIFO can be discarded as it is + * not part of a valid response. + */ + while( tx_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + /* Send another byte. */ + if( tx_idx == transfer_size ) /* Last frame is special... */ + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received command byte. */ + cmd_response_buffer[transfer_idx] = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now, we are writing dummy bytes to push through the response from + * the slave, which we store in the command response buffer. + */ + while( transfer_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + if( tx_idx < transfer_size ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received command byte. */ + cmd_response_buffer[transfer_idx] = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now we are now only sending dummy data to push through the + * valid response data which we store in the data response buffer. + */ + while( tx_idx < transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received data byte. */ + rx_data_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* If we still need to send the last frame */ + while( tx_idx == transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received data byte. */ + rx_data_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* + * Finally, we are now finished sending data and are only reading + * valid response data which we store in the data response buffer. + */ + while( transfer_idx <= transfer_size ) + { + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received data byte. */ + rx_data_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + } + } + } + } +} +/***************************************************************************//** + * SPI_set_frame_rx_handler() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_frame_rx_handler +( + spi_instance_t * this_spi, + spi_frame_rx_handler_t rx_handler +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if(NULL_INSTANCE != this_spi) + { + /* This function is only intended to be used with an SPI slave. */ + if(DISABLE == HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER)) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Disable SSEND and CMD interrupts as we are not doing block transfers */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTSSEND, DISABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + + /* Disable block Rx handler as they are mutually exclusive. */ + this_spi->block_rx_handler = 0U; + + /* Keep a copy of the pointer to the Rx handler function. */ + this_spi->frame_rx_handler = rx_handler; + + if( SPI_SLAVE_XFER_FRAME != this_spi->slave_xfer_mode ) + { + /* + * Either just coming from init or were previously in block mode + * so no tx frame handler is set at this point in time... + * + * Don't allow TXDONE interrupts. + */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXDONE, DISABLE ); + } + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK); + + /* Enable Rx and FIFO error interrupts */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTRXOVFLOW, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXURUN, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTRXDATA, ENABLE ); + + /* Make sure correct mode is selected */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_FRAME; + + /* Finally re-enable the CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } + } +} + +/***************************************************************************//** + * SPI_set_slave_tx_frame() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_slave_tx_frame +( + spi_instance_t * this_spi, + uint32_t frame_value, + spi_slave_frame_tx_handler_t slave_tx_frame_handler +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI slave. */ + if( DISABLE == HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Disable SSEND and CMD interrupts as we are not doing block transfers */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTSSEND, DISABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + + if( SPI_SLAVE_XFER_FRAME != this_spi->slave_xfer_mode ) + { + /* + * Either just coming from init or were previously in block mode + * so no rx frame handler is set at this point in time... + * + * Don't allow RXDATA interrupts. + */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTRXDATA, DISABLE ); + } + + /* Disable slave block tx buffer as it is mutually exclusive with frame + * level handling. */ + this_spi->slave_tx_buffer = NULL_BUFF; + this_spi->slave_tx_size = 0U; + this_spi->slave_tx_idx = 0U; + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK); + + /* Assign the slave frame update handler - NULL_SLAVE_TX_UPDATE_HANDLER for none */ + this_spi->slave_tx_frame_handler = slave_tx_frame_handler; + + /* Keep a copy of the slave Tx frame value. */ + this_spi->slave_tx_frame = frame_value; + + /* Load one frame into Tx data register. */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, this_spi->slave_tx_frame ); + + /* Enable Tx Done interrupt in order to reload the slave Tx frame after each + * time it has been sent. */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXDONE, ENABLE ); + + /* Make sure correct mode is selected */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_FRAME; + + /* Ready to go so enable CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } + } +} + +/***************************************************************************//** + * SPI_set_slave_block_buffers() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_slave_block_buffers +( + spi_instance_t * this_spi, + const uint8_t * tx_buffer, + uint32_t tx_buff_size, + uint8_t * rx_buffer, + uint32_t rx_buff_size, + spi_block_rx_handler_t block_rx_handler +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI slave. */ + if( DISABLE == HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Make sure correct mode is selected */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_BLOCK; + /* + * No command handler should be setup at this stage so fake this + * to ensure 0 padding works. + */ + this_spi->cmd_done = 1u; + + /* Disable frame handlers as they are mutually exclusive with block Rx handler. */ + this_spi->frame_rx_handler = NULL_FRAME_HANDLER; + this_spi->slave_tx_frame_handler = NULL_SLAVE_TX_UPDATE_HANDLER; + + /* Keep a copy of the pointer to the block Rx handler function. */ + this_spi->block_rx_handler = block_rx_handler; + + /* Assign slave receive buffer */ + this_spi->slave_rx_buffer = rx_buffer; + this_spi->slave_rx_size = rx_buff_size; + this_spi->slave_rx_idx = 0U; + + /* Assign slave transmit buffer*/ + this_spi->slave_tx_buffer = tx_buffer; + this_spi->slave_tx_size = tx_buff_size; + this_spi->slave_tx_idx = 0U; + + /* Flush the receive and transmit FIFOs */ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Preload the transmit FIFO. */ + while( !(HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_TXFULL)) && + ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->slave_tx_buffer[this_spi->slave_tx_idx] ); + ++this_spi->slave_tx_idx; + } + /* + * Disable TXDATA interrupt as we will look after transmission in rx handling + * because we know that once we have read a frame it is safe to send another one. + */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTTXDATA, DISABLE ); + + /* Enable Rx, FIFO error and SSEND interrupts */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTRXOVFLOW, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXURUN, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTRXDATA, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTSSEND, ENABLE ); + + /* Disable command handler until it is set explicitly */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + + /* Now enable the CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } + } +} + +/***************************************************************************//** + * SPI_set_cmd_handler() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_cmd_handler +( + spi_instance_t * this_spi, + spi_block_rx_handler_t cmd_handler, + uint32_t cmd_size +) +{ + uint32_t ctrl2 = 0u; + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( NULL_SLAVE_CMD_HANDLER != cmd_handler ); + HAL_ASSERT( 0u < cmd_size ); + + if( ( NULL_INSTANCE != this_spi ) && ( 0u < cmd_size ) && + ( NULL_SLAVE_CMD_HANDLER != cmd_handler ) ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + /* + * Note we don't flush the FIFOs as this has been done already when + * block mode was configured. + * + * Clear this flag so zero padding is disabled until command response + * has been taken care of. + */ + this_spi->cmd_done = 0u; + + /* Assign user handler for Command received interrupt */ + this_spi->cmd_handler = cmd_handler; + + /* Configure the command size and Enable Command received interrupt */ + ctrl2 = HAL_get_8bit_reg( this_spi->base_addr, CTRL2 ); + + /* First clear the count field then insert count and int enables */ + ctrl2 &= ~(uint32_t)CTRL2_CMDSIZE_MASK; + ctrl2 |= (uint32_t)((cmd_size & CTRL2_CMDSIZE_MASK) | CTRL2_INTCMD_MASK | CTRL2_INTRXDATA_MASK); + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, ctrl2 ); + + /* Now enable the CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } +} + +/***************************************************************************//** + * SPI_set_cmd_response() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_cmd_response +( + spi_instance_t * this_spi, + const uint8_t * resp_tx_buffer, + uint32_t resp_buff_size +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( NULL_BUFF != resp_tx_buffer ); + HAL_ASSERT( 0u < resp_buff_size ); + + if( ( NULL_INSTANCE != this_spi ) && ( 0u < resp_buff_size ) && + ( NULL_BUFF != resp_tx_buffer ) ) + { + this_spi->resp_tx_buffer = resp_tx_buffer; + this_spi->resp_buff_size = resp_buff_size; + this_spi->resp_buff_tx_idx = 0u; + + fill_slave_tx_fifo(this_spi); + } +} + + +/***************************************************************************//** + * SPI_enable() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_enable +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } +} + + +/***************************************************************************//** + * SPI_disable() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_disable +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + } +} + + +/***************************************************************************//** + * SPI interrupt service routine. + */ +void SPI_isr +( + spi_instance_t * this_spi +) +{ + uint32_t rx_frame; + int32_t guard; + +/* + * The assert and the NULL check here can be commented out to reduce the interrupt + * latency once you are sure the interrupt vector code is correct. + */ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + if( NULL_INSTANCE != this_spi ) + { + /* Handle receive. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_RXDATA ) ) + { + /* + * Service receive data according to transfer mode in operation. + * + * We check block mode first as this is most likely to have back to back + * transfers with multiple bytes. + * + * Note the order of the checks here will effect interrupt latency and + * for critical timing the mode you are using most often should probably be + * be the first checked. + */ + if( SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode ) /* Block handling mode. */ + { + while( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Read irrespective to clear the RX IRQ */ + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + if( this_spi->slave_rx_idx < this_spi->slave_rx_size ) + { + this_spi->slave_rx_buffer[this_spi->slave_rx_idx] = (uint8_t)rx_frame; + } + ++this_spi->slave_rx_idx; + } + /* + * Now handle updating of tx FIFO to keep the data flowing. + * First see if there is anything in slave_tx_buffer to send. + */ + while( ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) + && ( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->slave_tx_buffer[this_spi->slave_tx_idx] ); + ++this_spi->slave_tx_idx; + } + /* + * Next see if there is anything in resp_tx_buffer to send. + */ + if( this_spi->slave_tx_idx >= this_spi->slave_tx_size ) + { + while( ( this_spi->resp_buff_tx_idx < this_spi->resp_buff_size ) + && ( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->resp_tx_buffer[this_spi->resp_buff_tx_idx] ); + ++this_spi->resp_buff_tx_idx; + } + } + /* + * Lastly, see if we are ready to pad with 0s . + */ + if( this_spi->cmd_done && ( this_spi->slave_tx_idx >= this_spi->slave_tx_size ) && + ( this_spi->resp_buff_tx_idx >= this_spi->resp_buff_size ) ) + { + guard = 1 + ((int32_t)this_spi->fifo_depth / 4); + while( ( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) + && ( 0 != guard ) ) + { + /* + * Pad TX FIFO with 0s for consistent behaviour if the master + * tries to transfer more than we expected. + */ + HAL_set_32bit_reg(this_spi->base_addr, TXDATA, 0x00u); + /* + * We use the guard count to cover the event that we are never + * seeing the TX FIFO full because the data is being pulled + * out as fast as we can stuff it in. In this case we never spend + * more than our allocated time spinning here. + */ + guard--; + } + } + } + else if( SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode ) /* Single frame handling mode. */ + { + while( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + if( NULL_FRAME_HANDLER != this_spi->frame_rx_handler ) + { + this_spi->frame_rx_handler( rx_frame ); + } + } + } + else /* Slave transfer mode not set up so discard anything in RX FIFO */ + { + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_RXFIFORST_MASK ); + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_RXDATA, ENABLE ); + } + + /* Handle transmit. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_TXDONE ) ) + { + /* + * Note, the driver only currently uses the txdone interrupt when + * in frame transmit mode. In block mode all TX handling is done by the + * receive interrupt handling code as we know that for every frame received + * a frame must be placed in the TX FIFO. + */ + if( SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode ) + { + /* Execute the user callback to update the slave_tx_frame */ + if( NULL_SLAVE_TX_UPDATE_HANDLER != this_spi->slave_tx_frame_handler ) + { + this_spi->slave_tx_frame_handler ( this_spi ); + } + + /* Reload slave tx frame into Tx data register. */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, this_spi->slave_tx_frame ); + } + else if( SPI_SLAVE_XFER_BLOCK != this_spi->slave_xfer_mode ) + { + /* Slave transfer mode not set up so discard anything in TX FIFO */ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK ); + } + else + { + /* Nothing to do, no slave mode configured */ + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_TXDONE, ENABLE ); + } + + + /* Handle receive overflow. */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, INTMASK_RXOVERFLOW)) + { + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_RXFIFORST_MASK); + HAL_set_8bit_reg_field(this_spi->base_addr, INTCLR_RXOVERFLOW, ENABLE); + } + + /* Handle transmit under run. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_TXUNDERRUN ) ) + { + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK ); + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_TXUNDERRUN, ENABLE ); + } + + /* Handle command interrupt. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_CMDINT ) ) + { + read_slave_rx_fifo( this_spi ); + + /* + * Call the command handler if one exists. + */ + if( NULL_SLAVE_CMD_HANDLER != this_spi->cmd_handler ) + { + this_spi->cmd_handler( this_spi->slave_rx_buffer, this_spi->slave_rx_idx ); + } + this_spi->cmd_done = 1u; + /* Disable command interrupt until slave select becomes de-asserted to avoid retriggering. */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_CMDINT, ENABLE ); + } + + /* Handle slave select becoming de-asserted. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_SSEND) ) + { + /* Only supposed to do all this if transferring blocks... */ + if(SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode) + { + uint32_t rx_size; + + /* Empty any remaining bytes in RX FIFO */ + read_slave_rx_fifo( this_spi ); + rx_size = this_spi->slave_rx_idx; + /* + * Re-enable command interrupt if required. + * Must be done before re loading FIFO to ensure stale response + * data is not pushed into the FIFO. + */ + if(NULL_SLAVE_CMD_HANDLER != this_spi->cmd_handler) + { + this_spi->cmd_done = 0u; + this_spi->resp_tx_buffer = 0u; + this_spi->resp_buff_size = 0u; + this_spi->resp_buff_tx_idx = 0u; + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_CMDINT, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, ENABLE ); + } + /* + * Reset the transmit index to 0 to restart transmit at the start of the + * transmit buffer in the next transaction. This also requires flushing + * the Tx FIFO and refilling it with the start of Tx data buffer. + */ + this_spi->slave_tx_idx = 0u; + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + fill_slave_tx_fifo( this_spi ); + + /* Prepare to receive next packet. */ + this_spi->slave_rx_idx = 0u; + /* + * Call the receive handler if one exists. + */ + if( NULL_BLOCK_HANDLER != this_spi->block_rx_handler ) + { + this_spi->block_rx_handler( this_spi->slave_rx_buffer, rx_size ); + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_RXDATA, ENABLE ); + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_SSEND, ENABLE ); + } + } +} + +/******************************************************************************* + * Local function definitions + */ + +/***************************************************************************//** + * Fill the transmit FIFO (used for slave block transfers). + */ +static void fill_slave_tx_fifo +( + spi_instance_t * this_spi +) +{ + /* First see if slave_tx_buffer needs transmitting */ + while( ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) && + !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->slave_tx_buffer[this_spi->slave_tx_idx] ); + ++this_spi->slave_tx_idx; + } + + /* Then see if it is safe to look at putting resp_tx_buffer in FIFO? */ + if( this_spi->slave_tx_idx >= this_spi->slave_tx_size ) + { + while( ( this_spi->resp_buff_tx_idx < this_spi->resp_buff_size ) && + !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->resp_tx_buffer[this_spi->resp_buff_tx_idx] ); + ++this_spi->resp_buff_tx_idx; + } + } +} + +/***************************************************************************//** + * + */ +static void read_slave_rx_fifo +( + spi_instance_t * this_spi +) +{ + uint32_t rx_frame; + + if( SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode ) /* Block handling mode. */ + { + while( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); /* Read irresepective to clear the RX IRQ */ + if( this_spi->slave_rx_idx < this_spi->slave_rx_size ) + { + this_spi->slave_rx_buffer[this_spi->slave_rx_idx] = (uint8_t)rx_frame; + } + ++this_spi->slave_rx_idx; + } + } + else if( SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode ) /* Frame handling mode */ + { + while( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Single frame handling mode. */ + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + if( NULL_FRAME_HANDLER != this_spi->frame_rx_handler ) + { + this_spi->frame_rx_handler( rx_frame ); + } + } + } + else /* Slave transfer mode not set up so discard anything in RX FIFO */ + { + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_RXFIFORST_MASK ); + } +} + +/***************************************************************************//** + * This function is to recover the CoreSPI from receiver overflow. + * It temporarily disables the CoreSPI from interacting with external world, flushes + * the transmit and receiver FIFOs, clears all interrupts and then re-enables + * the CoreSPI instance referred by this_spi parameter. + */ +static void recover_from_rx_overflow +( + const spi_instance_t * this_spi +) +{ + /* Disable CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Reset TX and RX FIFOs */ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Enable CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); +} + + diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreSPI/core_spi.h b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreSPI/core_spi.h new file mode 100644 index 0000000..c6873f7 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreSPI/core_spi.h @@ -0,0 +1,1324 @@ +/***************************************************************************//** + * Copyright 2013-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Core SPI bare metal software driver public API. + * + * This Core SPI driver provides functions for implementing SPI master or + * SPI slave operations with the CoreSPI version 4.2.xxx It is not compatible + * with CoreSPI version 3.0.xxx. + * + * The Core SPI driver supports two classes of data transfer operation: + * SPI frame operation or SPI block transfer operations. + * + * Frame operations allow transferring individual SPI frames from 4 to 32-bits + * in length. Block operations allow transferring blocks of data organized as + * 8-bit frames. + * + * @file core_spi.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreSPI prototypes + * + */ + +/*=========================================================================*//** + @mainpage Core SPI Bare Metal Driver. + + ============================================================================== + Introduction + ============================================================================== + CoreSPI is an IP component that implements a full-duplex, synchronous, and + configurable serial peripheral interface (SPI) with frame sizes from 4 to 32 + bits and bus interface sizes of 8-, 16-, or 32-bit. Each CoreSPI instance + communicates with up to eight slave devices. + + This driver provides a set of functions for controlling CoreSPI as part of + the bare metal system where no operating system is available. These drivers + can be adapted to be used as a part of an operating system, but the + implementation of the adaptation layer between driver and the operating + system's driver model is outside the scope of this User's Guide. + + ============================================================================== + Driver Configuration + ============================================================================== + Your application software should configure the CoreSPI driver through calls + to the SPI_init() function for each CoreSPI instance in the hardware design. + This function configures a default set of parameters that include a CoreSPI + hardware instance base address and the depth of the FIFOs for this instance. + + The CoreSPI instance is configured at the time of instantiation in hardware + design for APB width, frame size, FIFO depth, serial clock speed, serial + clock polarity, serial clock phase, and slave select state parameters. + + CoreSPI can communicate with up to eight different slave devices that match + the CoreSPI configuration at the time of hardware instantiation. + + The functions SPI_configure_slave_mode() and SPI_configure_master_mode() are + used to configure the CoreSPI instance as a master or slave as required by + the application. + + When CoreSPI wishes to communicate with a specific slave device, call + the SPI_set_slave_select() function with the slave number as an argument. + This function selects the slave device. A previously selected slave gets + unselected by calling the SPI_clear_slave_select() function. + + ============================================================================== + Theory of Operation + ============================================================================== + The CoreSPI driver functions are grouped into the following categories: + • Initialization + • Configuration for either master or slave operations + • SPI master frame transfer control + • SPI master block transfer control + • SPI slave frame transfer control + • SPI slave block transfer control + + Frame transfers allow CoreSPI to write or read up to 32-bits of data in a + single SPI transaction. For example, a frame transfer of 12-bits might be used + to read the result of an ADC conversion from a SPI analog to digital converter. + + Block transfers allow CoreSPI to write and/or read a number of bytes in a single + SPI transaction. With the driver as is, block transfer transactions allow data + transfers in multiples of 8-bits (8, 16, 24, 32, 40,...) and the CoreSPI instance + has to be configured for 8-bit frames. For other frame sizes, the + SPI_transfer_block() code can act as a template for developing a frame block + transfer function. + Block transfers are typically used with byte oriented devices like SPI + FLASH devices. + + Note: The CoreSPI instance in the hardware design must be configured for + the frame size required by the application; configuration by driver is + not possible. + + -------------------------------- + Initialization + -------------------------------- + The CoreSPI driver is initialized through a call to the SPI_init() function. + The SPI_init() function takes a pointer to the global CoreSPI instance data + structure of type spi_instance_t and the base address of the CoreSPI instance + as defined by the hardware design. The CoreSPI instance global data structure + is used by the driver to store state information for each CoreSPI instance. + A pointer to these data structures is also used as the first parameter to + any of the driver functions to identify which CoreSPI will be used by the + called function. It is the responsibility of the application programmer to + create and maintain these global CoreSPI instance data structures. Any call + to a CoreSPI driver function should be of the form SPI_function_name + ( &g_core_spi0, ... ). + The SPI_init() function resets the transmit and receives FIFOs of CoreSPI + instance being initialized. + The SPI_init() function must be called before any other CoreSPI driver + functions can be called. + + ---------------------------------------------------- + Configuration + ---------------------------------------------------- + A CoreSPI instance can operate either as a master or as a slave SPI device. + There are two distinct functions for configuring a CoreSPI instance for + master or slave operations. + + ## Master Configuration + The SPI_configure_master_mode() function configures the specified CoreSPI + block for operations as an SPI master. This function must be called once + before the CoreSPI block communicates with an SPI slave device. + + ## Slave Configuration + The SPI_configure_slave_mode() function configures the specified CoreSPI + block for operations as a SPI slave. This function must be called after + calling the SPI_init() to configure the CoreSPI instance referred by this_spi + parameter to operate in the slave mode. + + ------------------------------------- + SPI Master Frame Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI master frame transfers: + • SPI_set_slave_select() + • SPI_transfer_frame() + • SPI_clear_slave_select() + + The master must first select the target slave or slaves to be addressed by + calling the SPI_set_slave_select() function. This causes the relevant select + line(s) to become asserted while data is clocked out onto the SPI data line. + + A function call is then made to SPI_transfer_frame() specifying the value + of the data frame to be sent and returning the value read. + + After the transfer is complete, use the SPI_clear_slave_select() function + to prevent this slave select line from being asserted during subsequent SPI + transactions. A call to this function is required only if the master is + communicating with multiple slave devices. + + ------------------------------------- + SPI Master Block Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI master block transfers: + • SPI_set_slave_select() + • SPI_transfer_block() + • SPI_clear_slave_select() + + The master must first select the target slave or slaves by calling + SPI_set_slave_select(). This causes the relevant slave select line(s) to + become asserted while data is clocked out onto the SPI data line. + Alternatively, a general purpose input/output (GPIO) can be used to control + the state of the target slave device's chip select signal. + + A call is then made to the SPI_transfer_block() function. The parameters of + this function specify the following: + • The number of bytes to be transmitted + • A pointer to the buffer containing the data to be transmitted + • The number of bytes to be received + • A pointer to the buffer where the received data gets stored + + The number of bytes to be transmitted can be set to zero to indicate that the + transfer is purely a block read transfer. The number of bytes to be received + can be set to zero to specify that the transfer is purely a block write + transfer. + + Block mode transfers as implemented by the driver are effectively half duplex + as we do not store the values received from the slave device whilst we are + transmitting. If full duplex operation is required, the driver + SPI_transfer_block() function can serve as a starting point for implementing + full duplex block transfers. + + The SPI_clear_slave_select() function can be used after the transfer is + complete to prevent this slave select line from being asserted during + subsequent SPI transactions. A call to this function is only required if + the master is communicating with multiple slave devices. + + ------------------------------------- + SPI Slave Frame Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI slave frame transfers: + • SPI_set_frame_rx_handler() + • SPI_set_slave_tx_frame() + + The SPI_set_frame_rx_handler() function specifies the receive handler + function that is called when a frame of data has been received by the + SPI when it is configured as a slave. The receive handler function specified + through this call processes the frame data written over the SPI bus to the + SPI slave by the remote SPI master. The receive handler function must be + implemented as part of the application. It is only required if the SPI slave + is the target of SPI frame write transactions. + + The SPI_set_slave_tx_frame() function specifies the frame data that is + returned to the SPI master. The frame data specified through this function + is the value that will be read over the SPI bus by the remote SPI master, + when it initiates a transaction. Call the SPI_set_slave_tx_frame() function + only if the SPI slave is the target of SPI read transactions. That is, if + data is meant to be read over CoreSPI. + + If both frame handlers are required, call the SPI_set_frame_rx_handler() + first, otherwise the initial TX frame gets discarded when SPI_set_frame_rx_handler() + clears the FIFOs as part of its initialization. + + ------------------------------------- + SPI Slave Block Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI slave block transfers: + • SPI_set_slave_block_buffers() + • SPI_set_cmd_handler() + • SPI_set_cmd_response() + + The SPI_set_slave_block_buffers() function is used to configure an SPI slave + for block transfer operations. It specifies the following: + • The buffer containing the data that will be returned to the remote SPI + master + • The buffer where data received from the remote SPI master will be + stored + • The optional handler function that will be called after the receive + buffer is filled + + The SPI_set_cmd_handler() function specifies a command handler function that + is called by the driver once a specific number of frames have been + received after the SPI chip select signal becomes active. The number of + bytes making up the command part of the transaction is specified as part of + the parameters to the SPI_set_cmd_handler() function. The command handler + function is implemented as a part of the application making use of the SPI + driver and typically calls the SPI_set_cmd_response() function. + + The SPI_set_cmd_response() function specifies the data that gets returned + to the master. Typically, the SPI_set_slave_block_buffers() function is + called as a part of the system initialisation to specify the data sent to + the master while the command bytes are being received. The transmit buffer + specified through calling the SPI_set_slave_block_buffers() function would + also typically include one or more bytes allowing the turn around time + for the command handler function to execute and call the + SPI_set_cmd_response() function. + + *//*=========================================================================*/ +#ifndef CORE_SPI_H_ +#define CORE_SPI_H_ + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#include "hal_assert.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + SPI FIFO Depth + ======================================= + SPI_MAX_FIFO_DEPTH & SPI_MIN_FIFO_DEPTH constants define the maximum and minimum + FIFO depths allowed for the CoreSPI instance. User need to inform the driver of + the FIFO depth for each CoreSPI instance to ensure that the FIFOs are managed correctly. + + | Constant | Description | + |--------------------|----------------------------------------------------| + | SPI_MAX_FIFO_DEPTH | Maximum FIFO depth allowed for the CoreSPI instance| + | SPI_MIN_FIFO_DEPTH | Minimum FIFO depth allowed for the CoreSPI instance| + + */ +#define SPI_MAX_FIFO_DEPTH 32u +#define SPI_MIN_FIFO_DEPTH 1u + +/***************************************************************************//** + Instances of this structure are used to identify the specific CoreSPI hardware + instances. A pointer to an instance of the spi_instance_t structure is passed + as the first parameter to the CoreSPI driver functions to identify which SPI + performs the requested operation. + */ +typedef struct spi_instance spi_instance_t; + +/***************************************************************************//** + This function pointer type is to assign a callback function for TX interrupt + when slave wants to send the next updated frame. + + Declaring and Implementing Slave Frame Transmit Handler Functions: + Slave transmit frame update handler functions should follow the following + prototype: + void slave_tx_frame_update_handler ( spi_instance_t * this_spi ); + The actual name of the transmit handler is unimportant. You can use any name + of your choice for the frame update handler. + + A common handler function may be used when multiple CoreSPI instances are + configured as slave, as the particular slave device currently requiring + service is indicated by the function parameter. + */ +typedef void (*spi_slave_frame_tx_handler_t)( spi_instance_t * this_spi ); + +/***************************************************************************//** + This defines the function prototype that must be followed by the SPI slave + frame receive handler functions. These functions are registered with the SPI + driver through the SPI_set_frame_rx_handler() function. + + Declaring and Implementing the Slave Frame Receive Handler Functions: + The Slave frame receive handler functions should follow the following + prototype: + void slave_frame_receive_handler(uint32_t rx_frame); + The actual name of the receive handler is unimportant. You can use any name + of your choice for the receive frame handler. The rx_frame parameter contains + the value of the received frame. + + Separate handler functions are required for each slave instance as there is + no indication of the slave requiring service passed to the handler. + + */ +typedef void (*spi_frame_rx_handler_t)( uint32_t rx_frame ); + +/***************************************************************************//** + This defines the function prototype that must be followed by SPI slave + block receive handler functions. These functions are registered with the + SPI driver through the SPI_set_slave_block_buffers() function. + + Declaring and Implementing Slave Block Receive Handler Functions: + Slave block receive handler functions should follow the following prototype: + void spi_block_rx_handler ( uint8_t * rx_buff, uint16_t rx_size ); + The actual name of the receive handler is unimportant. You can use any name + of your choice for the receive frame handler. The rx_buff parameter contains + a pointer to the start of the received block. The rx_size parameter contains + the number of bytes of the received block. + + Separate handler functions are required for each slave instance as there is + no indication of the slave requiring service passed to the handler. + + */ +typedef void (*spi_block_rx_handler_t)( uint8_t * rx_buff, uint32_t rx_size ); + +/***************************************************************************//** + This enumeration is used to select a specific SPI slave device (0 to 7). It is + used as a parameter to the SPI_configure_master_mode(), SPI_set_slave_select(), + and SPI_clear_slave_select() functions. + */ +typedef enum __spi_slave_t +{ + SPI_SLAVE_0 = 0, + SPI_SLAVE_1 = 1, + SPI_SLAVE_2 = 2, + SPI_SLAVE_3 = 3, + SPI_SLAVE_4 = 4, + SPI_SLAVE_5 = 5, + SPI_SLAVE_6 = 6, + SPI_SLAVE_7 = 7, + SPI_MAX_NB_OF_SLAVES = 8 +} spi_slave_t; + +/***************************************************************************//** + This enumeration is used to indicate the current slave mode transfer type so + that we are not relying on buffer comparisons to dictate the logic of the driver. + */ +typedef enum __spi_sxfer_mode_t +{ + SPI_SLAVE_XFER_NONE = 0, /* Not configured yet */ + SPI_SLAVE_XFER_BLOCK = 1, /* Block transfers, with SSEND delimiting end of block */ + SPI_SLAVE_XFER_FRAME = 2 /* Single frame transfers */ +} spi_sxfer_mode_t; + +/***************************************************************************//** + There is one instance of this structure for each of the core SPIs. Instances + of this structure are used to identify a specific SPI. A pointer to an + instance of the spi_instance_t structure is passed as the first parameter to + SPI driver functions to identify which SPI should perform the requested operation. + */ +struct spi_instance{ + + /* Base address in the processor's memory map for the + registers of the CoreSPI instance being initialized */ + addr_t base_addr; /* Base address of SPI hardware instance */ + + uint32_t rx_frame; /* received data */ + + /* Internal transmit state: */ + const uint8_t * slave_tx_buffer; /* Pointer to slave transmit buffer */ + uint32_t slave_tx_size; /* Size of slave transmit buffer */ + uint32_t slave_tx_idx; /* Current index into slave transmit buffer */ + + /* Slave command response buffer: */ + const uint8_t * resp_tx_buffer; + uint32_t resp_buff_size; + uint32_t resp_buff_tx_idx; + spi_block_rx_handler_t cmd_handler; + uint32_t cmd_done; /* Flag which indicates response has been set up and + it is safe to pad with 0s once the response is sent */ + + /* Internal receive state: */ + uint8_t * slave_rx_buffer; /* Pointer to buffer where data received by a slave will be stored */ + uint32_t slave_rx_size; /* Slave receive buffer size */ + uint32_t slave_rx_idx; /* Current index into slave receive buffer */ + + /* Slave received frame handler: */ + spi_frame_rx_handler_t frame_rx_handler; /* Pointer to function that will be called when a frame + is received when the SPI block is configured as slave */ + /* Slave transmitted frame handler: */ + uint32_t slave_tx_frame; /* Value of the data frame that will be transmitted + when the SPI block is configured as slave */ + spi_slave_frame_tx_handler_t slave_tx_frame_handler; /* Callback function pointer to update slave_tx_frame */ + + /* Slave block rx handler: */ + spi_block_rx_handler_t block_rx_handler; /* Pointer to the function that will be called when a data block has been received */ + + /* Per instance specific hardware information that the driver needs to know */ + uint16_t fifo_depth; /* Depth of RX and TX FIFOs in frames */ + + /* How we are expecting to deal with slave transfers */ + spi_sxfer_mode_t slave_xfer_mode; /* Current slave mode transfer configuration */ +}; + +/*------------------------Public Function-------------------------------------*/ + +/***************************************************************************//** + The SPI_init() function initializes the hardware and data structures of a + CoreSPI instance referenced by this_spi parameter. This function must be + called for each CoreSPI instance with a unique this_spi and base_addr + parameter combination. The SPI_init() function must be called before any + other CoreSPI driver functions are called. + + After calling the SPI_init() the CoreSPI is configured as a master, + all interrupt sources will be masked and all the slaves are deselected. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to be initialized. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @param base_addr + The base_addr parameter is the base address in the processor's memory map for + the registers of the CoreSPI instance being initialized. It is assumed that + any non NULL value passed in here points to a valid instance of a CoreSPI as + the driver has no way of verifying this. Failure to pass in a valid address + can result in system instability. + + @param fifo_depth + The fifo_depth parameter specifies the number of frames in the receive + and transmit FIFOs of the CoreSPI instance being initialized. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + @endcode + */ +void SPI_init +( + spi_instance_t * this_spi, + addr_t base_addr, + uint16_t fifo_depth +); + +/***************************************************************************//** + The SPI_configure_slave_mode() function is used when a CoreSPI instance is + to be configured as a SPI slave. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to be configured. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + + int main(void) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_slave_mode ( &g _spi0 ); + } + @endcode + */ +void SPI_configure_slave_mode +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_configure_master_mode() function is used when a CoreSPI instance is + to be configured as a SPI master. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to be configured. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + + int main(void) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_master_mode ( &g _spi0 ); + } + @endcode + */ +void SPI_configure_master_mode +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_set_slave_select() function is used by a CoreSPI master to select a + specific slave. This function causes the relevant slave select signal to be + asserted while data is clocked out onto the SPI data line. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param slave + The slave parameter is one of the spi_slave_t enumerated constants + identifying a slave. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + const uint32_t master_tx_frame = 0x0100A0E1; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0 ); + SPI_transfer_frame( &g_spi0, master_tx_frame ); + SPI_clear_slave_select( &g_spi0, SPI_SLAVE_0 ); + + @endcode + */ +void SPI_set_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +); + +/***************************************************************************//** + The SPI_clear_slave_select() function is used by a CoreSPI master to + deselect a specific slave. This function causes the relevant slave select + signal to be de-asserted. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param slave + The slave parameter is one of the spi_slave_t enumerated constants + identifying a slave. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + const uint32_t master_tx_frame = 0x0100A0E1; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0 ); + SPI_transfer_frame( &g_spi0, master_tx_frame ); + SPI_clear_slave_select( &g_spi0, SPI_SLAVE_0 ); + @endcode + */ +void SPI_clear_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +); + +/***************************************************************************//** + The SPI_transfer_frame() function is used by a SPI master to transmit and + receive a single frame of the size that has been configured at the time of + CoreSPI hardware instantiation. This function is typically used for + transactions with a SPI slave where the number of transmit and receive bits + are not divisible by 8 or where full duplex exchange of frames is required. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param tx_bits + The tx_bits parameter is a 32-bit word containing the value that will be + transmitted. If the frame size configured for the CoreSPI is less than 32-bits, + the upper bits will be ignored. + Note: The bit length of the value to be transmitted to the slave is + set when the CoreSPI is instantiated in the hardware design. + + @return + This function returns a 32-bit word containing the value that is received + from the slave. If the frame size configured for the CoreSPI in question is + less that 32-bits, the upper bits will be 0. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + const uint32_t master_tx_frame = 0x0100A0E1; + uint32_t master_rx; + + SPI_init(&g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ); + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0 ); + master_rx = SPI_transfer_frame( &g_spi0, master_tx_frame ); + SPI_clear_slave_select( &g_spi0, SPI_SLAVE_0 ); + @endcode + */ +uint32_t SPI_transfer_frame +( + spi_instance_t * this_spi, + uint32_t tx_bits +); + +/***************************************************************************//** + The SPI_transfer_block() function is used by the SPI master to transmit and + receive blocks of data organized as a specified number of 8-bit frames. It + can be used for the following: + • Writing a data block to a slave + • Reading a data block from a slave + • Sending a command to a slave followed by reading the outcome of + the command in a single SPI transaction. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param cmd_buffer + The cmd_buffer parameter is a pointer to the buffer that contains the data + sent by the master from the beginning of the transfer. This pointer can be + null (0) if the master does not need to send a command before reading data. + + @param cmd_byte_size + The cmd_byte_size parameter specifies the number of bytes in cmd_buffer that + will be sent. A value ‘0’ indicates that no data needs to be sent to the slave. + + @param rx_buffer + The rx_buffer parameter is a pointer to the buffer that stores the data received + from the slave after sending the command. This pointer can be null (0) if the + master does not receive any data from the slave. + + @param rx_byte_size + The rx_byte_size parameter specifies the number of bytes received from + the slave and stored in the rx_buffer. A value ‘0’ indicates that no data is + to be read from the slave. + + @return + This function does not return any value. + + @example + @code + Polled write transfer example + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + + uint8_t master_tx_buffer[MASTER_TX_BUFFER] = + { + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A + }; + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0) ; + SPI_transfer_block + ( + &g_spi0, + master_tx_buffer, + sizeof(master_tx_buffer), + 0, + 0 + ); + SPI_clear_slave_select(&g_spi0, SPI_SLAVE_0 ); + @endcode + */ +void SPI_transfer_block +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_buffer, + uint16_t rx_byte_size +); + +/***************************************************************************//** + The SPI_transfer_block_store_all_resp() function is used by the SPI master + to transmit and receive blocks of data organized as a specified number + of 8-bit frames. It can be used for the following: + • Writing a data block to a slave + • Reading a data block from a slave + • Sending a command to a slave followed by reading the outcome of + the command in a single SPI transaction + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param cmd_buffer + The cmd_buffer parameter is a pointer to the buffer that contains the data sent by + the master from the beginning of the transfer. This pointer can be null (0) + if the master does not need to send a command before reading data. + + @param cmd_byte_size + The cmd_byte_size parameter specifies the number of bytes contained in + cmd_buffer that will be sent. A value ‘0’ indicates that no data needs + to be sent to the slave. + + @param rx_data_buffer + The rx_data_buffer parameter is a pointer to the buffer that stores the data received + from the slave after sending the command. This pointer can be null (0) if the + master does not receive any data from the slave. + + @param rx_byte_size + The rx_byte_size parameter specifies the number of bytes received from + the slave and stores in the rx_buffer. A value ‘0’ indicates that no data is + to be read from the slave. + + @param cmd_response_buffer + The cmd_response_buffer parameter is a pointer to the buffer which stores the + command response from the slave, while the master is transmitting the number + of bytes indicated by cmd_byte_size parameter. + + @return + This function does not return any value. + + @example + @code + Polled write transfer example + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + + uint8_t master_tx_buffer[MASTER_TX_BUFFER] = + { + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A + }; + + uint8_t cmd_rx_buffer[CMD_RX_BUFFER]={0}; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0) ; + SPI_transfer_block_store_all_resp + ( + &g_spi0, + master_tx_buffer, + sizeof(master_tx_buffer), + 0, + 0, + cmd_response_buffer + ); + SPI_clear_slave_select(&g_spi0, SPI_SLAVE_0 ); + @endcode + */ +void SPI_transfer_block_store_all_resp +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_data_buffer, + uint16_t rx_byte_size, + uint8_t * cmd_response_buffer +); + +/***************************************************************************//** + The SPI_set_frame_rx_handler() function is used by the SPI slaves to specify + the receive handler function that is called by the SPI driver interrupt + handler when a frame of data is received by the SPI slave. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param rx_handler + The rx_handler parameter is a pointer to the frame receive handler that must + be called when a frame is received by the CoreSPI slave. Passing in a NULL + pointer disables the receive handler but does enable the receive interrupt to + ensure the RX FIFO is empty each time a frame is received. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + uint32_t g_slave_rx_frame = 0; + spi_instance_t g_spi0; + + void slave_frame_handler(uint32_t rx_frame) + { + g_slave_rx_frame = rx_frame; + } + int setup_slave( void ) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_slave_mode( &g_spi0 ); + SPI_set_frame_rx_handler( &g_spi0, slave_frame_handler ); + } + @endcode + */ +void SPI_set_frame_rx_handler +( + spi_instance_t * this_spi, + spi_frame_rx_handler_t rx_handler +); + +/***************************************************************************//** + The SPI_set_slave_tx_frame() function is used by the SPI slaves to specify + the frame that gets transmitted when a transaction is initiated by the SPI + master. This function allows you to assign a slave_tx_frame_handler function, + which will be executed upon transmit interrupt when the SPI is in slave mode. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param frame_value + The frame_value parameter contains the value of the frame to be sent to the + master. + Note: The bit length of the value to be transmitted to the master is + set when the CoreSPI is instantiated in the hardware design. + + @param slave_tx_frame_handler + The slave_tx_frame_handler function pointer is executed upon occurrence of + transmit interrupt when CoreSPI is operating in slave mode. This parameter + is optional and if set to NULL it is assumed that the frame value is static or + updated asynchronously. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + const uint32_t slave_tx_frame[2] = { 0x0110F761, 0x0110F671 }; + uint32_t master_rx; + uint32_t slave_frame_idx = 0 ; + + slave_frame_update( spi_instance_t * this_spi ) + { + this_spi->slave_tx_frame = slave_tx_frame[slave_frame_idx++]; + if( slave_frame_idx > 2 ) + slave_frame_idx = 0; + } + main() + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ) ; + SPI_set_slave_tx_frame( &g_spi0, slave_tx_frame[slave_frame_idx++], + &slave_frame_update ); + } + @endcode + */ +void SPI_set_slave_tx_frame +( + spi_instance_t * this_spi, + uint32_t frame_value, + spi_slave_frame_tx_handler_t slave_tx_frame_handler +); + +/***************************************************************************//** + The SPI_set_slave_block_buffers() function is used to configure an SPI slave + for block transfer operations. It specifies one or more of the following: + • The data that is transmitted when accessed by a master. + • The buffer where the data received from a master is stored. + • The handler function that must be called after the receive buffer has + been filled. + • The number of bytes that must be received from the master before calling + the recieve handler function. + These parameters allow the following use cases: + • Slave performing an action after receiving a block of data from a + master containing a command. This action is performed by the + receive handler based on the content of the receive data buffer. + • Slave returning a block of data to the master. The type of information + is always the same but the actual values change over time. For example, + returning the voltage of a predefined set of analog inputs. + • Slave returning data based on a command contained in the first part of + the SPI transaction. For example, reading the voltage of the analog + input specified by the first data byte by the master. This is achieved + by using the SPI_set_slave_block_buffers() function in conjunction with + functions SPI_set_cmd_handler() and SPI_set_cmd_response(). + + See the SPI_set_cmd_handler() function description for details of + this use case. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param tx_buffer + The tx_buffer parameter is a pointer to a buffer containing the data that + will be sent to the master. This parameter can be set to ‘0’ if the SPI + slave is not intended to be the target of SPI read transactions. + + @param tx_buff_size + The tx_buff_size parameter specifies the number of bytes that are + transmitted by the SPI slave. It is the number of bytes contained in the + tx_buffer. This parameter can be set to ‘0’ if the SPI slave is not + intended to be the target of SPI read transactions. The driver returns 0s + to the master if there is no buffer specified or the master reads beyond the + end of the buffer. + Note: If SPI_transfer_block() is used to read from this slave and there is + no command handler involved, the buffer size here must be at least the + combined length of the command and response specified by the master. + On receiving this data, the master discards the data bytes equal to + command length bytes from the start of the received buffer. + + @param rx_buffer + The rx_buffer parameter is a pointer to the buffer where data received + from the master is stored. This parameter can be set to ‘0’ if the + SPI slave is not intended to be the target of SPI write or write-read + transactions. + + @param rx_buff_size + The rx_buff_size parameter specifies the size of the receive buffer. It is + also the number of bytes that must be received before the receive handler + is called, if a receive handler is specified using the block_rx_handler + parameter. Any bytes received in excess of the size specified by the + rx_buff_size parameter are discarded. This parameter can be set to ‘0’ + if the SPI slave is not intended to be the target of SPI write or + write-read transactions. + + @param block_rx_handler + The block_rx_handler parameter is a pointer to a function that is called + when receive buffer has been filled or the slave select has been de-asserted. + This parameter can be set to ‘0’ if the SPI slave is not intended to be the + target of SPI write or write-read transactions. + + @return + This function does not return any value. + + @example + @code + Slave Performing Operation Based on Master Command: + In this example the SPI slave is configured to receive 10 bytes of data + or command from the SPI slave, and process the data received from the master. + + #define SPI0_BASE_ADDR 0xC2000000 + + uint32_t nb_of_rx_handler_calls = 0; + spi_instance_t g_spi0; + + void spi1_block_rx_handler_b + ( + uint8_t * rx_buff, + uint16_t rx_size + ) + { + ++nb_of_rx_handler_calls; + } + + void setup_slave( void ) + { + uint8_t slave_rx_buffer[10] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_slave_mode( &g_spi0 ); + + SPI_set_slave_block_buffers + ( + &g_spi0, + 0, + 0, + slave_rx_buffer, + sizeof( master_tx_buffer ), + spi1_block_rx_handler_b + ); + } + @endcode + */ +void SPI_set_slave_block_buffers +( + spi_instance_t * this_spi, + const uint8_t * tx_buffer, + uint32_t tx_buff_size, + uint8_t * rx_buffer, + uint32_t rx_buff_size, + spi_block_rx_handler_t block_rx_handler +); + +/***************************************************************************//** + The SPI_isr() function is the top level interrupt handler function for the + CoreSPI driver. You must call SPI_isr() from the system level + (CoreInterrupt and NVIC level) interrupt handler assigned to the interrupt + triggered by the CoreSPI SPIINT signal. Your system level interrupt handler + must also clear the system level interrupt triggered by the CoreSPI SPIINT + signal before returning, to prevent a re-assertion of the same interrupt. + + This function supports all types of interrupt triggered by CoreSPI. It is not + a complete interrupt handler by itself; rather, it is a top level wrapper that + abstracts CoreSPI command interrupt and slave mode transmit interrupt handling + by calling lower level handler functions specific to each type of CoreSPI + interrupt. You must create the lower level handler functions to suit your + application and register them with the driver through calling the + SPI_set_cmd_handler(), SPI_set_cmd_response(), and SPI_set_slave_tx_frame() + functions. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + + @example + @code + + Example of configuring a CoreInterrupt connected to the Fabric Interrupt on a + SmartFusion device to handle CoreSPI interrupt. + + #define #define SPI1_INT_IRQ_NB 0 + spi_instance_t g_spi0; + + Void CIC_irq1_handler(void) + { + SPI_isr( &g_spi0 ); + } + + void Fabric_IRQHandler( void ) + { + // Call the CoreInterrupt driver ISR to determine the source of the + // interrupt and call the relevant ISR registered to it. + CIC_irq_handler(); + + // Clear NVIC interrupt status to allow further interrupts + NVIC_ClearPendingIRQ( Fabric_IRQn ); + } + + main() + { + ... + + CIC_init( CIC_BASE_ADDR ); + + // Install handler for SPI IRQ + CIC_set_irq_handler( SPI0_INT_IRQ_NB, CIC_irq1_handler ); + + NVIC_ClearPendingIRQ( Fabric_IRQn ); + NVIC_EnableIRQ( Fabric_IRQn ); + + CIC_enable_irq( SPI1_INT_IRQ_NB ); + + ... + } + @endcode + */ +void SPI_isr +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_set_cmd_handler() function specifies a command handler function that + will be called when the number of bytes received reaches the command size + specified as cmd_size parameter. + + This function is used by the SPI slaves performing block transfers. Its + purpose is to allow an SPI slave to decide the data that will be returned to + the master while an SPI transaction is taking place. Typically, one or more + command bytes are sent by the master to request some specific data. The slave + interprets the command byte(s) while one or more turn-around bytes are + transmitted. The slave adjusts its transmit data buffer based on the command + during the turn around time. + + The following table provides an example of the use of this function where the + SPI slave returns data bytes D0 to D6 based on the value of a command. The + 3 bytes long command is made up of a command opcode byte followed by an + address byte followed by a size byte. The cmd_handler() function specified + through an earlier call to SPI_set_cmd_handler() is called by the CoreSPI + driver once the third byte is received. The cmd_handler() function + interprets the command bytes and calls SPI_set_cmd_response() to set the SPI + slave's response transmit buffer with the data to be transmitted after the + turnaround bytes (T0 to T3). The number of turnaround bytes must be + sufficient to give enough time for the cmd_handler() to execute. The number + of turnaround bytes is specified by the protocol used on top of the SPI + transport layer so that master and slave agree on the number of turn around + bytes. + +|Timestamp| SPI Transaction | Bytes | Comments | +|---------|-------------|----------------------|---------------| +| t0|COMMAND|C A S |C - command opcode byte, A - address byte, S - size byte| +|t1| TURN-AROUND|T0 T1 |cmd_handler() called here (T0 to T3 are TURN-AROUND bytes)| +|t2|TURN-AROUND|T2 T3|SPI_set_cmd_response() called here by implementation of cmd_handler() +|| | |to set the data that will be transmitted by the SPI slave.| +|t3| DATA | D0 D1 D2 D3 D4 D5 D6 |Data transmition (SPI slave return data bytes)| + + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure identifying + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @param cmd_handler + The cmd_handler parameter is a pointer to a function with the prototype: + void cmd_handler(uint8_t * rx_buff, uint32_t rx_size); + It specifies the function that will be called when the number of bytes + specified by the cmd_size parameter has been received. + + @param cmd_size + The cmd_size parameter specifies the number of bytes that must be received + before calling the command handler function specified by the cmd_handler. + The CoreSPI supports cmd_size values in the range 1 to 7. + + @return + This function does not return any value. + + @example + @code + The following example demonstrates how to configure CoreSPI to implement + the protocol given as an example above. The configure_slave() function + configures CoreSPI. It sets receive and transmit buffers. The transmit + buffer specified through the call to SPI_set_slave_block_buffers() function + specifies the data that will be returned to the master in bytes between + t0 and t3. These bytes will be sent to the master while the master transmits + the command and dummy bytes. The spi_slave_cmd_handler() function will be + called by the driver at time t1 after the 3 command bytes have been received. + The spi_block_rx_handler() function will be called by the driver at time t4, + when the transaction completes and the slave select signal becomes + de-asserted. + + #define SPI0_BASE_ADDR 0xC2000000 + #define COMMAND_SIZE 3 + #define NB_OF_DUMMY_BYTES 4 + #define MAX_TRANSACTION_SIZE 16 + + spi_instance_t g_spi0; + uint8_t slave_tx_buffer[COMMAND_SIZE + NB_OF_DUMMY_BYTES]; + uint8_t slave_rx_buffer[MAX_TRANSACTION_SIZE]; + + void configure_slave( void ) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_slave_mode( &g_spi0 ); + SPI_set_slave_block_buffers + ( + &g_spi0, + slave_tx_buffer, + COMMAND_SIZE + NB_OF_DUMMY_BYTES, + slave_rx_buffer, + sizeof(slave_rx_buffer), + spi_block_rx_handler + ); + + SPI_set_cmd_handler + ( + &g_spi0, + spi_slave_cmd_handler, + COMMAND_SIZE + ); + } + + void spi_slave_cmd_handler + ( + uint8_t * rx_buff, + uint32_t rx_size + ) + { + uint8_t command; + uint8_t address; + uint8_t size; + uint8_t * p_response; + uint32_t response_size; + + command = rx_buff[0]; + address = rx_buff[1]; + size = rx_buff[2]; + + p_response = get_response_data( command, address, size, &response_size ); + SPI_set_cmd_response( &g_spi0, p_response, response_size ); + } + + void spi_block_rx_handler + ( + uint8_t * rx_buff, + uint32_t rx_size + ) + { + process_rx_data( rx_buff, rx_size ); + } + @endcode + */ +void SPI_set_cmd_handler +( + spi_instance_t * this_spi, + spi_block_rx_handler_t cmd_handler, + uint32_t cmd_size +); + +/***************************************************************************//** + The SPI_set_cmd_response() function specifies the data that will be returned + to the master. See the description of SPI_set_cmd_handler() for details. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param resp_tx_buffer + The resp_tx_buffer parameter is a pointer to the buffer containing the data + that must be returned to the host in the data phase of an SPI transaction. + + @param resp_buff_size + The resp_buff_size parameter specifies the size of the buffer pointed by the + resp_tx_buffer parameter. + + @return + This function does not return any value. + */ +void SPI_set_cmd_response +( + spi_instance_t * this_spi, + const uint8_t * resp_tx_buffer, + uint32_t resp_buff_size +); + +/***************************************************************************//** + The SPI_enable() function enables the CoreSPI and allows it to respond to the external + signals. It is usually called to re-enable a CoreSPI instance which has been + disabled previously via by calling the SPI_disable() as the normal state of a CoreSPI + after enabling the initialization. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + */ +void SPI_enable +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_disable() function disables the CoreSPI and stops responding to the + external signals. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + */ +void SPI_disable +( + spi_instance_t * this_spi +); + +#ifdef __cplusplus +} +#endif + +#endif /* CORE_SPI_H_*/ diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreSPI/corespi_regs.h b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreSPI/corespi_regs.h new file mode 100644 index 0000000..a3e5b2a --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreSPI/corespi_regs.h @@ -0,0 +1,270 @@ +/***************************************************************************//** + * Copyright 2011-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file corespi_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreSPI memory map + * + */ + +#ifndef CORESPI_REGS_H_ +#define CORESPI_REGS_H_ + +/******************************************************************************* + * Control register 1: + *------------------------------------------------------------------------------ + */ +#define CTRL1_REG_OFFSET 0x00u + +#define CTRL1_ENABLE_OFFSET 0x00u +#define CTRL1_ENABLE_MASK 0x01u +#define CTRL1_ENABLE_SHIFT 0x00 + +#define CTRL1_MASTER_OFFSET 0x00u +#define CTRL1_MASTER_MASK 0x02u +#define CTRL1_MASTER_SHIFT 0x01 + +#define CTRL1_INTRXDATA_OFFSET 0x00u +#define CTRL1_INTRXDATA_MASK 0x04u +#define CTRL1_INTRXDATA_SHIFT 0x02 + +#define CTRL1_INTTXDONE_OFFSET 0x00u +#define CTRL1_INTTXDONE_MASK 0x08u +#define CTRL1_INTTXDONE_SHIFT 0x03 + +#define CTRL1_INTRXOVFLOW_OFFSET 0x00u +#define CTRL1_INTRXOVFLOW_MASK 0x10u +#define CTRL1_INTRXOVFLOW_SHIFT 0x04 + +#define CTRL1_INTTXURUN_OFFSET 0x00u +#define CTRL1_INTTXURUN_MASK 0x20u +#define CTRL1_INTTXURUN_SHIFT 0x05 + +#define CTRL1_FRAMEURUN_OFFSET 0x00u +#define CTRL1_FRAMEURUN_MASK 0x40u +#define CTRL1_FRAMEURUN_SHIFT 0x06 + +#define CTRL1_OENOFF_OFFSET 0x00u +#define CTRL1_OENOFF_MASK 0x80u +#define CTRL1_OENOFF_SHIFT 0x07 + +/******************************************************************************* + * Interrupt clear register: + *------------------------------------------------------------------------------ + */ +#define INTCLR_REG_OFFSET 0x04u + +#define INTCLR_TXDONE_OFFSET 0x04u +#define INTCLR_TXDONE_MASK 0x01u +#define INTCLR_TXDONE_SHIFT 0x00 + +#define INTCLR_RXDONE_OFFSET 0x04u +#define INTCLR_RXDONE_MASK 0x02u +#define INTCLR_RXDONE_SHIFT 0x01 + +#define INTCLR_RXOVERFLOW_OFFSET 0x04u +#define INTCLR_RXOVERFLOW_MASK 0x04u +#define INTCLR_RXOVERFLOW_SHIFT 0x02 + +#define INTCLR_TXUNDERRUN_OFFSET 0x04u +#define INTCLR_TXUNDERRUN_MASK 0x08u +#define INTCLR_TXUNDERRUN_SHIFT 0x03 + +#define INTCLR_CMDINT_OFFSET 0x04u +#define INTCLR_CMDINT_MASK 0x10u +#define INTCLR_CMDINT_SHIFT 0x04 + +#define INTCLR_SSEND_OFFSET 0x04u +#define INTCLR_SSEND_MASK 0x20u +#define INTCLR_SSEND_SHIFT 0x05 + +#define INTCLR_RXDATA_OFFSET 0x04u +#define INTCLR_RXDATA_MASK 0x40u +#define INTCLR_RXDATA_SHIFT 0x06 + +#define INTCLR_TXDATA_OFFSET 0x04u +#define INTCLR_TXDATA_MASK 0x80u +#define INTCLR_TXDATA_SHIFT 0x07 + +/******************************************************************************* + * Receive data register: + *------------------------------------------------------------------------------ + */ +#define RXDATA_REG_OFFSET 0x08u + +/******************************************************************************* + * Transmit data register: + *------------------------------------------------------------------------------ + */ +#define TXDATA_REG_OFFSET 0x0Cu + +/******************************************************************************* + * Masked interrupt status register: + *------------------------------------------------------------------------------ + */ +#define INTMASK_REG_OFFSET 0x10u + +#define INTMASK_TXDONE_OFFSET 0x10u +#define INTMASK_TXDONE_MASK 0x01u +#define INTMASK_TXDONE_SHIFT 0x00 + +#define INTMASK_RXDONE_OFFSET 0x10u +#define INTMASK_RXDONE_MASK 0x02u +#define INTMASK_RXDONE_SHIFT 0x01 + +#define INTMASK_RXOVERFLOW_OFFSET 0x10u +#define INTMASK_RXOVERFLOW_MASK 0x04u +#define INTMASK_RXOVERFLOW_SHIFT 0x02 + +#define INTMASK_TXUNDERRUN_OFFSET 0x10u +#define INTMASK_TXUNDERRUN_MASK 0x08u +#define INTMASK_TXUNDERRUN_SHIFT 0x03 + +#define INTMASK_CMDINT_OFFSET 0x10u +#define INTMASK_CMDINT_MASK 0x10u +#define INTMASK_CMDINT_SHIFT 0x04 + +#define INTMASK_SSEND_OFFSET 0x10u +#define INTMASK_SSEND_MASK 0x20u +#define INTMASK_SSEND_SHIFT 0x05 + +#define INTMASK_RXDATA_OFFSET 0x10u +#define INTMASK_RXDATA_MASK 0x40u +#define INTMASK_RXDATA_SHIFT 0x06 + +#define INTMASK_TXDATA_OFFSET 0x10u +#define INTMASK_TXDATA_MASK 0x80u +#define INTMASK_TXDATA_SHIFT 0x07 + +/******************************************************************************* + * Raw interrupt status register: + *------------------------------------------------------------------------------ + */ +#define INTRAW_REG_OFFSET 0x14u + +#define INTRAW_TXDONE_OFFSET 0x14u +#define INTRAW_TXDONE_MASK 0x01u +#define INTRAW_TXDONE_SHIFT 0x00 + +#define INTRAW_RXDONE_OFFSET 0x14u +#define INTRAW_RXDONE_MASK 0x02u +#define INTRAW_RXDONE_SHIFT 0x01 + +#define INTRAW_RXOVERFLOW_OFFSET 0x14u +#define INTRAW_RXOVERFLOW_MASK 0x04u +#define INTRAW_RXOVERFLOW_SHIFT 0x02 + +#define INTRAW_TXUNDERRUN_OFFSET 0x14u +#define INTRAW_TXUNDERRUN_MASK 0x08u +#define INTRAW_TXUNDERRUN_SHIFT 0x03 + +#define INTRAW_CMDINT_OFFSET 0x14u +#define INTRAW_CMDINT_MASK 0x10u +#define INTRAW_CMDINT_SHIFT 0x04 + +#define INTRAW_SSEND_OFFSET 0x14u +#define INTRAW_SSEND_MASK 0x20u +#define INTRAW_SSEND_SHIFT 0x05 + +#define INTRAW_RXDATA_OFFSET 0x14u +#define INTRAW_RXDATA_MASK 0x40u +#define INTRAW_RXDATA_SHIFT 0x06 + +#define INTRAW_TXDATA_OFFSET 0x14u +#define INTRAW_TXDATA_MASK 0x80u +#define INTRAW_TXDATA_SHIFT 0x07 + +/******************************************************************************* + * Control register 2: + *------------------------------------------------------------------------------ + */ +#define CTRL2_REG_OFFSET 0x18u + +#define CTRL2_CMDSIZE_OFFSET 0x18u +#define CTRL2_CMDSIZE_MASK 0x07u +#define CTRL2_CMDSIZE_SHIFT 0x00 + +#define CTRL2_INTCMD_OFFSET 0x18u +#define CTRL2_INTCMD_MASK 0x10u +#define CTRL2_INTCMD_SHIFT 0x04 + +#define CTRL2_INTSSEND_OFFSET 0x18u +#define CTRL2_INTSSEND_MASK 0x20u +#define CTRL2_INTSSEND_SHIFT 0x05 + +#define CTRL2_INTRXDATA_OFFSET 0x18u +#define CTRL2_INTRXDATA_MASK 0x40u +#define CTRL2_INTRXDATA_SHIFT 0x06 + +#define CTRL2_INTTXDATA_OFFSET 0x18u +#define CTRL2_INTTXDATA_MASK 0x80u +#define CTRL2_INTTXDATA_SHIFT 0x07 + +/******************************************************************************* + * Command register: + *------------------------------------------------------------------------------ + */ +#define CMD_REG_OFFSET 0x1Cu + +#define CMD_RXFIFORST_OFFSET 0x1Cu +#define CMD_RXFIFORST_MASK 0x01u +#define CMD_RXFIFORST_SHIFT 0x00 + +#define CMD_TXFIFORST_OFFSET 0x1Cu +#define CMD_TXFIFORST_MASK 0x02u +#define CMD_TXFIFORST_SHIFT 0x01 + +/******************************************************************************* + * Status register: + *------------------------------------------------------------------------------ + */ +#define STATUS_REG_OFFSET 0x20u + +#define STATUS_FIRSTFRAME_OFFSET 0x20u +#define STATUS_FIRSTFRAME_MASK 0x01u +#define STATUS_FIRSTFRAME_SHIFT 0x00 + +#define STATUS_DONE_OFFSET 0x20u +#define STATUS_DONE_MASK 0x02u +#define STATUS_DONE_SHIFT 0x01 + +#define STATUS_RXEMPTY_OFFSET 0x20u +#define STATUS_RXEMPTY_MASK 0x04u +#define STATUS_RXEMPTY_SHIFT 0x02 + +#define STATUS_TXFULL_OFFSET 0x20u +#define STATUS_TXFULL_MASK 0x08u +#define STATUS_TXFULL_SHIFT 0x03 + +#define STATUS_RXOVFLOW_OFFSET 0x20u +#define STATUS_RXOVFLOW_MASK 0x10u +#define STATUS_RXOVFLOW_SHIFT 0x04 + +#define STATUS_TXUNDERRUN_OFFSET 0x20u +#define STATUS_TXUNDERRUN_MASK 0x20u +#define STATUS_TXUNDERRUN_SHIFT 0x05 + +#define STATUS_SSEL_OFFSET 0x20u +#define STATUS_SSEL_MASK 0x40u +#define STATUS_SSEL_SHIFT 0x06 + +#define STATUS_ACTIVE_OFFSET 0x20u +#define STATUS_ACTIVE_MASK 0x80u +#define STATUS_ACTIVE_SHIFT 0x07 + +/******************************************************************************* + * Slave select register: + *------------------------------------------------------------------------------ + */ +#define SSEL_REG_OFFSET 0x24u + +/******************************************************************************* + * Transmit data last register: + *------------------------------------------------------------------------------ + */ +#define TXLAST_REG_OFFSET 0x28u + + +#endif /*CORESPI_REGS_H_*/ diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.c b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.c new file mode 100644 index 0000000..b8adaed --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.c @@ -0,0 +1,889 @@ +/******************************************************************************* + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * PF_System_Services driver implementation. See file "core_syservices_pf.h" for + * description of the functions implemented in this file. + * + */ + +#include "core_sysservices_pf.h" +#include "coresysservicespf_regs.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define NULL_BUFFER (( uint8_t* ) 0) + +static uint8_t execute_ss_command +( + uint8_t cmd_opcode, + const uint8_t* cmd_data, + uint16_t cmd_data_size, + const uint8_t* p_response, + uint16_t response_size, + uint16_t mb_offset, + uint16_t response_offset +); + +uint32_t g_css_pf_base_addr = 0u; + +/***************************************************************************//** + * SYS_init() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +void +SYS_init +( + uint32_t base_addr +) +{ + g_css_pf_base_addr = base_addr; +} + +/***************************************************************************//** + * SYS_get_serial_number() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_serial_number +( + const uint8_t * p_serial_number, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if (p_serial_number == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(SERIAL_NUMBER_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_serial_number, + SERIAL_NUMBER_RESP_LEN, + mb_offset, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_get_user_code() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_user_code +( + const uint8_t * p_user_code, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_user_code == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(USERCODE_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_user_code, + USERCODE_RESP_LEN, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_get_design_info() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_design_info +( + const uint8_t * p_design_info, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_design_info == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(DESIGN_INFO_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_design_info, + DESIGN_INFO_RESP_LEN, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_get_device_certificate() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_device_certificate +( + const uint8_t * p_device_certificate, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_device_certificate == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(DEVICE_CERTIFICATE_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_device_certificate, + DEVICE_CERTIFICATE_RESP_LEN, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_read_digest() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_read_digest +( + const uint8_t * p_digest, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_digest == NULL_BUFFER) + { + return status; + } + +#ifndef CORESYSSERVICES_MPFS + status = execute_ss_command(READ_DIGEST_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_digest, + READ_DIGEST_RESP_LEN, + mb_offset, + 0u); +#else + status = execute_ss_command(READ_DIGEST_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_digest, + READ_DIGEST_MPFS_RESP_LEN, + mb_offset, + 0u); +#endif + return status; + +} + +/***************************************************************************//** + * SYS_query_security() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_query_security +( + uint8_t * p_security_locks, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint8_t idx = 0u; + + if(p_security_locks == NULL_BUFFER) + { + return status; + } + +#ifndef CORESYSSERVICES_MPFS + uint8_t buf[12] = {0}; + /* Actual QUERY_SECURITY_RESP_LEN is 9 or 33 but PF_System_Services core + * needs number of words instead of number of bytes to be written to or read + * from MailBox */ + status = execute_ss_command(QUERY_SECURITY_REQUEST_CMD, + NULL_BUFFER, + 0u, + buf, + (QUERY_SECURITY_RESP_LEN + 3u), + mb_offset, + 0u); + + for (idx = 0u; idx < 9u; idx++) + { + *(p_security_locks+idx) = buf[idx]; + } + +#else + uint8_t buf[36] = {0}; + + status = execute_ss_command(QUERY_SECURITY_REQUEST_CMD, + NULL_BUFFER, + 0u, + buf, + (QUERY_SECURITY_MPFS_RESP_LEN + 3u), + mb_offset, + 0u); + + for (idx = 0u; idx < 33u; idx++) + { + *(p_security_locks+idx) = buf[idx]; + } + +#endif + + return status; +} + +/***************************************************************************//** + * SYS_read_debug_info() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_read_debug_info +( + const uint8_t * p_debug_info, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_debug_info == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(READ_DEBUG_INFO_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_debug_info, + READ_DEBUG_INFO_RESP_LEN, + mb_offset, + 0u); + return status; +} + +#ifdef CORESYSSERVICES_MPFS +/***************************************************************************//** + * SYS_read_envm_parameter() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_read_envm_parameter +( + uint8_t * p_envm_param, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_envm_param == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(READ_ENVM_PARAM_REQUEST_CMD, + NULL_BUFFER, + 0, + p_envm_param, + READ_ENVM_PARAM_RESP_LEN, + mb_offset, + 0); + return status; +} + +#endif + +/***************************************************************************//** + * SYS_puf_emulation_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_puf_emulation_service +( + const uint8_t * p_challenge, + uint8_t op_type, + uint8_t* p_response, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint8_t mb_format[20] = {0x00}; + uint8_t index = 0u; + + if((p_response == NULL_BUFFER) || (p_challenge == NULL_BUFFER)) + { + return status; + } + + /* Frame the data required for mailbox */ + mb_format[index] = op_type; + + for (index = 4u; index < 20u; index++) + { + mb_format[index] = p_challenge[index - 4u]; + } + + status = execute_ss_command(PUF_EMULATION_SERVICE_REQUEST_CMD, + mb_format, + PUF_EMULATION_SERVICE_CMD_LEN, + p_response, + PUF_EMULATION_SERVICE_RESP_LEN, + mb_offset, + 5u); /* mentioning offset to number of words instead of bytes */ + + return status; +} + +/***************************************************************************//** + * SYS_digital_signature_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_digital_signature_service +( + const uint8_t* p_hash, + uint8_t format, + uint8_t* p_response, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if((p_hash == NULL_BUFFER) || (p_response == NULL_BUFFER)) + { + return status; + } + + if (format == DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD) + { + status = execute_ss_command(DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD, + p_hash, + DIGITAL_SIGNATURE_HASH_LEN, + p_response, + DIGITAL_SIGNATURE_RAW_FORMAT_RESP_SIZE, + mb_offset, + 12u); /* mentioning offset to number of words instead of bytes */ + } + else + { + status = execute_ss_command(DIGITAL_SIGNATURE_DER_FORMAT_REQUEST_CMD, + p_hash, + DIGITAL_SIGNATURE_HASH_LEN, + p_response, + DIGITAL_SIGNATURE_DER_FORMAT_RESP_SIZE, + mb_offset, + 12u); /* mentioning offset to number of words instead of bytes */ + } + + return status; +} + +/***************************************************************************//** + * SYS_secure_nvm_write() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_secure_nvm_write +( + uint8_t format, + uint8_t snvm_module, + const uint8_t* p_data, + const uint8_t* p_user_key, + uint16_t mb_offset +) +{ + uint8_t frame[256] = {0x00}; + uint8_t* p_frame = &frame[0]; + uint16_t index = 0u; + uint8_t status = SYS_PARAM_ERR; + + HAL_ASSERT(!(NULL_BUFFER == p_data)); + HAL_ASSERT(!(snvm_module >= 221u)); + if (format != SNVM_NON_AUTHEN_TEXT_REQUEST_CMD) + { + HAL_ASSERT(!(NULL_BUFFER == p_user_key)); + } + + if ((p_data == NULL_BUFFER) || (snvm_module >= 221)) + { + return status; + } + + if ((format != SNVM_NON_AUTHEN_TEXT_REQUEST_CMD) + && (p_user_key == NULL_BUFFER)) + { + return status; + } + + if ((format != SNVM_NON_AUTHEN_TEXT_REQUEST_CMD) + && (format != SNVM_AUTHEN_TEXT_REQUEST_CMD) + && (format != SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD)) + { + return status; + } + + *p_frame = snvm_module; /* SNVMADDR - SNVM module */ + + p_frame += 4u; /* Next 3 bytes RESERVED - For alignment */ + + /* Copy user key and send the command/data to mailbox. */ + if ((format == SNVM_AUTHEN_TEXT_REQUEST_CMD) || + (format == SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD)) + { + /* Copy user data */ + for (index = 0u; index < (AUTHENTICATED_TEXT_DATA_LEN - USER_SECRET_KEY_LEN - 4u); index++) + { + *p_frame = p_data[index]; + p_frame++; + } + + /* Copy user key */ + for (index = 0u; index < USER_SECRET_KEY_LEN; index++) + { + *p_frame = p_user_key[index]; + p_frame++; + } + + status = execute_ss_command(format, + &frame[0], + AUTHENTICATED_TEXT_DATA_LEN, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + } + else + { + /* Copy user data */ + for (index = 0u; index < (NON_AUTHENTICATED_TEXT_DATA_LEN - 4u); index++) + { + *(p_frame+index) = p_data[index]; + } + + status = execute_ss_command(format, + &frame[0], + NON_AUTHENTICATED_TEXT_DATA_LEN, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + } + + return status; +} + +/***************************************************************************//** + * SYS_secure_nvm_read() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_secure_nvm_read +( + uint8_t snvm_module, + const uint8_t* p_user_key, + uint8_t* p_admin, + uint8_t* p_data, + uint16_t data_len, + uint16_t mb_offset +) +{ + /* Frame the message. */ + uint8_t frame[16] = {0x00u}; + uint8_t* p_frame = &frame[0u]; + uint8_t status = SYS_PARAM_ERR; + uint8_t response[256] = {0x00u}; + uint16_t index = 0u; + + HAL_ASSERT(!(NULL_BUFFER == p_data)); + HAL_ASSERT(!(NULL_BUFFER == p_admin)); + HAL_ASSERT(!(snvm_module > 221u)); + + HAL_ASSERT(data_len == 236u || data_len == 252u); + + if((p_data == NULL_BUFFER) || + (snvm_module >= 221) || + (p_admin == NULL_BUFFER)) + { + return status; + } + + *p_frame = snvm_module; /* SNVMADDR - SNVM module */ + + p_frame += 4u; /* RESERVED - For alignment */ + + /* Copy user key */ + if (236u == data_len) + { + HAL_ASSERT(p_user_key != NULL_BUFFER); + + if(p_user_key == NULL_BUFFER) + { + return status; + } + + for (index = 0u; index < 12u; index++) + { + *p_frame = p_user_key[index]; + p_frame++; + } + } + else + { + p_frame += 12u; + } + + status = execute_ss_command(SNVM_READ_REQUEST_CMD, + &frame[0], + 16u, + response, + (data_len + 4u), + mb_offset, + 4u); /* mentioning offset to number of words instead of bytes */ + + if (SYS_SUCCESS == status) + { + for (index = 0u; index < 4u; index++) + { + *(p_admin+index) = (uint32_t)response[index]; + } + + + /* Copy data into user buffer. */ + for (index = 4u; index < (data_len + 4u); index++) + { + *(p_data + (index - 4u)) = response[index]; + } + } + else + { + ; + } + + return status; +} + +/***************************************************************************//** + * SYS_nonce_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_nonce_service +( + const uint8_t * p_nonce, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if((p_nonce == NULL_BUFFER)) + { + return status; + } + + status = execute_ss_command(NONCE_SERVICE_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_nonce, + NONCE_SERVICE_RESP_LEN, + mb_offset, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_bitstream_authenticate_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_bitstream_authenticate_service +( + uint32_t spi_flash_address, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint32_t l_spi_flash_address = spi_flash_address; + status = execute_ss_command(BITSTREAM_AUTHENTICATE_CMD, + (uint8_t* )&l_spi_flash_address, + 4u, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_IAP_image_authenticate_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_IAP_image_authenticate_service +( + uint8_t spi_idx +) +{ + uint8_t status = SYS_PARAM_ERR; + + HAL_ASSERT(!(spi_idx == 1u)); + + if (spi_idx == 1u) + { + return status; + } + + status = execute_ss_command(IAP_BITSTREAM_AUTHENTICATE_CMD, + NULL_BUFFER, + 0u, + NULL_BUFFER, + 0u, + spi_idx, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_digest_check_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_digest_check_service +( + uint32_t options, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint32_t l_options = options; + + status = execute_ss_command(DIGEST_CHECK_CMD, + (uint8_t* )&l_options, + 4u, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_iap_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_iap_service +( + uint8_t iap_cmd, + uint32_t spiaddr, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint16_t l_mb_offset = 0u; + uint16_t cmd_data_size = 0u; + uint8_t* cmd_data = NULL_BUFFER; + bool invalid_param = false; + + if (((IAP_PROGRAM_BY_SPIIDX_CMD == iap_cmd) + || (IAP_VERIFY_BY_SPIIDX_CMD == iap_cmd)) + && (1u == spiaddr)) + { + invalid_param = true; + HAL_ASSERT(!invalid_param); + } + + if (!invalid_param) + { + switch(iap_cmd) + { + case IAP_PROGRAM_BY_SPIIDX_CMD: + case IAP_VERIFY_BY_SPIIDX_CMD: + /*In SPI_IDX based program and verify commands, + * Mailbox is not Required. Instead of mailbox offset + * SPI_IDX is passed as parameter.*/ + l_mb_offset = (uint16_t)(0xFFu & spiaddr); + break; + + case IAP_PROGRAM_BY_SPIADDR_CMD: + case IAP_VERIFY_BY_SPIADDR_CMD: + /*In SPI_ADDR based program and verify commands, + * Mailbox is Required*/ + l_mb_offset = mb_offset; + /*command data size is four bytes holding the + * SPI Address in it.*/ + cmd_data_size = 4u; + cmd_data = (uint8_t*)&spiaddr; + break; + + case IAP_AUTOUPDATE_CMD: + /*In auto update command Mailbox is not Required*/ + l_mb_offset = 0u; + break; + + default: + l_mb_offset = 0u; + + } + + status = execute_ss_command( + (uint8_t)iap_cmd, + cmd_data, + cmd_data_size, + NULL_BUFFER, + 0, + (uint16_t)l_mb_offset, + 0); + } + + return status; +} + +/***************************************************************************//** + Internal functions. +*/ +/* +This function executes the SS command. If Mailbox input data is required by the +it will first load it from cmd_data into the Mailbox. If the service requires +the response data to be read from mailbox, it will do so and store it in p_response. +*/ +static uint8_t execute_ss_command +( + uint8_t cmd_opcode, + const uint8_t* cmd_data, + uint16_t cmd_data_size, + const uint8_t* p_response, + uint16_t response_size, + uint16_t mb_offset, + uint16_t response_offset +) +{ + /* Pointer used during Writing to Mailbox memory. */ + uint32_t status = 0u; + uint16_t idx = 0u; + uint16_t ss_command = 0u; + uint32_t* word_buf; + uint16_t timeout_count = SS_TIMEOUT_COUNT; + + /* making sure that the system controller is not executing any service i.e. + SS_USER_BUSY is gone 0 */ + + while (1u == HAL_get_32bit_reg_field(g_css_pf_base_addr, SS_USER_BUSY)) + { + --timeout_count; + + if (timeout_count == 0) + { + return SS_USER_BUSY_TIMEOUT; + } + } + + /* Form the SS command: bit 0to6 is the opcode, bit 7to15 is the Mailbox offset + For some services this field has another meaning + (e.g. for IAP bitstream auth. it means spi_idx) */ + ss_command = ((mb_offset << 7u) | (cmd_opcode & 0x7Fu)); + + /* Load the command register with the SS request command code*/ + HAL_set_32bit_reg(g_css_pf_base_addr, SS_CMD, ss_command); + + if (cmd_data_size > 0u) + { + HAL_ASSERT(!(NULL_BUFFER == cmd_data)); + HAL_ASSERT(!(cmd_data_size % 4u)); + + /* Load the MBX_WCNT register with number of words */ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_WCNT, (cmd_data_size/4u)); + + /* Load the MBX_WADDR register with offset of input data (write to Mailbox) + For all the services this offset remains either 0 or Not applicable + for the services in which no Mailbox write is required.*/ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_WADDR, (0x00u + mb_offset)); + + } + + if (response_size > 0u) + { + HAL_ASSERT(!(NULL_BUFFER == p_response)); + HAL_ASSERT(!(response_size % 4u)); + + /* + Load the MBX_RWCNT register with number of words to be read from Mailbox + */ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_RCNT, (response_size/4u)); + + /* + Load the MBX_RADRDESC register with offset address within the mailbox + format for that particular service. + It will be 0 for the services where there is no output data from G5CONTROL + is expected. + This function assumes that this value is pre-calculated by service specific + functions as this value is fixed for each service. + */ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_RADDR, (response_offset + mb_offset)); + } + + /*Set the request bit in SYS_SERV_REQ register to start the service*/ + HAL_set_32bit_reg_field(g_css_pf_base_addr, SS_REQ_REQ, 0x01u); + + if (cmd_data_size > 0u) + { + word_buf = (uint32_t*)cmd_data; + + /* Write the user data into mail box. */ + for (idx = 0u; idx < (cmd_data_size/4u); idx++) + { + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_WDATA, word_buf[idx]); + } + } + + timeout_count = SS_TIMEOUT_COUNT; + if (response_size > 0u) + { + word_buf = (uint32_t*)p_response; + + for (idx = 0u; idx < (response_size/4u); idx++) + { + while (0u == HAL_get_32bit_reg_field(g_css_pf_base_addr, + SS_USER_RDVLD)) + { + --timeout_count; + + if (timeout_count == 0) + { + return SS_USER_RDVLD_TIMEOUT; + } + } + word_buf[idx] = HAL_get_32bit_reg(g_css_pf_base_addr, MBX_RDATA); + } + } + + timeout_count = SS_TIMEOUT_COUNT; + /* make sure that service is complete i.e. SS_USER_BUSY is gone 0 */ + while (1u == HAL_get_32bit_reg_field(g_css_pf_base_addr, SS_USER_BUSY)) + { + --timeout_count; + + if (timeout_count == 0) + { + return SS_USER_RDVLD_TIMEOUT; + } + } + + /* Read the status returned by System Controller */ + status = HAL_get_32bit_reg(g_css_pf_base_addr, SS_STAT); + + return (uint8_t)status; +} + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h new file mode 100644 index 0000000..8e0ebb6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h @@ -0,0 +1,1249 @@ +/******************************************************************************* + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the + * CoreSysServices_PF bare metal driver. + */ +/*=========================================================================*//** + @mainpage CoreSysServices_PF Bare Metal Driver. + + @section intro_sec Introduction + The PolarFire System Services (PF_SYSTEM_SERVICES) SgCore enables executing + the system services on the PolarFire and PolarFire SoC device. The system services + are the system controller actions initiated by the System Controller's System + Service Interface (SSI). The PolarFire System Services "SgCore" provides a + method to initiate these system services. The PF_SYSTEM_SERVICES interacts + with the system controller on SSI and Mailbox interface to initiate system + services, exchange data required for that services, and to know the successful + completion or error status. + + The PF_SYSTEM_SERVICES provides an APB interface for controlling the registers + functions for controlling the PF_SYSTEM_SERVICES as part of a bare metal system + register implemented within it. This software driver provides a set of where no + part of an operating system but the implementation of the adaptation layer + operating system is available. This driver is adapted for use in + between this driver and the operating system's driver model is outside the + scope of this driver. + + ## Features + The CoreSysServices_PF driver provides the following features: + - Executing device and design information services + - Executing design services + - Executing data security services + - Executing Fabric services + + The CoreSysServices_PF driver is provided as C source code. + + @section Driver Configuration + The application software should configure the CoreSysServices_PF driver through + calling the SYS_init() function. Only one instance of PF_SYSTEM_SERVICES SgCore is + supported. No additional configuration files are required to use the driver. + If using this driver on RT PolarFire device FPGA, define RT_DEVICE_FAMILY + macro in application. + + @section theory_op Theory of Operation + The CoreSysServices_PF driver provides access to the PolarFire system services. + These system services are grouped into the following categories: + + Device and Design Information Service + - Serial Number Service + - USERCODE Service + - Design Info Service + - Device Certificate Services + - Read Digests + - Query Security + - Read Debug Info + - Read eNVM param + + Design Services + - Bitstream authentication service + - IAP bitstream authentication service + + Data Security Services + - Digital Signature Service + - Secure NVM (SNVM) Functions + - PUF Emulation Service + - Nonce Service + + Fabric Services + - Digest Check Service + - In Application programming(IAP)/Auto-Update service + + Initialization and Configuration + + The CoreSysServices_PF driver is initialized by calling the SYS_init() + function. The SYS_init() function must be called before calling any other + CoreSysServices_PF driver functions. + + Device and Design Information Services + + The CoreSysServices_PF driver is used to read information about the device + and the design using the following functions: + - SYS_get_serial_number() + - SYS_get_user_code() + - SYS_get_design_info() + - SYS_get_device_certificate() + - SYS_read_digest() + - SYS_query_security() + - SYS_read_debug_info() + + Design Authentication Services + + The CoreSysServices_PF driver is used to execute design services using the + following functions: + - SYS_bitstream_authenticate_service() + - SYS_IAP_image_authenticate_service() + + Data Security Services + + The CoreSysServices_PF driver is used to execute data security services + using the following functions: + - SYS_digital_signature_service() + - SYS_secure_nvm_write() + - SYS_secure_nvm_read() + - SYS_puf_emulation_service () + - SYS_nonce_service () + + Executing Fabric Services + + The CoreSysServices_PF driver is used to execute fabric services using the + following functions: + - SYS_digest_check_service() + - SYS_iap_service() + + All the service execution functions return the 8-bit status, which is returned + by the system controller on executing the given service. A '0' value indicates + successful execution of that service. A non-zero value indicates error. + The error codes for each service are different. See individual function + description to know the exact meanings of the error codes for each service. + + The function descriptions in this file mainly focus on the details required + by the user to use the APIs provided by this driver to execute the services. + To know the complete details of the system services, see the + PolarFire FPGA and PolarFire SoC FPGA System Services [document](https://onlinedocs.microchip.com/pr/GUID-1409CF11-8EF9-4C24-A94E-70979A688632-en-US-3/index.html) + + *//*=========================================================================*/ +#ifndef __CORE_SYSSERV_PF_H +#define __CORE_SYSSERV_PF_H 1 + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#include "hal_assert.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** +* # Service Execution Success and Error Status Codes +* +* The following status codes are the return values from the system service functions. +* For any service, a return value '0' indicates that the service was executed +* successfully. A non-zero return value indicates that the service was not +* executed successfully. For all the services, the return value represents the +* status code returned by the system controller for the respective service, +* except the values SYS_PARAM_ERR, SS_USER_BUSY_TIMEOUT, and SS_USER_RDVLD_TIMEOUT. +* These three values indicate the error conditions detected by this driver and +* they do not overlap with the status code returned by the system controller for +* any of the system service. +* +* SYS_SUCCESS +* System service executed successfully +* +* SYS_PARAM_ERR +* System service cannot be executed as one or more parameters are not as +* expected by this driver. No read/write access is performed with the +* IP. +* +* SS_USER_BUSY_TIMEOUT +* The System service request is initiated and the driver timed-out while +* waiting for the system service to complete. The System Service +* completion is indicated by de-assertion of the SS_USER_BUSY bit by the +* IP. +* +* SS_USER_RDVLD_TIMEOUT +* The System service request is initiated and the driver timed-out while +* waiting for SS_USER_RDVLD bit, which indicates availability of data to +* be read from the mailbox, to become active. +*/ +#define SYS_SUCCESS 0u +#define SYS_PARAM_ERR 0xFFu +#define SS_USER_BUSY_TIMEOUT 0xFAu +#define SS_USER_RDVLD_TIMEOUT 0xFBu + +/** +* # System Service Timeout Count +* +* The SS_TIMEOUT_COUNT value is used by the driver as a timeout count +* while waiting for either the SS_USER_BUSY or SS_USER_RDVLD. This empirical +* value is sufficiently large so that the operations are falsely +* timeout in the normal circumstance. It is provided as a way to provide +* more debug information to the application in case there are some +* unforeseen issues. You may change this value for your need based on your +* system design. +*/ +#define SS_TIMEOUT_COUNT 40000u +/* + * SYS_DCF_DEVICE_MISMATCH + * Public key or FSN do not match device + * + * + * SYS_DCF_INVALID_SIGNATURE + * Certificate signature is invalid + * + * SYS_DCF_SYSTEM_ERROR + * PUF or storage failure + */ +#define SYS_DCF_DEVICE_MISMATCH 1u +#define SYS_DCF_INVALID_SIGNATURE 2u +#define SYS_DCF_SYSTEM_ERROR 3u + +/* + * SYS_NONCE_PUK_FETCH_ERROR + * Error fetching PUK + * + * SYS_NONCE_SEED_GEN_ERROR + * Error generating seed + */ +#define SYS_NONCE_PUK_FETCH_ERROR 1u +#define SYS_NONCE_SEED_GEN_ERROR 2u + +/** + * # Secure Nvm Write Error Codes + * + * SNVM_WRITE_INVALID_SNVMADDR + * Illegal page address + * + * SNVM_WRITE_FAILURE + * PNVM program/verify failed + * + * SNVM_WRITE_SYSTEM_ERROR + * PUF or storage failure + * + * SNVM_WRITE_NOT_PERMITTED + * Write is not permitted + */ +#define SNVM_WRITE_INVALID_SNVMADDR 1u +#define SNVM_WRITE_FAILURE 2u +#define SNVM_WRITE_SYSTEM_ERROR 3u +#define SNVM_WRITE_NOT_PERMITTED 4u + +/** + * # Secure Nvm Read Error Codes + * + * SNVM_READ_INVALID_SNVMADDR + * Illegal page address + * + * SNVM_READ_AUTHENTICATION_FAILURE + * Storage corrupt or incorrect USK + * + * SNVM_READ_SYSTEM_ERROR + * PUF or storage failure + * + */ +#define SNVM_READ_INVALID_SNVMADDR 1u +#define SNVM_READ_AUTHENTICATION_FAILURE 2u +#define SNVM_READ_SYSTEM_ERROR 3u + +/** + * # Digital Signature Service Error Codes + * + * DIGITAL_SIGNATURE_FEK_FAILURE_ERROR + * Error retrieving FEK + * + * DIGITAL_SIGNATURE_DRBG_ERROR + * Failed to generate nonce + * + * DIGITAL_SIGNATURE_ECDSA_ERROR + * ECDSA failed + */ +#define DIGITAL_SIGNATURE_FEK_FAILURE_ERROR 1u +#define DIGITAL_SIGNATURE_DRBG_ERROR 2u +#define DIGITAL_SIGNATURE_ECDSA_ERROR 3u + +/** + * # Digest Check Error Codes + * + * NOTE: When these error occur, the DIGEST tamper flag is triggered. + * + * DIGEST_CHECK_FABRICERR + * Fabric digest check error + * + * DIGEST_CHECK_CCERR + * UFS Fabric Configuration (CC) segment digest check error + * + * DIGEST_CHECK_SNVMERR + * ROM digest in SNVM segment digest check error + * + * DIGEST_CHECK_ULERR + * UFS UL segment digest check error + * + * DIGEST_CHECK_UK0ERR + * UKDIGEST0 in User Key segment digest check error + * + * DIGEST_CHECK_UK1ERR + * UKDIGEST1 in User Key segment digest check error + * + * DIGEST_CHECK_UK2ERR + * UKDIGEST2 in User Key segment (UPK1) digest check error + * + * DIGEST_CHECK_UK3ERR + * UKDIGEST3 in User Key segment (UK1) digest check error + * + * DIGEST_CHECK_UK4ERR + * UKDIGEST4 in User Key segment (DPK) digest check error + * + * DIGEST_CHECK_UK5ERR + * UKDIGEST5 in User Key segment (UPK2) digest check error + * + * DIGEST_CHECK_UK6ERR + * UKDIGEST6 in User Key segment (UK2) digest check error + * + * DIGEST_CHECK_UPERR + * UFS Permanent Lock (UPERM) segment digest check error + * + * DIGEST_CHECK_SYSERR + * M3 ROM, Factory and Factory Key Segments digest check error + * + */ +#define DIGEST_CHECK_FABRICERR 0x00u +#define DIGEST_CHECK_CCERR 0x01u +#define DIGEST_CHECK_SNVMERR 0x02u +#define DIGEST_CHECK_ULERR 0x03u +#define DIGEST_CHECK_UK0ERR 0x04u +#define DIGEST_CHECK_UK1ERR 0x05u +#define DIGEST_CHECK_UK2ERR 0x06u +#define DIGEST_CHECK_UK3ERR 0x07u +#define DIGEST_CHECK_UK4ERR 0x08u +#define DIGEST_CHECK_UK5ERR 0x09u +#define DIGEST_CHECK_UK6ERR 0x10u +#define DIGEST_CHECK_UPERR 0x11u +#define DIGEST_CHECK_SYSERR 0x12u + +/** + * # Bitstream Authentication and Iap Bitstream Authentication Return Status + * + * BSTREAM_AUTH_CHAINING_MISMATCH_ERR + * Validator or hash chaining mismatch. Incorrectly constructed bitstream or + * wrong key used. + * + * BSTREAM_AUTH_UNEXPECTED_DATA_ERR + * Unexpected data received. + * Additional data received after end of EOB component. + * + * BSTREAM_AUTH_INVALID_ENCRY_KEY_ERR + * Invalid/corrupt encryption key. + * The requested key mode is disabled or the key could not be read/reconstructed. + * + * BSTREAM_AUTH_INVALID_HEADER_ERR + * Invalid component header + * + * BSTREAM_AUTH_BACK_LEVEL_NOT_SATISFIED_ERR + * Back level not satisfied + * + * BSTREAM_AUTH_ILLEGAL_BITSTREAM_MODE_ERR + * Illegal bitstream mode. + * Requested bitstream mode is disabled by user security. + * + * BSTREAM_AUTH_DNS_BINDING_MISMATCH_ERR + * DSN binding mismatch + * + * BSTREAM_AUTH_ILLEGAL_COMPONENT_SEQUENCE_ERR + * Illegal component sequence + * + * BSTREAM_AUTH_INSUFF_DEVICE_CAPAB_ERR + * Insufficient device capabilities + * + * BSTREAM_AUTH_INCORRECT_DEVICEID_ERR + * Incorrect DEVICEID + * + * BSTREAM_AUTH_PROTOCOL_VERSION_ERR + * Unsupported bitstream protocol version (regeneration required) + * + * BSTREAM_AUTH_VERIFY_ERR + * Verify not permitted on this bitstream + * + * BSTREAM_AUTH_INVALID_DEV_CERT_ERR + * Invalid Device Certificate. + * Device SCAC is invalid or not present. + * + * BSTREAM_AUTH_INVALID_DIB_ERR + * Invalid DIB + * + * BSTREAM_AUTH_SPI_NOT_MASTER_ERR + * Device not in SPI Master Mode. + * Error may occur only when bitstream is executed through IAP mode. + * + * BSTREAM_AUTH_AUTOIAP_NO_VALID_IMAGE_ERR + * No valid images found. + * Error may occur when bitstream is executed through Auto Update mode. + * Occurs when no valid image pointers are found. + * + * BSTREAM_AUTH_INDEXIAP_NO_VALID_IMAGE_ERR + * No valid images found. + * Error may occur when bitstream is executed through IAP mode via Index Mode. + * Occurs when No valid image pointers are found. + * + * BSTREAM_AUTH_NEWER_DESIGN_VERSION_ERR + * Programmed design version is newer than AutoUpdate image found. + * Error may occur when bitstream is executed through Auto Update mode. + * + * BSTREAM_AUTH_INVALID_IMAGE_ERR + * Selected image was invalid and no recovery was performed due to valid design + * in device. + * Error may occur only when bitstream is executed through Auto Update or IAP mode + * (This error is here for completeness but only can be observed by running the + * READ_DEBUG_INFO instruction and looking at IAP Error code field). + * + * BSTREAM_AUTH_IMAGE_PROGRAM_FAILED_ERR + * Selected and Recovery image failed to program. + * Error may occur only when bitstream is executed through Auto Update or + * IAP mode + * (This error is here for completeness but only can be observed by running the + * READ_DEBUG_INFO instruction and looking at IAP Error code field). + * + * BSTREAM_AUTH_ABORT_ERR + * Abort. + * Non-bitstream instruction executed during bitstream loading. + * + * BSTREAM_AUTH_NVMVERIFY_ERR + * Fabric/UFS verification failed (min or weak limit) + * + * BSTREAM_AUTH_PROTECTED_ERR + * Device security prevented modification of non-volatile memory + * + * BSTREAM_AUTH_NOTENA + * Programming mode not enabled + * + * BSTREAM_AUTH_PNVMVERIFY + * pNVM verify operation failed + * + * BSTREAM_AUTH_SYSTEM + * System hardware error (PUF or DRBG) + * + * BSTREAM_AUTH_BADCOMPONENT + * An internal error was detected in a component payload + * + * BSTREAM_AUTH_HVPROGERR + * HV programming subsystem failure (pump failure) + * + * BSTREAM_AUTH_HVSTATE + * HV programming subsystem in unexpected state (internal error) + * + */ +#define BSTREAM_AUTH_CHAINING_MISMATCH_ERR 1 +#define BSTREAM_AUTH_UNEXPECTED_DATA_ERR 2 +#define BSTREAM_AUTH_INVALID_ENCRY_KEY_ERR 3 +#define BSTREAM_AUTH_INVALID_HEADER_ERR 4 +#define BSTREAM_AUTH_BACK_LEVEL_NOT_SATISFIED_ERR 5 +#define BSTREAM_AUTH_ILLEGAL_BITSTREAM_MODE_ERR 6 +#define BSTREAM_AUTH_DNS_BINDING_MISMATCH_ERR 7 +#define BSTREAM_AUTH_ILLEGAL_COMPONENT_SEQUENCE_ERR 8 +#define BSTREAM_AUTH_INSUFF_DEVICE_CAPAB_ERR 9 +#define BSTREAM_AUTH_INCORRECT_DEVICEID_ERR 10 +#define BSTREAM_AUTH_PROTOCOL_VERSION_ERR 11 +#define BSTREAM_AUTH_VERIFY_ERR 12 +#define BSTREAM_AUTH_INVALID_DEV_CERT_ERR 13 +#define BSTREAM_AUTH_INVALID_DIB_ERR 14 +#define BSTREAM_AUTH_SPI_NOT_MASTER_ERR 21 +#define BSTREAM_AUTH_AUTOIAP_NO_VALID_IMAGE_ERR 22 +#define BSTREAM_AUTH_INDEXIAP_NO_VALID_IMAGE_ERR 23 +#define BSTREAM_AUTH_NEWER_DESIGN_VERSION_ERR 24 +/* 25 Reserved */ +#define BSTREAM_AUTH_INVALID_IMAGE_ERR 26 +#define BSTREAM_AUTH_IMAGE_PROGRAM_FAILED_ERR 27 +#define BSTREAM_AUTH_ABORT_ERR 127 +#define BSTREAM_AUTH_NVMVERIFY_ERR 128 +#define BSTREAM_AUTH_PROTECTED_ERR 129 +#define BSTREAM_AUTH_NOTENA 130 +#define BSTREAM_AUTH_PNVMVERIFY 131 +#define BSTREAM_AUTH_SYSTEM 132 +#define BSTREAM_AUTH_BADCOMPONENT 133 +#define BSTREAM_AUTH_HVPROGERR 134 +#define BSTREAM_AUTH_HVSTATE 135 + +/***************************************************************************//** + * # Mailbox ECC Status + * Provides ECC status when the mailbox is read. The values are as follows: + * 00: No ECC errors detected, data is correct. + * 01: Exactly one bit error occurred and has been corrected. + * 10: Exactly two bits error occurred and no correction performed. + * 11: Reserved. + */ +#define SYS_MBOX_ECC_NO_ERROR_MASK 0x00u +#define SYS_MBOX_ONEBIT_ERROR_CORRECTED_MASK 0x40u +#define SYS_MBOX_TWOBIT_ERROR_MASK 0xC0u + +/***************************************************************************//** + * Service request command opcodes: +*/ +#define SERIAL_NUMBER_REQUEST_CMD 0x00u +#define USERCODE_REQUEST_CMD 0x01u +#define DESIGN_INFO_REQUEST_CMD 0x02u +#define DEVICE_CERTIFICATE_REQUEST_CMD 0x03u +#define READ_DIGEST_REQUEST_CMD 0x04u +#define QUERY_SECURITY_REQUEST_CMD 0x05u +#define READ_DEBUG_INFO_REQUEST_CMD 0x06u +#define READ_ENVM_PARAM_REQUEST_CMD 0x07u +#define SNVM_NON_AUTHEN_TEXT_REQUEST_CMD 0x10u +#define SNVM_AUTHEN_TEXT_REQUEST_CMD 0x11u +#define SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD 0x12u +#define SNVM_READ_REQUEST_CMD 0x18u +#define DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD 0x19u +#define PUF_EMULATION_SERVICE_REQUEST_CMD 0x20u +#define NONCE_SERVICE_REQUEST_CMD 0x21u +#define DIGITAL_SIGNATURE_DER_FORMAT_REQUEST_CMD 0x1Au + +#define BITSTREAM_AUTHENTICATE_CMD 0x23u +#define IAP_BITSTREAM_AUTHENTICATE_CMD 0x22u + +#define DIGEST_CHECK_CMD 0x47u + +#define IAP_PROGRAM_BY_SPIIDX_CMD 0x42u +#define IAP_VERIFY_BY_SPIIDX_CMD 0x44u +#define IAP_PROGRAM_BY_SPIADDR_CMD 0x43u +#define IAP_VERIFY_BY_SPIADDR_CMD 0x45u +#define IAP_AUTOUPDATE_CMD 0x46u + +/***************************************************************************//** + * Service request Mailbox return data length + */ +#define SERIAL_NUMBER_RESP_LEN 16u +#define USERCODE_RESP_LEN 4u +#define DESIGN_INFO_RESP_LEN 36u +#define DEVICE_CERTIFICATE_RESP_LEN 1024u +#define READ_DIGEST_RESP_LEN 416u +#define QUERY_SECURITY_RESP_LEN 9u +#define READ_DEBUG_INFO_RESP_LEN 76u +#define READ_ENVM_PARAM_RESP_LEN 256u +#define NONCE_SERVICE_RESP_LEN 32u + +#define PUF_EMULATION_SERVICE_CMD_LEN 20u +#define PUF_EMULATION_SERVICE_RESP_LEN 32u + +#define DIGITAL_SIGNATURE_HASH_LEN 48u +#define DIGITAL_SIGNATURE_RAW_FORMAT_RESP_SIZE 96u +#define DIGITAL_SIGNATURE_DER_FORMAT_RESP_SIZE 104u + +#define USER_SECRET_KEY_LEN 12u + +/* Same driver can be used on PolarFire SoC platform and the response length + * is different for PolarFire SoC. Constants defined below are used only when the + * PF System services driver is used with PolarFire SoC Platform. + */ +#define READ_DIGEST_MPFS_RESP_LEN 576u +#define QUERY_SECURITY_MPFS_RESP_LEN 33u + +/* SNVM Input data length from sNVM write. */ +#ifndef RT_DEVICE_FAMILY +/* SNVMADDR + RESERVED + PT + USK */ +#define NON_AUTHENTICATED_TEXT_DATA_LEN 256u + +/* SNVMADDR + RESERVED + PT */ +#define AUTHENTICATED_TEXT_DATA_LEN 252u +#else +/* SNVMADDR + RESERVED + PT + USK */ +#define NON_AUTHENTICATED_TEXT_DATA_LEN 224u + +/* SNVMADDR + RESERVED + PT */ +#define AUTHENTICATED_TEXT_DATA_LEN 220u +#endif + +/** + * # Digest Check Input Options + * + * DIGEST_CHECK_FABRIC + * Carry out digest check on Fabric + * + * DIGEST_CHECK_CC + * Carry out digest check on UFS Fabric Configuration (CC) segment + * + * DIGEST_CHECK_SNVM + * Carry out digest check on ROM digest in SNVM segment + * + * DIGEST_CHECK_UL + * Carry out digest check on UFS UL segment + * + * DIGEST_CHECK_UKDIGEST0 + * Carry out digest check on UKDIGEST0 in User Key segment + * + * DIGEST_CHECK_UKDIGEST1 + * Carry out digest check on UKDIGEST1 in User Key segment + * + * DIGEST_CHECK_UKDIGEST2 + * Carry out digest check on UKDIGEST2 in User Key segment (UPK1) + * + * DIGEST_CHECK_UKDIGEST3 + * Carry out digest check on UKDIGEST3 in User Key segment (UK1) + * + * DIGEST_CHECK_UKDIGEST4 + * Carry out digest check on UKDIGEST4 in User Key segment (DPK) + * + * DIGEST_CHECK_UKDIGEST5 + * Carry out digest check on UKDIGEST5 in User Key segment (UPK2) + * + * DIGEST_CHECK_UKDIGEST6 + * Carry out digest check on UKDIGEST6 in User Key segment (UK2) + * + * DIGEST_CHECK_UPERM + * Carry out digest check on UFS Permanent lock (UPERM) segment + * + * DIGEST_CHECK_SYS + * Carry out digest check on Factory and Factory Key Segments + * + */ +#define DIGEST_CHECK_FABRIC (0x01<<0x00u) /*Fabric digest*/ +#define DIGEST_CHECK_CC (0x01<<0x01u) /*UFS Fabric Configuration (CC) segment*/ +#define DIGEST_CHECK_SNVM (0x01<<0x02u) /*ROM digest in SNVM segment*/ +#define DIGEST_CHECK_UL (0x01<<0x03u) /*UFS UL segment*/ +#define DIGEST_CHECK_UKDIGEST0 (0x01<<0x04u) /*UKDIGEST0 in User Key segment*/ +#define DIGEST_CHECK_UKDIGEST1 (0x01<<0x05u) /*UKDIGEST1 in User Key segment*/ +#define DIGEST_CHECK_UKDIGEST2 (0x01<<0x06u) /*UKDIGEST2 in User Key segment (UPK1)*/ +#define DIGEST_CHECK_UKDIGEST3 (0x01<<0x07u) /*UKDIGEST3 in User Key segment (UK1)*/ +#define DIGEST_CHECK_UKDIGEST4 (0x01<<0x08u) /*UKDIGEST4 in User Key segment (DPK)*/ +#define DIGEST_CHECK_UKDIGEST5 (0x01<<0x09u) /*UKDIGEST5 in User Key segment (UPK2)*/ +#define DIGEST_CHECK_UKDIGEST6 (0x01<<0x0au) /*UKDIGEST6 in User Key segment (UK2)*/ +#define DIGEST_CHECK_UPERM (0x01<<0x0bu) /*UFS Permanent lock (UPERM) segment*/ +#define DIGEST_CHECK_SYS (0x01<<0x0cu) /*Factory and Factory Key Segments.*/ + +/***************************************************************************//** + * The function SYS_init() is used to initialize the internal data structures of + * this driver. Currently this function is empty. + * + * @param base_addr The base_addr parameter specifies the base address of the + * PF_System_services core. + * + * @return This function does not return a value. + */ +void +SYS_init +( + uint32_t base_addr +); + +/***************************************************************************//** + * The function SYS_get_serial_number() is used to execute "serial number" system + * service. + * + * @param p_serial_number The p_serial_number parameter is a pointer to a buffer + * in which the data returned by system controller + * is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t +SYS_get_serial_number +( + const uint8_t * p_serial_number, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_get_user_code() is used to execute "USERCODE" system + * service. + * @param p_user_code The p_user_code parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t +SYS_get_user_code +( + const uint8_t * p_user_code, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_get_design_info() is used to execute "Get Design Info" system + * service. + * + * @param p_design_info The p_design_info parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. Total size of debug information is 36 bytes. + * The data from the system controller includes the 256-bit + * user-defined design ID, 16-bit design version, and 16-bit + * design back level. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t +SYS_get_design_info +( + const uint8_t * p_design_info, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_get_device_certificate() is used to execute "Get Device + * Certificate" system service. + * + * @param p_device_certificate The p_device_certificate parameter is a pointer + * to a buffer in which the data returned by the + * system controller is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code means that + * the service was executed successfully. + * + */ +uint8_t +SYS_get_device_certificate +( + const uint8_t * p_device_certificate, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_read_digest() is used to execute "Read Digest" system service. + * + * @param p_digest The p_digest parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t SYS_read_digest +( + const uint8_t * p_digest, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_query_security() is used to execute "Query Security" system + * service. + * + * @param p_security_locks The p_security_locks parameter is a pointer to a buffer + * in which the data returned by system controller is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code means that + * the service was executed successfully. + */ +uint8_t SYS_query_security +( + uint8_t * p_security_locks, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_read_debug_info() is used to execute "Read Debug info" system + * service. + * + * @param p_debug_info The p_debug_info parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t SYS_read_debug_info +( + const uint8_t * p_debug_info, + uint16_t mb_offset +); + +#ifdef CORESYSSERVICES_PFSOC +/***************************************************************************//** + * The function SYS_read_envm_parameter() is used to retrieve all parameters needed + * for the eNVM operation and programming. + * + * NOTE: This service is available only on PolarFire SoC Platform. + * This service is not yet supported by PF_SYSTEM_SERVICES 3.0.100. + * + * @param p_envm_param The p_envm_param parameter is a pointer to a buffer + * in which the data returned by system controller is copied. + * This buffer stores all the eNVM parameters. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_read_envm_parameter service will return zero if the + * service executed successfully, otherwise, it will return + * one indicating error. + */ +uint8_t SYS_read_envm_parameter +( + uint8_t * p_envm_param, + uint16_t mb_offset +); +#endif +/***************************************************************************//** + * The function SYS_puf_emulation_service() is used to authenticate a device. + * + * The SYS_puf_emulation_service() function accept a challenge comprising a + * 8-bit optype and 128-bit challenge and return a 256-bit response unique to + * the given challenge and the device. + * + * @param p_challenge The p_challenge parameter specifies the 128-bit challenge + * to generate the 256-bits unique response. + * + * @param op_type The op_type parameter specifies the operational parameter + * to generate the 256-bits unique response. + * + * @param p_response The p_response parameter is a pointer to a buffer where + * the data returned which is the response by system controller + * is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_puf_emulation_service function will return zero + * if the service executed successfully, otherwise, it will + * return one indicating error. + */ +uint8_t SYS_puf_emulation_service +( + const uint8_t * p_challenge, + uint8_t op_type, + uint8_t* p_response, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_digital_signature_service() function is used to generate P-384 ECDSA + * signature based on SHA384 hash value. + * + * @param p_hash The p_hash parameter is a pointer to the buffer which + * contain the 48 bytes SHA384 Hash value (input value). + * + * @param format The format parameter specifies the output format of + * generated SIGNATURE field. The different types of output + * signature formats are as follow: + * - DIGITAL_SIGNATURE_RAW_FORMAT + * - DIGITAL_SIGNATURE_DER_FORMAT + * + * @param p_response The p_response parameter is a pointer to a buffer that + * contains the generated ECDSA signature. The field may be + * 96 bytes or 104 bytes depending upon the output format. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digital_signature_service function returns + * zero if the service executed successfully, otherwise, it + * returns non-zero values indicating error. + */ +uint8_t SYS_digital_signature_service +( + const uint8_t* p_hash, + uint8_t format, + uint8_t* p_response, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_secure_nvm_write() function writes data in the sNVM region. + * Data gets stored in the following format: + * - Non-authenticated plaintext + * - Authenticated plaintext + * - Authenticated ciphertext + * + * Note: If you are executing this function with Authenticated plaintext + * or Authenticated ciphertext on a device whose sNVM was never previously + * written to, then the service may fail. For it to work, you must first write + * Authenticated data to the sNVM using Libero along with USK client and + * custom security. This flow generates the SMK. See UG0753 PolarFire FPGA + * Security User Guide for further details. + + * @param format The format parameter specifies the format used to write + * data in sNVM region. The different type of text formats + * are as follow: + * - NON_AUTHENTICATED_PLAINTEXT_FORMAT + * - AUTHENTICATED_PLAINTEXT_FORMAT + * - AUTHENTICATED_CIPHERTEXT_FORMAT + * + * @param snvm_module The snvm_module parameter specifies the the sNVM module + * in which the data need to be written. + * + * @param p_data The p_data parameter is a pointer to a buffer which + * contains the data to be stored in sNVM region. The data + * length to be written is fixed depending on the format + * parameter. If NON_AUTHENTICATED_PLAINTEXT_FORMAT is + * selected, then you can write 252 bytes in the sNVM module. + * For other two formats the data length is 236 bytes. + * + * @param p_user_key The p_user_key parameter is a pointer to a buffer which + * contain the 96-bit key USK (user secret key). This user + * secret key will enhance the security when authentication + * is used. That is, when Authenticated plaintext and + * Authenticated ciphertext format is selected. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digital_signature_service function returns + * zero if the service executed successfully, otherwise, it + * returns non-zero values indicating error. + */ +uint8_t SYS_secure_nvm_write +( + uint8_t format, + uint8_t snvm_module, + const uint8_t* p_data, + const uint8_t* p_user_key, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_secure_nvm_read() function is used to read data present in sNVM region. + * User should provide USK key, if the data was programmed using authentication. + * If the data was written in the sNVM using the authenticated plaintext or the + * authenticated ciphertext service option then this service will return the + * valid data only when authentication is successful. For more details, see + * SYS_secure_nvm_write() function. If the data was written in + * the sNVM using the authenticated plaintext or the authenticated ciphertext + * service option then this service will return the valid data only when + * authentication is successful. For more details, see SYS_secure_nvm_write() + * function and its parameter description. + * + * @param snvm_module The snvm_module parameter specifies the sNVM module + * from which the data need to be read. + * + * @param p_user_key The p_user_key parameter is a pointer to a buffer which + * contain the 96-bit key USK (user secret key). User should + * provide same secret key which is previously used for + * authentication while writing data in sNVM region. + * + * @param p_admin The p_admin parameter is a pointer to the buffer where + * the output page admin data is stored. The page admin + * data is 4 bytes long. + * + * @param p_data The p_data parameter is a pointer to a buffer which + * contains the data read from sNVM region. User should + * provide the buffer large enough to store the read data. + * + * @param data_len The data_len parameter specifies the number of bytes to be + * read from sNVM. + * The application should know whether the data written in the + * chose sNVM module was previously stored using Authentication + * or not. + * The data_len should be 236 bytes, for authenticated data. + * For not authenticated data the data_len should be 252 bytes. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digital_signature_service function returns + * zero if the service executed successfully, otherwise, it + * returns non-zero values indicating error. + */ +uint8_t SYS_secure_nvm_read +( + uint8_t snvm_module, + const uint8_t* p_user_key, + uint8_t* p_admin, + uint8_t* p_data, + uint16_t data_len, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_nonce_service() is used to issue "Nonce Service" system + * service to the system controller. + * + * @param p_nonce The p_nonce parameter is a pointer to a buffer + * in which the data returned by system controller is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code means + * that the service was executed successfully and a non-zero + * value indicates error. See the document link + * provided in the theory of operation section to know more + * about the service and service response. + */ +uint8_t SYS_nonce_service +( + const uint8_t * p_nonce, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_bitstream_authenticate_service() function is used to authenticate + * the Bitstream which is located in SPI through a system service routine. Prior + * to using the IAP service, it may be required to first validate the new + * bitstream before committing the device to reprogramming, thus avoiding the + * need to invoke recovery procedures if the bitstream is invalid. + * + * This service is applicable to bitstreams stored in SPI Flash memory only. + * + * @param spi_flash_address + * The spi_flash_address parameter specifies the address within + * SPI Flash memory where the bit-stream is stored. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_bitstream_authenticate_service function will return + * zero if the service executed successfully and the non-zero + * response from system controller indicates error. See + * the document link provided in the theory of + * operation section to know more about the service and service + * response. + */ +uint8_t SYS_bitstream_authenticate_service +( + uint32_t spi_flash_address, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_IAP_image_authenticate_service() function is used to authenticate + * the IAP image which is located in SPI through a system service routine. The + * service checks the image descriptor and the referenced bitstream and optional + * initialization data. If the image is authenticated successfully, then the + * image is guaranteed to be valid when used by an IAP function. + * + * This service is applicable to bitstreams stored in SPI Flash memory only. + * + * @param spi_idx + * The spi_idx parameter specifies the index in the SPI directory to + * be used where the IAP bit-stream is stored. + * Note: To support recovery SPI_IDX=1 should be an empty slot and the recovery + * image should be located in SPI_IDX=0. Since SPI_IDX=1 should be an + * empty slot, it shouldn’t be passed into the system service. + * + * @return The SYS_IAP_image_authenticate_service function will return + * zero if the service executed successfully the non-zero + * response from system controller indicates error. Please + * refer to the document link provided in the theory of + * operation section to know more about the service and service + * response. + */ +uint8_t SYS_IAP_image_authenticate_service +( + uint8_t spi_idx +); + +/***************************************************************************//** + * The SYS_digest_check_service() function is used to Recalculates and compares + * digests of selected non-volatile memories. If the fabric digest is to be + * checked, then the user design must follow all prerequisite steps for the + * FlashFreeze service before invoking this service. + * This service is applicable to bitstreams stored in SPI Flash memory only. + * @param options + * The options parameter specifies the digest check options which + * indicate the area on which the digest check should be performed. + * Below is the list of options. You can OR these options to indicate + * to perform digest check on multiple segments. + * Note: The options parameter is of 2 bytes when used with PF + * device and 4 bytes when used with PolarFire SoC device. + * Options[i] | Description + * ---------------|---------------------------------- + * 0x01 | Fabric digest + * 0x02 | Fabric Configuration (CC) segment + * 0x04 | ROM digest in SNVM segment + * 0x08 | UL segment + * 0x10 | UKDIGEST0 in User Key segment + * 0x20 | UKDIGEST1 in User Key segment + * 0x40 | UKDIGEST2 in User Key segment (UPK1) + * 0x80 | UKDIGEST3 in User Key segment (UK1) + * 0x100 | UKDIGEST4 in User Key segment (DPK) + * 0x200 | UKDIGEST5 in User Key segment (UPK2) + * 0x400 | UKDIGEST6 in User Key segment (UK2) + * 0x800 | UFS Permanent lock (UPERM) segment + * 0x1000 | Factory and Factory Key Segments. + * 0x2000 | UKDIGEST7 in User Key segment (HWM) (PFSoC) + * 0x4000 | ENVMDIGEST (PFSoC only) + * 0x8000 | UKDIGEST8 for MSS Boot Info (PFSoC only) + * 0x10000 | SNVM_RW_ACCESS_MAP Digest (PFSoC only) + * 0x20000 | SBIC revocation digest (PFSoC only) + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digest_check_service function will return + * zero if the service executed successfully the non-zero + * response from system controller indicates error. Pleaes + * refer to the document link provided in the theory of + * operation section to know more about the service and service + * response. + */ +uint8_t SYS_digest_check_service +( + uint32_t options, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_iap_service() function is used to IAP service. The IAP service allows + * the user to reprogram the device without the need for an external master. The + * user design writes the bitstream to be programmed into a SPI Flash connected + * to the SPI port. When the service is invoked, the System Controller + * automatically reads the bitstream from the SPI flash and programs the device. + * The service allows the image to be executed in either VERIFY or PROGRAM modes. + * Another option for IAP is to perform the auto-update sequence. In this case + * the newest image of the first two images in the SPI directory is chosen to be + * programmed. + * + * @param iap_cmd + * The iap_cmd parameter specifies the specific IAP command which + * depends upon VERIFY or PROGRAM modes and the SPI address method. + * iap_cmd | Description + * -----------------------|------------ + * IAP_PROGRAM_BY_SPIIDX_CMD | IAP program. + * IAP_VERIFY_BY_SPIIDX_CMD | Fabric Configuration (CC) segment + * IAP_PROGRAM_BY_SPIADDR_CMD | ROM digest in SNVM segment + * IAP_VERIFY_BY_SPIADDR_CMD | UL segment + * IAP_AUTOUPDATE_CMD | UKDIGEST0 in User Key segment + * + * @param spiaddr + * The spiaddr parameter specifies either the index + * in the SPI directory or the SPI address in the SPI Flash memory. + * Below is the list of the possible meaning of spiaddr parameter + * in accordance with the iap_cmd parameter. + * iap_cmd | spiaddr + * ----------------------|----------------- + * IAP_PROGRAM_BY_SPIIDX_CMD | Index in the SPI directory. + * IAP_VERIFY_BY_SPIIDX_CMD | Index in the SPI directory. + * IAP_PROGRAM_BY_SPIADDR_CMD | SPI address in the SPI Flash memory + * IAP_VERIFY_BY_SPIADDR_CMD | SPI address in the SPI Flash memory + * IAP_AUTOUPDATE_CMD | spiaddr is ignored as No index/address required for this command. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * Note: For the IAP services with command IAP_PROGRAM_BY_SPIIDX_CMD and + * IAP_VERIFY_BY_SPIIDX_CMD To support recovery SPI_IDX=1 should be an + * empty slot and the recovery image should be located in SPI_IDX=0. + * Since SPI_IDX=1 should be an empty slot it shouldn’t be passed into + * the system service. + * + * @return The SYS_iap_service function will return zero if the service + * executed successfully and the non-zero response from system + * controller indicates error. Please refer to the document + * link provided in the theory of operation section to know + * more about the service and service response. + */ +uint8_t SYS_iap_service +( + uint8_t iap_cmd, + uint32_t spiaddr, + uint16_t mb_offset +); + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_SYSSERV_PF_H */ diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h new file mode 100644 index 0000000..8b14b7e --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h @@ -0,0 +1,149 @@ +/******************************************************************************* + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Register bit offsets and masks definitions for CoreSysServices_PF driver. + */ + +#ifndef __CORE_SYSSERV_PF_REGISTERS +#define __CORE_SYSSERV_PF_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * SYS_SERV_CMD (offset 0x04) register details + */ +#define SS_CMD_REG_OFFSET 0x04u + +#define SS_CMD_OFFSET 0x04 +#define SS_CMD_MASK 0x0000FFFFu +#define SS_CMD_SHIFT 0u + +/*------------------------------------------------------------------------------ + * SYS_SERV_STAT (offset 0x08) register details + */ +#define SS_STAT_REG_OFFSET 0x08u + +#define SS_STAT_OFFSET 0x08 +#define SS_STAT_MASK 0x0000FFFFu +#define SS_STAT_SHIFT 0u + +/*------------------------------------------------------------------------------ + * SYS_SERV_REQ (offset 0x0C) register details + */ +#define SS_REQ_REG_OFFSET 0x0Cu + + +#define SS_REQ_REQ_OFFSET 0x0Cu +#define SS_REQ_REQ_MASK 0x00000001UL +#define SS_REQ_REQ_SHIFT 0u + +#define SS_REQ_ABUSY_OFFSET 0x0Cu +#define SS_REQ_ABUSY_MASK 0x00000002UL +#define SS_REQ_ABUSY_SHIFT 1u + +#define SS_REQ_NABUSY_OFFSET 0x0Cu +#define SS_REQ_NABUSY_MASK 0x00000004UL +#define SS_REQ_NABUSY_SHIFT 2u + +#define SS_REQ_SSBUSY_OFFSET 0x0Cu +#define SS_REQ_SSBUSY_MASK 0x00000008UL +#define SS_REQ_SSBUSY_SHIFT 3u + +#define SS_REQ_AREQ_OFFSET 0x0Cu +#define SS_REQ_AREQ_MASK 0x00000010UL +#define SS_REQ_AREQ_SHIFT 4u + +#define SS_REQ_NAREQ_OFFSET 0x0Cu +#define SS_REQ_NAREQ_MASK 0x00000020UL +#define SS_REQ_NAREQ_SHIFT 5u +/*------------------------------------------------------------------------------ + * MBX_ECCSTATUS (offset 0x10) register details + */ +#define MBX_ECCSTATUS_REG_OFFSET 0x10u + +#define MBX_ECCSTATUS_OFFSET 0x10 +#define MBX_ECCSTATUS_MASK 0x03u +#define MBX_ECCSTATUS_SHIFT 0u + + +/*------------------------------------------------------------------------------ + * MBX_WCNT (offset 0x14) register details + */ +#define MBX_WCNT_REG_OFFSET 0x14u + +#define MBX_WCNT_OFFSET 0x14 +#define MBX_WCNT_MASK 0x000001FFu +#define MBX_WCNT_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_RWCNT (offset 0x18) register details + */ +#define MBX_RCNT_REG_OFFSET 0x18u + +#define MBX_RCNT_OFFSET 0x18 +#define MBX_RCNT_MASK 0x000001FFu +#define MBX_RCNT_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_WADRDESC (offset 0x1C) register details + */ +#define MBX_WADDR_REG_OFFSET 0x1Cu + +#define MBX_WADDR_OFFSET 0x1C +#define MBX_WADDR_MASK 0x000001FFu +#define MBX_WADDR_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_RADRDESC (offset 0x20) register details + */ +#define MBX_RADDR_REG_OFFSET 0x20u + +#define MBX_RADDR_OFFSET 0x20 +#define MBX_RADDR_MASK 0x000001FFu +#define MBX_RADDR_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_WDATA (offset 0x28) register details + */ +#define MBX_WDATA_REG_OFFSET 0x28u + +#define MBX_WDATA_OFFSET 0x28 +#define MBX_WDATA_MASK 0xFFFFFFFFu +#define MBX_WDATA_SHIFT 0u + + +/*------------------------------------------------------------------------------ + * MBX_RDATA (offset 0x2C) register details + */ +#define MBX_RDATA_REG_OFFSET 0x2Cu + +#define MBX_RDATA_OFFSET 0x2C +#define MBX_RDATA_MASK 0xFFFFFFFFu +#define MBX_RDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * SS_USER (offset 0x30) register details + */ +#define SS_USER_REG_OFFSET 0x30u + +#define SS_USER_BUSY_OFFSET 0x30 +#define SS_USER_BUSY_MASK 0x00000001u +#define SS_USER_BUSY_SHIFT 0u + +#define SS_USER_RDVLD_OFFSET 0x30 +#define SS_USER_RDVLD_MASK 0x00000002u +#define SS_USER_RDVLD_SHIFT 1u + +#define SS_USER_CMDERR_OFFSET 0x30 +#define SS_USER_CMDERR_MASK 0x00000004u +#define SS_USER_CMDERR_SHIFT 2u + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_SYSSERV_PF_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c new file mode 100644 index 0000000..0c0a866 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c @@ -0,0 +1,297 @@ +/******************************************************************************* + * (c) Copyright 2007-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file core_uart_apb.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreUARTapb driver implementation. See file "core_uart_apb.h" for + * description of the functions implemented in this file. + * + */ + +#include "coreuartapb_regs.h" +#include "core_uart_apb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define NULL_INSTANCE ( ( UART_instance_t* ) 0 ) +#define NULL_BUFFER ( ( uint8_t* ) 0 ) + +#define MAX_LINE_CONFIG ( ( uint8_t )( DATA_8_BITS | ODD_PARITY ) ) +#define MAX_BAUD_VALUE ( ( uint16_t )( 0x1FFF ) ) +#define STATUS_ERROR_MASK ( ( uint8_t )( STATUS_PARITYERR_MASK | \ + STATUS_OVERFLOW_MASK | \ + STATUS_FRAMERR_MASK ) ) +#define BAUDVALUE_LSB ( (uint16_t) (0x00FF) ) +#define BAUDVALUE_MSB ( (uint16_t) (0xFF00) ) +#define BAUDVALUE_SHIFT ( (uint8_t) (5) ) + +#define STATUS_ERROR_OFFSET STATUS_PARITYERR_SHIFT + +/***************************************************************************//** + * UART_init() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_init +( + UART_instance_t * this_uart, + addr_t base_addr, + uint16_t baud_value, + uint8_t line_config +) +{ + uint8_t rx_full; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( line_config <= MAX_LINE_CONFIG ) + HAL_ASSERT( baud_value <= MAX_BAUD_VALUE ) + + if( ( this_uart != NULL_INSTANCE ) && + ( line_config <= MAX_LINE_CONFIG ) && + ( baud_value <= MAX_BAUD_VALUE ) ) + { + /* + * Store lower 8-bits of baud value in CTRL1. + */ + HAL_set_8bit_reg( base_addr, CTRL1, (uint_fast8_t)(baud_value & + BAUDVALUE_LSB ) ); + + /* + * Extract higher 5-bits of baud value and store in higher 5-bits + * of CTRL2, along with line configuration in lower 3 three bits. + */ + HAL_set_8bit_reg( base_addr, CTRL2, (uint_fast8_t)line_config | + (uint_fast8_t)((baud_value & + BAUDVALUE_MSB) >> BAUDVALUE_SHIFT ) ); + + this_uart->base_address = base_addr; +#ifndef NDEBUG + { + uint8_t config; + uint8_t temp; + uint16_t baud_val; + baud_val = HAL_get_8bit_reg( this_uart->base_address, CTRL1 ); + config = HAL_get_8bit_reg( this_uart->base_address, CTRL2 ); + /* + * To resolve operator precedence between & and << + */ + temp = ( config & (uint8_t)(CTRL2_BAUDVALUE_MASK ) ); + baud_val |= (uint16_t)( (uint16_t)(temp) << BAUDVALUE_SHIFT ); + config &= (uint8_t)(~CTRL2_BAUDVALUE_MASK); + HAL_ASSERT( baud_val == baud_value ); + HAL_ASSERT( config == line_config ); + } +#endif + + /* + * Flush the receive FIFO of data that may have been received before the + * driver was initialized. + */ + rx_full = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_RXFULL_MASK; + while ( rx_full ) + { + HAL_get_8bit_reg( this_uart->base_address, RXDATA ); + rx_full = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_RXFULL_MASK; + } + + /* + * Clear status of the UART instance. + */ + this_uart->status = (uint8_t)0; + } +} + +/***************************************************************************//** + * UART_send() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_send +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +) +{ + size_t char_idx; + uint8_t tx_ready; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( tx_buffer != NULL_BUFFER ) + HAL_ASSERT( tx_size > 0 ) + + if( (this_uart != NULL_INSTANCE) && + (tx_buffer != NULL_BUFFER) && + (tx_size > (size_t)0) ) + { + for ( char_idx = (size_t)0; char_idx < tx_size; char_idx++ ) + { + /* Wait for UART to become ready to transmit. */ + do { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( !tx_ready ); + /* Send next character in the buffer. */ + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)tx_buffer[char_idx] ); + } + } +} + +/***************************************************************************//** + * UART_fill_tx_fifo() + * See "core_uart_apb.h" for details of how to use this function. + */ +size_t +UART_fill_tx_fifo +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +) +{ + uint8_t tx_ready; + size_t size_sent = 0u; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( tx_buffer != NULL_BUFFER ) + HAL_ASSERT( tx_size > 0 ) + + /* Fill the UART's Tx FIFO until the FIFO is full or the complete input + * buffer has been written. */ + if( (this_uart != NULL_INSTANCE) && + (tx_buffer != NULL_BUFFER) && + (tx_size > 0u) ) + { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + if ( tx_ready ) + { + do { + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)tx_buffer[size_sent] ); + size_sent++; + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( (tx_ready) && ( size_sent < tx_size ) ); + } + } + return size_sent; +} + +/***************************************************************************//** + * UART_get_rx() + * See "core_uart_apb.h" for details of how to use this function. + */ +size_t +UART_get_rx +( + UART_instance_t * this_uart, + uint8_t * rx_buffer, + size_t buff_size +) +{ + uint8_t new_status; + uint8_t rx_full; + size_t rx_idx = 0u; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( rx_buffer != NULL_BUFFER ) + HAL_ASSERT( buff_size > 0 ) + + if( (this_uart != NULL_INSTANCE) && + (rx_buffer != NULL_BUFFER) && + (buff_size > 0u) ) + { + rx_idx = 0u; + new_status = HAL_get_8bit_reg( this_uart->base_address, STATUS ); + this_uart->status |= new_status; + rx_full = new_status & STATUS_RXFULL_MASK; + while ( ( rx_full ) && ( rx_idx < buff_size ) ) + { + rx_buffer[rx_idx] = HAL_get_8bit_reg( this_uart->base_address, + RXDATA ); + rx_idx++; + new_status = HAL_get_8bit_reg( this_uart->base_address, STATUS ); + this_uart->status |= new_status; + rx_full = new_status & STATUS_RXFULL_MASK; + } + } + return rx_idx; +} + +/***************************************************************************//** + * UART_polled_tx_string() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_polled_tx_string +( + UART_instance_t * this_uart, + const uint8_t * p_sz_string +) +{ + uint32_t char_idx; + uint8_t tx_ready; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( p_sz_string != NULL_BUFFER ) + + if( ( this_uart != NULL_INSTANCE ) && ( p_sz_string != NULL_BUFFER ) ) + { + char_idx = 0U; + while( 0U != p_sz_string[char_idx] ) + { + /* Wait for UART to become ready to transmit. */ + do { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( !tx_ready ); + /* Send next character in the buffer. */ + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)p_sz_string[char_idx] ); + char_idx++; + } + } +} + +/***************************************************************************//** + * UART_get_rx_status() + * See "core_uart_apb.h" for details of how to use this function. + */ +uint8_t +UART_get_rx_status +( + UART_instance_t * this_uart +) +{ + uint8_t status = UART_APB_INVALID_PARAM; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + /* + * Extract UART error status and place in lower bits of "status". + * Bit 0 - Parity error status + * Bit 1 - Overflow error status + * Bit 2 - Frame error status + */ + if( this_uart != NULL_INSTANCE ) + { + status = ( ( this_uart->status & STATUS_ERROR_MASK ) >> + STATUS_ERROR_OFFSET ); + /* + * Clear the sticky status for this instance. + */ + this_uart->status = (uint8_t)0; + } + return status; +} + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h new file mode 100644 index 0000000..c016403 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h @@ -0,0 +1,451 @@ +/******************************************************************************* + * (c) Copyright 2007-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file core_uart_apb.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief This file contains the application programming interface for the + * CoreUARTapb bare metal driver. + * + */ +/*=========================================================================*//** + @mainpage CoreUARTapb Bare Metal Driver. + + @section intro_sec Introduction + CoreUARTapb is an implementation of the Universal Asynchronous + Receiver/Transmitter aimed at minimal FPGA tile usage within a Microchip FPGA. + The CoreUARTapb bare metal software driver is designed to be used in systems + with no operating system. + + The CoreUARTapb driver provides functions for basic polled transmitting and + receiving operations. It also provide functions that allow the use of the + CoreUARTapb in interrupt-driven mode but leaves the management of interrupts + to the calling application, as interrupt enabling and disabling are not + controlled through the CoreUARTapb registers. The CoreUARTapb driver is + provided as C source code. + + @section driver_configuration Driver Configuration + Your application software should configure the CoreUARTapb driver by calling + the UART_init() function for each CoreUARTapb instance in the hardware design. + The configuration parameters include the CoreUARTapb hardware instance base + address and other runtime parameters, such as baud rate, bit width, and + parity. No CoreUARTapb hardware configuration parameters are needed by the + driver, apart from the CoreUARTapb hardware instance base address. Hence, no + additional configuration files are required to use the driver. + + A CoreUARTapb hardware instance is generated with fixed baud rate, character + size, and parity configuration settings as part of the hardware flow. The + baud_value and line_config parameter values passed to the UART_init() function + have no effect if fixed values were selected for the baud rate, character + size, and parity in the hardware configuration of CoreUARTapb. When fixed + values are selected for these hardware configuration parameters, the driver is + unable to overwrite the fixed values in the CoreUARTapb control registers, + CTRL1 and CTRL2. + + @section theory_op Theory of Operation + The CoreUARTapb software driver is designed to allow the control of multiple + instances of CoreUARTapb. Each instance of CoreUARTapb in the hardware design + is associated with a single instance of the UART_instance_t structure in the + software. You need to allocate memory for one unique UART_instance_t structure + instance for each CoreUARTapb hardware instance. The contents of these data + structures are initialized while calling the UART_init() function. A pointer + to the structure is passed to the subsequent driver functions in order to + identify the CoreUARTapb hardware instance you wish to perform the requested + operation on. + + Note: Do not attempt to directly manipulate the content of UART_instance_t + structures. This structure is only intended to be modified by the driver + function. + + Once initialized, the driver transmits and receives data. Transmit is + performed using the UART_send() function. If this function blocks, then it + returns only when the data passed to it has been sent to the CoreUARTapb + hardware. Data received by the CoreUARTapb hardware is read by the user + application using the UART_get_rx() function. + + The UART_fill_tx_fifo() function is also provided as a part of the + interrupt-driven transmit. This function fills the CoreUARTapb hardware + transmit FIFO with the content of a data buffer passed as a parameter before + returning. The control of the interrupts must be implemented outside the + driver, as the CoreUARTapb hardware does not provide the ability to enable + or disable its interrupt sources. + + The UART_polled_tx_string() function is provided to transmit a NULL-terminated + string in polled mode. If this function blocks, then it returns only when the + data passed to it has been sent to the CoreUARTapb hardware. + + The UART_get_rx_status() function returns the error status of the CoreUARTapb + receiver. This is used by applications to take appropriate action in case of + receiver errors. +*//*=========================================================================*/ +#ifndef __CORE_UART_APB_H +#define __CORE_UART_APB_H 1 + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + Data Bits Length Defines + ======================== + These constants define the data length in a UART packet. + | Constant | Description | + |-------------|---------------------------------------| + | DATA_7_BITS | Data length is 7-bits | + | DATA_8_BITS | Data length is 8-bits | + */ +#define DATA_7_BITS 0x00u +#define DATA_8_BITS 0x01u + +/***************************************************************************//** + Parity Defines + ============== + These constants define parity check options. + | Constant | Description | + |-------------|---------------------------------------| + | NO_PARITY | No Parity bit | + | EVEN_PARITY | Even Parity bit | + | ODD_PARITY | ODD Parity bit | + */ +#define NO_PARITY 0x00u +#define EVEN_PARITY 0x02u +#define ODD_PARITY 0x06u + +/***************************************************************************//** + Error Status Definitions + ======================== + These constants define the different types of possible errors in UART + transmission of data. + | Constant | Description | + |-------------------------|---------------------------------------| + | UART_APB_PARITY_ERROR | Data parity error | + | UART_APB_OVERFLOW_ERROR | Data overflow error | + | UART_APB_FRAMING_ERROR | Data framing error | + | UART_APB_NO_ERROR | No error | + | UART_APB_INVALID_PARAM | Invalid parameter | + */ +#define UART_APB_PARITY_ERROR 0x01u +#define UART_APB_OVERFLOW_ERROR 0x02u +#define UART_APB_FRAMING_ERROR 0x04u +#define UART_APB_NO_ERROR 0x00u +#define UART_APB_INVALID_PARAM 0xFFu + +/***************************************************************************//** + * There should be one instance of this structure for each instance of + * CoreUARTapb in your system. This structure instance identifies various UARTs + * in a system and should be passed as first parameter to UART functions to + * identify which UART performs the requested operation. The 'status' element in + * the structure is used to provide sticky status information. + */ +typedef struct +{ + addr_t base_address; + uint8_t status; +} UART_instance_t; + +/***************************************************************************//** + * The UART_init() function initializes the UART with the configuration passed + * as parameters. The configuration parameters are the baud_value that generates + * the baud rate and the line configuration (bit length and parity). + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data regarding + * this instance of the CoreUARTapb. This pointer is used to + * identify the target CoreUARTapb hardware instance in + * subsequent calls to the CoreUARTapb functions. + * @param base_addr The base_address parameter is the base address in the + * processor's memory map for the registers of the + * CoreUARTapb instance being initialized. + * @param baud_value The baud_value parameter selects the baud rate for the + * UART. The baud value is calculated from the frequency of + * the system clock in hertz and the desired baud rate using + * the following equation: + * baud_value = (clock / (baud_rate * 16)) - 1. + * The baud_value parameter must be a value in the range 0 + * to 8191 (or 0x0000 to 0x1FFF). + * @param line_config This parameter is the line configuration, specifies the + * bit length and parity settings. This is the logical OR of: + * - DATA_7_BITS + * - DATA_8_BITS + * - NO_PARITY + * - EVEN_PARITY + * - ODD_PARITY + * For example, 8 bits even parity would be specified as + * (DATA_8_BITS | EVEN_PARITY). + * @return This function does not return a value. + * @example + * @code + * #define BAUD_VALUE_57600 25 + * + * #define COREUARTAPB0_BASE_ADDR 0xC3000000UL + * + * UART_instance_t g_uart; + * int main() + * { + * UART_init(&g_uart, COREUARTAPB0_BASE_ADDR, + BAUD_VALUE_57600, (DATA_8_BITS | EVEN_PARITY)); + * } + * @endcode + */ +void +UART_init +( + UART_instance_t * this_uart, + addr_t base_addr, + uint16_t baud_value, + uint8_t line_config +); + +/***************************************************************************//** + * The UART_send() function is used to transmit data. It transfers the content + * of the transmitter data buffer, passed as a function parameter, into the + * UART's hardware transmitter FIFO. It returns when the full content of the + * transmitter data buffer has been transferred to the UART's transmitter FIFO. + * + * Note: You should not assume that the data you are sending using this function + * has been received at the other end by the time this function returns. The + * actual transmission over the serial connection is still be taking place at + * the time of the function return. It is safe to release or reuse the memory + * used as the transmit buffer once this function returns. + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data + * regarding this instance of the CoreUARTapbUART. + * @param tx_buffer The tx_buffer parameter is a pointer to a buffer that + * contains the data to be transmitted. + * @param tx_size The tx_size parameter is the size in bytes of the + * transmitted data. + * + * @return This function does not return a value. + * + * @example + * @code + * uint8_t testmsg1[] = {"\n\r\n\r\n\rUART_send() test message 1"}; + * UART_send(&g_uart,(const uint8_t *)&testmsg1,sizeof(testmsg1)); + * @endcode + */ +void +UART_send +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +); + +/***************************************************************************//** + * The UART_fill_tx_fifo() function fills the UART's transmitter hardware FIFO + * with the data found in the transmitter buffer that is passed in as a + * function parameter. The function returns either when the FIFO is full or + * when the complete contents of the transmitter buffer have been copied into + * the FIFO. It returns the number of bytes copied into the UART's transmitter + * hardware FIFO. This function is intended to be used as part of + * interrupt-driven transmission. + * + * Note: You should not assume that the data you transmit using this function + * has been received at the other end by the time this function returns. The + * actual transmission over the serial connection is still be taking place at + * the time of the function return. + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data + * regarding this instance of the UART. + * @param tx_buffer The tx_buffer parameter is a pointer to a buffer that + * contains the data to be transmitted. + * @param tx_size The tx_size parameter is the size in bytes of the + * transmitted data. + * @return This function returns the number of bytes copied into + * the UART's transmitter hardware FIFO. + * + * @example + * @code + * void send_using_interrupt + * ( + * uint8_t * pbuff, + * size_t tx_size + * ) + * { + * size_t size_in_fifo; + * size_in_fifo = UART_fill_tx_fifo( &g_uart, pbuff, tx_size ); + * } + * @endcode + */ +size_t +UART_fill_tx_fifo +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +); + +/***************************************************************************//** + * The UART_get_rx() function reads the content of the UART's receiver hardware + * FIFO and stores it in the receiver buffer that is passed in as a function + * parameter. It copies either the full contents of the FIFO into the receiver + * buffer, or just enough data from the FIFO to fill the receiver buffer, + * depending on the size of the receiver buffer. The size of the receiver + * buffer is passed in as a function parameter. UART_get_rx() returns the number + * of bytes copied into the receiver buffer. If no data was received at the time + * the function is called, the function returns 0. + * + * Note: This function reads and accumulates the receiver status of the + * CoreUARTapb instance before reading each byte from the receiver's + * data register/FIFO. This allows the driver to maintain a sticky + * record of any receiver errors that occur as the UART receives each + * data byte; receiver errors would otherwise be lost after each read + * from the receiver's data register. A call to the UART_get_rx_status() + * function returns any receiver errors accumulated during the execution + * of the UART_get_rx() function. + * + * Note: When FIFO mode is disabled in the CoreUARTapb hardware configuration, + * the driver accumulates a sticky record of any parity errors, framing + * errors, or overflow errors. When FIFO mode is enabled, the driver + * accumulates a sticky record of overflow errors only; in this case, + * interrupts must be used to handle parity errors or framing errors. + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data + * regarding this instance of the UART. + * @param rx_buffer The rx_buffer parameter is a pointer to a buffer where + * the received data is copied. + * @param buff_size The buff_size parameter is the size of the receive + * buffer in bytes. + * @return This function returns the number of bytes copied into + * the receive buffer. + * + * @example + * @code + * #define MAX_RX_DATA_SIZE 256 + * + * uint8_t rx_data[MAX_RX_DATA_SIZE]; + * uint8_t rx_size = 0; + * + * rx_size = UART_get_rx( &g_uart, rx_data, sizeof(rx_data) ); + * @endcode + */ +size_t +UART_get_rx +( + UART_instance_t * this_uart, + uint8_t * rx_buffer, + size_t buff_size +); + +/***************************************************************************//** + * The UART_polled_tx_string() function is used to transmit a NULL ('\0') + * terminated string. Internally, it polls for the transmit ready status and + * transfers the text starting at the address pointed by p_sz_string into + * the UART's hardware transmitter FIFO. It is a blocking function and returns + * only when the complete string has been transferred to the UART's transmit + * FIFO. + * + * Note: You should not assume that the data you transmit using this function + * has been received at the other end by the time this function returns. The + * actual transmission over the serial connection is still be taking place at + * the time of the function return. + * + * @param this_uart The this_uart parameter is the pointer to a + * UART_instance_t structure, which holds all data + * regarding this instance of the UART. + * @param p_sz_string The p_sz_string parameter is a pointer to a buffer + * containing the NULL ('\0') terminated string to be + * transmitted. + * @return This function does not return a value. + * + * @example + * @code + * uint8_t testmsg1[] = {"\r\n\r\nUART_polled_tx_string() test message 1\0"}; + * UART_polled_tx_string(&g_uart,(const uint8_t *)&testmsg1); + * @endcode + */ +void +UART_polled_tx_string +( + UART_instance_t * this_uart, + const uint8_t * p_sz_string +); + +/***************************************************************************//** + * The UART_get_rx_status() function returns the receiver error status of the + * CoreUARTapb instance. It reads both the current error status of the receiver + * and the accumulated error status from preceding calls to the UART_get_rx() + * function and combines them using a bitwise OR. It returns the cumulative + * parity, framing, and overflow error status of the receiver, since the + * previous call to UART_get_rx_status() as an 8-bit encoded value. + * + * Note: The UART_get_rx() function reads and accumulates the receiver status + * of the CoreUARTapb instance before reading each byte from the receiver's data + * register/FIFO. The driver maintains a sticky record of the cumulative error + * status, which persists after the UART_get_rx() function returns. The + * UART_get_rx_status() function clears this accumulated record of receiver + * errors before returning. + * + * @param this_uart The this_uart parameter is a pointer to a + * UART_instance_t structure which holds all data regarding + * this instance of the UART. + * @return This function returns the UART receiver error status as + * an 8-bit encoded value. The return value is 0, if there + * are no receiver errors occurred. The driver provides a + * set of bit mask constants, which should be compared with + * and/or used to mask the returned value to determine the + * receiver error status. + * When the return value is compared to the following bit + * masks, a non-zero result indicates that the + * corresponding error occurred: + * UART_APB_PARITY_ERROR (bit mask = 0x01) + * UART_APB_OVERFLOW_ERROR (bit mask = 0x02) + * UART_APB_FRAMING_ERROR (bit mask = 0x04) + * When the return value is compared to the following bit + * mask, a non-zero result indicates that no error + * occurred: + * UART_APB_NO_ERROR (0x00) + * + * @example + * @code + * UART_instance_t g_uart; + * uint8_t rx_data[MAX_RX_DATA_SIZE]; + * uint8_t err_status; + * err_status = UART_get_err_status(&g_uart); + * + * if(UART_APB_NO_ERROR == err_status ) + * { + * rx_size = UART_get_rx( &g_uart, rx_data, MAX_RX_DATA_SIZE ); + * } + * @endcode + */ +uint8_t +UART_get_rx_status +( + UART_instance_t * this_uart +); + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_UART_APB_H */ diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h new file mode 100644 index 0000000..c123cc3 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h @@ -0,0 +1,133 @@ +/******************************************************************************* + * (c) Copyright 2007-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file coreuartapb_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreUARTapb register definitions + */ + +#ifndef __CORE_UART_APB_REGISTERS +#define __CORE_UART_APB_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * TxData register details + */ +#define TXDATA_REG_OFFSET 0x0u + +/* + * TxData bits. + */ +#define TXDATA_OFFSET 0x0u +#define TXDATA_MASK 0xFFu +#define TXDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * RxData register details + */ +#define RXDATA_REG_OFFSET 0x4u + +/* + * RxData bits. + */ +#define RXDATA_OFFSET 0x4u +#define RXDATA_MASK 0xFFu +#define RXDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * ControReg1 register details + */ +#define CTRL1_REG_OFFSET 0x8u + +/* + * Baud value (Lower 8-bits) + */ +#define CTRL1_BAUDVALUE_OFFSET 0x8u +#define CTRL1_BAUDVALUE_MASK 0xFFu +#define CTRL1_BAUDVALUE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * ControReg2 register details + */ +#define CTRL2_REG_OFFSET 0xCu + +/* + * Bit length + */ +#define CTRL2_BIT_LENGTH_OFFSET 0xCu +#define CTRL2_BIT_LENGTH_MASK 0x01u +#define CTRL2_BIT_LENGTH_SHIFT 0u + +/* + * Parity enable. + */ +#define CTRL2_PARITY_EN_OFFSET 0xCu +#define CTRL2_PARITY_EN_MASK 0x02u +#define CTRL2_PARITY_EN_SHIFT 1u + +/* + * Odd/even parity selection. + */ +#define CTRL2_ODD_EVEN_OFFSET 0xCu +#define CTRL2_ODD_EVEN_MASK 0x04u +#define CTRL2_ODD_EVEN_SHIFT 2u + +/* + * Baud value (Higher 5-bits) + */ +#define CTRL2_BAUDVALUE_OFFSET 0xCu +#define CTRL2_BAUDVALUE_MASK 0xF8u +#define CTRL2_BAUDVALUE_SHIFT 3u + +/*------------------------------------------------------------------------------ + * StatusReg register details + */ +#define StatusReg_REG_OFFSET 0x10u + +#define STATUS_REG_OFFSET 0x10u + +/* + * Transmit ready. + */ +#define STATUS_TXRDY_OFFSET 0x10u +#define STATUS_TXRDY_MASK 0x01u +#define STATUS_TXRDY_SHIFT 0u + +/* + * Receive full. + */ +#define STATUS_RXFULL_OFFSET 0x10u +#define STATUS_RXFULL_MASK 0x02u +#define STATUS_RXFULL_SHIFT 1u + +/* + * Parity error. + */ +#define STATUS_PARITYERR_OFFSET 0x10u +#define STATUS_PARITYERR_MASK 0x04u +#define STATUS_PARITYERR_SHIFT 2u + +/* + * Overflow. + */ +#define STATUS_OVERFLOW_OFFSET 0x10u +#define STATUS_OVERFLOW_MASK 0x08u +#define STATUS_OVERFLOW_SHIFT 3u + +/* + * Frame Error. + */ +#define STATUS_FRAMERR_OFFSET 0x10u +#define STATUS_FRAMERR_MASK 0x10u +#define STATUS_FRAMERR_SHIFT 4u + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_UART_APB_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.c b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.c new file mode 100644 index 0000000..a2f4911 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.c @@ -0,0 +1,765 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Mi-V I2C Soft IP bare-metal driver. This module is delivered as part of + * Extended Sub System(ESS) MIV_ESS. + * Please refer to miv_i2c.h file for more information. + */ + +#include "miv_i2c.h" + +#define MIV_I2C_ERROR 0xFFu + +/*------------------------------------------------------------------------------ + * MIV I2C transaction direction. + */ +#define MIV_I2C_WRITE_DIR 0u +#define MIV_I2C_READ_DIR 1u + +/* -- TRANSACTIONS TYPES -- */ +#define MIV_I2C_NO_TRANSACTION 0u +#define MIV_I2C_MASTER_WRITE_TRANSACTION 1u +#define MIV_I2C_MASTER_READ_TRANSACTION 2u +#define MIV_I2C_MASTER_SEQUENTIAL_READ_TRANSACTION 3u + +/*------------------------------------------------------------------------------ + * MIV I2C HW states + */ +#define MIV_I2C_IDLE 0x00u +#define MIV_I2C_TX_STA_CB 0x01u +#define MIV_I2C_TX_DATA 0x02u +#define MIV_I2C_RX_DATA 0x03u + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_disable_irq() disables the Mi-V I2C interrupt. + */ +void +MIV_I2C_disable_irq +( + void +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_enable_irq() enables the Mi-V I2C interrupt. + */ +void +MIV_I2C_enable_irq +( + void +); + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_init +( + miv_i2c_instance_t *this_i2c, + addr_t base_addr +) +{ + /* Assign the base address + * Clock Prescale value set + * MIV_I2C interrupt enabled + * I2C core enable + */ + psr_t processor_state; + + /* Disabling the interrupts */ + processor_state = HAL_disable_interrupts(); + + /* + * Initialize all items of the this_miv_i2c data structure to zero. This + * initializes all state variables to their init value. It relies on + * the fact that NO_TRANSACTION, MIV_I2C_SUCCESS and I2C_RELEASE_BUS all + * have an actual value of zero. + */ + memset(this_i2c, 0, sizeof(miv_i2c_instance_t)); + + this_i2c->base_addr = base_addr; + + HAL_restore_interrupts(processor_state); +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_config +( + miv_i2c_instance_t *this_i2c, + uint16_t clk_prescale +) +{ + /* Assign the base address + * Clock Prescale value set + * MIV_I2C interrupt enabled + * I2C core enable + */ + psr_t processor_state; + + /* Disabling the interrupts */ + processor_state = HAL_disable_interrupts(); + + /* Before writing to prescale reg, the core enable must be zero */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CTRL_CORE_EN, 0x00u); + + /* Set the prescale value */ + HAL_set_16bit_reg(this_i2c->base_addr, PRESCALE, clk_prescale); + + /* Enable the MIV I2C interrupts */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CTRL_IRQ_EN, 0x01u); + + /* Enable the MIV I2C core */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CTRL_CORE_EN, 0x01u); + + this_i2c->master_state = MIV_I2C_IDLE; + + HAL_restore_interrupts(processor_state); +} + +/* + * Please refer to miv_i2c.h for more info + */ +uint8_t +MIV_I2C_start +( + miv_i2c_instance_t *this_i2c +) +{ + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + /* Generate I2C start condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + HAL_restore_interrupts(processor_state); + + return 0u; +} + +/* + * Please refer to miv_i2c.h for more info + */ +uint8_t +MIV_I2C_stop +( + miv_i2c_instance_t *this_i2c +) +{ + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + /* Generate I2C stop condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + HAL_restore_interrupts(processor_state); + + return 0u; +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_write +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t bus_options, + uint8_t ack_polling_options +) +{ + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + /* I2C write flow + * + * Check I2C status for ongoing transaction + * Populate the structure with input data + * Generate start condition + * Set the write_direction and target address. + */ + + /* Update the transaction only when there is no ongoing I2C transaction */ + if (this_i2c->transaction == MIV_I2C_NO_TRANSACTION) + { + this_i2c->transaction = MIV_I2C_MASTER_WRITE_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MIV_I2C_MASTER_WRITE_TRANSACTION ; + + /* Populate the i2c instance structure */ + + /* Set the target addr */ + this_i2c->target_addr = i2c_target_addr; + this_i2c->dir = MIV_I2C_WRITE_DIR; + + /* Set up the tx buffer */ + this_i2c->master_tx_buffer = write_buffer; + this_i2c->master_tx_size = write_size; + this_i2c->master_tx_idx = 0u; + + /* Set the I2C status in progress and setup the options */ + this_i2c->bus_options = bus_options; + this_i2c->ack_polling_options = ack_polling_options; + this_i2c->master_status = MIV_I2C_IN_PROGRESS; + + + /* Generate I2C start condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* write target address and write bit */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, MIV_I2C_WRITE_DIR); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, i2c_target_addr); + + /* Set WR bit to transmit start condition and control byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + /* Set current master hw state -> transmitted start condition and + * control byte + */ + this_i2c->master_state = MIV_I2C_TX_STA_CB; + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( MIV_I2C_HOLD_BUS == this_i2c->bus_status ) + { + /* Must toggle IACK bit to clear the MIV_I2C IRQ*/ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00); + } + + MIV_I2C_enable_irq(); + + HAL_restore_interrupts(processor_state); + +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_read +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +) +{ + psr_t processor_state; + uint8_t status = MIV_I2C_SUCCESS; + + processor_state = HAL_disable_interrupts(); + + /* MIV I2C Read operation flow + * + * Check for ongoing transaction + * Populate the i2c instance structure + * Generate the start condition + * Set the READ_direction bit and target addr + */ + + uint8_t read_stat = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_TIP); + + /* Update the transaction only when there is no ongoing I2C transaction */ + if (this_i2c->transaction == MIV_I2C_NO_TRANSACTION) + { + this_i2c->transaction = MIV_I2C_MASTER_READ_TRANSACTION; + } + + this_i2c->pending_transaction = MIV_I2C_MASTER_READ_TRANSACTION; + + /* Populate the MIV I2C instance structure */ + + this_i2c->target_addr = i2c_target_addr; + this_i2c->dir = MIV_I2C_READ_DIR; + + /* Populate read buffer */ + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set the BUS and ACK polling options */ + this_i2c->bus_options = bus_options; + this_i2c->ack_polling_options = ack_polling_options; + + /* Generate the start condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* Set the DIR bit and target addr */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, MIV_I2C_READ_DIR); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, i2c_target_addr); + + /* Set the WR bit to transmit the start condition and command byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + /* Set the i2c master state and status transmitting STA and Command Byte */ + this_i2c->master_state = MIV_I2C_TX_STA_CB; + this_i2c->master_status = MIV_I2C_IN_PROGRESS; + + /* Toggle the IACK bit if required */ + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( MIV_I2C_HOLD_BUS == this_i2c->bus_status ) + { + /* Must toggle IACK bit to clear the MIV_I2C IRQ*/ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00); + } + /* Enable the I2C interrupt */ + MIV_I2C_enable_irq(); + + HAL_restore_interrupts(processor_state); +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_write_read +( + miv_i2c_instance_t *this_i2c, + uint8_t target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +) +{ + uint8_t status = MIV_I2C_SUCCESS; + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + uint8_t read_stat = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_TIP); + + /* I2C write read operation flow + * + * Used to read the data from set address offset + * + * Configure the i2c instance structure + * generate the start and configure the dir and target addr + * set wr bit to transmit the start and command byte + * + */ + + /* Update the transaction only when there is no ongoing I2C transaction */ + if (this_i2c->transaction == MIV_I2C_NO_TRANSACTION) + { + this_i2c->transaction = MIV_I2C_MASTER_READ_TRANSACTION; + } + + this_i2c->pending_transaction = MIV_I2C_MASTER_READ_TRANSACTION; + + /* Populate the I2C instance */ + + this_i2c->target_addr = target_addr; + + /* setup the i2c direction */ + this_i2c->dir = MIV_I2C_WRITE_DIR; + + /* set up transmit buffer */ + this_i2c->master_tx_buffer = write_buffer; + this_i2c->master_tx_size = write_size; + this_i2c->master_tx_idx = 0u; + + /* set up receive buffer */ + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set the bus and ack polling options */ + this_i2c->bus_options = bus_options; + this_i2c->ack_polling_options = ack_polling_options; + + /* Generate the start command */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* Set the DIR and target addr */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + /* Set the WR bit to transmit the start command and command byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + /* Set the i2c master state and status transmitting STA and Command Byte */ + this_i2c->master_state = MIV_I2C_TX_STA_CB; + this_i2c->master_status = MIV_I2C_IN_PROGRESS; + + /* + * Clear interrupt if required + */ + if ( MIV_I2C_HOLD_BUS == this_i2c->bus_status ) + { + /* Must toggle IACK bit to clear the MIV_I2C IRQ*/ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00u); + } + + /* Enable the I2C interrupt */ + MIV_I2C_enable_irq(); + + HAL_restore_interrupts(processor_state); +} + +/* MIV_I2C_isr() + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_isr +( + miv_i2c_instance_t *this_i2c +) +{ + uint8_t i2c_state; + uint8_t i2c_ack_status; + uint8_t i2c_al_status; + uint8_t hold_bus; + + /* Read the I2C master state */ + i2c_state = this_i2c->master_state; + + /* Read the ack and al status */ + i2c_ack_status = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_RXACK); + i2c_al_status = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_AL); + + switch (i2c_state) + { + /* I2C ISR State Machine + * + * Cases: + * - Transmit start condition and control byte + * - Received ACK and bus arbitration was not lost (Read or Write) + * - Received NACK + * - Bus arbitration lost + * + * - Transmit data + * - Received ACK and bus arbitration was not lost (Read or Write) + * - Received NACK + * - Bus arbitration lost + * + * - Receive data + * - Received ACK and bus arbitration was not lost (Read or Write) + * - Bus arbitration lost + */ + + case MIV_I2C_TX_STA_CB: + + /* Received ACK from target and I2C bus arbitration is not lost */ + if (i2c_ack_status == 0u && i2c_al_status == 0u) + { + /* If I2C master write operation */ + if (this_i2c->dir == MIV_I2C_WRITE_DIR) + { + /* write first byte of data and set the WR bit to transfer the data */ + HAL_set_8bit_reg(this_i2c->base_addr, TRANSMIT, + this_i2c->master_tx_buffer[this_i2c->master_tx_idx]); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + /* Increment the index */ + this_i2c->master_tx_idx++; + + /* Set the master state to TX data */ + this_i2c->master_state = MIV_I2C_TX_DATA; + } + /* Master read operation */ + else + { + if (this_i2c->master_rx_size == 1u) + { + /* Send the ACK if the rx size is 1, transmit NACK to slave + * after receiving 1 byte to indicate slave to stop sending + * the data + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_ACK, 0x01u); + } + + /* Send the RD command to slave */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_RD, 0x01u); + + /* Increment the index */ + this_i2c->master_rx_idx++; + + /* Change state to receive data */ + this_i2c->master_state = MIV_I2C_RX_DATA; + } + } + else if (i2c_ack_status == 1u) + { + if (this_i2c->ack_polling_options == MIV_I2C_ACK_POLLING_ENABLE) + { + /* Target responded with NACK and ACK polling option is enabled + * + * Re-send the start condition and control byte + * + * TO-DO: This might become infinite loop check for timeout + * options. + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + this_i2c->master_tx_idx = 0u; + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + else + { + /* Target responded with NACK and ACK polling is disabled + * Abort the transaction and move to IDLE state + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + + this_i2c->master_status = MIV_I2C_FAILED; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + + this_i2c->master_state = MIV_I2C_IDLE; + } + } + + else if (i2c_al_status == 1u) + { + /* Arbitration was lost on the BUS during the transmission of + * previous start condition and control byte. + * Re-send the STA and CB + */ + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + break; + + /* Transmit master data */ + case MIV_I2C_TX_DATA: + + /* ACK received and arbitration was not lost */ + if (i2c_ack_status == 0u && i2c_al_status == 0u) + { + uint8_t tx_buff[this_i2c->master_tx_size]; + if (this_i2c->master_tx_idx < this_i2c->master_tx_size) + { + HAL_set_8bit_reg(this_i2c->base_addr, TRANSMIT, + this_i2c->master_tx_buffer[this_i2c->master_tx_idx]); + + tx_buff[this_i2c->master_tx_idx] = this_i2c->master_tx_buffer[this_i2c->master_tx_idx]; + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + /* Increment the index */ + this_i2c->master_tx_idx++; + + /* Set the master state to TX data */ + this_i2c->master_state = MIV_I2C_TX_DATA; + } + + /* All the bytes are transmitted */ + else if (this_i2c->master_tx_idx == this_i2c->master_tx_size) + { + /* If this is a MASTER_READ_TRANSACTION, hold bus and start a + new transfer in read mode now that the read address has been + written to the slave */ + if(this_i2c->transaction == MIV_I2C_MASTER_READ_TRANSACTION) + + { + //Switch direction to READ + this_i2c->dir = MIV_I2C_READ_DIR; + + // Set the STA bit + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* Set the DIR bit and target addr */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, MIV_I2C_READ_DIR); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, this_i2c->target_addr); + + /* Set the WR bit to transmit the start condition and command byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + // Reset the buffer index + this_i2c->master_tx_idx = 0u; + this_i2c->master_rx_idx = 0u; + + /* Set the master state to RX data */ + this_i2c->master_state = MIV_I2C_RX_DATA; + } + + else + { + /* If releasing the bus, transmit the stop condition at the end + * of the transfer. + */ + hold_bus = this_i2c->bus_status & MIV_I2C_HOLD_BUS; + + if (hold_bus == 0) + { + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + } + else + { + MIV_I2C_disable_irq(); + } + this_i2c->master_status = MIV_I2C_SUCCESS; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + this_i2c->master_state = MIV_I2C_IDLE; + } + } + } + + else if (i2c_ack_status == 1u) + { + /* Received NACK from target device + * + * Release the bus and end the transfer + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + + this_i2c->master_status = MIV_I2C_FAILED; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + + this_i2c->master_state = MIV_I2C_IDLE; + } + + else if (i2c_al_status == 1u) + { + /* Arbitration was lost on the BUS during the transmission of + * previous start condition and control byte. + * Re-send the STA and CB + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, + this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + break; + + /* Receive target device data */ + case MIV_I2C_RX_DATA: + + if (i2c_al_status == 0u) + { + if (this_i2c->master_rx_idx < this_i2c->master_rx_size) + { + this_i2c->master_rx_buffer[this_i2c->master_rx_idx - 1u] = + HAL_get_8bit_reg(this_i2c->base_addr, RECEIVE); + + /* If next byte is last one + * Send NACK to target device to stop sending data + */ + if (this_i2c->master_rx_idx == (this_i2c->master_rx_size - 1u)) + { + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_ACK, 0x01u); + } + + else + { + /* Send ACK to receive next bytes */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_ACK, 0x00u); + } + + /* Set RD bit to receive next byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_RD, 0x01u); + + this_i2c->master_rx_idx++; + } + + /* Received all bytes */ + else //if (this_i2c->master_rx_idx == this_i2c->master_rx_size) + { + this_i2c->master_rx_buffer[this_i2c->master_rx_idx - 1] = + HAL_get_8bit_reg(this_i2c->base_addr, RECEIVE); + + hold_bus = this_i2c->bus_status & MIV_I2C_HOLD_BUS; + + if (hold_bus == 0) + { + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + } + else + { + MIV_I2C_disable_irq(); + } + this_i2c->master_status = MIV_I2C_SUCCESS; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + + this_i2c->master_state = MIV_I2C_IDLE; + } + } + + else if (i2c_al_status == 1u) + { + /* Arbitration was lost on the BUS during the transmission of + * previous start condition and control byte. + * Re-send the STA and CB + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, + this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + break; + } + + /* Toggle the IACK bit to clear interrupt */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00u); +} + +/* + * Please refer to miv_i2c.h for more info + */ +uint8_t +MIV_I2C_get_status +( + miv_i2c_instance_t *this_i2c +) +{ + uint8_t i2c_status; + + i2c_status = HAL_get_8bit_reg(this_i2c->base_addr, STATUS); + + return i2c_status; +} diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.h b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.h new file mode 100644 index 0000000..c5e704d --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.h @@ -0,0 +1,854 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * I2C module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(MIV_ESS). + */ + +/*=========================================================================*//** + @mainpage Mi-V I2C Bare Metal Driver + + ============================================================================== + Introduction + ============================================================================== + The Mi-V I2C driver provides a set of functions for controlling the Mi-V I2C + Soft-IP module. This module is delivered as a part of the Mi-V Extended + Sub System(MIV_ESS). The driver provides a minimal APB-driven I2C interface, + supporting initiator read and write access to peripheral I2C devices. + + The major features provided by the Mi-V I2C driver are: + - Support for configuring the I2C instance. + - I2C master operations. + - I2C ISR. + + This driver can be used as part of a bare metal system where no operating + system is available. The driver can be adapted for use as part of an + operating system, but the implementation of the adaptation layer between the + driver and the operating system's driver model is outside the scope of this + driver. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + The application software should initialize and configure the Mi-V I2C through + the call to the MIV_I2C_init() and MIV_I2C_config() function for Mi-V I2C + instance in the design. The configuration parameter include base address and + Prescaler value. + + ------------------------------ + Interrupt Control + ------------------------------ + The Mi-V I2C driver has to enable and disable the generation of interrupts by + Mi-V I2C at various times while operating. This enabling and disabling of the + interrupts must be done through the Mi-V RV32 HAL provided interrupt handlers. + For that reason, the method controlling the Mi-V I2C interrupts is system + specific and it is necessary to customize the MIV_I2C_enable_irq() and + MIV_I2C_disable_irq() functions as per requirement. + + The implementation of MIV_I2C_enable_irq() should permit the interrupts + generated by the Mi-V I2C to the processor through a call to respective miv-hal + interrupt handler. The implementation of MIV_I2C_disable_irq() should prevent + the interrupts generated by a Mi-V I2C from interrupting the processor. + Please refer to the miv_i2c_interrupt.c for more information about the + implementation. + + No MIV_I2C hardware configuration parameters are used by the driver, apart + from the MIV_I2C base address. Hence, no additional configuration files + are required to use the driver. + + ============================================================================== + Theory of Operation + ============================================================================== + The Mi-V I2C software driver is designed to allow the control of multiple + instances of Mi-V I2C. Each instance of Mi-V I2C in the hardware design is + associated with a single instance of the miv_i2c_instance_t structure in the + software. User must allocate memory for one unique miv_i2c_instance_t + structure for each instance of Mi-V I2C in the hardware. + A pointer to the structure is passed to the subsequent driver functions in + order to identify the MIV_I2C hardware instance and to perform requested + operation. + + Note: Do not attempt to directly manipulate the contents of the + miv_i2c_instance_t structure. These structures are only intended to be modified + by the driver functions. + + The Mi-V I2C driver functions are grouped into following categories: + - Initialization and configuration + - I2C master operation functions to handle write, read and write_read + operations. + - Interrupt control + + -------------------------------- + Initialization and configuration + -------------------------------- + The Mi-V I2C device is first initialized by the call to MIV_I2C_init(). This + function initializes the instance of Mi-V I2C with the base address. + MIV_I2C_init() function must be called before any other Mi-V I2C driver API. + + The configuration of the Mi-V I2C instance is done via call to the + MIV_I2C_config() function. This function will set the prescale value which is + used to set the frequency of the I2C clock(SCLK) generated by I2C module. + + --------------------------------- + Transaction types + --------------------------------- + The driver is designed to handle three types of transactions: + - Write transactions + - Read transactions + - Write-Read transaction + + ### Write Transaction + The write transaction begins with master sending a start condition, followed + by device address byte with the R/W bit set to logic '0', and then by the + word address bytes. The slave acknowledges the receipt of its address with + acknowledge bit. The master sends one byte at a time to the slave, which must + acknowledge the receipt of each byte for the next byte to be sent. The master + sends STOP condition to complete the transaction. The slave can abort the + transaction by replying with negative acknowledge. + + The application programmer can choose not to send the STOP bit at the end of + the transaction causing repetitive start conditions. + + ### Read Transaction + The master I2C device initiates a read transaction by sending a START bit + as soon as the bus becomes free. The start condition is followed by the + control byte which contains 7-bit slave address followed by R/W bit set to + logic '1'. The slave sends data one byte at a time to the master, which must + acknowledge receipt of each byte for the next byte to be sent. The master + sends a non-acknowledge bit following the last byte it wishes to read + followed by a STOP bit. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ### Write-Read Transaction + The write read transaction is a combination of a write transaction + immediately followed by a read transaction. There is no STOP condition sent + between the write and read phase of write-read transaction. A repeated START + condition is sent between the write and read phases. + + Whilst the write handler is being executed, the slave holds the clock line + low to stretch the clock until the response is ready. + + The write-read transaction is typically used to send an memory/register + address in the write transaction specifying the start address of the data to + be transferred during the read phase. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ------------------------------------- + Interrupt Control + ------------------------------------- + The Mi-V I2C driver is interrupt driven and it uses the MIV_I2C_irq() function + to drive the ISR state machine which is at the heart of the driver. The + application is responsible for providing the link between the interrupt + generating hardware and the Mi-V I2C interrupt handler and must ensure that + the MIV_I2C_isr() function is called with the correct miv_i2c_instance_t + structure pointer for the Mi-V I2C instance initiating the interrupt. + +*//*=========================================================================*/ +#ifndef MIV_I2C_H_ +#define MIV_I2C_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "miv_i2c_regs.h" +#include + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#else +#include "hal.h" +#endif + +/*-------------------------------------------------------------------------*//** + The miv_i2c_status_t type is used to report the status of I2C transactions. + */ +typedef enum miv_i2c_status +{ + MIV_I2C_SUCCESS = 0u, + MIV_I2C_IN_PROGRESS, + MIV_I2C_FAILED, + MIV_I2C_TIMED_OUT +}miv_i2c_status_t; + +/*-------------------------------------------------------------------------*//** + This structure is used to identify the MIV_I2C hardware instances in a system. + Your application software should declare one instance of this structure for + each instance of the MIV_I2C in your system. The function MIV_I2C_init() + Initializes this structure. A pointer to an initialised instance of the structure + should be passed as the first parameter to the MIV_I2C driver functions, to + identify which MIV_I2C hardware instance should perform the requested operation. + + The contents of this data structure should not be modified or used outside of + the MIV_I2C driver. Software using the MIV_I2C driver should only need to + create one single instance of this data structure for each MIV_I2C hardware + instance in the system, then pass a pointer to these data structures with each + call to the MIV_I2C driver in order to identify the MIV_I2C hardware instance + it wishes to use. +*/ + +typedef struct miv_i2c_instance +{ + addr_t base_addr; + + /* Transmit related info:*/ + uint_fast8_t target_addr; + + /* Current transaction type */ + uint8_t transaction; + + uint8_t bus_options; + + uint8_t ack_polling_options; + + /* Current State of the I2C master */ + uint8_t master_state; + + /* Master TX INFO: */ + const uint8_t * master_tx_buffer; + uint_fast16_t master_tx_size; + uint_fast16_t master_tx_idx; + uint_fast8_t dir; + + /* Master RX INFO: */ + uint8_t * master_rx_buffer; + uint_fast16_t master_rx_size; + uint_fast16_t master_rx_idx; + + /* Master Status */ + volatile miv_i2c_status_t master_status; + uint32_t master_timeout_ms; + + /* user specific data */ + void *p_user_data ; + + /* I2C bus status */ + uint8_t bus_status; + + /* Is transaction pending flag */ + uint8_t is_transaction_pending; + + /* I2C Pending transaction */ + uint8_t pending_transaction; + +}miv_i2c_instance_t; + + +/*-------------------------------------------------------------------------*//** + MIV_I2C_RELEASE_BUS + ===================== + The MIV_I2C_RELEASE_BUS constant is used to specify the bus_options parameter + for MIV_I2C_read(), MIV_I2C_write() and MIV_I2C_write_read() to indicate + that a STOP bit must be generated at the end of the I2C transaction to release + the bus. + */ +#define MIV_I2C_RELEASE_BUS 0x00u + + +/*-------------------------------------------------------------------------*//** + MIV_I2C_HOLD_BUS + ===================== + The MIV_I2C_HOLD_BUS constant is used to specify the bus_optionsparameter + for MIV_I2C_read(), MIV_I2C_write() and MIV_I2C_write_read() to indicate + that a STOP bit must not be generated at the end of the I2C transaction in + order to retain the bus ownership. This causes the next transaction to + begin with a repeated START bit and no STOP bit between the transactions. + */ +#define MIV_I2C_HOLD_BUS 0x01u + +/*-------------------------------------------------------------------------*//** + MIV_I2C_ACK_POLLING_DISABLE + ===================== + The MIV_I2C_ACK_POLLING_DISABLE constant is used to specify the + ack_polling_options parameter to functions MIV_I2C_write(), + MIV_I2C_write_read() and MIV_I2C_read(). Acknowledgment polling is used when + working with I2C memory devices such as EEPROM, which feature an internal + write cycle. + + With acknowledgment polling disabled, if the target slave device responds to the + control byte with a NACK, the MIV_I2C will abort the transfer. + */ +#define MIV_I2C_ACK_POLLING_DISABLE 0x00u + +/*-------------------------------------------------------------------------*//** + MIV_I2C_ACK_POLLING_ENABLE + ===================== + The MIV_I2C_ACK_POLLING_ENABLE constant is used to specify the + ack_polling_options parameter to functions MIV_I2C_write(), + MIV_I2C_write_read() and MIV_I2C_read(). acknowledgment polling is used when + working with I2C memory devices such as EEPROM, which feature an internal + write cycle. + + With acknowledgment polling enabled, if the slave device responds to the + control byte with a NACK, the MIV_I2C will repeatedly transmit another control + byte until the slave device accepts the connection with an ACK, or the timeout + specified in the MIV_I2C_wait_complete() function is reached. Acknowledgment + polling allows for the next read/write operation to be started as soon as the + EEPROM has completed its internal write cycle. + */ +#define MIV_I2C_ACK_POLLING_ENABLE 0x01u + +/*--------------------------------Public APIs---------------------------------*/ + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_init() function is used to initialize the Mi-V I2C module instance + with the base address. + + Note: This function should be called before calling any other Mi-V I2C + functions. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + @param base_addr + Base address of the Mi-V I2C module instance in the MIV_ESS + soft IP. + + @return + This function does not return any value. + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + } + @endcode + */ +void +MIV_I2C_init +( + miv_i2c_instance_t *this_i2c, + addr_t base_addr +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_config() function is used to configure the Mi-V I2C module. This + function will set the prescale value which is used to set the frequency of + the I2C clock(SCLK) generated by I2C module and also enables the I2C core and + interrupts. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param clk_prescale + The value used to set the frequency of Mi-V I2C serial clock + (SCLK) generated by the Mi-V I2C module instance. The + prescaler value required to set particular frequency of + Mi-V I2C can be calculated using following formula: + + prescaler = (System Clock Frequency) / (5 * (Desired I2C Clock Frequency)) - 1 + + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + } + @endcode + */ +void +MIV_I2C_config +( + miv_i2c_instance_t *this_i2c, + uint16_t clk_prescale +); + + +uint8_t +MIV_I2C_start +( + miv_i2c_instance_t *this_i2c +); + + +uint8_t +MIV_I2C_stop +( + miv_i2c_instance_t *this_i2c +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_write() is used to set up and start the Mi-V I2C master write + transaction. This function is used for all Mi-V master write operation. + + For more information about the operation, please refer to the 'theory of + operations' section at the start of this document. + + This function returns immediately after initiating the transaction. The content + of the write buffer passed as parameter should not be modified until the write + transaction completes. It also means that the memory allocated for the write + buffer should not be freed or should not go out of scope before the write + completes. + You can check for the write transaction completion by polling the master_status + from miv_i2c_instance_t structure as shown in the sample code. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param i2c_target_addr + This parameter specifies the serial address for the slave + device. + + @param write_buffer + This parameter is a pointer to the buffer holding data to be + written to target I2C device. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param write_size + Number of bytes held in the write_buffer to be written to the + I2C device. + @param bus_options: + The bus_options parameter is used to indicate if the I2C bus + should be released on completion of the write transaction. + Using the MIV_I2C_RELEASE_BUS constant for the bus_options + parameter causes a STOP bit to be generated at the end of the + write transaction causing the bus to be released for other I2C + devices to use. Using the MIV_I2C_HOLD_BUS constant as + bus_options parameter prevents a STOP bit from being generated + at the end of the write transaction, preventing other I2C + devices from initiating a bus transaction. + + @param ack_polling_options: + The ack_polling_options parameter is used to indicate how the + MIV_I2C will respond if the slave device transmits a NACK to + the I2C control byte. Using the MIV_I2C_ACK_POLLING_DISABLE + constant for the ack_polling_options parameter causes the + MIV_I2C to abort the transfer if the slave device responds to + the I2C control byte with a NACK. Using the + MIV_I2C_ACK_POLLING_ENABLE constant for the ack_polling_options + parameter causes the MIV_I2C to repeatedly transmit a control + byte to the slave device until the slave device responds with + an ACK. + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + + MIV_I2C_write (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_tx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + } + @endcode + */ +void +MIV_I2C_write +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t bus_options, + uint8_t ack_polling_options +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_read() is used to set up and start the Mi-V I2C master read + transaction. This function is used for all MIV_I2C master read operation. + + For more information about the operation, please refer to the 'theory of + operations' section at the start of this document. + + This function returns immediately after initiating the transaction. The content + of the read buffer passed as parameter should not be modified until the write + transaction completes. It also means that the memory allocated for the read + buffer should not be freed or should not go out of scope before the read + completes. + You can check for the write transaction completion by polling the master_status + from miv_i2c_instance_t structure as shown in the sample code. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param i2c_target_addr + This parameter specifies the serial address for the slave + device. + + @param read_buffer + This parameter is a pointer to the buffer where the data + received from the I2C slave device is stored. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param read_size + Number of bytes held in the write_buffer to be read from the + I2C device. + + @param bus_options: + The bus_options parameter is used to indicate if the I2C bus + should be released on completion of the write transaction. + Using the MIV_I2C_RELEASE_BUS constant for the bus_options + parameter causes a STOP bit to be generated at the end of the + write transaction causing the bus to be released for other I2C + devices to use. Using the MIV_I2C_HOLD_BUS constant as + bus_options parameter prevents a STOP bit from being generated + at the end of the write transaction, preventing other I2C + devices from initiating a bus transaction. + + @param ack_polling_options: + The ack_polling_options parameter is used to indicate how the + MIV_I2C will respond if the slave device transmits a NACK to + the I2C control byte. Using the MIV_I2C_ACK_POLLING_DISABLE + constant for the ack_polling_options parameter causes the + MIV_I2C to abort the transfer if the slave device responds to + the I2C control byte with a NACK. Using the + MIV_I2C_ACK_POLLING_ENABLE constant for the ack_polling_options + parameter causes the MIV_I2C to repeatedly transmit a control + byte to the slave device until the slave device responds with + an ACK. + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + + MIV_I2C_write (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_tx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + + // reset miv_i2c_status variable + miv_i2c_status = 0u; + + MIV_I2C_read (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_rx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + } + @endcode + */ +void +MIV_I2C_read +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_write_read() is used to set up and start the Mi-V I2C master + write_read transaction. This function is used for all MIV_I2C master write_read + operation. + + This function is used in cases where data is being requested from a specific + address offset inside the target I2C slave device. + In this type of I2C operation, the I2C master starts by initiating a write + operation. During this write operation, the specific address offset is written + to the I2C slave. Once the address offset has been written to the I2C slave, + the I2C master transmits a repeated start, and initiates a read operation to + read data from the set address. + + For more information about the operation, please refer to the 'theory of + operations' section at the start of this document. + + This function returns immediately after initiating the transaction. The content + of the write and read buffer passed as parameter should not be modified until + the write transaction completes. It also means that the memory allocated for + the write and read buffer should not be freed or should not go out of scope + before the operation completes. + You can check for the write_read transaction completion by polling the + master_status from miv_i2c_instance_t structure. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param i2c_target_addr + This parameter specifies the serial address for the slave + device. + + @param write_buffer + This parameter is a pointer to the buffer holding data to be + written to target I2C device. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param write_size + Number of bytes held in the write_buffer to be written to the + I2C device. + + @param read_buffer + This parameter is a pointer to the buffer where the data + received from the I2C slave device is stored. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param read_size + Number of bytes held in the write_buffer to be read from the + I2C device. + + @param bus_options: + The bus_options parameter is used to indicate if the I2C bus + should be released on completion of the write transaction. + Using the MIV_I2C_RELEASE_BUS constant for the bus_options + parameter causes a STOP bit to be generated at the end of the + write transaction causing the bus to be released for other I2C + devices to use. Using the MIV_I2C_HOLD_BUS constant as + bus_options parameter prevents a STOP bit from being generated + at the end of the write transaction, preventing other I2C + devices from initiating a bus transaction. + + @param ack_polling_options: + The ack_polling_options parameter is used to indicate how the + MIV_I2C will respond if the slave device transmits a NACK to + the I2C control byte. Using the MIV_I2C_ACK_POLLING_DISABLE + constant for the ack_polling_options parameter causes the + MIV_I2C to abort the transfer if the slave device responds to + the I2C control byte with a NACK. Using the + MIV_I2C_ACK_POLLING_ENABLE constant for the ack_polling_options + parameter causes the MIV_I2C to repeatedly transmit a control + byte to the slave device until the slave device responds with + an ACK or the timeout specified in the MIV_I2C_wait_complete() + function is reached. + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + + MIV_I2C_write (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_tx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + + // reset miv_i2c_status variable + miv_i2c_status = 0u; + + uint8_t addr_offset[2] = {0x00, 0x00}; + MIV_I2C_write_read(&miv_i2c, + DUALEE_SLAVEADDRESS_1, + addr_offset, + sizeof(addr_offset), + i2c_rx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + } + @endcode + */ +void +MIV_I2C_write_read +( + miv_i2c_instance_t *this_i2c, + uint8_t target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_isr() function contains the MIV_I2C's interrupt service routine. + This ISR is at the heart of the MIV_I2C driver, and is used to control the + interrupt-driven, byte-by-byte I2C read and write operations. + + The ISR operates as a Finite State Machine (FSM), which uses the previously + completed I2C operation and its result to determine which I2C operation will + be performed next. + + The ISR operation is divided into following categories: + - MIV_I2C_IDLE + - MIV_I2C_TX_STA_CB + - MIV_I2C_TX_DATA + - MIV_I2C_RX_DATA + + ##### MIV_I2C_IDLE + The MIV_I2C_IDLE is entered on reset, or when an I2C master operation has been + completed or aborted. + Upon entering, the FSM will remain in this state until a write, read, or + write-read operation is requested + + ##### MIV_I2C_STA_CB + The MIV_I2C_TX_STA_CB operation is performed when the start condition and + control byte(i2c target address(7-bit) and direction of transaction(1-bit)) is + transmitted by the Mi-V I2C master device to the slave. + If the target I2C slave device responded to the previous START Condition + + Control Byte with an ACK, the MIV_I2C will start the requested I2C + read/write operation. + If the target slave I2C slave device responds with NACK, the MIV_I2C will + remain in this state or return to the idle state based on ack_polling + configuration. + + ##### MIV_I2C_TX_DATA + The MIV_I2C_TX_DATA state is entered after the target slave device accepts a + write request with an ACK. + This state is used to handle the byte-by-byte MIV_I2C write operations. + The FSM will remain in this state until either all data bytes have been + written to the target slave device, or an error occurs during the write + operation. + + ##### MIV_I2C_RX_DATA + The MIV_I2C_RX_DATA state is entered after the target slave device accepts a + read request with an ACK. + This state is used to handle the byte-by-byte MIV_I2C read operations. + The FSM will remain in this state until either all data bytes have been + received from the target slave device, or an error occurs. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + */ +void +MIV_I2C_isr +( + miv_i2c_instance_t *this_i2c +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_get_status() returns the 8-bit Mi-V I2C status register value. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + @return + This function returns 8-bit Mi-V I2C status register value. + */ +uint8_t +MIV_I2C_get_status +( + miv_i2c_instance_t *this_i2c +); + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_I2C_H_ */ diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_interrupt.c b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_interrupt.c new file mode 100644 index 0000000..871eafe --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_interrupt.c @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains functions used for MIV_I2C driver interrupt control. + * User should enable and disable the interrupts according to their design. + * Please refer to miv_i2c.h file for more information. + */ + +#include "miv_rv32_hal/miv_rv32_hal.h" + +void MIV_I2C_disable_irq(void) +{ +/* Disable I2C interrupt */ + MRV_disable_local_irq(MRV32_MSYS_EIE2_IRQn); +} + +void MIV_I2C_enable_irq(void) +{ +/* Enable I2C interrupt */ + MRV_enable_local_irq(MRV32_MSYS_EIE2_IRQn); +} + + diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_regs.h b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_regs.h new file mode 100644 index 0000000..9a4bfbf --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_regs.h @@ -0,0 +1,158 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP I2C module driver. This module is delivered as a part of Mi-V extended + * Sub-System(MIV_ESS). + */ + +#ifndef MIV_I2C_APB_REGISTERS +#define MIV_I2C_APB_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * Prescale register details + */ +#define PRESCALE_REG_OFFSET 0x00u + +/* Prescale register bits */ +#define PRESCALE_OFFSET 0x00u +#define PRESCALE_MASK 0xFFFFu +#define PRESCALE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Control register details + */ +#define CONTROL_REG_OFFSET 0x04u + +/* Control register bits */ +#define CONTROL_OFFSET 0x04u +#define CONTROL_MASK 0xC0u +#define CONTROL_SHIFT 0u + +/* Control register Core Enable Bit */ +#define CTRL_CORE_EN_OFFSET 0x04u +#define CTRL_CORE_EN_MASK 0x80u +#define CTRL_CORE_EN_SHIFT 7u + +/* Control register IRQ Enable bit */ +#define CTRL_IRQ_EN_OFFSET 0x04u +#define CTRL_IRQ_EN_MASK 0x40u +#define CTRL_IRQ_EN_SHIFT 6u + +/*------------------------------------------------------------------------------ + * Transmit register details + */ +#define TRANSMIT_REG_OFFSET 0x08u + +/* Transmit register bits */ +#define TRANSMIT_OFFSET 0x08u +#define TRANSMIT_MASK 0xFFu +#define TRANSMIT_SHIFT 0u + +/* Transmit register DIR bit */ +#define TX_DIR_OFFSET 0x08u +#define TX_DIR_MASK 0x01u +#define TX_DIR_SHIFT 0u + +/* Transmit register TARGET_ADDR bit */ +#define TX_TARGET_ADDR_OFFSET 0x08u +#define TX_TARGET_ADDR_MASK 0xFEu +#define TX_TARGET_ADDR_SHIFT 1u + +/*------------------------------------------------------------------------------ + * Receive register details + */ +#define RECEIVE_REG_OFFSET 0x0Cu + +/* Receive register bits */ +#define RECEIVE_OFFSET 0x0Cu +#define RECEIVE_MASK 0xFFu +#define RECEIVE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Command register details + */ +#define COMMAND_REG_OFFSET 0x10u + +/* Command register bits */ +#define COMMAND_OFFSET 0x10u +#define COMMAND_MASK 0xF9u +#define COMMAND_SHIFT 0u + +/* Command register IACK bit */ +#define CMD_IACK_OFFSET 0x10u +#define CMD_IACK_MASK 0x01u +#define CMD_IACK_SHIFT 0u + +/* Command register ACK bit */ +#define CMD_ACK_OFFSET 0x10u +#define CMD_ACK_MASK 0x08u +#define CMD_ACK_SHIFT 3u + +/* Command register WR bit */ +#define CMD_WR_OFFSET 0x10u +#define CMD_WR_MASK 0x10u +#define CMD_WR_SHIFT 4u + +/* Command register RD bit */ +#define CMD_RD_OFFSET 0x10u +#define CMD_RD_MASK 0x20u +#define CMD_RD_SHIFT 5u + +/* Command register STO bit */ +#define CMD_STO_OFFSET 0x10u +#define CMD_STO_MASK 0x40u +#define CMD_STO_SHIFT 6u + +/* Command register STA bit */ +#define CMD_STA_OFFSET 0x10u +#define CMD_STA_MASK 0x80u +#define CMD_STA_SHIFT 7u + +/*------------------------------------------------------------------------------ + * Status register details + */ +#define STATUS_REG_OFFSET 0x14u + +/* Command register bits */ +#define STATUS_OFFSET 0x14u +#define STATUS_MASK 0xFFu +#define STATUS_SHIFT 0u + +/* Status register Interrupt Flag(IF) bit */ +#define STAT_IF_OFFSET 0x14u +#define STAT_IF_MASK 0x01u +#define STAT_IF_SHIFT 0u + +/* Status register Transfer in Progress(TIP) bit */ +#define STAT_TIP_OFFSET 0x14u +#define STAT_TIP_MASK 0x02u +#define STAT_TIP_SHIFT 1u + +/* Status register Arbitration Lost(AL) bit */ +#define STAT_AL_OFFSET 0x14u +#define STAT_AL_MASK 0x20u +#define STAT_AL_SHIFT 5u + +/* Status register Busy(BUSY) bit */ +#define STAT_BUSY_OFFSET 0x14u +#define STAT_BUSY_MASK 0x40u +#define STAT_BUSY_SHIFT 6u + +/* Status register Ack received(RXACK) bit */ +#define STAT_RXACK_OFFSET 0x14u +#define STAT_RXACK_MASK 0x80u +#define STAT_RXACK_SHIFT 7u + + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_I2C_APB_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_plic/miv_plic.c b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_plic/miv_plic.c new file mode 100644 index 0000000..903f029 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_plic/miv_plic.c @@ -0,0 +1,283 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * MI-V Soft IP fabric bare-metal driver for Mi-V PLIC module. This module is + * delivered as a part of Mi-V Extended Sub System(MIV_ESS). + * Please refer to miv_plic.h file for more information. + */ + +#include "miv_plic.h" + +/***************************************************************************//** + * Mi-V PLIC interrupt handler function declaration. + * These functions are called by the external interrupt handler of the MIV_RV32 + * core base on the PLIC source causing the interrupt. + */ +uint8_t Invalid_IRQHandler(void); +uint8_t MIV_PLIC_EXT0_IRQHandler(void); +uint8_t MIV_PLIC_EXT1_IRQHandler(void); +uint8_t MIV_PLIC_EXT2_IRQHandler(void); +uint8_t MIV_PLIC_EXT3_IRQHandler(void); +uint8_t MIV_PLIC_EXT4_IRQHandler(void); +uint8_t MIV_PLIC_EXT5_IRQHandler(void); +uint8_t MIV_PLIC_EXT6_IRQHandler(void); +uint8_t MIV_PLIC_EXT7_IRQHandler(void); +uint8_t MIV_PLIC_EXT8_IRQHandler(void); +uint8_t MIV_PLIC_EXT9_IRQHandler(void); +uint8_t MIV_PLIC_EXT10_IRQHandler(void); +uint8_t MIV_PLIC_EXT11_IRQHandler(void); +uint8_t MIV_PLIC_EXT12_IRQHandler(void); +uint8_t MIV_PLIC_EXT13_IRQHandler(void); +uint8_t MIV_PLIC_EXT14_IRQHandler(void); +uint8_t MIV_PLIC_EXT15_IRQHandler(void); +uint8_t MIV_PLIC_EXT16_IRQHandler(void); +uint8_t MIV_PLIC_EXT17_IRQHandler(void); +uint8_t MIV_PLIC_EXT18_IRQHandler(void); +uint8_t MIV_PLIC_EXT19_IRQHandler(void); +uint8_t MIV_PLIC_EXT20_IRQHandler(void); +uint8_t MIV_PLIC_EXT21_IRQHandler(void); +uint8_t MIV_PLIC_EXT22_IRQHandler(void); +uint8_t MIV_PLIC_EXT23_IRQHandler(void); +uint8_t MIV_PLIC_EXT24_IRQHandler(void); +uint8_t MIV_PLIC_EXT25_IRQHandler(void); +uint8_t MIV_PLIC_EXT26_IRQHandler(void); +uint8_t MIV_PLIC_EXT27_IRQHandler(void); +uint8_t MIV_PLIC_EXT28_IRQHandler(void); +uint8_t MIV_PLIC_EXT29_IRQHandler(void); +uint8_t MIV_PLIC_EXT30_IRQHandler(void); + +/***************************************************************************//** + * MIV_PLIC interrupt handler for external interrupts. + * The array of the function pointers pointing to the weak handler of the Mi-V + * PLIC interrupt handlers. + * These functions are called by the external interrupt handler of the MIV_RV32 + * core base on the PLIC source causing the interrupt. + */ +uint8_t (* const ext_irq_handler_table[32]) (void) = +{ + Invalid_IRQHandler, + MIV_PLIC_EXT0_IRQHandler, + MIV_PLIC_EXT1_IRQHandler, + MIV_PLIC_EXT2_IRQHandler, + MIV_PLIC_EXT3_IRQHandler, + MIV_PLIC_EXT4_IRQHandler, + MIV_PLIC_EXT5_IRQHandler, + MIV_PLIC_EXT6_IRQHandler, + MIV_PLIC_EXT7_IRQHandler, + MIV_PLIC_EXT8_IRQHandler, + MIV_PLIC_EXT9_IRQHandler, + MIV_PLIC_EXT10_IRQHandler, + MIV_PLIC_EXT11_IRQHandler, + MIV_PLIC_EXT12_IRQHandler, + MIV_PLIC_EXT13_IRQHandler, + MIV_PLIC_EXT14_IRQHandler, + MIV_PLIC_EXT15_IRQHandler, + MIV_PLIC_EXT16_IRQHandler, + MIV_PLIC_EXT17_IRQHandler, + MIV_PLIC_EXT18_IRQHandler, + MIV_PLIC_EXT19_IRQHandler, + MIV_PLIC_EXT20_IRQHandler, + MIV_PLIC_EXT21_IRQHandler, + MIV_PLIC_EXT22_IRQHandler, + MIV_PLIC_EXT23_IRQHandler, + MIV_PLIC_EXT24_IRQHandler, + MIV_PLIC_EXT25_IRQHandler, + MIV_PLIC_EXT26_IRQHandler, + MIV_PLIC_EXT27_IRQHandler, + MIV_PLIC_EXT28_IRQHandler, + MIV_PLIC_EXT29_IRQHandler, + MIV_PLIC_EXT30_IRQHandler +}; + +/* Mi-V PLIC interrupt weak handlers */ +__attribute__((weak)) uint8_t Invalid_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT0_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT1_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT2_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT3_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT4_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT5_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT6_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT7_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT8_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT9_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT10_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT11_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT12_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT13_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT14_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT15_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT16_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT17_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT18_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT19_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT20_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT21_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT22_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT23_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT24_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT25_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT26_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT27_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT28_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT29_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT30_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +/*-------------------------------------------------------------------------*//** + * Please refer to miv_plic.h for more information about this function. +*/ +void +MIV_PLIC_isr +( + miv_plic_instance_t *this_plic +) +{ + unsigned long hart_id = read_csr(mhartid); + + /* claim the interrupt from PLIC controller */ + + uint32_t int_num = HAL_get_32bit_reg(this_plic->base_addr + + (0x1000 * hart_id), INT_CLAIM_COMPLETE); + + uint8_t disable = EXT_IRQ_KEEP_ENABLED; + disable = ext_irq_handler_table[int_num](); + + /* Indicate the PLIC controller that the interrupt is processed and claim is + * complete. */ + HAL_set_32bit_reg(this_plic->base_addr + + (0x1000 * hart_id), INT_CLAIM_COMPLETE, int_num); + + if (EXT_IRQ_DISABLE == disable) + { + MIV_PLIC_disable_irq(this_plic, (miv_plic_irq_num_t)int_num); + } +} diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_plic/miv_plic.h b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_plic/miv_plic.h new file mode 100644 index 0000000..f5d64cd --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_plic/miv_plic.h @@ -0,0 +1,425 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * PLIC module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(ESS). + */ + /*=========================================================================*//** + @mainpage Mi-V PLIC Bare Metal Driver + + ============================================================================== + Introduction + ============================================================================== + The Mi-V driver provides a set of functions for controlling the Mi-V PLIC + (platform level interrupt controller) soft-IP module. This module is delivered + as a part of the MIV_ESS. The PLIC multiplexes external interrupt signals into + a single interrupt signal that is connected to an external interrupt of the + processor. + + The major features provided by the driver are: + - Support for configuring the PLIC instances. + - Enabling and Disabling interrupts + - Interrupt Handling + + This driver can be used as part of a bare metal system where no operating + system is available. The driver can be adapted for use as part of an + operating system, but the implementation of the adaptation layer between the + driver and the operating system's driver model is outside the scope of this + driver. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + The application software should initialize the Mi-V PLIC through the call to + the MIV_PLIC_init() function for Mi-V PLIC instance in the design. + + No Mi-V PLIC hardware configuration parameters are used by the driver, apart + from the Mi-V PLIC base address. Hence, no additional configuration files + are required to use the driver. + + ============================================================================== + Theory of Operation + ============================================================================== + The operation of Mi-V PLIC driver is divided into following steps: + - Initialization + - Enabling and Disabling interrupts + - Interrupt control + + -------------------------------------------- + Initialization + -------------------------------------------- + The Mi-V PLIC module is first initialized by the call to MIV_PLIC_init(). This + function takes a pointer to the Mi-V PLIC instance data structure and the base + address of the Mi-V PLIC instance is defined by the hardware design. The + instance data structure is used to store the base address of the Mi-V PLIC + module and a pointer to the Mi-V PLIC register data structure. The Mi-V PLIC + register data structure maps the address of the Mi-V PLIC registers. + + --------------------------------------------- + Enabling and Disabling interrupts + --------------------------------------------- + The MIV_PLIC_enable_irq() function enables the specific interrupt provided by + user. A call to this function will allow the enabling of each of the global + interrupts corresponding to the bit in the interrupt enable register of Mi-V + PLIC. + The MIV_PLIC_disable_irq() function disables the specific interrupt provided + by the user. This function can be used to disable the interrupts from outside + of the external interrupt handler. + + ---------------------------------------- + Interrupt Control + ---------------------------------------- + When an interrupt occurs on an enabled interrupt, the PLIC gateway captures + the interrupt and asserts the corresponding interrupt pending bit. Once + the enable bit and pending bit are asserted, then the PLIC_IRQ signal asserts + until the interrupt is claimed by the driver interrupt handler MIV_PLIC_irq() + function. + When multiple interrupts assert then the lowest interrupt number will be + serviced first, for example, if interrupt 1 and 6 assert at the same time, + interrupt 1 will be serviced first, followed by interrupt 6. + +*/ + +#ifndef MIV_PLIC_H_ +#define MIV_PLIC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "miv_plic_regs.h" + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#include "miv_rv32_hal/miv_rv32_hal.h" +#else +#include "hal.h" +#include "miv_rv32_hal.h" +#endif + +/*-------------------------------------------------------------------------*//** + This enumeration is used to select a specific Mi-V PLIC interrupt. It is + used as a parameter to enable or disable the interrupt. +*/ +typedef enum miv_plic_irq_num +{ + NoInterrupt_IRQn = 0, + MIV_PLIC_EXT0_IRQn = 1, + MIV_PLIC_EXT1_IRQn = 2, + MIV_PLIC_EXT2_IRQn = 3, + MIV_PLIC_EXT3_IRQn = 4, + MIV_PLIC_EXT4_IRQn = 5, + MIV_PLIC_EXT5_IRQn = 6, + MIV_PLIC_EXT6_IRQn = 7, + MIV_PLIC_EXT7_IRQn = 8, + MIV_PLIC_EXT8_IRQn = 9, + MIV_PLIC_EXT9_IRQn = 10, + MIV_PLIC_EXT10_IRQn = 11, + MIV_PLIC_EXT11_IRQn = 12, + MIV_PLIC_EXT12_IRQn = 13, + MIV_PLIC_EXT13_IRQn = 14, + MIV_PLIC_EXT14_IRQn = 15, + MIV_PLIC_EXT15_IRQn = 16, + MIV_PLIC_EXT16_IRQn = 17, + MIV_PLIC_EXT17_IRQn = 18, + MIV_PLIC_EXT18_IRQn = 19, + MIV_PLIC_EXT19_IRQn = 20, + MIV_PLIC_EXT20_IRQn = 21, + MIV_PLIC_EXT21_IRQn = 22, + MIV_PLIC_EXT22_IRQn = 23, + MIV_PLIC_EXT23_IRQn = 24, + MIV_PLIC_EXT24_IRQn = 25, + MIV_PLIC_EXT25_IRQn = 26, + MIV_PLIC_EXT26_IRQn = 27, + MIV_PLIC_EXT27_IRQn = 28, + MIV_PLIC_EXT28_IRQn = 29, + MIV_PLIC_EXT29_IRQn = 30, + MIV_PLIC_EXT30_IRQn = 31 +} miv_plic_irq_num_t; + +/*--------------------------------------------------------------------------*//* + * This structure maps the priority threshold and claim complete register in + * the memory. + */ +typedef struct +{ + volatile uint32_t PRIORITY_THRESHOLD; + volatile uint32_t CLAIM_COMPLETE; + volatile uint32_t reserved[1022]; +} IRQ_Target_Type; + +/*--------------------------------------------------------------------------*//* + * This structure maps the Interrupt enable sources from 0 - 1023 for one + * context. + */ +typedef struct +{ + volatile uint32_t ENABLES[32]; +} Target_Enables_Type; + +/*-------------------------------------------------------------------------*//** + This structure holds the base address of the Mi-V PLIC module. This structure + is used by all the functions to access the Mi-V PLIC registers. +*/ +typedef struct miv_plic_instance +{ + addr_t base_addr; +} miv_plic_instance_t; + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_isr is the top level interrupt handler function for the Mi-V PLIC + * driver. You must call the MIV_PLIC_isr() from the system level interrupt + * handler(External_IRQHandler). + * This function must be called from the external interrupt handler function + * provided by the processor hardware abstraction layer. In case of MIV_RV32 + * soft processor, it must be called from External_IRQHandler() function + * provided by MIV_RV32 HAL. + * + * The MIV_PLIC_isr() function claims the interrupt number + * that triggered the interrupt and then invokes the appropriate PLIC interrupt + * handler. + * After handling the PLIC interrupt, this function will complete the interrupt + * by clearing the claim complete bit for the particular interrupt source. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * + * @return + * This function does not return any value. + * + * Example: + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * uint8_t MIV_PLIC_EXT0_IRQHandler(void) + * { + * *** ISR operation *** + * + * return(EXT_IRQ_KEEP_ENABLED); + * } + * + * void External_IRQHandler(void) + * { + * uint32_t reg_val = read_csr(mip); + * MIV_PLIC_isr(&g_plic); + * } + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * } + * @endcode + */ +void MIV_PLIC_isr(miv_plic_instance_t *this_plic); + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_init() function initializes the Mi-V PLIC instance with base + * address. This function resets the PLIC controller by disabling all the PLIC + * interrupts. + * + * Note: This function must be called before calling any other Mi-V PLIC driver + * function. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * + * @param base_addr + * Base address of the Mi-V PLIC instance in the MIV_ESS soft-IP. + * + * @param ext_intr_sources + * Number of interrupts initialized in the design. + * + * @return + * This function does not return any value. + * + * Example + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * } + * @endcode + */ +static inline void +MIV_PLIC_init +( + miv_plic_instance_t *this_plic, + addr_t base_addr, + uint8_t ext_intr_sources +) +{ + uint32_t inc; + unsigned long hart_id = read_csr(mhartid); + + this_plic->base_addr = base_addr; + + /* Disable all interrupts for the current hart. + * The PLIC_EXT_INTR_SOURCES should be defined in the hw_platform.h. This + * macro holds the number of PLIC interrupts enabled in the design. + */ + for(inc = 0; inc < ((ext_intr_sources + 32u) / 32u); ++inc) + { + HAL_set_32bit_reg( + (this_plic->base_addr + inc + (hart_id * 128)), INT_ENABLE , 0x0u); + } +} + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_enable_irq() function enables the PLIC interrupt provided with + * IRQn parameter. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * @param IRQn + * Number of PLIC interrupt to enable. + * + * @return + * This function does not return any value. + * + * Example + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * } + * @endcode + */ +static inline void +MIV_PLIC_enable_irq +( + miv_plic_instance_t *this_plic, + miv_plic_irq_num_t IRQn +) +{ + unsigned long hart_id = read_csr(mhartid); + + uint32_t current = HAL_get_32bit_reg( + (this_plic->base_addr + (IRQn/32) + (hart_id * 128)) , INT_ENABLE); + + current |= (uint32_t)1 << (IRQn % 32); + + HAL_set_32bit_reg( + (this_plic->base_addr + (IRQn/32) + (hart_id * 128)), INT_ENABLE, current); + +} + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_disable_irq() function disables the PLIC interrupt provided with + * IRQn parameter. + * + * NOTE: + * This function can be used to disable the PLIC interrupt from outside the + * external interrupt handler functions. + * If you wish to disable the PLIC interrupt from the external interrupt handler, + * you should use the return value of EXT_IRQ_DISABLE. This will disable the + * selected PLIC interrupt from the Mi-V PLIC driver interrupt handler. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * @param IRQn + * Number of PLIC interrupt to disable. + * + * @return + * This function does not return any value. + * + * Example + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * } + * @endcode + */ +static inline void +MIV_PLIC_disable_irq +( + miv_plic_instance_t *this_plic, + miv_plic_irq_num_t IRQn +) +{ + unsigned long hart_id = read_csr(mhartid); + + uint32_t current = HAL_get_32bit_reg((this_plic->base_addr + (IRQn/32) + (hart_id * 128)) , INT_ENABLE); + + current &= ~((uint32_t)1 << (IRQn % 32)); + + HAL_set_32bit_reg((this_plic->base_addr + (IRQn/32) + (hart_id * 128)), INT_ENABLE, current); + +} + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_PLIC_H_ */ diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_plic/miv_plic_regs.h b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_plic/miv_plic_regs.h new file mode 100644 index 0000000..76cbc0b --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_plic/miv_plic_regs.h @@ -0,0 +1,31 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP PLIC module driver. This module is delivered as a part of Mi-V extended + * Sub-System(MIV_ESS). + */ + +#ifndef MIV_PLIC_REGISTERS +#define MIV_PLIC_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Interrupt pending register offset */ +#define INT_PENDING_REG_OFFSET 0x1000u + +/* Interrupt enable register */ +#define INT_ENABLE_REG_OFFSET 0x2000u + +/* Interrupt claim complete register */ +#define INT_CLAIM_COMPLETE_REG_OFFSET 0x200004u + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_PLIC_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_timer/miv_timer.h b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_timer/miv_timer.h new file mode 100644 index 0000000..5f00889 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_timer/miv_timer.h @@ -0,0 +1,329 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Mi-V Timer Soft IP bare-metal driver. This module is delivered as part of + * the Mi-V Extended Sub System(ESS) MIV_ESS. + */ + +/*=========================================================================*//** + @mainpage Mi-V Timer Bare Metal Driver. + The Mi-V Timer bare metal software driver supports the timer module which + serves as a system timer for the Mi-V Extended Sub System(ESS). + + @section intro_sec Introduction + The MI-V Timer driver supports set of functions for controlling the Mi-V + Timer module. + The Mi-V Timer can generate a timer interrupt signal for the system based on + special system clock intervals specified by the parameters that can be passed + in by the user. + + The major features provided by Mi-V Timer driver are: + - Support for Mi-V Timer instance for each Mi-V Timer peripheral. + - Read current time + - Write to the machine time compare register + + @section hw_dependencies Hardware Flow dependency + The application should configure the Mi-V Timer driver through calls to + MIV_TIMER_init() functions for each MIV_TIMER instance in the hardware + design. The configuration parameter include the MIV_TIMER hardware instance, + base address and number of ticks to generate timer interrupt. + + MIV_RV32 core offers flexibility in terms of generating the MTIME and MTIMECMP + registers internal to the core or using external time reference. + When MIV_ESS is interfaced with MIV_RV32 core, the timer module in the MIV_ESS + can be configured as follows: + - Internal MTIME External MTIME IRQ + Generate the MTIME internally(MIV_RV32) and have a timer interrupt input + to the core as external pin(from MIV_ESS). + + - External MTIME Internal MTIME IRQ + Generate the time value externally(from MIV_ESS), in this case a 64-bit + port will open in the MIV_RV32 core as input and MIV_ESS will output the + 64-bit TIME_COUNT value. The generation of mtimecmp and interrupt is + done internally(MIV_RV32). + + - External MTIME External MTIME IRQ + Generate both the time and timer interrupt externally. + In this case 64-bit port will be available on the Mi-V RV32 core as input + and a 1 pin port will be available for timer interrupt. + + The design must be configured accordingly to use these combinations in the + firmware. + + No MIV_TIMER hardware configuration parameters are used by the driver, apart + from MIV_TIMER base address. Hence, no additional configuration files are + required to use the driver. + + @section theory_op Theory of Operation + + The MIV_TIMER module is a simple systick timer which can generate a timer + interrupt signal for the system at specific intervals specified by the + parameters that can be passed by the user. + These interrupt signal are then fed to the MIV_RV32 core via timer interrupt. + + The operation of MIV_TIMER is divided into following steps: + - Initialization + - Configuration + - Read/Write TIME + + ## Initialization + The MIV_TIMER is first initialized by a call to MIV_TIMER_init(). This + function initializes the instance of Mi-V TIMER with the base address. + The MIV_TIMER_init() function must be called before any other Mi-V Timer driver + function. + + ## Configuration + The Mi-V TIMER configuration includes writing the mtimecmp register with the + initial time value at which timer interrupt should be generated. + When the mtime register value becomes greater than or equal to mtimecmp value, + a timer interrupt signal(TIMER_IRQ) is generated. + + ## Read/Write TIME + The time value can be read by reading the mtime register via call to the + MIV_TIMER_read_mtime(). This function reads the MTIME register which contains + the 64-bit value of the timer count. The count increments by 1 every time the + prescale ticks. This function returns 64-bit MTIME_COUNT value which is the + current value of timer count. + + The time value read in the MIV_TIMER_read_mtime() function can be written to + the mtimecmp register by calling MIV_TIMER_write_mtimecmp() to generate + periodic interrupts. + The writing of the mtimecmp register should be done in the systick_handler() + function. + */ + +#ifndef MIV_TIMER_H_ +#define MIV_TIMER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#endif +/*-------------------------------------------------------------------------*//** +MIV_TIMER_SUCCESS +===================== + +The MIV_TIMER_SUCCESS constant indicates successful configuration of +Mi-V Timer module. +*/ +#define MIV_TIMER_SUCCESS 0u + +/*-------------------------------------------------------------------------*//** +MIV_TIMER_ERROR +===================== + +The MIV_TIMER_ERROR constant indicates that there is an error with +configuring the Mi-V Timer module. +*/ +#define MIV_TIMER_ERROR 1u + +/*-------------------------------------------------------------------------*//* +MIV_TIMER_MASK_32BIT +===================== + +32-bit mask constant used in calculation of 64-bit register value. +*/ +#define MIV_TIMER_MASK_32BIT 0xFFFFFFFFu + +/*-------------------------------------------------------------------------*//* +Mi-V Timer register offsets +===================== +The MTIMECMP is the 64-bit timer compare register, it pre-sets the threshold +which needs to be reached by the timer count register. +This 64-bit register is accessed with 2 32-bit address offset, lower 32-bits +and higher 32-bits. + - MIV_TIMER_MTIMECMP_L_REG_OFFSET + - MIV_TIMER_MTIMECMP_H_REG_OFFSET + +The MTIME is the 64-bit register that contains the 64-bit timer count. The +count increments by 1 every time the prescaler ticks. +This 64-bit register is accessed with 2 32-bit address offset, lower 32-bits +and higher 32-bits. + - MIV_TIMER_MTIME_L_REG_OFFSET + - MIV_TIMER_MTIME_H_REG_OFFSET + +The PRESCALE register is used to determine the amount of clock cycles the +selected clock needs to go through, for MTIME register to increment count. + - MIV_TIMER_PRESCALAR_REG_OFFSET +*/ + +/// @cond private +#define MIV_TIMER_MTIMECMP_L_REG_OFFSET 0x4000u +#define MIV_TIMER_MTIMECMP_H_REG_OFFSET 0x4004u + +#define MIV_TIMER_MTIME_L_REG_OFFSET 0xBFF8u +#define MIV_TIMER_MTIME_H_REG_OFFSET 0xBFFCu + +#define MIV_TIMER_PRESCALAR_REG_OFFSET 0x5000u +/// @endcond + +/*-------------------------------------------------------------------------*//** + This structure holds the base address of the Mi-V Timer module and instance + of the Mi-V Timer register structure. +*/ +typedef struct miv_timer_instance +{ + addr_t base_addr; +} miv_timer_instance_t; + +/** The MIV_TIMER_init() is used to initialize the Mi-V Timer module. This + function will assign the base addresses of the Mi-V Timer module. + User should call this function before calling any of the Mi-V Timer driver + APIs. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @param base_address + Base address of the Mi-V Timer module. + + @return + This function does not return any value. + */ +static inline void +MIV_TIMER_init +( + miv_timer_instance_t* this_timer, + addr_t base_addr +) +{ + this_timer->base_addr = base_addr; +} + +/** MIV_TIMER_read_current_time() is used to read the mtimecmp register values. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @return + This function returns 64-bit mtimecmp register value. + */ +static inline uint64_t +MIV_TIMER_read_current_time +( + miv_timer_instance_t* this_timer +) +{ + volatile uint64_t read_data = 0u; + volatile uint32_t mtime_hi = 0u; + volatile uint32_t mtime_lo = 0u; + + /* when mtime lower word is 0xFFFFFFFF, there will be rollover and + * returned value could be wrong. */ + do { + mtime_hi = HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIME_H); + mtime_lo = HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIME_L); + + } while(mtime_hi != HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIME_H)); + + read_data = mtime_hi; + + return(((read_data) << 32u) | mtime_lo); +} + +/** MIV_TIMER_write_compare_time() is used to write to the MTIMECMP register in + the event of interrupt. User must use this function in the interrupt handler + to de-assert the MIV_TIMER interrupt. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @param write_value + Value to write into the mtimecmp register. + + @return + This function does not return any value. + */ +static inline void +MIV_TIMER_write_compare_time +( + miv_timer_instance_t* this_timer, + uint64_t compare_reg_value +) +{ + HAL_set_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIMECMP_H, MIV_TIMER_MASK_32BIT); + + HAL_set_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIMECMP_L, + (compare_reg_value & MIV_TIMER_MASK_32BIT)); + + HAL_set_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIMECMP_H, + ((compare_reg_value >> 32u) & MIV_TIMER_MASK_32BIT)); +} + +/** The MIV_TIMER_config() is used to configure the MIV_ESS Timer module. The + prescale value serves to divide the count of clock cycles for the timer and + provides control over what point in time, the timer interrupt gets + asserted. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @param ticks + Number of ticks after which interrupt will be generated. + + @return + This function returns Mi-V Timer configuration status. + */ +static inline uint32_t +MIV_TIMER_config +( + miv_timer_instance_t* this_timer, + uint64_t ticks +) +{ + uint32_t ret_val = MIV_TIMER_ERROR; + uint64_t mtime_val = 0u; + uint32_t prescalar = 0u; + uint64_t miv_timer_increment = 0U; + + prescalar = HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_PRESCALAR); + + miv_timer_increment = (uint64_t)(ticks) / prescalar; + + if (miv_timer_increment > 0U) + { + mtime_val = MIV_TIMER_read_current_time(this_timer); + + MIV_TIMER_write_compare_time(this_timer ,(mtime_val + miv_timer_increment)); + + ret_val = MIV_TIMER_SUCCESS; + } + + return ret_val; +} + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_TIMER_H */ diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c new file mode 100644 index 0000000..cbd9652 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c @@ -0,0 +1,109 @@ +/******************************************************************************* + * (c) Copyright 2022-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Mi-V uDMA Soft IP bare-metal driver. This module is delivered as part of + * Mi-V Extended Sub System(MIV_ESS) + */ + +#include "miv_udma_regs.h" +#include "miv_udma.h" + +/***************************************************************************//** + * MIV_uDMA_init() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_init +( + miv_udma_instance_t* this_udma, + addr_t base_addr +) +{ + /* Assign the Mi-V uDMA base address to the uDMA instance structure */ + this_udma->base_address = base_addr; +} + +/***************************************************************************//** + * MIV_uDMA_config() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_config +( + miv_udma_instance_t* this_udma, + addr_t src_addr, + addr_t dest_addr, + uint32_t transfer_size, + uint32_t irq_config +) +{ + /* Source memory start address */ + HAL_set_32bit_reg(this_udma->base_address, SRC_START_ADDR, src_addr); + + /* Destination memory start address */ + HAL_set_32bit_reg(this_udma->base_address, DEST_START_ADDR, dest_addr); + + /* Data transfer size */ + HAL_set_32bit_reg(this_udma->base_address, BLK_SIZE, transfer_size); + + /* Configure the uDMA IRQ */ + HAL_set_32bit_reg(this_udma->base_address, IRQ_CFG, irq_config); +} + +/***************************************************************************//** + * MIV_uDMA_start() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_start +( + miv_udma_instance_t* this_udma +) +{ + /* Start the uDMA transfer */ + HAL_set_32bit_reg(this_udma->base_address, CONTROL_SR, CTRL_START_TX_MASK); +} + +/***************************************************************************//** + * MIV_uDMA_reset() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_reset +( + miv_udma_instance_t* this_udma +) +{ + /* Toggle the uDMA_reset bit to reset the uDMA. + * Resetting the uDMA will clear all the configuration made by + * MIV_uDMA_config(). + * + * This function should be called from the interrupt handler to clear the + * IRQ. + */ + HAL_set_32bit_reg_field(this_udma->base_address, CTRL_RESET_TX, 0x1u); + HAL_set_32bit_reg_field(this_udma->base_address, CTRL_RESET_TX, 0x0u); +} + +/***************************************************************************//** + * MIV_uDMA_read_status() + * See "miv_udma.h" for details of how to use this function. + */ +uint32_t +MIV_uDMA_read_status +( + miv_udma_instance_t* this_udma +) +{ + uint32_t status = 0u; + + /* Read the status of the uDMA transfer. + * The transfer status register can be Error or Busy depending on the + * current uDMA transfer. + */ + status = HAL_get_32bit_reg(this_udma->base_address, TX_STATUS); + + return status; +} diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h new file mode 100644 index 0000000..efa8731 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h @@ -0,0 +1,290 @@ +/******************************************************************************* + * Copyright 2022-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * uDMA module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(MIV_ESS). + */ + +/*=========================================================================*//** + @mainpage Mi-V uDMA Bare Metal Driver. + The Mi-V uDMA bare metal software driver. + + @section intro_sec Introduction + The Mi-V uDMA driver provides a set of functions to control the Mi-V uDMA + module in the Mi-V Extended Subsystem (MIV_ESS) soft-IP. The Mi-V uDMA module + allows peripherals with AHB interfaces to transfer data independently of the + MIV_RV32 RISC-V processor. + + Following are the major features provided by the Mi-V uDMA driver: + - Initialization and configuration + - Start and reset the transaction + + This driver can be used as part of a bare metal system where no operating + system is available. The driver can be adapted for use as part of an + operating system, but the implementation of the adaptation layer between the + driver and the operating system's driver model is outside the scope of this + driver. + + @section hw_dependencies Hardware Flow Dependency + The application software should initialize and configure the Mi-V uDMA through + calling the MIV_uDMA_init() and MIV_uDMA_config() functions for each Mi-V + uDMA instance in the design. + + The uDMA can operate in two possible transfer configurations: + + - AHBL Read -> AHBL Write: + In this configuration, the uDMA reads data from the source memory over an + AHBL (mirrored main/initiator) read interface and writes data to the + destination memory over an AHBL (mirrored main/initiator) write interface. + + - AHBL Read -> TAS Write: + In this configuration, the uDMA reads data from the source memory over an + AHBL (mirrored main/initiator) read interface and writes data to the + destination memory over the TAS (mirrored main/initiator) write interface. + + Note: The AHBL Read -> TAS Write configuration is out of scope for this + driver. + + @section theory_op Theory of Operation + The uDMA module in the Mi-V Extended Sub System (MIV_ESS) is a single-channel + uDMA module that allows peripherals to perform read-write operations between + source and destination memory. The Mi-V uDMA driver is used in + interrupt-driven mode and uses the Mi-V uDMA IRQ signal to drive the + interrupt service routine (ISR), which signifies a transfer has completed. + The status is checked in the ISR to ensure the transfer is completed + successfully. + The reset operation in the ISR resets the Mi-V uDMA controller. Once the Mi-V + uDMA transfer is complete, Mi-V uDMA retires. To initiate another + transaction, Mi-V uDMA needs to be configured again. + + The operation of the Mi-V uDMA driver is divided into the following + categories: + - Initialization + - Configuration + - Start and reset the transfer + + Initialization and configuration: + Mi-V uDMA is first initialized by calling MIV_uDMA_init() function. This + function initializes the instance of Mi-V uDMA with the base address. The + MIV_uDMA_init() function must be called before calling any other Mi-V uDMA + driver functions. + + The Mi-V uDMA is configured by calling MIV_uDMA_config() function. This + function configures the source_addr and dest_addr registers of the Mi-V + uDMA with source and destination addresses for Mi-V uDMA transfers. + This function also configures the transfer size and interrupt preference for + successful transfers using Mi-V uDMA. + + Start and reset the transfer: + Once the Mi-V uDMA is configured, initiate the transfers by calling the + MIV_uDMA_start() function. Once the Mi-V uDMA transfer is started, it cannot + be aborted, and the status of the transfer should be read from the ISR by + calling the MIV_uDMA_read_status() function. + + Reset the Mi-V uDMA to the default state by calling the MIV_uDMA_reset() + function. After performing the reset operation, reconfigure the Mi-V uDMA to + perform transfers as MIV_uDMA_reset() resets the Mi-V uDMA controller. + */ + +#ifndef MIV_uDMA_H_ +#define MIV_uDMA_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#include "hal/cpu_types.h" + +#else +#include "hal.h" +#include "cpu_types.h" +#endif + +/*-------------------------------------------------------------------------*//** + MIV_uDMA_CTRL_IRQ_CONFIG + ===================== + + The MIV_uDMA_CTRL_IRQ_CONFIG macro is used to assert the uDMA IRQ when an error + occurs during a uDMA transfer or on the completion of a uDMA transfer. + */ +#define MIV_uDMA_CTRL_IRQ_CONFIG 1u + +/*-------------------------------------------------------------------------*//** + MIV_uDMA_STATUS_BUSY + ===================== + + The MIV_uDMA_STATUS_BUSY macro is used to indicate that the uDMA transfer is + in progress. + */ +#define MIV_uDMA_STATUS_BUSY 1u + +/*-------------------------------------------------------------------------*//** + MIV_uDMA_STATUS_ERROR + ===================== + + The MIV_uDMA_STATUS_ERROR macro is used to indicate that the last uDMA + transfer has caused an error. + */ +#define MIV_uDMA_STATUS_ERROR 2u + +/***************************************************************************//** + * This structure holds the base of the Mi-V uDMA module, which is used in the + * other functions of the driver to access the uDMA registers. + */ +typedef struct miv_udma_instance +{ + addr_t base_address; +} miv_udma_instance_t; + +/***************************************************************************//** + * The MIV_uDMA_init() function assigns the base address of the Mi-V uDMA module + * to the uDMA instance structure. + * This address is used in a later part of the driver to access the uDMA + * registers. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure. + * + * @param base_addr + * Base address of the Mi-V uDMA module. + * + * @return + * This function does not return a value. + */ +void +MIV_uDMA_init +( + miv_udma_instance_t* this_udma, + addr_t base_addr +); + +/***************************************************************************//** + * The MIV_uDMA_config() function is used to configure the Mi-V uDMA controller. + * This function will set the source address, destination address, block size, + * and IRQ configuration register. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @param base_addr + * Base address of the Mi-V uDMA. + * + * @param src_addr + * Source address of memory from where the uDMA reads the data. + * + * @param dest_addr + * Destination address where the data is written from src_addr. + * + * @param transfer_size + * Number of 32-bit words to transfer. + * + * @param irq_config + * uDMA IRQ configuration + * - When set, the IRQ is asserted when an error occurs during a uDMA + * transfer or on the completion of the uDMA transfer. + * - When clear, the IRQ is only asserted when an error occurs during a + * uDMA transfer. + * + * @return + * This function does not return any value. + */ +void +MIV_uDMA_config +( + miv_udma_instance_t* this_udma, + addr_t src_addr, + addr_t dest_addr, + uint32_t transfer_size, + uint32_t irq_config +); + +/***************************************************************************//** + * The MIV_uDMA_start() function is used to start the uDMA transfer. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @return + * This function does not return any value. + */ +void +MIV_uDMA_start +( + miv_udma_instance_t* this_udma +); + +/***************************************************************************//** + * The MIV_uDMA_reset() function is used to clear the uDMA interrupt and reset + * the uDMA transfer. + * + * This function should be called from the interrupt handler to reset the values + * set during MIV_uDMA_config(). + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @return + * This function does not return any value. + */ +void +MIV_uDMA_reset +( + miv_udma_instance_t* this_udma +); + +/***************************************************************************//** + * The MIV_uDMA_read_status() function is used to read the status of the uDMA + * transfer. When interrupt is enabled, this function can be called from the + * interrupt handler to know the reason for a uDMA interrupt. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @return + * The return value indicates an error due to the busy status of the uDMA + * channel. + * + * |Bit Number| Name | Description | + * |----------|---------|------------------------------------------------------| + * | 0 | Busy | When set indicates that uDMA transfer is in progress| + * | 1 | Error | When set indicates that last uDMA transfer caused an| + * | | | error. | + */ +uint32_t +MIV_uDMA_read_status +( + miv_udma_instance_t* this_pdma +); + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_uDMA_H_ */ diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h new file mode 100644 index 0000000..14d0759 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h @@ -0,0 +1,94 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP uDMA module driver. This module is delivered as a part of Mi-V + * extended Sub-System(ESS) MIV_ESS. + */ + +#ifndef MIV_UDMA_APB_REGISTERS +#define MIV_UDMA_APB_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/**************************************************************************//** + * Control start/Reset register details + */ + +#define CONTROL_SR_REG_OFFSET 0x0u + +/* Control start/Reset register bits */ +#define CONTROL_SR_OFFSET 0x00u +#define CONTROL_SR_MASK 0x03u +#define CONTROL_SR_SHIFT 0u + +/* uDMA Control Start Transfer */ + +#define CTRL_START_TX_OFFSET 0x00u +#define CTRL_START_TX_MASK 0x01u +#define CTRL_START_TX_SHIFT 0u + +/* uDMA Control Reset Transfer */ +#define CTRL_RESET_TX_OFFSET 0x00u +#define CTRL_RESET_TX_MASK 0x02u +#define CTRL_RESET_TX_SHIFT 1u + +/**************************************************************************//** + * IRQ Configuration register details + */ +#define IRQ_CFG_REG_OFFSET 0x4u + +/* Control start/Reset register bits */ +#define IRQ_CFG_OFFSET 0x04u +#define IRQ_CFG_MASK 0x01u +#define IRQ_CFG_SHIFT 0u + +/***************************************************************************//** + * Transfer Status register details + */ +#define TX_STATUS_REG_OFFSET 0x08u + +/* Transfer status register bits */ +#define TX_STATUS_OFFSET 0x08u +#define TX_STATUS_MASK 0x03u +#define TX_STATUS_SHIFT 0u + +/***************************************************************************//** + * Source Memory Start Address Register + */ +#define SRC_START_ADDR_REG_OFFSET 0x0cu + +/* Source Memory Start Address Register bits */ +#define SRC_START_ADDR_OFFSET 0x0cu +#define SRC_START_ADDR_MASK 0xFFFFFFFFu +#define SRC_START_ADDR_SHIFT 0u + +/***************************************************************************//** + * Destination Memory Start Address register details + */ +#define DEST_START_ADDR_REG_OFFSET 0x10u + +/* Destination Memory Start Address register bits */ +#define DEST_START_ADDR_OFFSET 0x10u +#define DEST_START_ADDR_MASK 0xFFFFFFFFu +#define DEST_START_ADDR_SHIFT 0x0u + +/***************************************************************************//** + * Block Size register details + */ +#define BLK_SIZE_REG_OFFSET 0x14u + +/* Destination Memory Start Address register bits */ +#define BLK_SIZE_OFFSET 0x14u +#define BLK_SIZE_MASK 0xFFFFFFFFu +#define BLK_SIZE_SHIFT 0x0u + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_UDMA_APB_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c new file mode 100644 index 0000000..525928a --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Mi-V Watchdog Soft IP bare-metal driver. This module is delivered as part of + * Extended Sub System(ESS) MIV_ESS. + * Please refer to miv_watchdog.h file for more information. + */ + +#include "miv_watchdog.h" + +addr_t g_this_wdog; + +/***************************************************************************//* + * Please refer to miv_watchdog.h for more info about this function + */ +void +MIV_WDOG_init +( + addr_t base_addr +) +{ + /* Register the Mi-V Watchdog base address to the driver */ + g_this_wdog = base_addr; +} + +/***************************************************************************//* + * Please refer to miv_watchdog.h for more info about this function + */ +uint8_t MIV_WDOG_configure +( + const miv_wdog_config_t *config +) +{ + uint8_t error = 0u; + + /* check load value and trigger max value */ + if (config->timeout_val <= MIV_WDOG_TRIGGER_MAX) + { + HAL_set_32bit_reg(g_this_wdog, WDOGTRIG,(config->timeout_val)); + } + else + { + error = 1u; + } + + if (config->time_val <= MIV_WDOG_TIMER_MAX) + { + HAL_set_32bit_reg(g_this_wdog, WDOGMSVP,(config->mvrp_val)); + } + else + { + error = 1u; + } + + HAL_set_32bit_reg_field(g_this_wdog, WDOGCNTL_NEXT_ENFORBIDDEN, + config->forbidden_en); + + /* Reload watchdog with new load if it is not in forbidden window */ + if (!(WDOGSTAT_FORBIDDEN_MASK & (HAL_get_32bit_reg(g_this_wdog, WDOGSTAT)))) + { + HAL_set_32bit_reg(g_this_wdog, WDOGRFSH, MIV_WDOG_REFRESH_KEY); + } + else + { + error = 1u; + } + + return (error); +} + +/***************************************************************************//* + * Please refer to miv_watchdog.h for more info about this function + */ +void MIV_WDOG_get_config +( + miv_wdog_config_t *config +) +{ + if (0 != g_this_wdog) + { + + config->time_val = HAL_get_32bit_reg(g_this_wdog, WDOGTIME); + + config->timeout_val = HAL_get_32bit_reg(g_this_wdog, WDOGTRIG); + + config->mvrp_val = HAL_get_32bit_reg(g_this_wdog, WDOGMSVP); + + config->forbidden_en = HAL_get_32bit_reg_field(g_this_wdog, + WDOGCNTL_NEXT_ENFORBIDDEN); + } +} + diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h new file mode 100644 index 0000000..8877e55 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h @@ -0,0 +1,553 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * Watchdog module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(MIV_ESS). + */ +/*=========================================================================*//** + @mainpage MiV Watchdog Bare Metal Driver + + ============================================================================== + Introduction + ============================================================================== + The Mi-V Watchdog module in the MIV_ESS is used to generate a reset for the + system automatically if the software doesn't periodically update or refresh + the timer countdown register. This software driver provides set of functions + for controlling Mi-V Watchdog module as a part of bare metal system where no + operating system is available. The driver can be adapted for use as a part of + an operating system, but the implementation of the adaptation layer between + the driver and the operating system's driver model is outside the scope of the + driver. + + Mi-V Watchdog provides following features: + - Initializing the Mi-V Watchdog + - Reading current value and status of watchdog timer + - Refreshing the watchdog timer value + - Enabling, disabling and clearing timeout and Maximum Value up to which + Refresh is Permitted (MVRP) interrupts. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + The application software should initialize and configure the Mi-V Watchdog + module the the call to the MIV_WDOG_init() and MIV_WDOG_configure() functions. + + No MIV_WDOG hardware configuration parameter are used by the driver, apart + from the MIV_WDOG base address. Hence, no additional configuration files are + required to use the driver. + + ============================================================================== + Theory of Operation + ============================================================================== + The Mi-V Watchdog driver functions are grouped into the following categories: + - Initialization and configuration + - Reading the current value and status of the watchdog timer + - Refreshing the watchdog timer value + - Support for enabling, disabling and clearing time-out and MVRP interrupts. + + -------------------------------- + Initialization and Configuration + -------------------------------- + The MIV_WDOG_init() function stores the base of MIV_WDT module in the MIV_ESS. + This base address is used by rest of the functions to access the Mi-V Watchdog + registers. Please make call this function before calling any other function + from this driver. + Note: The Mi-V Watchdog driver supports only one instance of MIV_WDT in the + hardware. + The Mi-V Watchdog driver provides the MIV_WDOG_configure() function to + configure the MIV_WDOG module with desired configuration values. It also + provides the MIV_WDOG_get_config() to read back the current configuration of + the MIV_WDOG. You can use this function to retrieve the current configurations + and then overwrite them with the application specific values, such as initial + watchdog timer value, Maximum Value (up to which) Refresh (is) Permitted, + watchdog time-out value, enable/disable forbidden region, enable/disable + MVRP interrupt and interrupt type. + + -------------------------------------------- + Reading the Watchdog Timer Value and Status + -------------------------------------------- + Mi-V Watchdog is a down counter. A refresh forbidden window can be created by + configuring the watchdog Maximum Value up to which Refresh is Permitted (MVRP). + When the current value of the watchdog timer is greater than the MVRP value, + refreshing the watchdog is forbidden. Attempting to refresh the watchdog timer + in the forbidden window will assert a timeout interrupt. The + MIV_WDOG_forbidden_status() function can be used to know whether the watchdog + timer is in forbidden window or has crossed it. By default, the forbidden + window is disabled. It can be enabled by providing an appropriate value as + parameter to the MIV_WDOG_configure() function. When the forbidden window is + disabled, any attempt to refresh the watchdog timer is ignored and the counter + keeps on down counting. + + The current value of the watchdog timer can be read using the + MIV_WDOG_current_value() function. This function can be called at any time. + + -------------------------------------------- + Refreshing the Watchdog Timer Value + -------------------------------------------- + The watchdog timer value is refreshed using the MIV_WDOG_reload() function. + The value reloaded into the watchdog timer down-counter is specified at the + configuration time with an appropriate value as parameter to the + MIV_WDOG_get_config() function. + + -------------------------------------------- + Interrupt Control + -------------------------------------------- + The Mi-V Watchdog generates two interrupts, The MVRP interrupt and + the timeout interrupt. + The MVRP interrupt is generated when the watchdog down-counter crosses the + Maximum Value up to which Refresh is Permitted (MVRP). Following functions to + control MVRP interrupt: + - MIV_WDOG_enable_mvrp_irq + - MIV_WDOG_disable_mvrp_irq + - MIV_WDOG_clear_mvrp_irq + + The timeout interrupt is generated when the watchdog down-counter crosses the + watchdog timeout value. The timeout value is a non-zero value and it can be + set to a maximum of MIV_WDOG_TRIGGER_MAX. The non-maskable interrupt is + generated when the watchdog crosses this timeout value, the down counter + keeps on down counting and a reset signal is generated when reaches zero. + Following functions to control timeout interrupt: + - MIV_WDOG_enable_timeout_irq + - MIV_WDOG_disable_timeout_irq + - MIV_WDOG_clear_timeout_irq + +*//*=========================================================================*/ + +#ifndef MIV_WATCHDOG_H_ +#define MIV_WATCHDOG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "miv_watchdog_regs.h" + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#else +#include "hal.h" +#endif + +/****************************************************************************//* + * The following constants can be used to configure the Mi-V Watchdog where a + * zero or non-zero value such as enable or disable is to be provided as a input + * parameter as shown below: + */ +#define MIV_WDOG_ENABLE 1u +#define MIV_WDOG_DISABLE 0u + +/***************************************************************************//** + The miv_wdog_config_t type for the watchdog Configuration structure. This + type is used as a parameter for the MIV_WDOG_configure() and the + MIV_WDOG_get_config() functions. + + Following are the values as part of this structure +| Parameter | Description | +|------------------|-----------------------------------------------------------| +| time_val | The value from which the watchdog timer counts down | +| mvrp_val | The Watchdog MVRP value | +| timeout_val | The watchdog timeout value | +| forbidden_en | Enable/disable the forbidden window | +| | When set, if a refresh occurs in the forbidden window, | +| | the watchdog timeout interrupt will be generated. | + +Time calculation example: + + time_val = 0xFFFFF0u + mvrp_val = 0x989680u + timeout_val = 0x3e8u + + A prescaler = 256 is used. + Considering clock = 50Mhz + + The MVRP interrupt will happen after + (0xFFFFF0 - 0x989680) * ( 1/(50MHz/256)) + mvrp interrupt will happen after 34 sec. after system reset + + (0xFFFFF0 - 0x3e8) * ( 1/(50MHz/256)) + timeout interrupt will happen after 85 sec. after system reset + */ +typedef struct miv_wdog_config +{ + uint32_t time_val; + uint32_t mvrp_val; + uint32_t timeout_val; + uint32_t forbidden_en; + uint32_t intr_type; +}miv_wdog_config_t; + +extern addr_t g_this_wdog; + +/***************************************************************************//* + Internal constants and types +*******************************************************************************/ + +/// @cond private +#define MIV_WDOG_TRIGGER_MAX 4095u +#define MIV_WDOG_TIMER_MAX 16777200u +/// @endcond + +/*-------------------------------------------------------------------------*//* +MIV_WDOG_REFRESH_KEY +===================== + +The MIV_WDOG_REFRESH_KEY macro holds the magic value which will cause a +reload of the watchdog's down counter when written to the watchdog's +WDOGREFRESH register. +*/ +#define MIV_WDOG_REFRESH_KEY (uint32_t)0xDEADC0DEU + +/*-------------------------------------------------------------------------*//* +MIV_WDOG_FORCE_RESET_KEY +===================== +The MIV_WDOG_FORCE_RESET_KEY macro holds the magic value which will force a +reset if the watchdog is already timeout. Writing any other value or writing +TRIGGER register at other times will trigger the watchdog NMI sequence +(i.e raise a timeout interrupt) + */ +#define MIV_WDOG_FORCE_RESET_KEY (uint32_t)0xDEADU + +/***************************************************************************//** + * The MIV_WDOG_init() is used to register the Mi-V Watchdog module base + * address to the driver. + * + * Note: User should call this function before calling any other Mi-V watchdog + * driver function. + * + * @param base_addr + * The base address of the Mi-V watchdog module. This address is used by + * rest of the watchdog driver functions to access the registers. + * + * @return + * This function does not return any value. + */ +void +MIV_WDOG_init +( + addr_t base_addr +); + +/***************************************************************************//** + * The MIV_WDOG_get_config() function returns the current configurations of the + * Mi-V Watchdog. The Mi-V Watchdog is pre-initialized by the flash + * bits at the design time. When used for the first time before calling the + * MIV_WDOG_configure() function, this function will return the default + * configurations as configured at the design time. + * + * @param config + * The config parameter is used to store the current configuration of the Mi-V + * Watchdog. + * + * Please see the description of miv_wdog_config_t for details. + * + * @return + * This function does not return any value. + * + * Example: + */ +void +MIV_WDOG_get_config +( + miv_wdog_config_t* config +); + +/***************************************************************************//** + * The MIV_WDOG_configure() function configures the watchdog module. The + * Watchdog module is pre-initialized by the flash bits at the design time to the + * default values. You can reconfigure the Watchdog module using + * MIV_WDOG_configure() function. + * + * Note that the MIV_WDOG_configure() function can be used only once, as it + * writes into the TIME register. After a write into the TIME register, the TIME, + * TRIGGER and MSVP register values are frozen and can't be altered again unless + * a system reset happens. + * + * Note also that the Mi-V Watchdog is not enabled at reset, calling this function + * will start the watchdog, it cannot then be disabled and must be refreshed + * periodically. + * + * @param config + * The config parameter is the input parameter in which the configurations to + * be applied to the watchdog module are provided by the application. + * Please see the description of miv_wdog_config_t for details. + * + * @return + * This function returns a zero value when executed successfully. A non-zero + * value is returned when the configuration values are out of bound. + * + * Example: + */ +uint8_t +MIV_WDOG_configure +( + const miv_wdog_config_t * config +); + +/***************************************************************************//** + * The MIV_WDOG_reload() function causes the watchdog to reload its down-counter + * timer with the load value configured through interrupt handler. This function + * must be called regularly to avoid a system reset or a watchdog interrupt. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_reload +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg(g_this_wdog, WDOGRFSH, MIV_WDOG_REFRESH_KEY); + } +} + +/***************************************************************************//** + * The MIV_WDOG_current_value() function returns the current value of the + * watchdog's down-counter. + * + * @param + * Void + * + * @return + * This function returns the current value of the watchdog’s down-counter as + * a 32-bit unsigned integer. + */ +static inline uint32_t +MIV_WDOG_current_value +( + void +) +{ + return (HAL_get_32bit_reg(g_this_wdog, WDOGRFSH)); +} + +/***************************************************************************//** + * The MIV_WDOG_forbidden_status() function returns the refresh status of the + * Mi-V Watchdog. + * + * @param + * Void + * + * @return + * This function returns the refresh status of the watchdog. A value of 1 + * indicates that watchdog's down-counter is within the forbidden window and + * that a reload should not be done. A value of 0 indicates that the watchdog's + * down counter is within the permitted window and that a reload is allowed. + */ +static inline uint32_t +MIV_WDOG_forbidden_status +( + void +) +{ + return (HAL_get_32bit_reg_field(g_this_wdog, WDOGSTAT_FORBIDDEN)); +} + +/***************************************************************************//** + * The MIV_WDOG_enable_mvrp_irq() function enables the MVRP interrupt. + * This interrupt is asserted when the timer countdown register leaves the + * maximum value up to which refresh is permitted (MVRP) window. + * + * @param + * Void + * + * @return + * This function does not return a value. + * + * Example: + */ +static inline void +MIV_WDOG_enable_mvrp_irq +( + void +) +{ + + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGCNTL_NEXT_INTENT_MSVP, 0x01u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_disable_mvrp_irq() function disables the generation of the + * MVRP interrupt. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_disable_mvrp_irq +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGCNTL_NEXT_INTENT_MSVP, 0x0u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_clear_timeout_irq() function clears the watchdog’s timeout + * interrupt which is connected to the MIV-RV32 interrupt. Calling + * MIV_WDOG_clear_timeout_irq() results in clearing the MIV-RV32 interrupt. + * Note: You must call the MIV_WDOG_clear_timeout_irq() function as part of your + * implementation of the interrupt handler in order to prevent the same + * interrupt event re-triggering a call to the timeout ISR. + * + * @param + * Void + * + * @return + * This function does not return any value. + * + */ +static inline void +MIV_WDOG_clear_timeout_irq +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_WDOG_TRIPPED, 0x01u); + /* + * Perform a second write to ensure that the first write completed before + * returning from this function. This is to account for posted writes across + * the AHB matrix. The second write ensures that the first write has + * completed and that the interrupt line has been de-asserted by the time + * the function returns. Omitting the second write may result in a delay + * in the de-assertion of the interrupt line going to the RISC-V and a + * retriggering of the interrupt. + */ + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_WDOG_TRIPPED, 0x01u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_clear_mvrp_irq() function clears the mvrp interrupt. + * + * Note: You must call the MIV_WDOG_clear_mvrp_irq() function as part of your + * implementation of the interrupt service routine (ISR) in order to + * prevent the same interrupt event re-triggering a call to the mvrp ISR. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_clear_mvrp_irq +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_MSVP_TRIPPED, 0x01u); + /* + * Perform a second write to ensure that the first write completed before + * returning from this function. This is to account for posted writes across + * the AHB matrix. The second write ensures that the first write has + * completed and that the interrupt line has been de-asserted by the time + * the function returns. Omitting the second write may result in a delay + * in the de-assertion of the interrupt line going to the RISC-V and a + * re-triggering of the interrupt. + */ + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_MSVP_TRIPPED, 0x01u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_timeout_occured() function reports the occurrence of a timeout + * event. + * + * @param + * Void + * + * @return + * A zero value indicates no watchdog timeout event occurred. A value of 1 + * indicates that a timeout event occurred. + */ +static inline uint32_t +MIV_WDOG_timeout_occured +( + void +) +{ + return (HAL_get_32bit_reg_field(g_this_wdog, WDOGSTAT_TRIGGERED)); +} + +/***************************************************************************//** + * The MIV_WDOG_force_reset() function is used to force an immediate reset + * if the watchdog has already triggered. Writing any value in this condition + * will result in watchdog timeout. + * The time out interrupt WDOG_IRQ will be set to high and watchdog timer + * countdown register updated with watchdog trigger timeout register value. + * If the Watchdog has timed out, a special 16-bit value needs to be written + * to the register to force a reset on CPU_RESETN, 0xDEAD + * Then the Watchdog countdown is reset/updated with the top Watchdog Runtime + * register value. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_force_reset +( + void +) +{ + if (WDOGSTAT_TRIGGERED_MASK == + HAL_get_32bit_reg_field(g_this_wdog, WDOGSTAT_TRIGGERED)) + + { + HAL_set_32bit_reg(g_this_wdog, WDOGFORCE, MIV_WDOG_FORCE_RESET_KEY); + } + + else + { + HAL_set_32bit_reg(g_this_wdog, WDOGFORCE, 0x0u); + } +} + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_WATCHDOG_H_ */ diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h new file mode 100644 index 0000000..2fca983 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h @@ -0,0 +1,122 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP watchdog module driver. This module is delivered as a part of Mi-V + * extended Sub-System(ESS) MIV_ESS. + */ + +#ifndef MIV_WDOG_REGISTERS +#define MIV_WDOG_REGISTERS 1u + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * Refresh register details + */ +#define WDOGRFSH_REG_OFFSET 0x00u + +/* Refresh register bits */ +#define WDOGRFSH_OFFSET 0x00u +#define WDOGRFSH_MASK 0xFFFFFFFFu +#define WDOGRFSH_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Control register details + */ +#define WDOGCNTL_REG_OFFSET 0x04u + +/* Control register next intent msvp bit */ +#define WDOGCNTL_NEXT_INTENT_MSVP_OFFSET 0x04u +#define WDOGCNTL_NEXT_INTENT_MSVP_MASK 0x01u +#define WDOGCNTL_NEXT_INTENT_MSVP_SHIFT 0u + +/* Control register next intent wdog bit */ +#define WDOGCNTL_NEXT_INTENT_WDOG_OFFSET 0x04u +#define WDOGCNTL_NEXT_INTENT_WDOG_MASK 0x02u +#define WDOGCNTL_NEXT_INTENT_WDOG_SHIFT 1u + +/* Control register next enforbidden bit */ +#define WDOGCNTL_NEXT_ENFORBIDDEN_OFFSET 0x04u +#define WDOGCNTL_NEXT_ENFORBIDDEN_MASK 0x10u +#define WDOGCNTL_NEXT_ENFORBIDDEN_SHIFT 4u + +/*------------------------------------------------------------------------------ + * Watchdog status register + */ +#define WDOGSTAT_REG_OFFSET 0x08u + +/* msvp_tripped bit */ +#define WDOGSTAT_MSVP_TRIPPED_OFFSET 0x08u +#define WDOGSTAT_MSVP_TRIPPED_MASK 0x01u +#define WDOGSTAT_MSVP_TRIPPED_SHIFT 0u + +/* WDOG Tripped bit */ +#define WDOGSTAT_WDOG_TRIPPED_OFFSET 0x08u +#define WDOGSTAT_WDOG_TRIPPED_MASK 0x02u +#define WDOGSTAT_WDOG_TRIPPED_SHIFT 1u + +/* Forbidden bit */ +#define WDOGSTAT_FORBIDDEN_OFFSET 0x08u +#define WDOGSTAT_FORBIDDEN_MASK 0x04u +#define WDOGSTAT_FORBIDDEN_SHIFT 2u + +/* Triggered bit */ +#define WDOGSTAT_TRIGGERED_OFFSET 0x08u +#define WDOGSTAT_TRIGGERED_MASK 0x08u +#define WDOGSTAT_TRIGGERED_SHIFT 3u + +/* wdoglocked bit */ +#define WDOGSTAT_WDOGLOCKED_OFFSET 0x08u +#define WDOGSTAT_WDOGLOCKED_MASK 0x10u +#define WDOGSTAT_WDOGLOCKED_SHIFT 4u + +/*------------------------------------------------------------------------------ + * Watchdog runtime register + */ +#define WDOGTIME_REG_OFFSET 0x0Cu + +/* wdogmsvp bit */ +#define WDOGTIME_WDOGVALUE_OFFSET 0x0Cu +#define WDOGTIME_WDOGVALUE_MASK 0xFFFFFFu +#define WDOGTIME_WDOGVALUE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Watchdog MVRP register + */ +#define WDOGMSVP_REG_OFFSET 0x10u + +/* wdogmsvp bit */ +#define WDOGMSVP_OFFSET 0x10u +#define WDOGMSVP_MASK 0xFFFFFFu +#define WDOGMSVP_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Watchdog Trigger Timeout register + */ +#define WDOGTRIG_REG_OFFSET 0x14u + +/* wdogmsvp bit */ +#define WDOGTRIG_WDOGRST_OFFSET 0x14u +#define WDOGTRIG_WDOGRST_MASK 0xFFFFFFu +#define WDOGTRIG_WDOGRST_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Watchdog Force Reset register details + */ +#define WDOGFORCE_REG_OFFSET 0x18u + +/* Refresh register bits */ +#define WDOGFORCE_OFFSET 0x18u +#define WDOGFORCE_MASK 0xFFFFFFFFu +#define WDOGFORCE_SHIFT 0u + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_WATCHDOG_REGS_H_ */ diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/off-chip/pac1934/pac1934.c b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/off-chip/pac1934/pac1934.c new file mode 100644 index 0000000..a040ce4 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/off-chip/pac1934/pac1934.c @@ -0,0 +1,438 @@ +/**************************************************************************//** + * Copyright 2019-2021 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file implements access functions for the PAC1934 using the MSS I2C + * driver APIs + * + */ +#include +#if 0 +#include "drivers/mss/mss_mmuart/mss_uart.h" +#include "mpfs_hal/mss_hal.h" +#include "pac1934_regs.h" +#include "drivers/mss/mss_i2c/mss_i2c.h" + + +static mss_uart_instance_t * const gp_usr_uart = &g_mss_uart0_lo; +unsigned long VPowerACC[4] = {0},VBus[4] = {0}, VSense[4] = {0}, \ + VBusAvg[4] = {0}, VSenseAvg[4] = {0}, VPower[4] = {0}; + +static mss_i2c_status_t do_write_transaction +( + uint8_t serial_addr, + uint8_t * tx_buffer, + uint8_t write_length +); + +/*------------------------------------------------------------------------------ + * MSS I2C instance + */ +#define I2C_MASTER &g_mss_i2c1_lo +#define I2C_SLAVE &g_mss_i2c0_lo + +/*------------------------------------------------------------------------------ + * I2C master serial address. + */ +#define MASTER_SER_ADDR 0x21 + +/*----------------------------------------------------------------------------- + * I2C slave serial address. + */ +#define SLAVE_SER_ADDR 0x20 +#define CURREN_SNSOR_ADDR 0x10 + +#define BUFFER_SIZE 32u +static uint8_t g_master_rx_buf[BUFFER_SIZE]; +static uint8_t g_master_tx_buf[BUFFER_SIZE]; +static uint8_t g_slave_rx_buffer[BUFFER_SIZE]; +static uint8_t g_slave_tx_buffer[BUFFER_SIZE]; + +/*----------------------------------------------------------------------------- + * I2C operation timeout value in mS. Define as MSS_I2C_NO_TIMEOUT to disable + * the timeout functionality. + */ +#define DEMO_I2C_TIMEOUT 3000u + +/*----------------------------------------------------------------------------- + * UI Buffer + */ +#define UIBufSize 100 +#define lineSymbol "+" +uint8_t g_ui_buf[UIBufSize] = {0}; + +/* Draw UI */ +#define windowWidth UIBufSize +#define windowHeight UIBufSize + +/*------------------------------------------------------------------------------ + I2C-0 completion handler + */ +static void i2c0_completion_handler(mss_i2c_instance_t * instance, mss_i2c_status_t status) +{ + if(status == MSS_I2C_SUCCESS) + { + } + else + { + ASSERT(0); + } +} + +/*------------------------------------------------------------------------------ + * Perform write-read transaction with parameters gathered from the command + * line interface. + */ +static mss_i2c_status_t do_write_read_transaction +( + uint8_t serial_addr, + uint8_t * tx_buffer, + uint8_t write_length, + uint8_t * rx_buffer, + uint8_t read_length +) +{ + mss_i2c_status_t status; + + MSS_I2C_write_read(I2C_MASTER, + serial_addr, + tx_buffer, + write_length, + rx_buffer, + read_length, + MSS_I2C_RELEASE_BUS); + + status = MSS_I2C_wait_complete(I2C_MASTER, MSS_I2C_NO_TIMEOUT); + + return status; +} + +/* Check PAC1934 sensor register value */ +static unsigned long sensor_reg_check(uint32_t reg) +{ + long value = 0; + mss_i2c_status_t instance; + uint8_t num_receive_bytes = 0; + float voltage = 0; + + g_master_tx_buf[0] = reg; + + if((reg == 0x00u) | (reg == 0x1Eu) | (reg == 0x1Fu)) /* refresh */ + { + instance = do_write_transaction(CURREN_SNSOR_ADDR, g_master_tx_buf, 1u); + for(uint32_t cnt=0u; cnt < 7250000u; cnt++); /* min 2ms TODO: improve this*/ + } + else if ((reg >= 0x3u) && (reg <= 0x6u)) /* Vpower_acc */ + { + num_receive_bytes = 6u; + instance = do_write_read_transaction(CURREN_SNSOR_ADDR, + g_master_tx_buf, + 0x01u, + g_master_rx_buf, + num_receive_bytes); + } + else if ((reg >= 0x7u) && (reg <= 0x16u)) /* vbus, Vsense, Vsense_avg*/ + { + num_receive_bytes = 2u; + instance = do_write_read_transaction(CURREN_SNSOR_ADDR, + g_master_tx_buf, + 0x01U, + g_master_rx_buf, + num_receive_bytes); + } + else if ((reg >= 0x17u) && (reg <= 0x1Au)) /* Vpower */ + { + num_receive_bytes = 4u; + instance = do_write_read_transaction(CURREN_SNSOR_ADDR, + g_master_tx_buf, + 0x01U, + g_master_rx_buf, + num_receive_bytes); + } + else if ((reg >= 0xFD) && (reg <= 0xFF)) /* IDs */ + { + num_receive_bytes = 1u; + instance = do_write_read_transaction(CURREN_SNSOR_ADDR, + g_master_tx_buf, + 0x01U, + g_master_rx_buf, + num_receive_bytes); + } + else + { + ASSERT(0U); + } + + if(MSS_I2C_SUCCESS == instance) + { + if ((reg >= 0x3) && (reg <= 0x6)) /*Vpower_acc*/ + { + value = g_master_rx_buf[0]; + value = value << 8; + value = value + g_master_rx_buf[1]; + value = value << 8; + value = value + g_master_rx_buf[2]; + value = value << 8; + value = value + g_master_rx_buf[3]; + value = value << 8; + value = value + g_master_rx_buf[4]; + value = value << 8; + value = value + g_master_rx_buf[5]; + } + else if ((reg >= 0x7) && (reg <= 0x16)) /* vbus, Vsense, Vsense_avg */ + { + value = g_master_rx_buf[0]; + value = value << 8; + value = value + g_master_rx_buf[1]; + } + else if ((reg >= 0x17) && (reg <= 0x1A)) /* Vpower */ + { + value = g_master_rx_buf[0]; + value = value << 8; + value = value + g_master_rx_buf[1]; + value = value << 8; + value = value + g_master_rx_buf[2]; + value = value << 8; + value = value + g_master_rx_buf[3]; + } + else if ((reg >= 0xFD) && (reg <= 0xFF)) /* IDs */ + { + value = g_master_rx_buf[0]; + } + + return(value); + } + else + { + return (0xFFFFFFFFUL); + } +} + +void cls(void) +{ + for (uint16_t x = 0u; x < windowHeight; x++) + { + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)"\n\r"); + } +} + +void drawBar(void) +{ + /* Draw bar */ + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)"\n\r"); + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)"+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)"\n\r"); + +} + +void blankLine(void) +{ + /* Draw name */ + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)"+ +"); + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)"\n\r"); + +} + +void drawName(void) +{ + /* Draw name */ + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)lineSymbol); + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)" ---------------------------------- "); + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)lineSymbol); + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)"\n\r"); + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)"+++++++++++++++| Reading Current sensor over I2C |++++++++++++++"); + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)"\n\r"); + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)lineSymbol); + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)" ---------------------------------- "); + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)lineSymbol); + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)"\n\r"); +} + +void PAC1934_drawISense(void) +{ + volatile float isense0,isense1,isense2,isense3; + + for (uint16_t cnt = 0u; cnt < UIBufSize; cnt++) + { + g_ui_buf[cnt] = 0u; + } + + sensor_reg_check(REFRESH_REG); + VBus[0] = sensor_reg_check(VSENSE1_AVG_REG); + isense0 = (VBus[0u]*10000.0)/65535.0; + + VBus[1] = sensor_reg_check(VSENSE2_AVG_REG); + isense1 = (VBus[1u]*10000.0)/65535.0; + + VBus[2] = sensor_reg_check(VSENSE3_AVG_REG); + isense2 = (VBus[2u]*10000.0)/65535.0; + + VBus[3] = sensor_reg_check(VSENSE4_AVG_REG); + isense3 = (VBus[3u]*10000.0)/65535.0; + + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)"\n\rCurrent values"); + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)"\n\r"); + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)lineSymbol); + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)" IVDD_REG IVDDA25 IVDD25 IVDDA_REG "); + MSS_UART_polled_tx(gp_usr_uart, g_ui_buf, UIBufSize); + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)lineSymbol); + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)"\n\r"); + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)lineSymbol); + sprintf((char*)&g_ui_buf, " %08.3fma %08.3fma %08.3fma %08.3fma ", + (VBus[0u]*10000.0)/65535.0, + (VBus[1u]*10000.0)/65535.0, + (VBus[2u]*10000.0)/65535.0, + (VBus[3u]*10000.0)/65535.0); + MSS_UART_polled_tx(gp_usr_uart, g_ui_buf, UIBufSize); + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)lineSymbol); + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)"\n\r\n\r\n\r\n\r"); +} + +void PAC1934_drawVB(void) +{ + for (uint16_t cnt = 0u; cnt < UIBufSize; cnt++) + { + g_ui_buf[cnt] = 0u; + } + sensor_reg_check(REFRESH_REG); + VBus[0u] = sensor_reg_check(VBUS1_AVG_REG); + VBus[1u] = sensor_reg_check(VBUS2_AVG_REG); + VBus[2u] = sensor_reg_check(VBUS3_AVG_REG); + VBus[3u] = sensor_reg_check(VBUS4_AVG_REG); + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)"\n\r\n\rVoltage values"); + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)"\n\r"); + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)lineSymbol); + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)" VDD_REG VDDA25 VDD25 VDDA_REG "); + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)lineSymbol); + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)"\n\r"); + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)lineSymbol); + sprintf((char*)&g_ui_buf, " %04.2fv %04.2fv %04.2fv %04.2fv ", + VBus[0]*32.0/65535.0, + VBus[1]*32.0/65535.0, + VBus[2]*32.0/65535.0, + VBus[3]*32.0/65535.0); + MSS_UART_polled_tx(gp_usr_uart, g_ui_buf, UIBufSize); + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)lineSymbol); + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)"\n\r"); +} + +void drawVPowerAcc(uint32_t *VPower) +{ + /* Draw name */ + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)lineSymbol); + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)" VPowerACC1 VPowerACC2 VPowerACC3 VPowerACC4 "); + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)lineSymbol); + MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t *)"\n\r"); +} + +/**************************************************************************//** + * MSS I2C accessing current sensor PAC1934 + */ +int32_t PAC1934_sensor_probe(void) +{ + uint8_t cmd_idx = 0; + int32_t i2c_test_result = -1; + + PLIC_init(); + PLIC_SetPriority(I2C0_MAIN_PLIC, 2); + PLIC_SetPriority(I2C1_MAIN_PLIC, 2); + PLIC_SetPriority(I2C1_ALERT_PLIC, 2); + PLIC_SetPriority(I2C1_SUS_PLIC, 2); + + __enable_irq(); + + PLIC_EnableIRQ(I2C0_MAIN_PLIC); + PLIC_EnableIRQ(I2C1_MAIN_PLIC); + PLIC_EnableIRQ(I2C1_ALERT_PLIC); + PLIC_EnableIRQ(I2C1_SUS_PLIC); + + /*------------------------------------------------------------------------- + * Initialize the MSS I2C master Driver + */ + MSS_I2C_init(I2C_MASTER, MASTER_SER_ADDR, MSS_I2C_PCLK_DIV_192); + MSS_I2C_register_transfer_completion_handler(I2C_MASTER, i2c0_completion_handler); + + + VPowerACC[0] = sensor_reg_check(PID_REG); + VPowerACC[1] = sensor_reg_check(MID_REG); + VPowerACC[2] = sensor_reg_check(REV_REG); + + if ((0x5b == VPowerACC[0]) && (0x5d == VPowerACC[1]) && (0x03 == VPowerACC[2])) + { + i2c_test_result= 0u; + } + else + { + i2c_test_result= -1; + } + + return(i2c_test_result); +} + +mss_i2c_slave_handler_ret_t slave_write_handler +( + mss_i2c_instance_t * this_i2c, + uint8_t * p_rx_data, + uint16_t rx_size +) +{ + uint8_t loop_count; + + if (rx_size > BUFFER_SIZE) /* Safety check and limit the data length */ + { + rx_size = BUFFER_SIZE; + } + + /* Copy only the data we have received */ + for (loop_count = 0; loop_count < rx_size; loop_count++) + { + g_slave_tx_buffer[loop_count] = g_slave_rx_buffer[loop_count]; + } + + return MSS_I2C_REENABLE_SLAVE_RX; +} + +/*------------------------------------------------------------------------------ + I2C-1 completion handler + */ +void i2c1_completion_handler(mss_i2c_instance_t * instance, mss_i2c_status_t status) +{ + if(status == MSS_I2C_SUCCESS) + { + //MSS_UART_polled_tx_string(gp_usr_uart, (const uint8_t*)"\rI2C1 Transfer completed.\n\r"); + } +} + +/*------------------------------------------------------------------------------ + * Perform write transaction with parameters gathered from the command line + * interface. This function is called as a result of the user's input in the + * command line interface. + */ +static mss_i2c_status_t do_write_transaction +( + uint8_t serial_addr, + uint8_t * tx_buffer, + uint8_t write_length +) +{ + mss_i2c_status_t status; + + MSS_I2C_write(I2C_MASTER, serial_addr, tx_buffer, write_length, + MSS_I2C_RELEASE_BUS); + + status = MSS_I2C_wait_complete(I2C_MASTER, DEMO_I2C_TIMEOUT); + + return status; +} + +/*------------------------------------------------------------------------------ + * Service the I2C timeout functionality (SysTick_Handler is called every 10mS). + */ +void SysTick_Handler_h0_IRQHandler(void) +{ + MSS_I2C_system_tick(I2C_MASTER, 10); + MSS_I2C_system_tick(I2C_SLAVE, 10); +} + +#endif diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/off-chip/pac1934/pac1934.h b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/off-chip/pac1934/pac1934.h new file mode 100644 index 0000000..f7fd450 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/off-chip/pac1934/pac1934.h @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright 2019-2020 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * PolarFire SoC Microprocessor Subsystem I2C bare metal software driver + * public API. + * + */ + +#ifndef PAC1934_H_ +#define PAC1934_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** + * typedefs + */ + + +/** + * extern variables + */ + +/** + * functions + */ + +void PAC1934_drawVB(void); +void PAC1934_drawISense(void); +int32_t PAC1934_sensor_probe(void); + +#ifdef __cplusplus +} +#endif + +#endif /* PAC1934_H_ */ + diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/off-chip/pac1934/pac1934_regs.h b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/off-chip/pac1934/pac1934_regs.h new file mode 100644 index 0000000..61629a8 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/drivers/off-chip/pac1934/pac1934_regs.h @@ -0,0 +1,55 @@ +/**************************************************************************//** + * Copyright 2019-2021 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Register defines for PAC1934 + * + */ + +#ifndef SRC_APPLICATION_HART0_PAC1934_REGS_H_ +#define SRC_APPLICATION_HART0_PAC1934_REGS_H_ + +#define REFRESH_REG 0x00 +#define CTRL_REG 0x1 +#define ACC_COUNT_REG 0x2 +#define VPOWER1_ACC_REG 0x3 +#define VPOWER2_ACC_REG 0x4 +#define VPOWER3_ACC_REG 0x5 +#define VPOWER4_ACC_REG 0x6 +#define VBUS1_REG 0x7 +#define VBUS2_REG 0x8 +#define VBUS3_REG 0x9 +#define VBUS4_REG 0xA +#define VSENSE1_REG 0xB +#define VSENSE2_REG 0xC +#define VSENSE3_REG 0xD +#define VSENSE4_REG 0xE +#define VBUS1_AVG_REG 0xF +#define VBUS2_AVG_REG 0x10 +#define VBUS3_AVG_REG 0x11 +#define VBUS4_AVG_REG 0x12 +#define VSENSE1_AVG_REG 0x13 +#define VSENSE2_AVG_REG 0x14 +#define VSENSE3_AVG_REG 0x15 +#define VSENSE4_AVG_REG 0x16 +#define VPOWER1_REG 0x17 +#define VPOWER2_REG 0x18 +#define VPOWER3_REG 0x19 +#define VPOWER4_REG 0x1A +#define CHANNEL_DIS_REG 0x1C +#define NEG_PWR_REG 0x1D +#define REFRESH_G_REG 0x1E +#define REFRESH_V_REG 0x1F +#define SLOW_REG 0x20 +#define CTRL_ACT_REG 0x21 +#define CHANNEL_DIS_ACT_REG 0x22 +#define NEG_PWR_ACT_REG 0x23 +#define CTRL_LAT_REG 0x24 +#define CHANNEL_DIS_LAT_REG 0x25 +#define NEG_PWR_LAT_REG 0x26 +#define PID_REG 0xFD +#define MID_REG 0xFE +#define REV_REG 0xFF + +#endif /* SRC_APPLICATION_HART0_PAC1934_REGS_H_ */ diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/hal/cpu_types.h b/applications/user-crypto/miv-rv32-message-authentication/src/platform/hal/cpu_types.h new file mode 100644 index 0000000..ef8ab20 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/hal/cpu_types.h @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file cpu_types.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Type definitions which can be commonly used by the fabric-ip drivers. + * + */ +#ifndef __CPU_TYPES_H +#define __CPU_TYPES_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned int size_t; + +/*------------------------------------------------------------------------------ + * addr_t: address type. + * Used to specify the address of peripherals present in the processor's memory + * map. + */ +typedef unsigned int addr_t; + +/*------------------------------------------------------------------------------ + * psr_t: processor state register. + * Used by HAL_disable_interrupts() and HAL_restore_interrupts() to store the + * processor's state between disabling and restoring interrupts. + */ +typedef unsigned int psr_t; + +#ifdef __cplusplus +} +#endif + +#endif /* CPU_TYPES_H */ + diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/hal/hal.h b/applications/user-crypto/miv-rv32-message-authentication/src/platform/hal/hal.h new file mode 100644 index 0000000..7eec17a --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/hal/hal.h @@ -0,0 +1,235 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file hal.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware abstraction layer functions for peripheral register accesses. + * + */ +#ifndef __HAL_H +#define __HAL_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include "cpu_types.h" +#include "hw_reg_access.h" +#include "hal_assert.h" +/***************************************************************************//** + * Enable all interrupts at the processor level. + */ +void HAL_enable_interrupts( void ); + +/***************************************************************************//** + * Disable all interrupts at the processor core level. + * Return the interrupts enable state before disabling occurred so that it can + * later be restored. + */ +psr_t HAL_disable_interrupts( void ); + +/***************************************************************************//** + * Restore the interrupts enable state at the processor core level. + * This function is normally passed the value returned from a previous call to + * HAL_disable_interrupts(). + */ +void HAL_restore_interrupts( psr_t saved_psr ); + +/***************************************************************************//** + */ +#define FIELD_OFFSET(FIELD_NAME) (FIELD_NAME##_OFFSET) +#define FIELD_SHIFT(FIELD_NAME) (FIELD_NAME##_SHIFT) +#define FIELD_MASK(FIELD_NAME) (FIELD_NAME##_MASK) + +/***************************************************************************//** + * The macro HAL_set_32bit_reg() allows writing a 32 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint32_t containing the value to write. + */ +#define HAL_set_32bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_32bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_32bit_reg() is used to read the value of a 32 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint32_t value. + */ +#define HAL_get_32bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_32bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)) )) + +/***************************************************************************//** + * The macro HAL_set_32bit_reg_field() is used to write a field within a + * 32 bits wide register. The field written can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * VALUE: A variable of type uint32_t containing the field value to write. + */ +#define HAL_set_32bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_32bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_32bit_reg_field() is used to read a register field from + * within a 32 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint32_t value. + */ +#define HAL_get_32bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_32bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +/***************************************************************************//** + * The macro HAL_set_16bit_reg() allows writing a 16 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint_fast16_t containing the value to write. + */ +#define HAL_set_16bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_16bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_16bit_reg() is used to read the value of a 16 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint16_t value. + */ +#define HAL_get_16bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_16bit_reg( (BASE_ADDR) + (REG_NAME##_REG_OFFSET) )) + +/***************************************************************************//** + * The macro HAL_set_16bit_reg_field() is used to write a field within a + * 16 bits wide register. The field written can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * VALUE: A variable of type uint16_t containing the field value to write. + */ +#define HAL_set_16bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_16bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_16bit_reg_field() is used to read a register field from + * within a 8 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint16_t value. + */ +#define HAL_get_16bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_16bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +/***************************************************************************//** + * The macro HAL_set_8bit_reg() allows writing a 8 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint_fast8_t containing the value to write. + */ +#define HAL_set_8bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_8bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_8bit_reg() is used to read the value of a 8 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint8_t value. + */ +#define HAL_get_8bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_8bit_reg( (BASE_ADDR) + (REG_NAME##_REG_OFFSET) )) + +/***************************************************************************//** + */ +#define HAL_set_8bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_8bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_8bit_reg_field() is used to read a register field from + * within a 8 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint8_t value. + */ +#define HAL_get_8bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_8bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +#ifdef __cplusplus +} +#endif + +#endif /*HAL_H*/ + diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/hal/hal_assert.h b/applications/user-crypto/miv-rv32-message-authentication/src/platform/hal/hal_assert.h new file mode 100644 index 0000000..1e18b54 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/hal/hal_assert.h @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hal_assert.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief HAL assert functions + */ +#ifndef __HAL_ASSERT_HEADER +#define __HAL_ASSERT_HEADER 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Disable assertions if we do not recognize the compiler. */ +#if defined ( __GNUC__ ) +#if defined(NDEBUG) +/***************************************************************************//** + * HAL_ASSERT() is defined out when the NDEBUG symbol is used. + ******************************************************************************/ +#define HAL_ASSERT(CHECK) + +#else + +/***************************************************************************//** + * Default behavior for HAL_ASSERT() macro: + *------------------------------------------------------------------------------ + The behavior is toolchain specific and project setting specific. + ******************************************************************************/ +#define HAL_ASSERT(CHECK)\ + do { \ + if (!(CHECK)) \ + { \ + __asm__ volatile ("ebreak"); \ + }\ + } while(0); + +#endif /* NDEBUG */ +#endif /*__GNUC__*/ + +#ifdef __cplusplus +} +#endif +#endif /* __HAL_ASSERT_HEADER */ + diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/hal/hal_irq.c b/applications/user-crypto/miv-rv32-message-authentication/src/platform/hal/hal_irq.c new file mode 100644 index 0000000..95a0775 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/hal/hal_irq.c @@ -0,0 +1,45 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hal_irq.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Legacy interrupt control functions for the Microchip driver library + * hardware abstraction layer. + * + */ +#include "hal.h" +#include "miv_rv32_hal/miv_rv32_hal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * + */ +void HAL_enable_interrupts(void) { + MRV_enable_interrupts(); +} + +/*------------------------------------------------------------------------------ + * + */ +psr_t HAL_disable_interrupts(void) { + psr_t psr; + psr = read_csr(mstatus); + MRV_disable_interrupts(); + return(psr); +} + +/*------------------------------------------------------------------------------ + * + */ +void HAL_restore_interrupts(psr_t saved_psr) { + write_csr(mstatus, saved_psr); +} + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/hal/hw_macros.h b/applications/user-crypto/miv-rv32-message-authentication/src/platform/hal/hw_macros.h new file mode 100644 index 0000000..189609c --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/hal/hw_macros.h @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hw_macros.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware registers access macros. + * + * THE MACROS DEFINED IN THIS FILE ARE DEPRECATED. DO NOT USE FOR NEW + * DEVELOPMENT. + * + * These macros are used to access peripheral registers. They allow access to + * 8, 16 and 32 bit wide registers. All accesses to peripheral registers should + * be done through these macros in order to ease porting across different + * processors/bus architectures. + * + * Some of these macros also allow access to a specific register field. + * + */ +#ifndef __HW_REGISTER_MACROS_H +#define __HW_REGISTER_MACROS_H 1 +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * 32 bits registers access: + */ +#define HW_get_uint32_reg(BASE_ADDR, REG_OFFSET) (*((uint32_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint32_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint32_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint32_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint32_t) \ + ( \ + (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint32_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint32_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 32 bits memory access: + */ +#define HW_get_uint32(BASE_ADDR) (*((uint32_t volatile *)(BASE_ADDR))) + +#define HW_set_uint32(BASE_ADDR, VALUE) (*((uint32_t volatile *)(BASE_ADDR)) = (VALUE)) + +/*------------------------------------------------------------------------------ + * 16 bits registers access: + */ +#define HW_get_uint16_reg(BASE_ADDR, REG_OFFSET) (*((uint16_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint16_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint16_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint16_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint16_t) \ + ( \ + (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint16_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint16_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 8 bits registers access: + */ +#define HW_get_uint8_reg(BASE_ADDR, REG_OFFSET) (*((uint8_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint8_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint8_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint8_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint8_t) \ + ( \ + (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint8_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint8_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 8 bits memory access: + */ +#define HW_get_uint8(BASE_ADDR) (*((uint8_t volatile *)(BASE_ADDR))) + +#define HW_set_uint8(BASE_ADDR, VALUE) (*((uint8_t volatile *)(BASE_ADDR)) = (VALUE)) + +#ifdef __cplusplus +extern "C" { +#endif + +#endif /* __HW_REGISTER_MACROS_H */ + diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/hal/hw_reg_access.S b/applications/user-crypto/miv-rv32-message-authentication/src/platform/hal/hw_reg_access.S new file mode 100644 index 0000000..dd29223 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/hal/hw_reg_access.S @@ -0,0 +1,215 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hw_reg_access.S + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware registers access functions. + * The implementation of these function is platform and toolchain specific. + * The functions declared here are implemented using assembler as part of the + * processor/toolchain specific HAL. This implementation is for the combination + * of the 32 bit RISC-V processors and GNU tool chain. + * + */ + +.section .text + .globl HW_set_32bit_reg + .globl HW_get_32bit_reg + .globl HW_set_32bit_reg_field + .globl HW_get_32bit_reg_field + .globl HW_set_16bit_reg + .globl HW_get_16bit_reg + .globl HW_set_16bit_reg_field + .globl HW_get_16bit_reg_field + .globl HW_set_8bit_reg + .globl HW_get_8bit_reg + .globl HW_set_8bit_reg_field + .globl HW_get_8bit_reg_field + + +/***************************************************************************//** + * HW_set_32bit_reg is used to write the content of a 32 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint32_t value + */ +HW_set_32bit_reg: + sw a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_32bit_reg is used to read the content of a 32 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + + * @return 32 bits value read from the peripheral register. + */ +HW_get_32bit_reg: + lw a0, 0(a0) + ret + +/***************************************************************************//** + * HW_set_32bit_reg_field is used to set the content of a field in a 32 bits + * wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint32_t mask + * a3: uint32_t value + */ +HW_set_32bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lw t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sw t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_32bit_reg_field is used to read the content of a field out of a + * 32 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint32_t mask + * + * @return 32 bits value containing the register field value specified + * as parameter. + */ +HW_get_32bit_reg_field: + lw a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +/***************************************************************************//** + * HW_set_16bit_reg is used to write the content of a 16 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint_fast16_t value + */ +HW_set_16bit_reg: + sh a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_16bit_reg is used to read the content of a 16 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + + * @return 16 bits value read from the peripheral register. + */ +HW_get_16bit_reg: + lh a0, (a0) + ret + +/***************************************************************************//** + * HW_set_16bit_reg_field is used to set the content of a field in a 16 bits + * wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast16_t mask + * a3: uint_fast16_t value + * @param value Value to be written in the specified field. + */ +HW_set_16bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lh t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sh t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_16bit_reg_field is used to read the content of a field from a + * 16 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast16_t mask + * + * @return 16 bits value containing the register field value specified + * as parameter. + */ +HW_get_16bit_reg_field: + lh a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +/***************************************************************************//** + * HW_set_8bit_reg is used to write the content of a 8 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint_fast8_t value + */ +HW_set_8bit_reg: + sb a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_8bit_reg is used to read the content of a 8 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + + * @return 8 bits value read from the peripheral register. + */ +HW_get_8bit_reg: + lb a0, 0(a0) + ret + +/***************************************************************************//** + * HW_set_8bit_reg_field is used to set the content of a field in a 8 bits + * wide peripheral register. + * + * a0: addr_t reg_addr, + * a1: int_fast8_t shift + * a2: uint_fast8_t mask + * a3: uint_fast8_t value + */ +HW_set_8bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lb t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sb t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_8bit_reg_field is used to read the content of a field from a + * 8 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast8_t mask + * + * @return 8 bits value containing the register field value specified + * as parameter. + */ +HW_get_8bit_reg_field: + lb a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +.end diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/hal/hw_reg_access.h b/applications/user-crypto/miv-rv32-message-authentication/src/platform/hal/hw_reg_access.h new file mode 100644 index 0000000..1a24309 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/hal/hw_reg_access.h @@ -0,0 +1,239 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hw_reg_access.S + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware registers access functions. + * The implementation of these function is platform and tool-chain specific. + * The functions declared here are implemented using assembler as part of the + * processor/tool-chain specific HAL. This implementation is for the combination + * of the 32 bit RISC-V processors and GNU tool chain. + * + */ +#ifndef __HW_REG_ACCESS +#define __HW_REG_ACCESS +#ifdef __cplusplus +extern "C" { +#endif + +#include "cpu_types.h" +/***************************************************************************//** + * HW_set_32bit_reg is used to write the content of a 32 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_32bit_reg +( + addr_t reg_addr, + uint32_t value +); + +/***************************************************************************//** + * HW_get_32bit_reg is used to read the content of a 32 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 32 bits value read from the peripheral register. + */ +uint32_t +HW_get_32bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_32bit_reg_field is used to set the content of a field in a 32 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void +HW_set_32bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint32_t mask, + uint32_t value +); + +/***************************************************************************//** + * HW_get_32bit_reg_field is used to read the content of a field out of a + * 32 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 32 bits value containing the register field value specified + * as parameter. + */ +uint32_t +HW_get_32bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint32_t mask +); + +/***************************************************************************//** + * HW_set_16bit_reg is used to write the content of a 16 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_16bit_reg +( + addr_t reg_addr, + uint_fast16_t value +); + +/***************************************************************************//** + * HW_get_16bit_reg is used to read the content of a 16 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 16 bits value read from the peripheral register. + */ +uint16_t +HW_get_16bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_16bit_reg_field is used to set the content of a field in a 16 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void HW_set_16bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast16_t mask, + uint_fast16_t value +); + +/***************************************************************************//** + * HW_get_16bit_reg_field is used to read the content of a field from a + * 16 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 16 bits value containing the register field value specified + * as parameter. + */ +uint16_t HW_get_16bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast16_t mask +); + +/***************************************************************************//** + * HW_set_8bit_reg is used to write the content of a 8 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_8bit_reg +( + addr_t reg_addr, + uint_fast8_t value +); + +/***************************************************************************//** + * HW_get_8bit_reg is used to read the content of a 8 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 8 bits value read from the peripheral register. + */ +uint8_t +HW_get_8bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_8bit_reg_field is used to set the content of a field in a 8 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void HW_set_8bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast8_t mask, + uint_fast8_t value +); + +/***************************************************************************//** + * HW_get_8bit_reg_field is used to read the content of a field from a + * 8 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 8 bits value containing the register field value specified + * as parameter. + */ +uint8_t HW_get_8bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast8_t mask +); + +#ifdef __cplusplus +} +#endif + +#endif /* __HW_REG_ACCESS */ + diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld b/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld new file mode 100644 index 0000000..474eb43 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld @@ -0,0 +1,154 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-execute-in-place.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * image executing from a one address space whereas the data, sdata and stack + * sections are placed in another address space. This could be used in cases such + * as: + * 1) When using MIV_RV32, the reset vector points to the LSRAM at address + * 0x80000000 and the data, sdata, bss and stack sections are placed in the + * TCM region. + * + * 2) Executing from a Non Volatile memory. The actual memory will depend on + * the FPGA platform. For exameple, it could be the eNVM on SmartFusion2, + * Igloo2 or on-board non-volatile memory which supports code execution. + * + * NOTE: Modify the memory section addresses and the sizes according to your + * Libero design. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + + +MEMORY +{ + rom (rx) : ORIGIN = 0x80000000, LENGTH = 16k + ram (rwx) : ORIGIN = 0x80004000, LENGTH = 16k +} + +STACK_SIZE = 1k; /* needs to be calculated for your application */ +HEAP_SIZE = 1k; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > rom + + .text : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.text.entry))) + . = ALIGN(0x10); + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } >rom + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } >ram AT>rom + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } >ram AT>rom + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram +} + diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv-rv32-ram.ld b/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv-rv32-ram.ld new file mode 100644 index 0000000..53076a0 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv-rv32-ram.ld @@ -0,0 +1,150 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-ram.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * debug image executing in SRAM. + * + * This linker script assumes that a RAM is connected at on Mi-V soft processor + * memory space pointed by the reset vector address. + * + * NOTE : Modify the memory section address and the size according to your + * Libero design. + * For example: + * 1) If you want to download and step debug at a different RAM memory address in + * your design (For example TCM base address) than the one provided in this file. + * 2) The MIV_RV32, when used with MIV_ESS IP, provides ways to copy the executable + * HEX file from external Non-Volatile memory into the TCM at reset. In this + * case your executable must be linked to the TCM address. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +MEMORY +{ + ram (rwx) : ORIGIN = 0x80000000, LENGTH = 32k +} + +STACK_SIZE = 2k; /* needs to be calculated for your application */ +HEAP_SIZE = 1k; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > ram + + .text : ALIGN(0x10) + { + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } > ram + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } > ram + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } > ram + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram +} + diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv_rv32_assert.h b/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv_rv32_assert.h new file mode 100644 index 0000000..b3912ed --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv_rv32_assert.h @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * MIV_RV32 HAL Embedded Software + * + */ +#ifndef MIV_RV32_ASSERT_HEADER +#define MIV_RV32_ASSERT_HEADER + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + * ASSERT() implementation. + ******************************************************************************/ +/* Disable assertions if we do not recognize the compiler. */ +#if defined ( __GNUC__ ) +#if defined(NDEBUG) +#define ASSERT(CHECK) +#else +#define ASSERT(CHECK)\ + do { \ + if (!(CHECK)) \ + { \ + __asm__ volatile ("ebreak"); \ + }\ + } while(0); + +#endif /* NDEBUG check */ +#endif /* compiler check */ + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_RV32_ASSERT_HEADER */ + diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv_rv32_entry.S b/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv_rv32_entry.S new file mode 100644 index 0000000..0ea3172 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv_rv32_entry.S @@ -0,0 +1,590 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_entry.S + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor vectors, trap handling and startup code. + * + */ +#ifndef ENTRY_S +#define ENTRY_S + +#define A_EXTENSION_MASK 0x00000001u +#define MTVEC_MODE_BIT_MASK 0x00000003u +#define MTVEC_VECTORED_MODE_VAL 0x00000001u + +#define MTIMEH_ADDR 0x200BFFCu + + +#if __riscv_xlen == 64 +# define LREG ld +# define SREG sd +# define REGBYTES 8 +#else +# define LREG lw +# define SREG sw +# define REGBYTES 4 +#endif + +#if defined(MIV_FP_CONTEXT_SAVE) && defined(__riscv_flen) +#define SP_SHIFT_OFFSET 64 +#else +#define SP_SHIFT_OFFSET 32 +#endif + +.macro STORE_CONTEXT + addi sp, sp, -SP_SHIFT_OFFSET*REGBYTES + SREG x1, 0 * REGBYTES(sp) + SREG x1, 0 * REGBYTES(sp) + SREG x2, 1 * REGBYTES(sp) + SREG x3, 2 * REGBYTES(sp) + SREG x4, 3 * REGBYTES(sp) + SREG x5, 4 * REGBYTES(sp) + SREG x6, 5 * REGBYTES(sp) + SREG x7, 6 * REGBYTES(sp) + SREG x8, 7 * REGBYTES(sp) + SREG x9, 8 * REGBYTES(sp) + SREG x10, 9 * REGBYTES(sp) + SREG x11, 10 * REGBYTES(sp) + SREG x12, 11 * REGBYTES(sp) + SREG x13, 12 * REGBYTES(sp) + SREG x14, 13 * REGBYTES(sp) + SREG x15, 14 * REGBYTES(sp) + SREG x16, 15 * REGBYTES(sp) + SREG x17, 16 * REGBYTES(sp) + SREG x18, 17 * REGBYTES(sp) + SREG x19, 18 * REGBYTES(sp) + SREG x20, 19 * REGBYTES(sp) + SREG x21, 20 * REGBYTES(sp) + SREG x22, 21 * REGBYTES(sp) + SREG x23, 22 * REGBYTES(sp) + SREG x24, 23 * REGBYTES(sp) + SREG x25, 24 * REGBYTES(sp) + SREG x26, 25 * REGBYTES(sp) + SREG x27, 26 * REGBYTES(sp) + SREG x28, 27 * REGBYTES(sp) + SREG x29, 28 * REGBYTES(sp) + SREG x30, 29 * REGBYTES(sp) + SREG x31, 30 * REGBYTES(sp) + + #ifdef __riscv_flen + #ifdef MIV_FP_CONTEXT_SAVE + fsw f0, 31*REGBYTES(sp) + fsw f1, 32*REGBYTES(sp) + fsw f2, 33*REGBYTES(sp) + fsw f3, 34*REGBYTES(sp) + fsw f4, 35*REGBYTES(sp) + fsw f5, 36*REGBYTES(sp) + fsw f6, 37*REGBYTES(sp) + fsw f7, 38*REGBYTES(sp) + fsw f8, 39*REGBYTES(sp) + fsw f9, 40*REGBYTES(sp) + fsw f10, 41*REGBYTES(sp) + fsw f11, 42*REGBYTES(sp) + fsw f12, 43*REGBYTES(sp) + fsw f13, 44*REGBYTES(sp) + fsw f14, 45*REGBYTES(sp) + fsw f15, 46*REGBYTES(sp) + fsw f16, 47*REGBYTES(sp) + fsw f17, 48*REGBYTES(sp) + fsw f18, 49*REGBYTES(sp) + fsw f19, 50*REGBYTES(sp) + fsw f20, 51*REGBYTES(sp) + fsw f21, 52*REGBYTES(sp) + fsw f22, 53*REGBYTES(sp) + fsw f23, 54*REGBYTES(sp) + fsw f24, 55*REGBYTES(sp) + fsw f25, 56*REGBYTES(sp) + fsw f26, 57*REGBYTES(sp) + fsw f27, 58*REGBYTES(sp) + fsw f28, 59*REGBYTES(sp) + fsw f29, 60*REGBYTES(sp) + fsw f30, 61*REGBYTES(sp) + fsw f31, 62*REGBYTES(sp) + #endif /* __riscv_flen */ + #endif /* MIV_FP_CONTEXT_SAVE */ +.endm + + .section .entry, "ax" + .globl _start + +_start: + j handle_reset + +/* Some of the Mi-V soft IP cores support compressed 'C' extension. If the Mi-V + core in your design doesn't support 'C' extension and you enable 'C' extension + in firmware project compiler options, then it would result in a trap. For this + case, we are avoiding compressed instruction here so you can put a breakpoint + at the jump and you can at least look at mcause, mepc and get some hints + about the crash. */ +trap_entry: +.option push +.option norvc +j generic_trap_handler +.option pop + .word 0 + .word 0 + +sw_trap_entry: + j vector_sw_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + +tmr_trap_entry: + j vector_tmr_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + +ext_trap_entry: + j vector_ext_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + .word 0 + +#ifndef MIV_LEGACY_RV32 +MGEUI_trap_entry: + j vector_MGEUI_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MGECI_trap_entry: + j vector_MGECI_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + .word 0 + +#ifndef MIV_RV32_V3_0 +MSYS_MIE22_trap_entry: +#ifndef MIV_RV32_V3_0 + j vector_SUBSYSR_IRQHandler +#endif /*MIV_RV32_V3_0*/ +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE23_trap_entry: + j vector_SUBSYS_IRQHandler +#ifdef __riscv_compressed + .2byte 0 +#endif +#endif /*MIV_RV32_V3_0*/ + +MSYS_MIE24_trap_entry: + j vector_MSYS_EI0_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE25_trap_entry: + j vector_MSYS_EI1_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE26_trap_entry: + j vector_MSYS_EI2_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE27_trap_entry: + j vector_MSYS_EI3_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE28_trap_entry: + j vector_MSYS_EI4_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE29_trap_entry: + j vector_MSYS_EI5_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE30_trap_entry: +#ifndef MIV_RV32_V3_0 + j vector_MSYS_EI6_trap_handler +#else + j vector_SUBSYS_IRQHandler +#endif +#ifdef __riscv_compressed + .2byte 0 +#endif + +#ifndef MIV_RV32_V3_0 +MSYS_MIE31_trap_entry: + j vector_MSYS_EI7_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif +#endif /* MIV_RV32_V3_0 */ +#endif /* MIV_LEGACY_RV32 */ + +.align 4 +generic_trap_handler: + STORE_CONTEXT + csrr a0, mcause + csrr a1, mepc + jal handle_trap + j generic_restore + +vector_sw_trap_handler: + STORE_CONTEXT + jal handle_m_soft_interrupt + j generic_restore + +vector_tmr_trap_handler: + STORE_CONTEXT + jal handle_m_timer_interrupt + j generic_restore + +vector_ext_trap_handler: + STORE_CONTEXT +#ifdef MIV_LEGACY_RV32 + jal handle_m_ext_interrupt +#else + jal External_IRQHandler +#endif /* MIV_LEGACY_RV32 */ + j generic_restore + +#ifndef MIV_LEGACY_RV32 +vector_MGEUI_trap_handler: + STORE_CONTEXT + jal MGEUI_IRQHandler + j generic_restore + +vector_MGECI_trap_handler: + STORE_CONTEXT + jal MGECI_IRQHandler + j generic_restore + +vector_MSYS_EI0_trap_handler: + STORE_CONTEXT + jal MSYS_EI0_IRQHandler + j generic_restore + +vector_MSYS_EI1_trap_handler: + STORE_CONTEXT + jal MSYS_EI1_IRQHandler + j generic_restore + +vector_MSYS_EI2_trap_handler: + STORE_CONTEXT + jal MSYS_EI2_IRQHandler + j generic_restore + +vector_MSYS_EI3_trap_handler: + STORE_CONTEXT + jal MSYS_EI3_IRQHandler + j generic_restore + +vector_MSYS_EI4_trap_handler: + STORE_CONTEXT + jal MSYS_EI4_IRQHandler + j generic_restore + +vector_MSYS_EI5_trap_handler: + STORE_CONTEXT + jal MSYS_EI5_IRQHandler + j generic_restore + +vector_SUBSYS_IRQHandler: + STORE_CONTEXT + jal SUBSYS_IRQHandler + j generic_restore + +#ifndef MIV_RV32_V3_0 +vector_MSYS_EI6_trap_handler: + STORE_CONTEXT + jal MSYS_EI6_IRQHandler + j generic_restore + +vector_MSYS_EI7_trap_handler: + STORE_CONTEXT + jal MSYS_EI7_IRQHandler + j generic_restore + + +vector_SUBSYSR_IRQHandler: + STORE_CONTEXT + jal SUBSYSR_IRQHandler + j generic_restore + +#endif /*MIV_RV32_V3_0*/ +#endif /* MIV_LEGACY_RV32 */ + +generic_restore: + LREG x1, 0 * REGBYTES(sp) + LREG x2, 1 * REGBYTES(sp) + LREG x3, 2 * REGBYTES(sp) + LREG x4, 3 * REGBYTES(sp) + LREG x5, 4 * REGBYTES(sp) + LREG x6, 5 * REGBYTES(sp) + LREG x7, 6 * REGBYTES(sp) + LREG x8, 7 * REGBYTES(sp) + LREG x9, 8 * REGBYTES(sp) + LREG x10, 9 * REGBYTES(sp) + LREG x11, 10 * REGBYTES(sp) + LREG x12, 11 * REGBYTES(sp) + LREG x13, 12 * REGBYTES(sp) + LREG x14, 13 * REGBYTES(sp) + LREG x15, 14 * REGBYTES(sp) + LREG x16, 15 * REGBYTES(sp) + LREG x17, 16 * REGBYTES(sp) + LREG x18, 17 * REGBYTES(sp) + LREG x19, 18 * REGBYTES(sp) + LREG x20, 19 * REGBYTES(sp) + LREG x21, 20 * REGBYTES(sp) + LREG x22, 21 * REGBYTES(sp) + LREG x23, 22 * REGBYTES(sp) + LREG x24, 23 * REGBYTES(sp) + LREG x25, 24 * REGBYTES(sp) + LREG x26, 25 * REGBYTES(sp) + LREG x27, 26 * REGBYTES(sp) + LREG x28, 27 * REGBYTES(sp) + LREG x29, 28 * REGBYTES(sp) + LREG x30, 29 * REGBYTES(sp) + LREG x31, 30 * REGBYTES(sp) + + #ifdef __riscv_flen + #ifdef MIV_FP_CONTEXT_SAVE + flw f0, 0 * REGBYTES(sp) + flw f1, 1 * REGBYTES(sp) + flw f2, 2 * REGBYTES(sp) + flw f3, 3 * REGBYTES(sp) + flw f4, 4 * REGBYTES(sp) + flw f5, 5 * REGBYTES(sp) + flw f6, 6 * REGBYTES(sp) + flw f7, 7 * REGBYTES(sp) + flw f8, 8 * REGBYTES(sp) + flw f9, 9 * REGBYTES(sp) + flw f10, 10 * REGBYTES(sp) + flw f11, 11 * REGBYTES(sp) + flw f12, 12 * REGBYTES(sp) + flw f13, 13 * REGBYTES(sp) + flw f14, 14 * REGBYTES(sp) + flw f15, 15 * REGBYTES(sp) + flw f16, 16 * REGBYTES(sp) + flw f17, 17 * REGBYTES(sp) + flw f18, 18 * REGBYTES(sp) + flw f19, 19 * REGBYTES(sp) + flw f20, 20 * REGBYTES(sp) + flw f21, 21 * REGBYTES(sp) + flw f22, 22 * REGBYTES(sp) + flw f23, 23 * REGBYTES(sp) + flw f24, 24 * REGBYTES(sp) + flw f25, 25 * REGBYTES(sp) + flw f26, 26 * REGBYTES(sp) + flw f27, 27 * REGBYTES(sp) + flw f28, 28 * REGBYTES(sp) + flw f29, 29 * REGBYTES(sp) + flw f30, 30 * REGBYTES(sp) + flw f31, 31 * REGBYTES(sp) + #endif /* __riscv_flen */ + #endif /* MIV_FP_CONTEXT_SAVE */ + + addi sp, sp, SP_SHIFT_OFFSET*REGBYTES + mret + + .section .text, "ax" +handle_reset: +/* Ensure instructions are not relaxed, since gp is not yet set */ +.option push +.option norelax + +#ifndef MIV_RV32_V3_0 + csrwi mstatus, 0 + csrwi mie, 0 + la ra, _start + +/* Clearnig this to be on safer side as RTL doesnt seem to clear it on reset. */ +#ifndef MIV_LEGACY_RV32 + li t0, MTIMEH_ADDR + sw x0, 0(t0) +#endif + + csrr t0, misa + andi t0, t0, A_EXTENSION_MASK + bnez t0, ima_cores_setup /* Jump to IMA core handling */ + + +/* For MIV_RV32 cores the mtvec exception base address is fixed at Reset vector + address + 0x4. Check the mode bits. */ +/* In the MIV_RV32 v3.1, the MTVEC exception base address is WARL, and can be + configured by the user at runtime */ + + csrr t0, mtvec + andi t0, t0, MTVEC_MODE_BIT_MASK + li t1, MTVEC_VECTORED_MODE_VAL + bne t0, t1, ima_cores_setup /* Jump to IMA core handling */ + + /* When mode = 1 => this is vectored mode on MIV_RV32 core. + Verify that the trap_handler address matches the configuration in MTVEC */ + csrr t0, mtvec + andi t0, t0, 0xFFFFFFFC + la t1, trap_entry + bne t0, t1, vector_address_not_matching + j generic_reset_handling + +#else /* MIV_RV32_V3_0 */ + +/* Clearnig this to be on safer side as RTL doesnt seem to clear it on reset. */ +#ifndef MIV_LEGACY_RV32 + li t0, MTIMEH_ADDR + sw x0, 0(t0) +#endif + +/* In the MIV_RV32 v3.1, the MTVEC exception base address is WARL, and can be + configured by the user at runtime */ + csrr t0, mtvec + andi t0, t0, MTVEC_MODE_BIT_MASK + li t1, MTVEC_VECTORED_MODE_VAL + bne t0, t1, ima_cores_setup /* Jump to IMA core handling */ + +/* When mode = 1 => this is vectored mode on MIV_RV32 core. + Verify that the trap_handler address matches the configuration in MTVEC */ + csrr t0, mtvec + andi t0, t0, 0xFFFFFFFC + la t1, trap_entry + bne t0, t1, vector_address_not_matching + j generic_reset_handling +#endif /*MIV_RV32_V3_0*/ + +ima_cores_setup: + la t0, trap_entry + +#ifdef MIV_LEGACY_RV32_VECTORED_INTERRUPTS + addi t0, t0, 0x01 /* Set the mode bit for IMA cores. + For both MIV_RV32 v3.1 and v3.0 cores this is done by configurator. */ +#endif + csrw mtvec, t0 + +generic_reset_handling: +/* Copy sdata section first so that the gp is set and linker relaxation can be + used */ + la a4, __sdata_load + la a5, __sdata_start + la a6, __sdata_end + beq a4, a5, 1f /* Exit if source and dest are same */ + beq a5, a6, 1f /* Exit if section start and end addresses are same */ + call block_copy + +1: + /* initialize global pointer */ + la gp, __global_pointer$ + +.option pop + +/* Floating point support configuration */ +#ifdef __riscv_flen + csrr t0, mstatus + lui t1, 0xffffa + addi t1, t1, -1 + and t0, t0, t1 + lui t1, 0x4 + or t1, t0, t1 + csrw mstatus, t1 + + lui t0, 0x0 + fscsr t0 +#endif + call initializations + /* Initialize stack pointer */ + la sp, __stack_top + + /* Jump into C code */ + j _init + +/* Error: trap_entry is not at the expected address of reset_vector+mtvec offset + as configured in the MIV_RV32 core vectored mode */ +vector_address_not_matching: + ebreak + +initializations: +/* Initialize the .bss section */ + mv t0, ra /* Store ra for future use */ + la a5, __bss_start + la a6, __bss_end + beq a5, a6, 1f /* Section start and end address are the same */ + call zeroize_block + +1: +/* Initialize the .sbss section */ + la a5, __sbss_start + la a6, __sbss_end + beq a5, a6, 1f /* Section start and end address are the same */ + call zeroize_block + +/* Clear heap */ + la a5, __heap_start + la a6, __heap_end + beq a5, a6, 1f /* Section start and end address are the same */ + call zeroize_block + +1: +/* Copy data section */ + la a4, __data_load + la a5, __data_start + la a6, __data_end + beq a4, a5, 1f /* Exit early if source and dest are same */ + beq a5, a6, 1f /* Section start and end addresses are the same */ + call block_copy + +1: + mv ra, t0 /* Retrieve ra */ + ret + +zeroize_block: + bltu a6, a5, block_copy_error /* Error. End address is less than start */ + or a7, a6, a5 /* Check if start or end is unalined */ + andi a7, a7, 0x03u + bgtz a7, block_copy_error /* Unaligned addresses error*/ +zeroize_loop: + sw x0, 0(a5) + add a5, a5, __SIZEOF_POINTER__ + blt a5, a6, zeroize_loop + ret + +block_copy: + bltu a6, a5, block_copy_error /* Error. End address is less than start */ + or a7, a6, a5 /* Check if start or end is unalined */ + andi a7, a7, 0x03u + bgtz a7, block_copy_error /* Unaligned addresses error*/ +block_copy_loop: + lw a7, 0(a4) + sw a7, 0(a5) + addi a5, a5, 0x04 + addi a4, a4, 0x04 + blt a5, a6, block_copy_loop + j block_copy_exit + +block_copy_error: + j block_copy_error + +block_copy_exit: + ret + +#endif /*ENTRY_S*/ diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv_rv32_hal.c b/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv_rv32_hal.c new file mode 100644 index 0000000..a112821 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv_rv32_hal.c @@ -0,0 +1,410 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_hal.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Implementation of Hardware Abstraction Layer for Mi-V soft processors + * + */ +#include +#include "miv_rv32_hal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SUCCESS 0U +#define ERROR 1U +#define MASK_32BIT 0xFFFFFFFFu + +/*------------------------------------------------------------------------------ + * Write in a sequence recommended by privileged spec to avoid spurious + * interrupts + + # New comparand is in a1:a0. + li t0, -1 + sw t0, mtimecmp # No smaller than old value. + sw a1, mtimecmp+4 # No smaller than new value. + sw a0, mtimecmp # New value. + */ +#ifndef MIV_RV32_EXT_TIMECMP +#define WRITE_MTIMECMP(value) MTIMECMPH = MASK_32BIT; \ + MTIMECMP = value & MASK_32BIT;\ + MTIMECMPH = (value >> 32u) & MASK_32BIT; +#else +#define WRITE_MTIMECMP(value) +#endif + +#ifndef MIV_RV32_EXT_TIMER +#define WRITE_MTIME(value) MTIME = value & MASK_32BIT;\ + MTIMEH = (value >> 32u) & MASK_32BIT; +#else +#define WRITE_MTIME(value) +#endif + +extern void Software_IRQHandler(void); + +#ifdef MIV_LEGACY_RV32 +#define MTIME_PRESCALER 100UL +/*------------------------------------------------------------------------------ + * + */ +uint8_t Invalid_IRQHandler(void); +uint8_t External_1_IRQHandler(void); +uint8_t External_2_IRQHandler(void); +uint8_t External_3_IRQHandler(void); +uint8_t External_4_IRQHandler(void); +uint8_t External_5_IRQHandler(void); +uint8_t External_6_IRQHandler(void); +uint8_t External_7_IRQHandler(void); +uint8_t External_8_IRQHandler(void); +uint8_t External_9_IRQHandler(void); +uint8_t External_10_IRQHandler(void); +uint8_t External_11_IRQHandler(void); +uint8_t External_12_IRQHandler(void); +uint8_t External_13_IRQHandler(void); +uint8_t External_14_IRQHandler(void); +uint8_t External_15_IRQHandler(void); +uint8_t External_16_IRQHandler(void); +uint8_t External_17_IRQHandler(void); +uint8_t External_18_IRQHandler(void); +uint8_t External_19_IRQHandler(void); +uint8_t External_20_IRQHandler(void); +uint8_t External_21_IRQHandler(void); +uint8_t External_22_IRQHandler(void); +uint8_t External_23_IRQHandler(void); +uint8_t External_24_IRQHandler(void); +uint8_t External_25_IRQHandler(void); +uint8_t External_26_IRQHandler(void); +uint8_t External_27_IRQHandler(void); +uint8_t External_28_IRQHandler(void); +uint8_t External_29_IRQHandler(void); +uint8_t External_30_IRQHandler(void); +uint8_t External_31_IRQHandler(void); + + +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for external interrupts. + */ +uint8_t (* const mrv_ext_irq_handler_table[32])(void) = +{ + + Invalid_IRQHandler, + External_1_IRQHandler, + External_2_IRQHandler, + External_3_IRQHandler, + External_4_IRQHandler, + External_5_IRQHandler, + External_6_IRQHandler, + External_7_IRQHandler, + External_8_IRQHandler, + External_9_IRQHandler, + External_10_IRQHandler, + External_11_IRQHandler, + External_12_IRQHandler, + External_13_IRQHandler, + External_14_IRQHandler, + External_15_IRQHandler, + External_16_IRQHandler, + External_17_IRQHandler, + External_18_IRQHandler, + External_19_IRQHandler, + External_20_IRQHandler, + External_21_IRQHandler, + External_22_IRQHandler, + External_23_IRQHandler, + External_24_IRQHandler, + External_25_IRQHandler, + External_26_IRQHandler, + External_27_IRQHandler, + External_28_IRQHandler, + External_29_IRQHandler, + External_30_IRQHandler, + External_31_IRQHandler +}; + +#else +/*------------------------------------------------------------------------------ + * Interrupt handlers as mapped into the MIE register of the MIV_RV32 + */ +extern void Reserved_IRQHandler(void); +extern void External_IRQHandler(void); +extern void MGEUI_IRQHandler(void); +extern void MGECI_IRQHandler(void); +extern void MSYS_EI0_IRQHandler(void); +extern void MSYS_EI1_IRQHandler(void); +extern void MSYS_EI2_IRQHandler(void); +extern void MSYS_EI3_IRQHandler(void); +extern void MSYS_EI4_IRQHandler(void); +extern void MSYS_EI5_IRQHandler(void); +extern void SUBSYS_IRQHandler(void); + +#ifndef MIV_RV32_V3_0 /*For MIV_RV32 v3.1*/ +extern void MSYS_EI6_IRQHandler(void); +extern void MSYS_EI7_IRQHandler(void); +extern void SUBSYSR_IRQHandler(void); // @suppress("Unused function declaration") +#endif /*MIV_RV32_V3_0*/ + +#endif /* MIV_LEGACY_RV32 */ + +/*------------------------------------------------------------------------------ + * Increment value for the mtimecmp register in order to achieve a system tick + * interrupt as specified through the MRV_systick_config() function. + */ +static uint64_t g_systick_increment = 0U; +static uint64_t g_systick_cmp_value = 0U; + +/*------------------------------------------------------------------------------ + * Configure the machine timer to generate an interrupt. + */ +uint32_t MRV_systick_config(uint64_t ticks) +{ + uint32_t ret_val = ERROR; + uint64_t remainder = ticks; + g_systick_increment = 0U; + g_systick_cmp_value = 0U; + + while (remainder >= MTIME_PRESCALER) + { + remainder -= MTIME_PRESCALER; + g_systick_increment++; + } + + g_systick_cmp_value = g_systick_increment + MRV_read_mtime(); + + if (g_systick_increment > 0U) + { + WRITE_MTIMECMP(g_systick_cmp_value); + set_csr(mie, MIP_MTIP); + MRV_enable_interrupts(); + ret_val = SUCCESS; + } + + return ret_val; +} + +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for machine timer interrupts. + */ +void handle_m_timer_interrupt(void) +{ + clear_csr(mie, MIP_MTIP); + + uint64_t mtime_at_irq = MRV_read_mtime(); + +#ifndef NDEBUG + static volatile uint32_t d_tick = 0u; +#endif + + while(g_systick_cmp_value < (mtime_at_irq + MTIME_DELTA)) { + g_systick_cmp_value = g_systick_cmp_value + g_systick_increment; + +#ifndef NDEBUG + d_tick += 1; +#endif + } +/***************************************************************************//** + /* + * Note: If d_tick > 1 it means, that a system timer interrupt has been + * missed. + * Please ensure that interrupt handlers are as short as possible to prevent + * them stopping other interrupts from being handled. For example, if a + * system timer interrupt occurs during a software interrupt, the system + * timer interrupt will not be handled until the software interrupt handling + * is complete. If the software interrupt handling time is more than one + * systick interval, it will result in d_tick > 1. + * If you are running the program using the debugger and halt the CPU at a + * breakpoint, MTIME will continue to increment and interrupts will be + * missed; resulting in d_tick > 1. + */ + + WRITE_MTIMECMP(g_systick_cmp_value); + + SysTick_Handler(); + + set_csr(mie, MIP_MTIP); +} + +void handle_m_soft_interrupt(void) +{ + Software_IRQHandler(); + MRV_clear_soft_irq(); +} +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for software interrupts. + */ +#ifdef MIV_LEGACY_RV32 +void handle_m_ext_interrupt(void) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; + uint8_t disable = EXT_IRQ_KEEP_ENABLED; + + if (0u !=int_num) + { + disable = mrv_ext_irq_handler_table[int_num](); + + PLIC->TARGET[hart_id].CLAIM_COMPLETE = int_num; + + if(EXT_IRQ_DISABLE == disable) + { + MRV_PLIC_disable_irq((IRQn_Type)int_num); + } + } +} +#else + +/*------------------------------------------------------------------------------ + * MSYS local interrupts table + */ +void (* const local_irq_handler_table[16])(void) = +{ +#ifndef MIV_RV32_V3_0 + MGEUI_IRQHandler, + MGECI_IRQHandler, + SUBSYS_IRQHandler, + SUBSYSR_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + MSYS_EI0_IRQHandler, + MSYS_EI1_IRQHandler, + MSYS_EI2_IRQHandler, + MSYS_EI3_IRQHandler, + MSYS_EI4_IRQHandler, + MSYS_EI5_IRQHandler, + MSYS_EI6_IRQHandler, + MSYS_EI7_IRQHandler +#else + MGEUI_IRQHandler, + MGECI_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + MSYS_EI0_IRQHandler, + MSYS_EI1_IRQHandler, + MSYS_EI2_IRQHandler, + MSYS_EI3_IRQHandler, + MSYS_EI4_IRQHandler, + MSYS_EI5_IRQHandler, + SUBSYS_IRQHandler, + Reserved_IRQHandler, +#endif +}; + +/*------------------------------------------------------------------------------ + * Jump to interrupt table containing local interrupts + */ +void handle_local_ei_interrupts(uint8_t irq_no) +{ + uint64_t mhart_id = read_csr(mhartid); + ASSERT(irq_no <= MIV_LOCAL_IRQ_MAX) + ASSERT(irq_no >= MIV_LOCAL_IRQ_MIN) + + uint8_t ei_no = (uint8_t)(irq_no - MIV_LOCAL_IRQ_MIN); + (*local_irq_handler_table[ei_no])(); +} +#endif /* MIV_LEGACY_RV32 */ + + +/*------------------------------------------------------------------------------ + * Trap handler. This function is invoked in the non-vectored mode. + */ +void handle_trap(uintptr_t mcause, uintptr_t mepc) +{ + uint64_t is_interrupt = mcause & MCAUSE_INT; + + if (is_interrupt) + { +#ifndef MIV_LEGACY_RV32 + if (((mcause & MCAUSE_CAUSE) >= MIV_LOCAL_IRQ_MIN) && ((mcause & MCAUSE_CAUSE) <= MIV_LOCAL_IRQ_MAX)) + { + handle_local_ei_interrupts((uint8_t)(mcause & MCAUSE_CAUSE)); + } + else if ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT) +#else + if ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT) +#endif + { +#ifndef MIV_LEGACY_RV32 + External_IRQHandler(); +#else + handle_m_ext_interrupt(); +#endif + } + else if ((mcause & MCAUSE_CAUSE) == IRQ_M_SOFT) + { + handle_m_soft_interrupt(); + } + else if ((mcause & MCAUSE_CAUSE) == IRQ_M_TIMER) + { + handle_m_timer_interrupt(); + } + } + else + { +#ifndef NDEBUG + /* + Arguments supplied to this function are mcause, mepc (exception PC) and + stack pointer. + Based on privileged-isa specification mcause values and meanings are: + + 0 Instruction address misaligned (mtval/mtval is the address) + 1 Instruction access fault (mtval/mtval is the address) + 2 Illegal instruction (mtval/mtval contains the + offending instruction opcode) + 3 Breakpoint + 4 Load address misaligned (mtval/mtval is the address) + 5 Load address fault (mtval/mtval is the address) + 6 Store/AMO address fault (mtval/mtval is the address) + 7 Store/AMO access fault (mtval/mtval is the address) + 8 Environment call from U-mode + 9 Environment call from S-mode + A Environment call from M-mode + B Instruction page fault + C Load page fault (mtval/mtval is the address) + E Store page fault (mtval/mtval is the address) + + # Please note: mtval is the newer name for register mbadaddr + # If you get a compile failure here, use the older name. + # At this point, both are supported in latest compiler, older compiler + # versions only support mbadaddr. + # See: https://github.com/riscv/riscv-gcc/issues/133 + */ + + /* interrupt pending */ + uintptr_t mip = read_csr(mip); + + /* additional info and meaning depends on mcause */ + uintptr_t mtval = read_csr(mtval); + + /* trap vector */ + uintptr_t mtvec = read_csr(mtvec); + + /* temporary, sometimes might hold temporary value of a0 */ + uintptr_t mscratch = read_csr(mscratch); + + /* status contains many smaller fields: */ + uintptr_t mstatus = read_csr(mstatus); + + /* PC value when the exception was taken*/ + uintptr_t mmepc = read_csr(mepc); + + /* breakpoint */ + __asm__("ebreak"); +#else + _exit(1 + mcause); +#endif /* NDEBUG */ + } +} + +#ifdef __cplusplus +} +#endif + diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv_rv32_hal.h b/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv_rv32_hal.h new file mode 100644 index 0000000..9ce9ef6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv_rv32_hal.h @@ -0,0 +1,773 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_hal.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware Abstraction Layer functions for Mi-V soft processors + * + */ + +/*=========================================================================*//** + @mainpage MIV_RV32 Hardware Abstraction Layer + + ============================================================================== + Introduction + ============================================================================== + This document describes the Hardware Abstraction Layer (HAL) for the MIV_RV32 + Soft IP Core. This release of the HAL corresponds to the Soft IP core MIV_RV32 + v3.1 release. It also supports earlier versions of the MIV_RV32 as well as the + legacy RV32 IP cores. + The preprocessor macros provided with the MIV_RV32 HAL are used to customize + it to target the Soft Processor IP version being used in your project. + + The term "MIV_RV32" represents following two cores: + - MIV_RV32 v3.0 and later (the latest and greatest Mi-V soft processor) + - MIV_RV32IMC v2.1 (MIV_RV32 v3.0 is a drop in replacement for this core) + It is highly recommended to migrate your design to MIV_RV32 v3.1 + + The term, Legacy RV32 IP cores, represents following IP cores: + - MIV_RV32IMA_L1_AHB + - MIV_RV32IMA_L1_AXI + - MIV_RV32IMAF_L1_AHB + + These legacy RV32 IP cores are deprecated. It is highly recommended to migrate + your designs to MIV_RV32 v3.1 (and subsequent IP releases) for the latest + enhancements, bug fixes, and support. + + -------------------------------- + MIV_RV32 V3.1 + -------------------------------- + This is the latest release of the MIV_RV32 Soft IP core. For more details, + refer to the MIV_RV32 User [Guide](https://www.microchip.com/en-us/products/fpgas-and-plds/ip-core-tools/miv-rv32) + + The MIV_RV32 Core as well as this document use the terms defined below: + + -------------------------------- + - SUBSYS - Processor Subsystem for RISC-V + - OPSRV - Offload Processor Subsystem for RISC-V + - GPR - General Purpose Registers + - MGECIE - Machine GPR ECC Correctable Interrupt Enable + - MGEUIE - Machine GPR ECC Uncorrectable Interrupt Enable + - MTIE - Machine Timer Interrupt Enable + - MEIE - Machine External Interrupt Enable + - MSIE - Machine Software Interrupt Enable + - ISR - Interrupt Service Routine + + ============================================================================== + Customizing MIV_RV32 HAL + ============================================================================== + To use the HAL with older releases of MIV_RV32, preprocessor macros have been + provided. Using these macros, any of the IP version is targeted. + The HAL is used to target any of the mentioned platforms by adding the + following macros in the way : + Project Properties > C/C++ Build > Settings > Preprocessor in Assembler and + Compiler settings. + The table below shows the macros corresponding to the MIV Core being used in + your libero project. By default, the HAL targets v3.1 of the IP core and no + macros need to be set for this configutation. + + | Libero MI-V Soft IP Version | SoftConsole Macro | + |-----------------------------|-------------------| + | MIV_RV32 v3.1 | no macro required | + | MIV_RV32 v3.0 | MIV_CORE_V3_0 | + | Legacy RV32 Cores | MIV_LEGACY_RV32 | + + -------------------------------- + Interrupt Handling + -------------------------------- + The MIE Register is defined as a enum in the HAL, and the table below is used + as a reference when the vectored interrupts are enabled in the GUI core + configurator. + + The MIE register is a RISC-V Control and Status Register (CSR), which stands + for the Machine Interrupt Enable. This is used to enable the machine mode + interrupts in the MIV_RV32 hart. Refer to the RISC-V Priv spec for more details. + + The following table shows the trap entry addresses when an interrupt occurs and + the vectored interrupts are enabled in the GUI configurator. + + | MIE Register Bit | Interrupt Enable | Vector Address | + |-------------------|------------------|----------------| + | 31 | MSYS_IE7 | mtvec.BASE + 0x7C | + | 30 | MSYS_IE6 | mtvec.BASE + 0x78 | + | 29 | MSYS_IE5 | mtvec.BASE + 0x74 | + | 28 | MSYS_IE4 | mtvec.BASE + 0x70 | + | 27 | MSYS_IE3 | mtvec.BASE + 0x6C | + | 26 | MSYS_IE2 | mtvec.BASE + 0x68 | + | 25 | MSYS_IE1 | mtvec.BASE + 0x64 | + | 24 | MSYS_IE0 | mtvec.BASE + 0x60 | + | 23 | SUBSYS_EI | mtvec.BASE + 0x5C | + | 22 | SUBSYSR | mtvec.BASE + 0x58 | + | 17 | MGECIE | mtvec.BASE + 0x44 | + | 16 | MGEUIE | mtvec.BASE + 0x40 | + | 11 | MEIE | mtvec.BASE + 0x2C | + | 7 | MTIE | mtvec.BASE + 0x1C | + | 3 | MSIE | mtvec.BASE + 0x0C | + + + For changes in MIE register map, see the [MIE Register Map for MIV_RV32 v3.0] + (#mie-register-map-for-miv_rv32-v3.0) section. + + SUBSYSR is currently not being used by the core and is Reserved for future use. + + The mtvec.BASE field corresponds to the bits [31:2], where mtvec stands for + Machine Trap Vector, and all traps set the PC to the the value stored in the + mtvec.BASE field when in Non-Vectored mode. In this case, a generic trap + handler is as an interrupt service routine. + + When Vectored interrupts are enabled, use this formula to calculate the trap + address: (mtvec.BASE + 4*cause), where cause comes from the mcause CSR. The + mcause register is written with a code indicating the event that caused the trap. + For more details, see the RISC-V priv specification. + + The MIV_RV32 Soft IP core does not contain a Platfrom Level Interrup Controller + (PLIC). It is advised to use the PLIC contained within the MIV_ESS sub-system. + Connect the PLIC interrupt output of the MIV_ESS to the EXT_IRQ pin on the + MIV_RV32. + + The following table is the MIE register map for the MIV_RV32 Core V3.0. It only + highlights the differences between the V3.0 and V3.1 of the core. + + -------------------------------- + MIE Register Map for MIV_RV32 V3.0 + -------------------------------- + + | MIE Register Bit | Target Interrupt | Vector Address | + |-------------------|------------------|----------------| + | 31 | Not in use | top table | + | 30 | SUBSYS_EI | addr + 0x78 | + | 23 | Not in use | Not in use | + | 22 | Not in use | Not in use | + + Other interrupt bit postions like the MGEUIE and MSYS_IE5 to MSYS_IE0 remain + unchanged. + + -------------------------------- + Floating Point Interrupt Support + -------------------------------- + When an interrupt is taken and Floating Point instructions are used in the + ISR, the floating point register context must be saved to resume the application + correctly. To use this feature, enable the provided macro in the + Softconsole build settings. + This feature is turned off by default as it adds overhead which is not required + when the ISR does not used FP insturctions and saving the general purpose + register context is sufficient. + + | Macro Name | Definition | + |--------------------------|-------------------------------------------------| + | MIV_FP_CONTEXT_SAVE | Define to save the FP register file | + + + -------------------------------- + SUBSYS - SubSystem for RISC-V + -------------------------------- + SUBSYS stands for SubSystem for RISC-V. This was previously (MIV_RV32 v3.0) + known as OPSRV, which stands for "Offload Processor Subsystem + for RISC-V". See the earlier versions of the handbook for more details. + In the latest release of the MIV_RV32 IP core v3.1, OPSRV has been renamed to + SUBSYS. The MIV_RV32 HAL now uses SUBSYS instead of OPSRV. + + *//*=========================================================================*/ +#ifndef RISCV_HAL_H +#define RISCV_HAL_H + +#include "miv_rv32_regs.h" +#include "miv_rv32_plic.h" +#include "miv_rv32_assert.h" +#include "miv_rv32_subsys.h" + +#ifndef LEGACY_DIR_STRUCTURE +#include "fpga_design_config/fpga_design_config.h" +#else +#include "hw_platform.h" +#endif /*LEGACY_DIR_STRUCTURE*/ + +#ifdef __cplusplus +extern "C" { +#endif +/*-------------------------------------------------------------------------*//** + SUBSYS Backwards Compatibility + ======================================= + For application code using the older macro names and API functions, these macros + act as a compatibility layer and applications which use OPSRV API features work + due to these macro definitions. However, it is adviced to update your + application code to use the SUBSYS macros and API functions. + + | Macro Name | Now Called | + |-------------------------|--------------------------| + | OPSRV_TCM_ECC_CE_IRQ | SUBSYS_TCM_ECC_CE_IRQ | + | OPSRV_TCM_ECC_UCE_IRQ | SUBSYS_TCM_ECC_UCE_IRQ | + | OPSRV_AXI_WR_RESP_IRQ | SUBSYS_AXI_WR_RESP_IRQ | + | MRV32_MSYS_OPSRV_IRQn | MRV32_SUBSYS_IRQn | + | MRV32_opsrv_enable_irq | MRV32_subsys_enable_irq | + | MRV32_opsrv_disable_irq | MRV32_subsys_disable_irq | + | MRV32_opsrv_clear_irq | MRV32_subsys_clear_irq | + | OPSRV_IRQHandler | SUBSYS_IRQHandler | + */ + +/*-------------------------------------------------------------------------*//** + MTIME Timer Interrupt Constants + ======================================= + These values contain the register addresses for the registers used by the + machine timer interrupt + + MTIME_PRESCALER is not defined on the MIV_RV32IMC v2.0 and v2.1. By using this + definition the system crashes. For those core, use the following definition: + + #define MTIME_PRESCALER 100u + + MTIME and MTIMECMP + -------------------------------- + MIV_RV32 core offers flexibility in terms of generating MTIME and MTIMECMP + registers internal to the core or using external time reference. There four + possible combinations: + + - Internal MTIME and Internal MTIME IRQ enabled Generate the MTIME and MTIMECMP + registers internally. (The only combination available on legacy RV32 cores) + + - Internal MTIME enabled and Internal MTIME IRQ disabled Generate the MTIME + internally and have a timer interrupt input to the core as external pin. In + this case, 1 pin port will be available on MIV_RV32 for timer interrupt. + + - When the internal MTIME is disabled, and the Internal MTIME IRQ is enabled, the + system generates the time value externally and generates the mtimecmp and + interrupt internally (for example, a multiprocessor system with a shared time + between all cores). In this case, a 64-bit port is available on the MIV_RV32 + core as input. + + - Internal MTIME and Internal MTIME IRQ disabled Generate both the time and + timer interrupts externally. In this case a 64 bit port will be available on + the MIV_RV32 core as input, and a 1 pin port will be available for timer + interrupt. + + To handle all these combinations in the firmware, the following constants must + be defined in accordance with the configuration that you have made on your + MIV_RV32 core design. + + MIV_RV32_EXT_TIMER + -------------------------------- + When defined, it means that the MTIME register is not available internal to + the core. In this case, a 64 bit port will be available on the MIV_RV32 core as + input. When this macro is not defined, it means that the MTIME register is + available internally to the core. + + MIV_RV32_EXT_TIMECMP + -------------------------------- + When defined, it means the MTIMECMP register is not available internally to + the core and the Timer interrupt input to the core comes as an external pin. + When this macro is not defined it means the that MTIMECMP register exists + internal to the core and that the timer interrupt is generated internally. + +NOTE: All these macros must not be defined if you are using a MIV_RV32 core. + */ + +#define OPSRV_TCM_ECC_CE_IRQ SUBSYS_TCM_ECC_CE_IRQ +#define OPSRV_TCM_ECC_UCE_IRQ SUBSYS_TCM_ECC_UCE_IRQ +#define OPSRV_AXI_WR_RESP_IRQ SUBSYS_AXI_WR_RESP_IRQ +#define MRV32_MSYS_OPSRV_IRQn MRV32_SUBSYS_IRQn +#define MRV32_opsrv_enable_irq MRV32_subsys_enable_irq +#define MRV32_opsrv_disable_irq MRV32_subsys_disable_irq +#define MRV32_opsrv_clear_irq MRV32_subsys_clear_irq +#define OPSRV_IRQHandler SUBSYS_IRQHandler + +/*-------------------------------------------------------------------------*//** + External IRQ + ======================================= + Return value from External IRQ handler. This is used to disable the + External Interrupt. + + | Macro Name | Value | Description| + |-------------------|--------|----------------| + | EXT_IRQ_KEEP_ENABLED | 0 | Keep external interrupts enabled | + | EXT_IRQ_DISABLE | 1 | Disable external interrupts | + */ +#define EXT_IRQ_KEEP_ENABLED 0U +#define EXT_IRQ_DISABLE 1U + +#define MTIME_DELTA 5 +#ifdef MIV_LEGACY_RV32 +#define MSIP (*(uint32_t*)0x44000000UL) +#define MTIMECMP (*(uint32_t*)0x44004000UL) +#define MTIMECMPH (*(uint32_t*)0x44004004UL) +#define MTIME (*(uint32_t*)0x4400BFF8UL) +#define MTIMEH (*(uint32_t*)0x4400BFFCUL) + +/* To maintain backward compatibility with FreeRTOS config code */ +#define PRCI_BASE 0x44000000UL +#else /* MIV_LEGACY_RV32 */ + +/* To maintain backward compatibility with FreeRTOS config code */ +#define PRCI_BASE 0x02000000UL + +#ifndef MIV_RV32_EXT_TIMECMP +#define MTIMECMP (*(volatile uint32_t*)0x02004000UL) +#define MTIMECMPH (*(volatile uint32_t*)0x02004004UL) +#else +#define MTIMECMP (0u) +#define MTIMECMPH (0u) +#endif + +#define MTIME_PRESCALER (*(volatile uint32_t*)0x02005000UL) + +#ifndef MIV_RV32_EXT_TIMER +#define MTIME (*(volatile uint32_t*)0x0200BFF8UL) +#define MTIMEH (*(volatile uint32_t*)0x0200BFFCUL) + +/***************************************************************************//** + MIMPID Register + The MIMPID register is a RISC-V Control and Status Register In the v3.0 of + MIV_RV32, the value of `MIMPID = 0x000540AD`. In the v3.1 of MIV_RV32, the + value if `MIMPID = 0xE5010301` corresponding to (E)mbedded (5)ystem(01) core + version (03).(01) this terminology will be followed in the subsequent releases + of the core read the csr value and store it in a varible which may be used to + check the MIV_RV32 core version during runtime. + + Future releases of the core will increment the 03 and 01 as major and minor + releases respectively and the register can be read at runtime to find the + Soft IP core version. + + | Core Version | Register | Value | Notes | + |----------------|------------|---------|---------| + | MIV_RV32 V3.1 | mimpid | 0xE5010301 | implimentation ID | + | MIV_RV32 V3.0 | mimpid | 0x000540AD | implimentation ID | + */ +#define MIMPID read_csr(mimpid) + +/*Used as a mask to read and write to mte mtvec.BASE address*/ +#define MTVEC_BASE_ADDR_MASK 0xFFFFFFFC + +#else +#define MTIME (0u) +#define MTIMEH (0u) +#endif /*MIV_RV32_EXT_TIMER*/ + +/*-------------------------------------------------------------------------*//** + RISC-V Specification Interrupts + ======================================= + These definitions are provided for easy identification of the interrupt + in the MIE/MIP registers. + Apart from the standard software, timer, and external interrupts, the names + of the additional interrupts correspond to the names as used in the MIV_RV32 + handbook. Please refer the MIV_RV32 handbook for more details. + + All the interrups, provided by the MIV_RV32 core, follow the interrupt priority + order and register description as mentioned in the RISC-V spec. + + | Macro Name | Value | Description| + |-------------------|--------|----------------| + | MRV32_SOFT_IRQn | MIE_3_IRQn | Software interrupt enable | + | MRV32_TIMER_IRQn | MIE_7_IRQn | Timer interrupt enable | + | MRV32_EXT_IRQn | MIE_11_IRQn | External interrupt enable | + + */ +#define MRV32_SOFT_IRQn MIE_3_IRQn +#define MRV32_TIMER_IRQn MIE_7_IRQn +#define MRV32_EXT_IRQn MIE_11_IRQn + +/***************************************************************************//** + Interrupt numbers: + This enum represents the interrupt enable bits in the MIE register. + */ +enum +{ + MIE_0_IRQn = (0x01u), + MIE_1_IRQn = (0x01u<<1u), + MIE_2_IRQn = (0x01u<<2u), + MIE_3_IRQn = (0x01u<<3u), /*MSIE 0xC*/ + MIE_4_IRQn = (0x01u<<4u), + MIE_5_IRQn = (0x01u<<5u), + MIE_6_IRQn = (0x01u<<6u), + MIE_7_IRQn = (0x01u<<7u), /*MTIE 0x1C*/ + MIE_8_IRQn = (0x01u<<8u), + MIE_9_IRQn = (0x01u<<9u), + MIE_10_IRQn = (0x01u<<10u), + MIE_11_IRQn = (0x01u<<11u), /*MEIE 0x2C*/ + MIE_12_IRQn = (0x01u<<12u), + MIE_13_IRQn = (0x01u<<13u), + MIE_14_IRQn = (0x01u<<14u), + MIE_15_IRQn = (0x01u<<15u), + MIE_16_IRQn = (0x01u<<16u), /*MGEUIE ECC Uncorrectable 0x40*/ + MIE_17_IRQn = (0x01u<<17u), /*MGECIE ECC Correctable 0x44*/ + MIE_18_IRQn = (0x01u<<18u), + MIE_19_IRQn = (0x01u<<19u), + MIE_20_IRQn = (0x01u<<20u), + MIE_21_IRQn = (0x01u<<21u), + MIE_22_IRQn = (0x01u<<22u), /*SUBSYSR 0x58 (R)eserved*/ + MIE_23_IRQn = (0x01u<<23u), /*SUBSYS_IE 0x5C for MIV_RV32 v3.1*/ + MIE_24_IRQn = (0x01u<<24u), /*MSYS_IE0 0x60*/ + MIE_25_IRQn = (0x01u<<25u), /*MSYS_IE1 0x64*/ + MIE_26_IRQn = (0x01u<<26u), /*MSYS_IE2 0x68*/ + MIE_27_IRQn = (0x01u<<27u), /*MSYS_IE3 0x6C*/ + MIE_28_IRQn = (0x01u<<28u), /*MSYS_IE4 0x70*/ + MIE_29_IRQn = (0x01u<<29u), /*MSYS_IE5 0x74*/ + MIE_30_IRQn = (0x01u<<30u), /*MSYS_IE6 0x78, read comment below*/ + MIE_31_IRQn = (0x01u<<31u) /*MSYS_IE7 0x7C*/ +} MRV_LOCAL_IRQn_Type; + +#define MRV32_MGEUIE_IRQn MIE_16_IRQn +#define MRV32_MGECIE_IRQn MIE_17_IRQn +#define MRV32_MSYS_EIE0_IRQn MIE_24_IRQn +#define MRV32_MSYS_EIE1_IRQn MIE_25_IRQn +#define MRV32_MSYS_EIE2_IRQn MIE_26_IRQn +#define MRV32_MSYS_EIE3_IRQn MIE_27_IRQn +#define MRV32_MSYS_EIE4_IRQn MIE_28_IRQn +#define MRV32_MSYS_EIE5_IRQn MIE_29_IRQn +#ifndef MIV_RV32_V3_0 /*For MIV_RV32 v3.1*/ +#define MRV32_SUBSYSR_IRQn MIE_22_IRQn +#define MRV32_SUBSYS_IRQn MIE_23_IRQn +#define MRV32_MSYS_EIE6_IRQn MIE_30_IRQn +#define MRV32_MSYS_EIE7_IRQn MIE_31_IRQn +#else +#define MRV32_SUBSYS_IRQn MIE_30_IRQn +#endif /*MIV_RV32_V3_0*/ + +/*--------------------------------Public APIs---------------------------------*/ + +/***************************************************************************//** + The MRV32_clear_gpr_ecc_errors() function clears single bit ECC errors on the + GPRs. The ECC block does not write back corrected data to memory. Hence, when + ECC is enabled for the GPRs and if that data has a single bit error then the + data coming out of the ECC block is corrected and will not have the error, but + the data source will still have the error. Therefore, if data has a single bit + error, then the corrected data must be written back to prevent the single bit + error from becoming a double bit error. Clear the pending interrupt bit after + this using MRV32_mgeci_clear_irq() function to complete the ECC error handling. + + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline void MRV32_clear_gpr_ecc_errors(void) +{ + uint32_t temp; + + __asm__ __volatile__ ( + "sw x31, %0" + :"=m" (temp)); + + __asm__ volatile ( + "mv x31, x1;" + "mv x1, x31;" + + "mv x31, x2;" + "mv x2, x31;" + + "mv x31, x3;" + "mv x3, x31;" + + "mv x31, x4;" + "mv x4, x31;" + + "mv x31, x5;" + "mv x5, x31;" + + "mv x31, x6;" + "mv x6, x31;" + + "mv x31, x7;" + "mv x7, x31;" + + "mv x31, x8;" + "mv x8, x31;" + + "mv x31, x9;" + "mv x9, x31;" + + "mv x31, x10;" + "mv x10, x31;" + + "mv x31, x11;" + "mv x11, x31;" + + "mv x31, x12;" + "mv x12, x31;" + + "mv x31, x13;" + "mv x13, x31;" + + "mv x31, x14;" + "mv x14, x31;" + + "mv x31, x15;" + "mv x15, x31;" + + "mv x31, x16;" + "mv x16, x31;" + + "mv x31, x17;" + "mv x17, x31;" + + "mv x31, x18;" + "mv x18, x31;" + + "mv x31, x19;" + "mv x19, x31;" + + "mv x31, x20;" + "mv x20, x31;" + + "mv x31, x21;" + "mv x21, x31;" + + "mv x31, x22;" + "mv x22, x31;" + + "mv x31, x23;" + "mv x23, x31;" + + "mv x31, x24;" + "mv x24, x31;" + + "mv x31, x25;" + "mv x25, x31;" + + "mv x31, x26;" + "mv x26, x31;" + + "mv x31, x27;" + "mv x27, x31;" + + "mv x31, x28;" + "mv x28, x31;" + + "mv x31, x29;" + "mv x29, x31;" + + "mv x31, x30;" + "mv x30, x31;"); + + __asm__ __volatile__ ( + "lw x31, %0;" + : + :"m" (temp)); +} + + +/***************************************************************************//** + The MRV32_mgeui_clear_irq() function clears the GPR ECC Uncorrectable + Interrupt. MGEUI interrupt is available only when ECC is enabled in the MIV_RV32 + IP configurator. + + @return + This function does not return any value. + */ +static inline void MRV32_mgeui_clear_irq(void) +{ + clear_csr(mip, MRV32_MGEUIE_IRQn); +} + +/***************************************************************************//** + The MRV32_mgeci_clear_irq() function clears the GPR ECC Correctable Interrupt + MGECI interrupt is available only when ECC is enabled in the MIV_RV32 IP + configurator. + + @return + This function does not return any value. + */ +static inline void MRV32_mgeci_clear_irq(void) +{ + clear_csr(mip, MRV32_MGECIE_IRQn); +} + +/***************************************************************************//** + The MRV_enable_local_irq() function enables the local interrupts. It takes a + mask value as input. For each set bit in the mask value, the corresponding + interrupt bit in the MIE register is enabled. + + MRV_enable_local_irq( MRV32_SOFT_IRQn | MRV32_TIMER_IRQn | MRV32_EXT_IRQn | + MRV32_MSYS_EIE0_IRQn | + MRV32_MSYS_SUBSYS_IRQn); + */ +static inline void MRV_enable_local_irq(uint32_t mask) +{ + set_csr(mie, mask); +} + +/***************************************************************************//** + The MRV_disable_local_irq() function disables the local interrupts. It takes a + mask value as input. For each set bit in the mask value, the corresponding + interrupt bit in the MIE register is disabled. + + MRV_disable_local_irq( MRV32_SOFT_IRQn | MRV32_TIMER_IRQn | MRV32_EXT_IRQn | + MRV32_MSYS_EIE0_IRQn | + MRV32_MSYS_SUBSYS_IRQn); + */ +static inline void MRV_disable_local_irq(uint32_t mask) +{ + clear_csr(mie, mask); +} +#endif /* MIV_LEGACY_RV32 */ + +/***************************************************************************//** + The MRV_enable_interrupts() function enables all interrupts by setting the + machine mode interrupt enable bit in MSTATUS register. + + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline void MRV_enable_interrupts(void) +{ + set_csr(mstatus, MSTATUS_MIE); +} + +/***************************************************************************//** + The MRV_disable_interrupts() function disables all interrupts by clearing the + machine mode interrupt enable bit in MSTATUS register. + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline void MRV_disable_interrupts(void) +{ + clear_csr(mstatus, MSTATUS_MPIE); + clear_csr(mstatus, MSTATUS_MIE); +} + +/***************************************************************************//** + The MRV_read_mtvec_base() function reads the mtvec base value, which is the + addr used when an interrupt/trap occurs. In the mtvec register, [31:2] is the + BASE address. NOTE: The BASE address must be aligned on a 4B boundary. + + @param + The function does not take any parameters. + + @return + The function returns the value of the BASE field [31:2] as an unsigned 32-bit + value. + */ + +#ifndef MIV_LEGACY_RV32 +#ifndef MIV_RV32_v3_0 +static inline uint32_t MRV_read_mtvec_base (void) +{ + uint32_t mtvec_addr_base = read_csr(mtvec); + return mtvec_addr_base & MTVEC_BASE_ADDR_MASK; +} + +/***************************************************************************//** + The MRV_set_mtvec_base() function takes the mtvec_base address as a unsigned int + and writes the value into the BASE field [31:2] in the mtvec CSR, MODE[1:0] + is Read-only. BASE is 4B aligned, so the lowest 2 bits of mtvec_base are + ignored. + + @param mtvec_base + Any legal value is passed into the function, and it is used as the trap_entry + for interrupts. The PC jumps to this address provided when an interrupt occurs. + In case of vectored interrupts, the address value mentioned in the vector + table under the MIE Register Map is updated to the value passed to this + function parameter. + + @return + This function does not return any value. + */ +static inline void MRV_set_mtvec_base (uint32_t mtvec_base) +{ + mtvec_base = mtvec_base & MTVEC_BASE_ADDR_MASK; + write_csr(mtvec, mtvec_base); +} +#endif /*MIV_RV32_v3_0*/ +#endif /*MIV_LEGACY_RV32*/ + +/***************************************************************************//** + The MRV_read_mtime() function returns the current MTIME register value. + */ +static inline uint64_t MRV_read_mtime(void) +{ + volatile uint32_t hi = 0u; + volatile uint32_t lo = 0u; + + /* when mtime lower word is 0xFFFFFFFF, there will be rollover and + * returned value could be wrong. */ + do { + hi = MTIMEH; + lo = MTIME; + } while(hi != MTIMEH); + + return((((uint64_t)MTIMEH) << 32u) | lo); +} + +/***************************************************************************//** + The MRV_raise_soft_irq() function raises a synchronous software interrupt + by writing into the MSIP register. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV_raise_soft_irq(void) +{ + set_csr(mie, MIP_MSIP); /* Enable software interrupt bit */ + +#ifdef MIV_LEGACY_RV32 + /* You need to make sure that the global interrupt is enabled */ + MSIP = 0x01; /* raise soft interrupt */ +#else + /* Raise soft IRQ on MIV_RV32 processor */ + SUBSYS->soft_reg |= SUBSYS_SOFT_IRQ; +#endif +} + +/***************************************************************************//** + The MRV_clear_soft_irq() function clears a synchronous software interrupt + by clearing the MSIP register. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV_clear_soft_irq(void) +{ +#ifdef MIV_LEGACY_RV32 + MSIP = 0x00u; /* clear soft interrupt */ +#else + /* Clear soft IRQ on MIV_RV32 processor */ + SUBSYS->soft_reg &= ~SUBSYS_SOFT_IRQ; +#endif +} + +/***************************************************************************//** + System tick handler. This handler function gets called when the Machine + timer interrupt asserts. An implementation of this function must be provided + by the application to implement the application specific machine timer + interrupt handling. If application does not provide such implementation, the + weakly linked handler stub function implemented in riscv_hal_stubs.c gets + linked. + */ +void SysTick_Handler(void); + +/***************************************************************************//** + System timer tick configuration. + Configures the machine timer to generate a system tick interrupt at regular + intervals. Takes the number of system clock ticks between interrupts. + + Though this function can take any valid ticks value as parameter, we expect + that, for all practical purposes, a small tick value (to generate periodic + interrupts every few miliseconds) is passed. If you need to generate periodic + events in the range of seconds or more, you may use the SysTick_Handler() to + further count the number of interrupts and hence the larger time intervals. + + @param ticks + This is the number of ticks or clock cycles which are counted down from the + interrupt to be triggered. + + @return + Returns 0 if successful. + Returns 1 if the interrupt interval is not achieved. + */ +uint32_t MRV_systick_config(uint64_t ticks); + +#ifdef __cplusplus +} +#endif +#endif /* RISCV_HAL_H */ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv_rv32_hal_version.h b/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv_rv32_hal_version.h new file mode 100644 index 0000000..4922bf2 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv_rv32_hal_version.h @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_hal_version.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware Abstraction Layer functions for Mi-V soft processors + * + */ + +#ifndef MIV_RV32_HAL_VERSION_H +#define MIV_RV32_HAL_VERSION_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MIV_RV32_HAL_VERSION_MAJOR 4 +#define MIV_RV32_HAL_VERSION_MINOR 2 +#define MIV_RV32_HAL_VERSION_PATCH 100 + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv_rv32_init.c b/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv_rv32_init.c new file mode 100644 index 0000000..85f8aca --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv_rv32_init.c @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_init.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor memory section initializations and start-up code. + * + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern void main(void); + +void _init(void) +{ + /* This function is a placeholder for the case where some more hardware + * specific initializations are required before jumping into the application + * code. You can implement it here. */ + + /* Jump to the application code after all initializations are completed */ + main(); +} + +/* Function called after main() finishes */ +void +_fini(void) +{ +} + +#ifdef __cplusplus +} +#endif + diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv_rv32_plic.h b/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv_rv32_plic.h new file mode 100644 index 0000000..3fd4103 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv_rv32_plic.h @@ -0,0 +1,214 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_plic.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V legacy RV32 soft processor PLIC access data structures and + * functions. + * Legacy RV32 soft processors are DEPRICATED. + * Migrate to MIV_RV32 v3.0 or later. + * + */ +#ifndef RISCV_PLIC_H +#define RISCV_PLIC_H + +#include +#include "miv_rv32_regs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================== + * Interrupt numbers: + */ +#ifdef MIV_LEGACY_RV32 +typedef enum +{ + MRV_NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + External_3_IRQn = 3, + External_4_IRQn = 4, + External_5_IRQn = 5, + External_6_IRQn = 6, + External_7_IRQn = 7, + External_8_IRQn = 8, + External_9_IRQn = 9, + External_10_IRQn = 10, + External_11_IRQn = 11, + External_12_IRQn = 12, + External_13_IRQn = 13, + External_14_IRQn = 14, + External_15_IRQn = 15, + External_16_IRQn = 16, + External_17_IRQn = 17, + External_18_IRQn = 18, + External_19_IRQn = 19, + External_20_IRQn = 20, + External_21_IRQn = 21, + External_22_IRQn = 22, + External_23_IRQn = 23, + External_24_IRQn = 24, + External_25_IRQn = 25, + External_26_IRQn = 26, + External_27_IRQn = 27, + External_28_IRQn = 28, + External_29_IRQn = 29, + External_30_IRQn = 30, + External_31_IRQn = 31 +} IRQn_Type; + +#define EXT_INTR_SOURCES 31 + +/*============================================================================== + * PLIC: Platform Level Interrupt Controller + */ +#define PLIC_BASE_ADDR 0x40000000UL + +typedef struct +{ + volatile uint32_t PRIORITY_THRESHOLD; + volatile uint32_t CLAIM_COMPLETE; + volatile uint32_t reserved[1022]; +} MRV_IRQ_Target_Type; + +typedef struct +{ + volatile uint32_t ENABLES[32]; +} MRV_Target_Enables_Type; + +typedef struct +{ + /*-------------------- Source Priority --------------------*/ + volatile uint32_t SOURCE_PRIORITY[1024]; + + /*-------------------- Pending array --------------------*/ + volatile const uint32_t PENDING_ARRAY[32]; + volatile uint32_t RESERVED1[992]; + + /*-------------------- Target enables --------------------*/ + volatile MRV_Target_Enables_Type TARGET_ENABLES[15808]; + + volatile uint32_t RESERVED2[16384]; + + /*--- Target Priority threshold and claim/complete---------*/ + MRV_IRQ_Target_Type TARGET[15872]; + +} PLIC_Type; + +#define PLIC ((PLIC_Type *)PLIC_BASE_ADDR) + +/*============================================================================== + * The function MRV_PLIC_init() initializes the PLIC controller and enables + * the global external interrupt bit. + */ +static inline void MRV_PLIC_init(void) +{ + uint32_t inc; + unsigned long hart_id = read_csr(mhartid); + + /* Disable all interrupts for the current hart. */ + for(inc = 0; inc < ((EXT_INTR_SOURCES + 32u) / 32u); ++inc) + { + PLIC->TARGET_ENABLES[hart_id].ENABLES[inc] = 0; + } + + /* Set priorities to zero. */ + for(inc = 0; inc < EXT_INTR_SOURCES; ++inc) + { + PLIC->SOURCE_PRIORITY[inc] = 0; + } + + /* Set the threshold to zero. */ + PLIC->TARGET[hart_id].PRIORITY_THRESHOLD = 0; + + /* Enable machine external interrupts. */ + set_csr(mie, MIP_MEIP); +} + +/*============================================================================== + * The function MRV_PLIC_enable_irq() enables the external interrupt for the + * interrupt number indicated by the parameter IRQn. + */ +static inline void MRV_PLIC_enable_irq(IRQn_Type IRQn) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t current = PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32]; + current |= (uint32_t)1 << (IRQn % 32); + PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32] = current; +} + +/*============================================================================== + * The function MRV_PLIC_disable_irq() disables the external interrupt for + * the interrupt number indicated by the parameter IRQn. + + * NOTE: + * This function can be used to disable the external interrupt from outside + * external interrupt handler function. + * This function MUST NOT be used from within the External Interrupt handler. + * If you wish to disable the external interrupt while the interrupt handler + * for that external interrupt is executing then you must use the return value + * EXT_IRQ_DISABLE to return from the extern interrupt handler. + */ +static inline void MRV_PLIC_disable_irq(IRQn_Type IRQn) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t current = PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32]; + + current &= ~((uint32_t)1 << (IRQn % 32)); + + PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32] = current; +} + +/*============================================================================== + * The function MRV_PLIC_set_priority() sets the priority for the external + * interrupt for the interrupt number indicated by the parameter IRQn. + */ +static inline void MRV_PLIC_set_priority(IRQn_Type IRQn, uint32_t priority) +{ + PLIC->SOURCE_PRIORITY[IRQn] = priority; +} + +/*============================================================================== + * The function MRV_PLIC_get_priority() returns the priority for the external + * interrupt for the interrupt number indicated by the parameter IRQn. + */ +static inline uint32_t MRV_PLIC_get_priority(IRQn_Type IRQn) +{ + return PLIC->SOURCE_PRIORITY[IRQn]; +} + +/***************************************************************************//** + * MRV_PLIC_clear_pending_irq(void) + * This is only called by the startup hart and only once + * Clears any pending interrupts as PLIC can be in unknown state on startup + */ +static inline void MRV_PLIC_clear_pending_irq(void) +{ + unsigned long hart_id = read_csr(mhartid); + volatile uint32_t int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; + volatile int32_t wait_possible_int; + + while (MRV_NoInterrupt_IRQn != int_num) + { + PLIC->TARGET[hart_id].CLAIM_COMPLETE = int_num; + wait_possible_int = 0xFU; + while (wait_possible_int) + { + wait_possible_int--; + } + + int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; + } +} + +#endif /* MIV_LEGACY_RV32 */ + +#ifdef __cplusplus +} +#endif + +#endif /* RISCV_PLIC_H */ diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv_rv32_regs.h b/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv_rv32_regs.h new file mode 100644 index 0000000..07d58e7 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv_rv32_regs.h @@ -0,0 +1,520 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor register bit mask and shift constants encodings. + * + */ +#ifndef MIV_RV32_REGS_H +#define MIV_RV32_REGS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MSTATUS_UIE 0x00000001UL +#define MSTATUS_SIE 0x00000002UL +#define MSTATUS_HIE 0x00000004UL +#define MSTATUS_MIE 0x00000008UL +#define MSTATUS_UPIE 0x00000010UL +#define MSTATUS_SPIE 0x00000020UL +#define MSTATUS_HPIE 0x00000040UL +#define MSTATUS_MPIE 0x00000080UL +#define MSTATUS_SPP 0x00000100UL +#define MSTATUS_HPP 0x00000600UL +#define MSTATUS_MPP 0x00001800UL +#define MSTATUS_FS 0x00006000UL +#define MSTATUS_XS 0x00018000UL +#define MSTATUS_MPRV 0x00020000UL +#define MSTATUS_SUM 0x00040000UL +#define MSTATUS_MXR 0x00080000UL +#define MSTATUS_TVM 0x00100000UL +#define MSTATUS_TW 0x00200000UL +#define MSTATUS_TSR 0x00400000UL +#define MSTATUS_RES 0x7F800000UL +#define MSTATUS32_SD 0x80000000UL +#define MSTATUS64_SD 0x8000000000000000UL + +#define MCAUSE32_CAUSE 0x7FFFFFFFUL +#define MCAUSE64_CAUSE 0x7FFFFFFFFFFFFFFFUL +#define MCAUSE32_INT 0x80000000UL +#define MCAUSE64_INT 0x8000000000000000UL + +#define MIP_SSIP (1u << IRQ_S_SOFT) +#define MIP_HSIP (1u << IRQ_H_SOFT) +#define MIP_MSIP (1u << IRQ_M_SOFT) +#define MIP_STIP (1u << IRQ_S_TIMER) +#define MIP_HTIP (1u << IRQ_H_TIMER) +#define MIP_MTIP (1u << IRQ_M_TIMER) +#define MIP_SEIP (1u << IRQ_S_EXT) +#define MIP_HEIP (1u << IRQ_H_EXT) +#define MIP_MEIP (1u << IRQ_M_EXT) + +#define PRV_M 3U + +#define VM_MBARE 0U +#define VM_MBB 1U +#define VM_MBBID 2U +#define VM_SV32 8U +#define VM_SV39 9U +#define VM_SV48 10U + +#define IRQ_S_SOFT 1U +#define IRQ_H_SOFT 2U +#define IRQ_M_SOFT 3U +#define IRQ_S_TIMER 5U +#define IRQ_H_TIMER 6U +#define IRQ_M_TIMER 7U +#define IRQ_S_EXT 9U +#define IRQ_H_EXT 10U +#define IRQ_M_EXT 11U + +#define DEFAULT_RSTVEC 0x00001000 +#define DEFAULT_NMIVEC 0x00001004 +#define DEFAULT_MTVEC 0x00001010 +#define CONFIG_STRING_ADDR 0x0000100C +#define EXT_IO_BASE 0x40000000 +#define DRAM_BASE 0x80000000 + +#ifdef __riscv + +#if __riscv_xlen == 64 +# define MSTATUS_SD MSTATUS64_SD +# define SSTATUS_SD SSTATUS64_SD +# define MCAUSE_INT MCAUSE64_INT +# define MCAUSE_CAUSE MCAUSE64_CAUSE +# define RISCV_PGLEVEL_BITS 9 +#else +# define MSTATUS_SD MSTATUS32_SD +# define SSTATUS_SD SSTATUS32_SD +# define RISCV_PGLEVEL_BITS 10 +# define MCAUSE_INT MCAUSE32_INT +# define MCAUSE_CAUSE MCAUSE32_CAUSE +#endif + +#define RISCV_PGSHIFT 12U +#define RISCV_PGSIZE (1U << RISCV_PGSHIFT) + +#ifndef __ASSEMBLER__ + +#ifdef __GNUC__ + +#define read_csr(reg) ({ unsigned long __tmp; \ + __asm__ volatile ("csrr %0, " #reg : "=r"(__tmp)); \ + __tmp; }) + +#define write_csr(reg, val) ({ \ + __asm__ volatile ("csrw " #reg ", %0" :: "rK"(val)); }) + +#define swap_csr(reg, val) ({ unsigned long __tmp; \ + __asm__ volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "rK"(val)); \ + __tmp; }) + +#define set_csr(reg, bit) ({ unsigned long __tmp; \ + __asm__ volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ + __tmp; }) + +#define clear_csr(reg, bit) ({ unsigned long __tmp; \ + __asm__ volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ + __tmp; }) + +#ifdef __riscv_atomic + +#define MASK(nr) (1UL << nr) +#define MASK_NOT(nr) (~(1UL << nr)) + +/** + * atomic_read - read atomic variable + * @v: pointer of type int + * + * Atomically reads the value of @v. + */ +static inline int atomic_read(const int *v) +{ + return *((volatile int *)(v)); +} + +/** + * atomic_set - set atomic variable + * @v: pointer of type int + * @i: required value + * + * Atomically sets the value of @v to @i. + */ +static inline void atomic_set(int *v, int i) +{ + *v = i; +} + +/** + * atomic_add - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v. + */ +static inline void atomic_add(int i, int *v) +{ + __asm__ __volatile__ ( + "amoadd.w zero, %1, %0" + : "+A" (*v) + : "r" (i)); +} + +static inline int atomic_fetch_add(unsigned int mask, int *v) +{ + int out; + + __asm__ __volatile__ ( + "amoadd.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_sub - subtract integer from atomic variable + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v. + */ +static inline void atomic_sub(int i, int *v) +{ + atomic_add(-i, v); +} + +static inline int atomic_fetch_sub(unsigned int mask, int *v) +{ + int out; + + __asm__ __volatile__ ( + "amosub.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_add_return - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v and returns the result + */ +static inline int atomic_add_return(int i, int *v) +{ + register int c; + __asm__ __volatile__ ( + "amoadd.w %0, %2, %1" + : "=r" (c), "+A" (*v) + : "r" (i)); + return (c + i); +} + +/** + * atomic_sub_return - subtract integer from atomic variable + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v and returns the result + */ +static inline int atomic_sub_return(int i, int *v) +{ + return atomic_add_return(-i, v); +} + +/** + * atomic_inc - increment atomic variable + * @v: pointer of type int + * + * Atomically increments @v by 1. + */ +static inline void atomic_inc(int *v) +{ + atomic_add(1, v); +} + +/** + * atomic_dec - decrement atomic variable + * @v: pointer of type int + * + * Atomically decrements @v by 1. + */ +static inline void atomic_dec(int *v) +{ + atomic_add(-1, v); +} + +static inline int atomic_inc_return(int *v) +{ + return atomic_add_return(1, v); +} + +static inline int atomic_dec_return(int *v) +{ + return atomic_sub_return(1, v); +} + +/** + * atomic_sub_and_test - subtract value from variable and test result + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v and returns + * true if the result is zero, or false for all + * other cases. + */ +static inline int atomic_sub_and_test(int i, int *v) +{ + return (atomic_sub_return(i, v) == 0); +} + +/** + * atomic_inc_and_test - increment and test + * @v: pointer of type int + * + * Atomically increments @v by 1 + * and returns true if the result is zero, or false for all + * other cases. + */ +static inline int atomic_inc_and_test(int *v) +{ + return (atomic_inc_return(v) == 0); +} + +/** + * atomic_dec_and_test - decrement and test + * @v: pointer of type int + * + * Atomically decrements @v by 1 and + * returns true if the result is 0, or false for all other + * cases. + */ +static inline int atomic_dec_and_test(int *v) +{ + return (atomic_dec_return(v) == 0); +} + +/** + * atomic_add_negative - add and test if negative + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v and returns true + * if the result is negative, or false when + * result is greater than or equal to zero. + */ +static inline int atomic_add_negative(int i, int *v) +{ + return (atomic_add_return(i, v) < 0); +} + +static inline int atomic_xchg(int *v, int n) +{ + register int c; + __asm__ __volatile__ ( + "amoswap.w %0, %2, %1" + : "=r" (c), "+A" (*v) + : "r" (n)); + return c; +} + +/** + * atomic_and - Atomically clear bits in atomic variable + * @mask: Mask of the bits to be retained + * @v: pointer of type int + * + * Atomically retains the bits set in @mask from @v + */ +static inline void atomic_and(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoand.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_and(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoand.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_or - Atomically set bits in atomic variable + * @mask: Mask of the bits to be set + * @v: pointer of type int + * + * Atomically sets the bits set in @mask in @v + */ +static inline void atomic_or(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoor.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_or(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoor.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_xor - Atomically flips bits in atomic variable + * @mask: Mask of the bits to be flipped + * @v: pointer of type int + * + * Atomically flips the bits set in @mask in @v + */ +static inline void atomic_xor(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoxor.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_xor(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoxor.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * test_and_set_bit - Set a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_set_bit(int nr, volatile unsigned long *addr) +{ + unsigned long __res, __mask; + __mask = MASK(nr); + __asm__ __volatile__ ( \ + "amoor.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to clear + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_clear_bit(int nr, volatile unsigned long *addr) +{ + unsigned long __res, __mask; + __mask = MASK_NOT(nr); + __asm__ __volatile__ ( \ + "amoand.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * test_and_change_bit - Change a bit and return its old value + * @nr: Bit to change + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_change_bit(int nr, volatile unsigned long *addr) +{ + + unsigned long __res, __mask; + __mask = MASK(nr); + __asm__ __volatile__ ( \ + "amoxor.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * set_bit - Atomically set a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * This function is atomic and may not be reordered. + */ + +static inline void set_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOOR.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK(nr))); +} + +/** + * clear_bit - Clears a bit in memory + * @nr: Bit to clear + * @addr: Address to start counting from + * + * clear_bit() is atomic and may not be reordered. + */ +static inline void clear_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOAND.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK_NOT(nr))); +} + +/** + * change_bit - Toggle a bit in memory + * @nr: Bit to change + * @addr: Address to start counting from + * + * change_bit() is atomic and may not be reordered. + */ +static inline void change_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOXOR.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK(nr))); +} + +#endif /* __riscv_atomic */ + +#endif /* __GNUC__ */ + +#endif /* __ASSEMBLER__ */ + +#endif /* __riscv */ + +#ifdef __cplusplus +} +#endif + +#endif /* RISCV_REGS_H */ diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv_rv32_stubs.c b/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv_rv32_stubs.c new file mode 100644 index 0000000..e26ecfc --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv_rv32_stubs.c @@ -0,0 +1,243 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_stubs.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Stubs for the Mi-V soft processor Interrupt handler. + * + * The functions below will only be linked with the application code if the user + * does not provide an implementation for these functions. These functions are + * defined with weak linking so that they can be overridden by a function with + * same prototype in the user's application code. + * + */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +__attribute__((weak)) void Software_IRQHandler(void) +{ + _exit(10); +} + +__attribute__((weak)) void SysTick_Handler(void) +{ + /* Default handler */ +} + +#ifdef MIV_LEGACY_RV32 +__attribute__((weak)) uint8_t Invalid_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_1_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_2_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_3_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_4_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_5_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_6_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_7_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_8_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_9_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_10_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_11_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_12_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_13_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_14_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_15_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_16_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_17_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_18_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_19_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_20_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_21_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_22_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_23_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_24_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_25_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_26_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_27_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_28_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_29_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_30_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_31_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +#else +__attribute__((weak)) void External_IRQHandler(void) +{ +} +__attribute__((weak)) void MGECI_IRQHandler(void) +{ +} +__attribute__((weak)) void MGEUI_IRQHandler(void) +{ +} +__attribute__((weak)) void SUBSYS_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI0_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI1_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI2_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI3_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI4_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI5_IRQHandler(void) +{ +} +__attribute__((weak)) void Reserved_IRQHandler(void) +{ + _exit(10); +} +#ifndef MIV_RV32_V3_0 /* For MIV_RV32 v3.0 */ +__attribute__((weak)) void MSYS_EI6_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI7_IRQHandler(void) +{ +} +__attribute__((weak)) void SUBSYSR_IRQHandler(void) +{ +} +#endif /* MIV_RV32_V3_0 */ +#endif /* MIV_LEGACY_RV32 */ + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv_rv32_subsys.h b/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv_rv32_subsys.h new file mode 100644 index 0000000..509f13b --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv_rv32_subsys.h @@ -0,0 +1,293 @@ +/******************************************************************************* + * Copyright 2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_subsys.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor SUBSYS regsiter description and API fuctions. + * + */ +#ifndef MIV_RV32_SUBSYS_H +#define MIV_RV32_SUBSYS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef MIV_LEGACY_RV32 +#define MGEUI 16U +#define MGECI 17U +#define MSYS_EI0 24U +#define MSYS_EI1 25U +#define MSYS_EI2 26U +#define MSYS_EI3 27U +#define MSYS_EI4 28U +#define MSYS_EI5 29U + +#define MGEUI_MEIP (1u << MGEUI) +#define MGECI_MEIP (1u << MGECI) +#define MSYS_EI0IP (1u << MSYS_EI0) +#define MSYS_EI1IP (1u << MSYS_EI1) +#define MSYS_EI2IP (1u << MSYS_EI2) +#define MSYS_EI3IP (1u << MSYS_EI3) +#define MSYS_EI4IP (1u << MSYS_EI4) +#define MSYS_EI5IP (1u << MSYS_EI5) + +#define MIV_LOCAL_IRQ_MIN 16 +#ifndef MIV_RV32_V3_0 /*For MIV_RV32 v3.1*/ +#define SUBSYSR 22U +#define SUBSYS_EI 23U +#define MSYS_EI6 30U +#define MSYS_EI7 31U +#define MIV_SUBSYSR (1u << SUBSYSR) +#define MIV_SUBSYS (1u << SUBSYS_EI) +#define MSYS_EI6IP (1u << MSYS_EI6) +#define MSYS_EI7IP (1u << MSYS_EI7) +#define MIV_LOCAL_IRQ_MAX 31 + +#else /* MIV_RV32_V3_0 */ +#define MIV_LOCAL_IRQ_MAX 29 +#define SUBSYS_EI 30U +#define MIP_SUBSYS_REG (1u << SUBSYS_EI) + +#endif /* MIV_RV32_V3_0 */ +#endif /* MIV_LEGACY_RV32 */ + +#ifdef MIV_LEGACY_RV32 +#define MIV_LOCAL_IRQ_MAX 0U +#define MIV_LOCAL_IRQ_MIN 0U +#endif /* MIV_LEGACY_RV32 */ + +#ifdef __cplusplus +} +#endif + +/*-------------------------------------------------------------------------*//** + SUBSYS Register Configuration + ======================================= + For the SUBSYS registers configutation, the following definitions are used in + the SUBSUS API functions. For example, to raise soft interrupts, enable parity + checks, soft reset, and so on. + + | Configuration | Value | Description | + |--------------------------|-------|------------------------------------------------| + | SUBSYS_SOFT_REG_GRP_DED | 0x04 | Mask for the Core GPR DED Reset Register | + | SUBSYS_CFG_PARITY_CHECK | 0x01 | Use to set or clear the parity check on the TCM | + | SUBSYS_SOFT_RESET | 0x01 | Use the SUBSYS soft reset the MIV_RV32 IP core | + | SUBSYS_SOFT_IRQ | 0x02 | Use to raise a software interrupt through SUBSYS| + */ +/*Mask for the Core GPR DED Reset Register*/ +#define SUBSYS_SOFT_REG_GRP_DED 0x04U + +/*Use to set or clear the parity check on the TCM*/ +#define SUBSYS_CFG_PARITY_CHECK 0x01U + +/*Use the SUBSYS soft reset the MIV_RV32 IP core*/ +#define SUBSYS_SOFT_RESET 0x01U + +/*Use to raise a software interrupt through SUBSYS*/ +#define SUBSYS_SOFT_IRQ 0x02U + +/*-------------------------------------------------------------------------*//** + SUBSYS Interrupt Request Masks + ======================================= + The following values correspond to the bit value of the SUBSYS interrupt + enable and interrupt pending register. + + | Interrupt Mask | Value | Description | + |----------------------------|---------|-------------------------------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | TCM ECC controllable error irq enable | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | TCM ECC uncontrollable error irq enable | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | AXI write response error irq enable | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | Icache ECC Correctable error irq | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | Icache ECC Uncorrectable error irq | + | SUBSYS_BASE_ADDR | 0x6000u | Base address of the SUBSYS | + */ +/* TCM ECC correctable error irq enable mask value */ +#define SUBSYS_TCM_ECC_CE_IRQ 0x01u + +/* TCMECC uncorrectable error irq enable */ +#define SUBSYS_TCM_ECC_UCE_IRQ 0x02u + +/* AXI write response error irq enable */ +#define SUBSYS_AXI_WR_RESP_IRQ 0x10u + +/*Icache ECC Correctable error irq*/ +#define SUBSYS_ICACHE_ECC_CE_IRQ 0x40u + +/*Icache ECC Uncorrectable error irq*/ +#define SUBSYS_ICACHE_ECC_UCE_IRQ 0x80u + +/*Base address of the SUBSYS*/ +#define SUBSYS_BASE_ADDR 0x00006000UL + +/***************************************************************************//** + Subsys contains interrupt enable, interrupt pending and Subsys registers + which can be used to enable SUBSYS specific features such as ECC for vaious + memories. For more available features refer to the MIV_RV32 User Guide +*/ +typedef struct +{ + volatile uint32_t cfg; /*Parity is not supported by MIV_RV32 v3.1 and MIV_RV32 v3.0.100*/ + volatile uint32_t reserved0[3]; + volatile uint32_t irq_en; /*offset 0x10*/ + volatile uint32_t irq_pend; + volatile uint32_t reserved1[2]; + volatile uint32_t soft_reg; /*offset 0x20*/ +} SUBSYS_Type; + +#define SUBSYS ((SUBSYS_Type *)SUBSYS_BASE_ADDR) + +/***************************************************************************//** + The MRV32_subsys_enable_irq() function initializes the SUBSYS interrupts. It + takes the logical OR of the following defined IRQ masks as a parameter. + + @param irq_mask + | irq_mask | Value | + |------------------------|------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | + Use logical OR values of one or more interrupts to enable them in the SUBSYS + @return + This function does not return any value. + */ +static inline void MRV32_subsys_enable_irq(uint32_t irq_mask) +{ + SUBSYS->irq_en |= irq_mask; +} + +/***************************************************************************//** + The MRV32_subsys_disable_irq() function disables the SUBSYS interrupts. It + takes the logical OR of the following defined IRQ masks as a parameter. + + @param irq_mask + | irq_mask | Value | + |------------------------|------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | + Use logical OR values of one or more interrupts to disable them in the SUBSYS + @return + This function does not return any value. + */ +static inline void MRV32_subsys_disable_irq(uint32_t irq_mask) +{ + SUBSYS->irq_en &= ~irq_mask; +} + +/***************************************************************************//** + The MRV32_subsys_clear_irq() function clears the SUBSYS interrupts, which was + triggered. It takes the logical OR of the following defined IRQ masks as a + parameter. + @param irq_mask + | irq_mask | Value | + |------------------------|------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | + Use logical OR values of one or more interrupts to disable them in the SUBSYS + @return + This function does not return any value. + */ +static inline void MRV32_subsys_clear_irq(uint32_t irq_mask) +{ + SUBSYS->irq_pend |= irq_mask; +} + +/***************************************************************************//** + The MRV32_subsys_irq_cause() function returns the irq_pend register value which + is present in the SUBSYS. This is be used to check which irq_mask value + caused the SUBSYS interrupt to occur. + @param + This function does not take any parameters + + @return + This function returns the irq_pend regsiter value. +*/ +static inline uint32_t MRV32_subsys_irq_cause() +{ + return SUBSYS->irq_pend; +} + +/***************************************************************************//** + The MRV32_is_gpr_ded() function returns the core_gpr_ded_reset_reg bit value. + When ECC is enabled, the core_gpr_ded_reset_reg is set when the core was + reset due to GPR DED error. + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline uint32_t MRV32_is_gpr_ded(void) +{ + return((SUBSYS->soft_reg & SUBSYS_SOFT_REG_GRP_DED) >> 0x02u); +} + +/***************************************************************************//** + The MRV32_clear_gpr_ded() function must be used to clear the + core_gpr_ded_reset_reg bit. When ECC is enabled, the core_gpr_ded_reset_reg is + set when the core was previously reset due to GPR DED error. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV32_clear_gpr_ded(void) +{ + SUBSYS->soft_reg &= ~SUBSYS_SOFT_REG_GRP_DED; +} + +/***************************************************************************//** + The MRV32_enable_parity_check() function is used to enable parity check on + the TCM and it's interface transactions. This feature is not available on + MIV_RV32 v3.1 and MIV_RV32 v3.0.100 + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV32_enable_parity_check(void) +{ + SUBSYS->cfg |= SUBSYS_CFG_PARITY_CHECK; +} + +/***************************************************************************//** + The MRV32_disable_parity_check() function is used to disable parity check on + the TCM and it's interface transactions. + @param + This function does not take any parameters + + @return + This function does not return any value. + + */ +static inline void MRV32_disable_parity_check(void) +{ + SUBSYS->cfg &= ~SUBSYS_CFG_PARITY_CHECK; +} + +/***************************************************************************//** + The MRV32_cpu_soft_reset() function is used to cause a soft cpu reset on + the MIV_RV32 soft processor core. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV32_cpu_soft_reset(void) +{ + SUBSYS->soft_reg |= SUBSYS_SOFT_RESET; +} +#endif /* MIV_RV32_SUBSYS_H */ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv_rv32_syscall.c b/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv_rv32_syscall.c new file mode 100644 index 0000000..bd2f881 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/miv_rv32_syscall.c @@ -0,0 +1,364 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_syscall.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Stubs for system calls. + * + */ +#include +#include +#include +#include +#include "miv_rv32_hal.h" + +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +#include + +#ifndef LEGACY_DIR_STRUCTURE +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" +#else +#include "core_uart_apb.h" +#endif + +#endif /*MSCC_STDIO_THRU_CORE_UART_APB*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + +/*------------------------------------------------------------------------------ + * CoreUARTapb instance data for the CoreUARTapb instance used for standard + * output. + */ +static UART_instance_t g_stdio_uart; + +/*============================================================================== + * Flag used to indicate if the UART driver needs to be initialized. + */ +static int g_stdio_uart_init_done = 0; + +/* + * Disable semihosting apis + */ +#pragma import(__use_no_semihosting_swi) + +/*============================================================================== + * sendchar() + */ +int sendchar(int ch) +{ + /*-------------------------------------------------------------------------- + * Initialize the UART driver if it is the first time this function is + * called. + */ + if ( !g_stdio_uart_init_done ) + { + /****************************************************************************** + * Baud value: + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + UART_init( &g_stdio_uart, + MSCC_STDIO_UART_BASE_ADDR, + ((SYS_CLK_FREQ/(16 * MSCC_STDIO_BAUD_VALUE))-1), + (DATA_8_BITS | NO_PARITY)); + + g_stdio_uart_init_done = 1; + } + + /*-------------------------------------------------------------------------- + * Output text to the UART. + */ + UART_send( &g_stdio_uart, (uint8_t *)&ch, 1 ); + + return (ch); +} + +/*============================================================================== + * getachar() + */ +int getachar(void) +{ + uint8_t rx_size; + uint8_t rx_byte; + + if ( !g_stdio_uart_init_done ) + { + /****************************************************************************** + * Baud value: + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + UART_init( &g_stdio_uart, + MSCC_STDIO_UART_BASE_ADDR, + ((SYS_CLK_FREQ/(16 * MSCC_STDIO_BAUD_VALUE))-1), + (DATA_8_BITS | NO_PARITY)); + + g_stdio_uart_init_done = 1; + } + + do + { + rx_size = UART_get_rx(&g_stdio_uart, &rx_byte, 1); + } while(0u == rx_size); + + return rx_byte; +} + +#endif /*MSCC_STDIO_THRU_CORE_UART_APB*/ + +#undef errno +static int errno; + +static char *__env[1] = { 0 }; +char **environ = __env; + +void write_hex(int fd, uint32_t hex) +{ + char towrite; + + write( fd , "0x", 2U ); + + for (uint32_t ii = 8U ; ii > 0U; ii--) + { + uint32_t jj = ii-1U; + uint8_t digit = ((hex & (0xFU << (jj*4U))) >> (jj*4U)); + towrite = digit < 0xAU ? (0x48U + digit) : (0x65U + (digit - 0xAU)); + write( fd, &towrite, 1U); + } +} + + +#ifdef GDB_TESTING +void __attribute__((optimize("O0"))) _exit(int code) +#else +void _exit(int code) +#endif +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + const char * message = "\nProgam has exited with code:"; + + write(STDERR_FILENO, message, strlen(message)); + write_hex(STDERR_FILENO, code); +#endif + + while (1){}; +} + +void *_sbrk(ptrdiff_t incr) +{ + extern char _end; + extern char _heap_end; + extern char __heap_start; + extern char __heap_end; + static char *curbrk = &_end; + void * ret = NULL; + + /* + * Did we allocated memory for the heap in the linker script? + * You need to set HEAP_SIZE to a non-zero value in your linker script if + * the following assertion fires. + */ + ASSERT(&__heap_end > &__heap_start); + + if (((curbrk + incr) < &_end) || ((curbrk + incr) > &_heap_end)) + { + errno = ENOMEM; + ret = ((char *) - 1); + } + else + { + curbrk += incr; + ret = curbrk - incr; + } + + /* + * Did we run out of heap? + * You need to increase the heap size in the linker script if the following + * assertion fires. + * */ + ASSERT(curbrk <= &__heap_end); + + return(ret); +} + +int _isatty(int fd) +{ + int ret = 0; + + if (fd <= 2) /* one of stdin, stdout, stderr */ + { + ret = 1; + } + else + { + errno = EBADF; + ret = 0; + } + + return(ret); +} + +static int stub(int err) +{ + errno = err; + return -1; +} + +int _open(const char* name, int flags, int mode) +{ + return stub(ENOENT); +} + +int _openat(int dirfd, const char* name, int flags, int mode) +{ + return stub(ENOENT); +} + +int _close(int fd) +{ + return stub(EBADF); +} + +int _execve(const char* name, char* const argv[], char* const env[]) +{ + return stub(ENOMEM); +} + +int _fork(void) +{ + return stub(EAGAIN); +} + +int _fstat(int fd, struct stat *st) +{ + int ret = 0; + + if (isatty(fd)) + { + st->st_mode = S_IFCHR; + ret = 0; + } + else + { + ret = stub(EBADF); + } + + return ret; +} + +int _getpid(void) +{ + return 1; +} + +int _kill(int pid, int sig) +{ + return stub(EINVAL); +} + +int _link(const char *old_name, const char *new_name) +{ + return stub(EMLINK); +} + +off_t _lseek(int fd, off_t ptr, int dir) +{ + off_t ret = 0; + if (_isatty(fd)) + { + ret = 0; + } + else + { + ret = stub(EBADF); + } + + return ret; +} + +ssize_t _read(int fd, void* ptr, size_t len) +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + + char* ptr1 = (char*)ptr; + + if (_isatty(fd)) + { + int count; + + for (count = 0; count < len; count++) + { + ptr1[count] = getachar(); + sendchar(ptr1[count]); + + /* Return partial buffer if we get EOL */ + if (('\r' == ptr1[count])||('\n' == ptr1[count])) + { + ptr1[count] = '\n'; + return count; + } + } + + return count; /* Filled the buffer */ + } +#endif + + return stub(EBADF); +} + +int _stat(const char* file, struct stat* st) +{ + return stub(EACCES); +} + +clock_t _times(struct tms* buf) +{ + return stub(EACCES); +} + +int _unlink(const char* name) +{ + return stub(ENOENT); +} + +int _wait(int* status) +{ + return stub(ECHILD); +} + +ssize_t _write(int fd, const void* ptr, size_t len) +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + int count_out; + char* ptr1 = (char*)ptr; + + /*-------------------------------------------------------------------------- + * Output text to the UART. + */ + count_out = 0; + while(len--) + { + sendchar(ptr1[count_out]); + count_out++; + } + + errno = 0; + return count_out; + +#else /* MSCC_STDIO_THRU_CORE_UART_APB */ + + return stub(EBADF); + +#endif /* MSCC_STDIO_THRU_CORE_UART_APB */ + +} + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/sample_fpga_design_config.h b/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/sample_fpga_design_config.h new file mode 100644 index 0000000..a380d96 --- /dev/null +++ b/applications/user-crypto/miv-rv32-message-authentication/src/platform/miv_rv32_hal/sample_fpga_design_config.h @@ -0,0 +1,167 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file sample_fpga_design_config.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Sample design configuration settings + * + */ + /*========================================================================*//** + @mainpage + Example file detailing how the fpga_design_config.h should be constructed + for the SoftConsole project targeted for Mi-V processors. + + @section intro_sec Introduction + The SoftConsole project targeted for Mi-V processors now have an improved + folder structure. Detailed description of the folder structure is available + at https://github.com/Mi-V-Soft-RISC-V/miv-rv32-documentation. + + The fpga_design_config.h must be stored as shown below + /boards//fpga_design_config.h + + Currently this file must be hand crafted when using the Mi-V Soft Processor. + In future, all the design and soft IP configurations will be automatically + generated from the Libero design description data. + + You can use this sample file as an example. + Rename this file from sample_fpga_design_config.h to fpga_design_config.h + and then customize it per your hardware design. + + @section Project configuration Instructions + 1. Change SYS_CLK_FREQ define to frequency of Mi-V Soft processor clock + 2 Add all the soft IP core BASE addresses + 3. Add the peripheral Core Interrupts to Mi-V Soft processor IRQ number + mappings + 4. Define MSCC_STDIO_UART_BASE_ADDR if you want a CoreUARTapb mapped to + STDIO + + **NOTE** + In the legacy folder structures, the file hw_config.h as was used at the + root of the project folder. This file is now depricated. + +*//*=========================================================================*/ + +#ifndef FPGA_DESIGN_CONFIG_H_ +#define FPGA_DESIGN_CONFIG_H_ + +/***************************************************************************//** + * Soft-processor clock definition + * This is the only clock brought over from the Mi-V Libero design. + */ +#ifndef SYS_CLK_FREQ +#define SYS_CLK_FREQ 50000000UL +#endif + +/***************************************************************************//** + * Peripheral base addresses. + * Format of define is: + * __BASE_ADDR + * The field is optional if there is only one instance of the core + * in the design + * MIV_ESS is an extended peripheral subsystem IP core with peripherals + * connections as defined below. + * The system can be further extended by attaching APB peripherals to the + * empty APB slots. + */ +#define MIV_ESS_PLIC_BASE_ADDR 0x70000000UL +#define COREUARTAPB0_BASE_ADDR 0x71000000UL +#define MIV_MTIMER_BASE_ADDR 0x72000000UL +#define MIV_ESS_APBSLOT3_BASE_ADDR 0x73000000UL +#define MIV_ESS_APBSLOT4_BASE_ADDR 0x74000000UL +#define COREGPIO_OUT_BASE_ADDR 0x75000000UL +#define CORESPI_BASE_ADDR 0x76000000UL +#define MIV_ESS_uDMA_BASE_ADDR 0x78000000UL +#define MIV_ESS_WDOG_BASE_ADDR 0x79000000UL +#define MIV_ESS_I2C_BASE_ADDR 0x7A000000UL +#define MIV_ESS_APBSLOTB_BASE_ADDR 0x7B000000UL +#define MIV_ESS_APBSLOTC_BASE_ADDR 0x7C000000UL +#define MIV_ESS_APBSLOTD_BASE_ADDR 0x7D000000UL +#define MIV_ESS_APBSLOTE_BASE_ADDR 0x7E000000UL +#define MIV_ESS_APBSLOTF_BASE_ADDR 0x7F000000UL + +/***************************************************************************//** + * Peripheral Interrupts are mapped to the corresponding Mi-V Soft processor + * interrupt in the Libero design. + * + * On the legacy RV32 cores, there can be up to 31 external interrupts (IRQ[30:0] + * pins). The legacy RV32 Soft processor external interrupts are defined in the + miv_rv32_plic.h + * + * These are of the form + * typedef enum +{ + NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + . + . + . + External_31_IRQn = 31 +} IRQn_Type; + + On the legacy RV32 processors, the PLIC identifies the interrupt and passes it + on to the processor core. The interrupt 0 is not used. The pin IRQ[0] should + map to External_1_IRQn likewise IRQ[30] should map to External_31_IRQn + +e.g + +#define TIMER0_IRQn External_30_IRQn +#define TIMER1_IRQn External_31_IRQn + + The MIV_RV32 soft processor has up to six optional system interrupts, MSYS_EI[n] + in addition to one EXT_IRQ. + The MIV_RV32 does not have an inbuilt PLIC and all the interrupts are directly + delivered to the processor core, hence unlike legacy RV32 cores, no interrupt + number mapping is necessary on MIV_RV32 core. + */ + +/**************************************************************************** + * Baud value to achieve a 115200 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ +#define BAUD_VALUE_115200 ((SYS_CLK_FREQ / (16 * 115200)) - 1) + +/****************************************************************************** + * Baud value to achieve a 57600 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + #define BAUD_VALUE_57600 ((SYS_CLK_FREQ / (16 * 57600)) - 1) + +/***************************************************************************//** + * Define MSCC_STDIO_THRU_CORE_UART_APB in the project settings if you want the + * standard IOs to be redirected to a terminal via UART. + */ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +/* + * A base address mapping for the STDIO printf/scanf mapping to CortUARTapb + * must be provided if it is being used + * + * e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR + */ +#define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB0_BASE_ADDR + +#ifndef MSCC_STDIO_UART_BASE_ADDR +#error MSCC_STDIO_UART_BASE_ADDR not defined- e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR +#endif + +#ifndef MSCC_STDIO_BAUD_VALUE +/* + * The MSCC_STDIO_BAUD_VALUE define should be set in your project's settings to + * specify the baud value used by the standard output CoreUARTapb instance for + * generating the UART's baud rate if you want a different baud rate from the + * default of 115200 baud + */ +#define MSCC_STDIO_BAUD_VALUE 115200 +#endif /*MSCC_STDIO_BAUD_VALUE*/ + +#endif /* end of MSCC_STDIO_THRU_CORE_UART_APB */ +/******************************************************************************* + * End of user edit section + */ +#endif /* FPGA_DESIGN_CONFIG_H_ */ diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/.cproject b/applications/user-crypto/miv-rv32-ndrbg-services/.cproject new file mode 100644 index 0000000..e0d068b --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/.cproject @@ -0,0 +1,334 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/.gitignore b/applications/user-crypto/miv-rv32-ndrbg-services/.gitignore new file mode 100644 index 0000000..f1b6b72 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/.gitignore @@ -0,0 +1,3 @@ +/.settings/ +/*miv-rv32-imc-debug*/ +/*miv-rv32-imc-release*/ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/.project b/applications/user-crypto/miv-rv32-ndrbg-services/.project new file mode 100644 index 0000000..9da825a --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/.project @@ -0,0 +1,26 @@ + + + miv-rv32-ndrbg-services + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/README.md b/applications/user-crypto/miv-rv32-ndrbg-services/README.md new file mode 100644 index 0000000..1075dc2 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/README.md @@ -0,0 +1,129 @@ +PolarFire User Crypto DRBG Services example +================================================================================ +This example project demonstrates the use of PolarFire User Crypto +deterministic random bit generator using functions: + + - CALDRBGInstantiate() + - CALDRBGGenerate() + - CALDRBGUninstantiate() + +There are two different build configurations provided with this project which +configure this SoftConsole project for RISC-V IMC instruction extension. +The following configurations are provided with the example: + + - miv-rv32-imc-debug + - miv-rv32-imc-release + +Mi-V Soft Processor +-------------------------------------------------------------------------------- +This example uses Mi-V SoftProcessor MiV_RV32.The design is built for debugging +MiV_RV32 through the PolarFire FPGA programming JTAG port using a FlashPro5. +To achieve this the CoreJTAGDebug IP is used to connect to the JTAG port of the +MiV_RV32. + +All the platform/design specific definitions such as peripheral base addresses, +system clock frequency etc. are included in fpga_design_config.h. The +fpga_design_config.h is located at the root folder of this project. + +The Mi-V Soft Processor MiV_RV32 firmware projects needs the miv_rv32_hal and +the hal firmware(RISC-V HAL). + +The RISC-V HAL is available at GitHub [Mi-V-Soft-RISC-V](https://mi-v-ecosystem.github.io/redirects/platform). + +How to use this example +-------------------------------------------------------------------------------- +This example project is targeted at a MIV_RV32 design running on a PolarFire-Eval-Kit +connected via a USB-UART serial cable to a host PC running a terminal emulator +such as TeraTerm or Putty configured as follows: + + - 115200 baud + - 8 data bits + - 1 stop bit + - no parity + - no flow control. + +Run the example project using a debugger. The example project will display +instructions over the serial port. To execute the particular service, user has +to select the options as shown over the serial port. + +Press the "i" to instantiate random numbers. Press the "g" to generate a random +number. Press "d" to un-instantiate the currently instantiated DRBG. +Please note that you will not be able to generate random numbers once the DRBG +instance has been un-instantiates DRBG service. + +fpga_design_config (formerly known as hw_config.h) +-------------------------------------------------------------------------------- +The SoftConsole project targeted for Mi-V processors now use an improved +directory structure. The fpga_design_config.h must be stored as shown below + +` + /boards//fpga_design_config/fpga_design_config.h +` + +Currently, this file must be hand crafted when using the Mi-V Soft Processor. +In future, all the design and soft IP configurations will be automatically +generated from the Libero design description data. + +You can use the sample file provided with MIV_RV32 HAL as an example. Rename it +from sample_fpga_design_config.h to fpga_design_config.h and then customize it +per your hardware design such as SYS_CLK_FREQ, peripheral BASE addresses, +interrupt numbers, definition of MSCC_STDIO_UART_BASE_ADDR if you want a +CoreUARTapb mapped to STDIO, etc. + +### Configurations + +The CAL library needs a config_user.h containing the configuration data. +This application provides following settings as per CAL requirement + 1. A variable which provides the base address of the User Crypto hardware block + is defined in main.c + + `uint32_t g_user_crypto_base_addr = 0x62000000UL;` + + 2. A symbol INC_STDINT_H is defined in project preprocessor setting. + For more detail, please refer to caltypes.h file present in CAL folder. + +**NOTE**: + 1. If you try to enter data values other than 0 - 9, a - f, A - F, an error + message will be displayed on the serial terminal. + 2. You must enter all input data as whole bytes. If you enter the 128-bit key + {1230...0} as 0x12 0x3 and press return, this will be treated as + byte0 = 0x12, byte1 = 0x30, byte2-127 = 0x00. + + +## Target hardware + +This project was tested on PolarFire-Eval-Kit with CFG4 configuration of the +MIV_RV32 design available [here](https://github.com/Mi-V-Soft-RISC-V/PolarFire-Eval-Kit/tree/main/Libero_Projects) + +All the design specific definitions such as peripheral base addresses, system +clock frequency etc. are included in fpga_design_config.h. + +The firmware projects needs the HAL and the MIV_RV32 HAL firmware components. + +This example project can be used with another design using a different hardware +configurations. This can be achieved by overwriting the content of this example +project's "fpga_design_config.h" file with the correct data per your Libero design. + +### Booting the system + +Currently the example project is configured to use FlashPro debugger to execute +from LSRAM in both Debug and Release mode. + +In the release mode build configuration, following setting is used +`--change-section-lma *-0x80000000` under +Tool Settings > Cross RISCV GNU Create Flash Image > General > Other flags. + +This will allow you to attach the release mode executable as the memory +initialization client in Libero when you want to execute it from non-volatile memory. + +## Silicon revision dependencies + +This example is tested on PolarFire MPF300TS device. + +### CAL library src + +To obtain the CAL source code and a SoftConsole project to generate the CAL +library archive file (*.a) refer [SoftConsole Documentation](https://mi-v-ecosystem.github.io/SoftConsole-Documentation/SoftConsole-v2021.3/using_softconsole/other.html#crypto-application-library). +The CAL source code is bound by license agreement and it will be available as +part of the SoftConsole installation if the CAL specific license was agreed +while installing it. \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/miv-rv32-ndrbg-services hw Debug.launch b/applications/user-crypto/miv-rv32-ndrbg-services/miv-rv32-ndrbg-services hw Debug.launch new file mode 100644 index 0000000..12020a1 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/miv-rv32-ndrbg-services hw Debug.launch @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/miv-rv32-ndrbg-services hw attach.launch b/applications/user-crypto/miv-rv32-ndrbg-services/miv-rv32-ndrbg-services hw attach.launch new file mode 100644 index 0000000..3324d25 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/miv-rv32-ndrbg-services hw attach.launch @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/application/helper.c b/applications/user-crypto/miv-rv32-ndrbg-services/src/application/helper.c new file mode 100644 index 0000000..4a78569 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/application/helper.c @@ -0,0 +1,312 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file helper.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Helper function for PolarFire User Crypto- Cryptography service example. + * + */ +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" +#include "helper.h" + +extern UART_instance_t g_uart; + +static const uint8_t g_separator[] = +"\r\n\ +------------------------------------------------------------------------------"; + + +/*============================================================================== + Function to clear local variable and array. + */ +static void clear_variable(uint8_t *p_var, uint16_t size) +{ + uint16_t inc; + + for(inc = 0; inc < size; inc++) + { + *p_var = 0x00; + p_var++; + } +} + +/*============================================================================== + Function to get the input data from user. + */ +uint16_t get_input_data +( + uint8_t* location, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +) +{ + uint16_t count = 0u; + + /* Clear the memory location. */ + clear_variable(location, size); + + /* Read data from UART terminal. */ + count = get_data_from_uart(location, size, msg, msg_size); + + return count; +} + +/*============================================================================== + Function to get the key from user. + */ +void get_key +( + uint8_t key_type, + uint8_t* location, + uint8_t size, + const uint8_t* msg, + uint8_t msg_size +) +{ + uint8_t status = 0u; + const uint8_t invalid_ms[] = "\r\n Invalid key type. "; + + if(status == VALID) + { + /* Read the 16 bytes of input data from UART terminal. */ + get_input_data(location, size, msg, msg_size); + } + else + { + UART_send(&g_uart, invalid_ms, sizeof( invalid_ms)); + } +} + +/*============================================================================== + Convert ASCII value to hex value. + */ +uint8_t convert_ascii_to_hex(uint8_t* dest, const uint8_t* src) +{ + uint8_t error_flag = 0u; + + if((*src >= '0') && (*src <= '9')) + { + *dest = (*src - '0'); + } + else if((*src >= 'a') && (*src <= 'f')) + { + *dest = (*src - 'a') + 10u; + } + else if((*src >= 'A') && (*src <= 'F')) + { + *dest = (*src - 'A') + 10u; + } + else if(*src != 0x00u) + { + UART_send(&g_uart, (const uint8_t *)"\r\n Invalid data.", sizeof("\r\n Invalid data.")); + error_flag = 1u; + } + return error_flag; +} + +/*============================================================================== + Validate the input hex value . + */ +uint8_t validate_input(uint8_t ascii_input) +{ + uint8_t valid_key = 0u; + + if(((ascii_input >= 'A') && (ascii_input <= 'F')) || \ + ((ascii_input >= 'a') && (ascii_input <= 'f')) || \ + ((ascii_input >= '0') && (ascii_input <= '9'))) + { + valid_key = 1u; + } + else + { + valid_key = 0u; + } + return valid_key; +} + +const uint8_t hex_chars[16] = { '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + +/*============================================================================== + Display content of buffer passed as parameter as hex values. + */ +void display_output +( + uint8_t* in_buffer, + uint32_t byte_length +) +{ + uint32_t inc; + uint8_t byte = 0; + + UART_send(&g_uart, (const uint8_t*)" ", sizeof(" ")); + for(inc = 0; inc < byte_length; ++inc) + { + if((inc > 1u) &&(0u == (inc % 16u))) + { + UART_send(&g_uart, (const uint8_t*)"\r\n ", sizeof("\r\n ")); + } + + byte = in_buffer[inc]; + UART_send(&g_uart, &hex_chars[((byte & 0xF0) >> 4) ], 1); + UART_send(&g_uart, &hex_chars[(byte & 0x0F)], 1); + } + +} + +/*============================================================================== + Function to read data from UART terminal and stored it. + */ +uint16_t get_data_from_uart +( + uint8_t* src_ptr, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +) +{ + uint8_t complete = 0u; + uint8_t rx_buff[1]; + uint8_t rx_size = 0u; + uint16_t count = 0u; + uint16_t ret_size = 0u; + uint8_t first = 0u; + uint16_t src_ind = 0u; + uint8_t prev = 0; + uint8_t curr = 0; + uint8_t temp = 0; + uint8_t next_byte = 0; + uint16_t read_data_size = 0; + + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, msg, msg_size); + + if(size != 1) + { + read_data_size = size * 2; + } + else + { + read_data_size = size; + } + + /* Read the key size sent by user and store it. */ + count = 0u; + while(!complete) + { + rx_size = UART_get_rx(&g_uart, rx_buff, sizeof(rx_buff)); + if(rx_size > 0u) + { + /* Is it to terminate from the loop */ + if(ENTER == rx_buff[0]) + { + complete = 1u; + } + /* Is entered key valid */ + else if(validate_input(rx_buff[0]) != 1u) + { + UART_send(&g_uart, rx_buff, sizeof(rx_buff)); + UART_send(&g_uart, (const uint8_t *)"\r\n Invalid input.", + sizeof("\r\n Invalid input.")); + UART_send(&g_uart, msg, msg_size); + complete = 0u; + count = 0u; + first = 0u; + clear_variable(src_ptr, 4); + } + else + { + if(next_byte == 0) + { + convert_ascii_to_hex(&src_ptr[src_ind], &rx_buff[0]); + prev = src_ptr[src_ind]; + next_byte = 1; + } + else + { + convert_ascii_to_hex(&curr, &rx_buff[0]); + temp = ((prev << 4) & 0xF0); + src_ptr[src_ind] = (temp | curr); + next_byte = 0; + src_ind++; + } + + + /* Switching to next line after every 8 bytes */ + if(((count % 32u) == 0x00u) && (count > 0x00u) && (complete != 0x01u)) + { + UART_send(&g_uart, (const uint8_t *)"\n\r", sizeof("\n\r")); + first = 0u; + } + + if(first == 0u) + { + UART_send(&g_uart, (const uint8_t *)" ", sizeof(" ")); + first++; + } + UART_send(&g_uart, rx_buff, sizeof(rx_buff)); + count++; + if(read_data_size == count) + { + complete = 1u; + } + } + } + } + + if((count%2) == 0) + { + ret_size = count/2; + } + else + { + if(size!=1) + { + temp = src_ptr[src_ind]; + src_ptr[src_ind] = ((temp << 4) & 0xF0); + + ret_size = (count/2)+1; + } + else + { + ret_size = 1; + } + } + + return ret_size; +} + +/*============================================================================== + Function to get the key from user. + */ +uint8_t enable_dma +( + const uint8_t* msg, + uint8_t msg_size +) +{ + volatile uint8_t invalid_ip = 1u; + uint8_t dma_enable = 0; + + const uint8_t invalid_ms[] = "\r\n Invalid input. "; + + while(invalid_ip != 0) + { + /* Read the 16 bytes of input data from UART terminal. */ + get_input_data(&dma_enable, 1, msg, msg_size); + + if(dma_enable >= 2) + { + UART_send(&g_uart, invalid_ms, sizeof( invalid_ms)); + } + else + { + invalid_ip = 0; + } + } + + return dma_enable; +} diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/application/helper.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/application/helper.h new file mode 100644 index 0000000..7f21b6e --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/application/helper.h @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file helper.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Helper function public API. + * + */ +#ifndef __HELPER_H_ +#define __HELPER_H_ 1 + +/****************************************************************************** + * Maximum buffer size. + *****************************************************************************/ +#define MAX_RX_DATA_SIZE 256 +#define MASTER_TX_BUFFER 10 + +/*============================================================================== + Macro + */ +#define VALID 0U +#define INVALID 1U +#define ENTER 13u + +/****************************************************************************** + * CoreUARTapb instance data. + *****************************************************************************/ + +uint16_t get_input_data +( + uint8_t* location, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +); +void get_key +( + uint8_t key_type, + uint8_t* location, + uint8_t size, + const uint8_t* msg, + uint8_t msg_size +); +uint16_t get_data_from_uart +( + uint8_t* src_ptr, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +); +uint8_t enable_dma +( + const uint8_t* msg, + uint8_t msg_size +); +void display_output +( + uint8_t* in_buffer, + uint32_t byte_length +); +#endif /* __HELPER_H_ */ diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/application/main.c b/applications/user-crypto/miv-rv32-ndrbg-services/src/application/main.c new file mode 100644 index 0000000..187d882 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/application/main.c @@ -0,0 +1,324 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file main.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Non Deterministic Random Bit Generator example for PolarFire user Crypto. + * + */ +#include +#include +#include +#include "stdint.h" +#include "helper.h" +#include "hal/hal.h" +#include "fpga_design_config/fpga_design_config.h" +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" +#include "drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h" +#include "drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h" + +#include "cal/calpolicy.h" +#include "cal/pk.h" +#include "cal/pkx.h" +#include "cal/pkxlib.h" +#include "cal/calini.h" +#include "cal/utils.h" +#include "cal/hash.h" +#include "cal/drbgf5200.h" +#include "cal/drbg.h" +#include "cal/nrbg.h" +#include "cal/sym.h" +#include "cal/shaf5200.h" +#include "cal/calenum.h" + +#define INVALID_USER_INPUT -1 +#define MAX_NB_OF_RANDOM_BYTES 8 +#define EACH_BLK_SIZE 16 + +/****************************************************************************** + * CoreUARTapb instance data. + *****************************************************************************/ +UART_instance_t g_uart; + +uint32_t g_user_crypto_base_addr = 0x62000000UL; +volatile uint8_t instantiate = 0; +uint8_t sc_nonce[NONCE_SERVICE_RESP_LEN] = {0x00}; +uint8_t random_bytes[MAX_NB_OF_RANDOM_BYTES * EACH_BLK_SIZE] = {0x00}; + +/*============================================================================== + Messages displayed over the Core UART. + */ +const uint8_t g_greeting_msg[] = +"\r\n\r\n\ +******************************************************************************\r\n\ +***** PolarFire User Crypto Random Bit Generator System Services Example *****\r\n\ +******************************************************************************\r\n\ + This example project exercises the random bit generator system\r\n\ + services.\r\n"; + +const uint8_t g_options[] = + "\r\n\r\n\ + - Press \"i\" to instantiate random numbers.\r\n\ + - Press \"g\" to generate random numbers.\r\n\ + - Press \"d\" to uninstantiated random numbers.\r\n\ +------------------------------------------------------------------------------"; +static const uint8_t g_separator[] = +"\r\n\ +------------------------------------------------------------------------------"; + +/* Error Message.*/ +const uint8_t g_errror_message_0[] = "\r\n Error - Operation failed because the DRBG is not instantiated."; +const uint8_t g_errror_message_1[] = "\r\n Error - Parameter is SAT_NULL."; +const uint8_t g_errror_message_2[] = "\r\n Error - Parameter exceeds capability of implementation.."; +const uint8_t g_errror_message_3[] = "\r\n Error - NRBG fatal error during operation."; +const uint8_t g_errror_message_4[] = "\r\n Error - Function implementation not populated."; + +/*============================================================================== + Display greeting message when application is started. + */ +static void display_greeting(void) +{ + UART_send(&g_uart, g_greeting_msg,sizeof(g_greeting_msg)); +} +static void display_options(void) +{ + UART_send(&g_uart, g_options,sizeof(g_options)); +} + +/*============================================================================== + Display error message. + */ +static void display_error_info(uint8_t status) +{ + switch(status) + { + case SATR_FAIL: + UART_send(&g_uart, g_errror_message_0, sizeof(g_errror_message_0)); + break; + + case SATR_BADPARAM: + UART_send(&g_uart, g_errror_message_1, sizeof(g_errror_message_1)); + break; + + case SATR_BADLEN: + UART_send(&g_uart, g_errror_message_2, sizeof(g_errror_message_2)); + break; + + case SATR_ROFATAL: + UART_send(&g_uart, g_errror_message_3, sizeof(g_errror_message_3)); + break; + + case SATR_FNP: + UART_send(&g_uart, g_errror_message_4, sizeof(g_errror_message_4)); + break; + + default: + break; + } +} + +/*============================================================================== + Retrieve a number typed by the user. + */ +static int32_t get_number_from_user(void) +{ + int32_t user_input = 0u; + uint8_t rx_buff[1]; + uint8_t complete = 0u; + size_t rx_size; + + while(!complete) + { + rx_size = UART_get_rx(&g_uart, rx_buff, sizeof(rx_buff)); + if(rx_size > 0) + { + UART_send(&g_uart, rx_buff, sizeof(rx_buff)); + if(ENTER == rx_buff[0]) + { + complete = 1u; + } + else if((rx_buff[0] >= '0') && (rx_buff[0] <= '9')) + { + user_input = (user_input * 10u) + (rx_buff[0] - '0'); + } + else + { + user_input = INVALID_USER_INPUT; + complete = 1u; + UART_send(&g_uart, rx_buff, sizeof(rx_buff)); + } + } + } + return user_input; +} + +/*============================================================================== + Function used to instantiates the DRBG + */ +uint8_t nrbg_instantiate(void) +{ + static int instantiate = 0; + SATR status; + + SYS_init((unsigned int) CORESYS_SERV_BASE_ADDR); + + status = SYS_nonce_service(sc_nonce, 0); + if((SYS_SUCCESS == status) && (instantiate == 0)) + { + status = CALDRBGInstantiate((uint32_t*)&sc_nonce[0], 8u, 0u, 0u, SATSYMKEYSIZE_AES128, + 2u, 10u, SAT_FALSE); + if(status == SATR_SUCCESS) + { + UART_send(&g_uart, (const uint8_t*)" DRBG instantiates successful.", + sizeof(" DRBG instantiates successful.")); + } + else + { + UART_send(&g_uart, (const uint8_t*)" DRBG instantiates fail.", + sizeof(" DRBG instantiates fail.")); + display_error_info(status); + } + } + + return status; +} + +/*============================================================================== + Generate Random number and display the status and generated number on UART + terminal. + */ +static void generate_random_bits(void) +{ + uint32_t nb_of_bytes; + SATR status; + const uint8_t read_no_of_byte_to_generate[] = + " Enter number of random block to generate( max 8 blocks): "; + const uint8_t success_msg[] = + "\r\n DRBG generate successful. \r\n Generated Number: \r\n"; + const uint8_t fail_msg[] = + "\r\n DRBG generate failure."; + + for(uint16_t i = 0; i< MAX_NB_OF_RANDOM_BYTES * EACH_BLK_SIZE; i++) + { + random_bytes[i] = 0; + } + + UART_send(&g_uart, read_no_of_byte_to_generate, + sizeof(read_no_of_byte_to_generate)); + nb_of_bytes = get_number_from_user(); + + if((nb_of_bytes >= 1) && (nb_of_bytes <= MAX_NB_OF_RANDOM_BYTES)) + { + /* Generate random bits */ + status = CALDRBGGenerate(SAT_NULL, 0u, SAT_FALSE, + (uint32_t*)&random_bytes[0] , nb_of_bytes); + + /* Display the generated number and status on UART terminal. */ + if(status == SATR_SUCCESS) + { + CALPKTrfRes(SAT_TRUE); + UART_send(&g_uart, success_msg, sizeof(success_msg)); + /* Display number of number of 128-bit blocks*/ + display_output(random_bytes, nb_of_bytes * EACH_BLK_SIZE); + } + else + { + UART_send(&g_uart,fail_msg, sizeof(fail_msg)); + display_error_info(status); + } + } + else + { + UART_send(&g_uart, (const uint8_t *)"\r\n\r\n Invalid entry.", + sizeof("\r\n\r\n Invalid entry.")); + } +} + +/*============================================================================== + Function used to un-instantiates the DRBG + */ +void nrbg_uninstantiate(void) +{ + SATR status; + + /* Un-instantiate the currently instantiated DRBG*/ + status = CALDRBGUninstantiate(); + + /* Display the status on UART terminal. */ + if(status == SATR_SUCCESS) + { + UART_send(&g_uart,(const uint8_t*)" DRBG uninstantiated successful.", + sizeof(" DRBG uninstantiated successful.")); + } + else + { + UART_send(&g_uart,(const uint8_t*)" DRBG uninstantiated failure.", + sizeof(" DRBG uninstantiated failure.")); + display_error_info(status); + } +} + +/****************************************************************************** + * main function. + *****************************************************************************/ +int main( void ) +{ + uint8_t rx_buff[1]; + size_t rx_size = 0; + + /* Initialize CoreUARTapb with its base address, baud value, and line + configuration. */ + UART_init(&g_uart, COREUARTAPB0_BASE_ADDR, BAUD_VALUE_115200, + (DATA_8_BITS | NO_PARITY)); + + /* Initialize the core. */ + CALIni(); + + /* Display greeting message. */ + display_greeting(); + + /* display options */ + display_options(); + + for(;;) + { + /* Start command line interface if any key is pressed. */ + rx_size = UART_get_rx(&g_uart, rx_buff, sizeof(rx_buff)); + if(rx_size > 0) + { + switch(rx_buff[0]) + { + case 'i': + UART_send(&g_uart, + (const uint8_t*)"\r\n Selected: DRBG instantiates service. \r\n", + sizeof("\r\n Selected: DRBG instantiates service. \r\n")); + nrbg_instantiate(); + UART_send(&g_uart, g_separator, sizeof(g_separator)); + display_options(); + break; + + case 'g': + UART_send(&g_uart,(const uint8_t*)"\r\n Selected: Random data generate service. \r\n", + sizeof("\r\n Selected: Random data generate service. \r\n")); + generate_random_bits(); + UART_send(&g_uart, g_separator, sizeof(g_separator)); + display_options(); + break; + + case 'd': + UART_send(&g_uart,(const uint8_t*)"\r\n Selected: Uninstantiated DRBG service. \r\n", + sizeof("\r\n Selected: Uninstantiated DRBG service. \r\n")); + nrbg_uninstantiate(); + UART_send(&g_uart, g_separator, sizeof(g_separator)); + display_options(); + break; + + default: + break; + } + } + } +} + diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h new file mode 100644 index 0000000..3fd1438 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h @@ -0,0 +1,156 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file fpga_design_config.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Sample design configuration settings. + * + */ + /*========================================================================*//** + @mainpage + Example file detailing how the fpga_design_config.h should be constructed + for the SoftConsole project targeted for Mi-V processors. + + @section intro_sec Introduction + The SoftConsole project targeted for Mi-V processors now have an improved + folder structure. Detailed description of the folder structure is available + at https://github.com/Mi-V-Soft-RISC-V/miv-rv32-documentation. + + The fpga_design_config.h must be stored as shown below + /boards//fpga_design_config.h + + Currently this file must be hand crafted when using the Mi-V Soft Processor. + In future, all the design and soft IP configurations will be automatically + generated from the Libero design description data. + + You can use this sample file as an example. + Rename this file from sample_fpga_design_config.h to fpga_design_config.h + and then customize it per your hardware design. + + @section Project configuration Instructions + 1. Change SYS_CLK_FREQ define to frequency of Mi-V Soft processor clock + 2 Add all the soft IP core BASE addresses + 3. Add the peripheral Core Interrupts to Mi-V Soft processor IRQ number + mappings + 4. Define MSCC_STDIO_UART_BASE_ADDR if you want a CoreUARTapb mapped to + STDIO + + **NOTE** + In the legacy folder structures, the file hw_config.h as was used at the + root of the project folder. This file is now depricated. + +*//*=========================================================================*/ + +#ifndef FPGA_DESIGN_CONFIG_H_ +#define FPGA_DESIGN_CONFIG_H_ + +/***************************************************************************//** + * Soft-processor clock definition + * This is the only clock brought over from the Mi-V Libero design. + */ +#ifndef SYS_CLK_FREQ +#define SYS_CLK_FREQ 83000000UL +#endif + +/***************************************************************************//** + * Peripheral base addresses. + * Format of define is: + * __BASE_ADDR + * The field is optional if there is only one instance of the core + * in the design + * MIV_ESS is an extended peripheral subsystem IP core with peripherals + * connections as defined below. + * The system can be further extended by attaching APB peripherals to the + * empty APB slots. + */ +#define COREUARTAPB0_BASE_ADDR 0x70000000UL +#define COREGPIO_OUT_BASE_ADDR 0x70001000UL +#define CORESPI_BASE_ADDR 0x70002000UL +#define CORESYS_SERV_BASE_ADDR 0x70003000UL + +/***************************************************************************//** + * Peripheral Interrupts are mapped to the corresponding Mi-V Soft processor + * interrupt in the Libero design. + * + * On the legacy RV32 cores, there can be up to 31 external interrupts (IRQ[30:0] + * pins). The legacy RV32 Soft processor external interrupts are defined in the + miv_rv32_plic.h + * + * These are of the form + * typedef enum +{ + NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + . + . + . + External_31_IRQn = 31 +} IRQn_Type; + + On the legacy RV32 processors, the PLIC identifies the interrupt and passes it + on to the processor core. The interrupt 0 is not used. The pin IRQ[0] should + map to External_1_IRQn likewise IRQ[30] should map to External_31_IRQn + +e.g + +#define TIMER0_IRQn External_30_IRQn +#define TIMER1_IRQn External_31_IRQn + + The MIV_RV32 soft processor has up to six optional system interrupts, MSYS_EI[n] + in addition to one EXT_IRQ. + The MIV_RV32 does not have an inbuilt PLIC and all the interrupts are directly + delivered to the processor core, hence unlike legacy RV32 cores, no interrupt + number mapping is necessary on MIV_RV32 core. + */ + +/**************************************************************************** + * Baud value to achieve a 115200 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ +#define BAUD_VALUE_115200 ((SYS_CLK_FREQ / (16 * 115200)) - 1) + +/****************************************************************************** + * Baud value to achieve a 57600 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + #define BAUD_VALUE_57600 ((SYS_CLK_FREQ / (16 * 57600)) - 1) + +/***************************************************************************//** + * Define MSCC_STDIO_THRU_CORE_UART_APB in the project settings if you want the + * standard IOs to be redirected to a terminal via UART. + */ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +/* + * A base address mapping for the STDIO printf/scanf mapping to CortUARTapb + * must be provided if it is being used + * + * e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR + */ +#define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB0_BASE_ADDR + +#ifndef MSCC_STDIO_UART_BASE_ADDR +#error MSCC_STDIO_UART_BASE_ADDR not defined- e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR +#endif + +#ifndef MSCC_STDIO_BAUD_VALUE +/* + * The MSCC_STDIO_BAUD_VALUE define should be set in your project's settings to + * specify the baud value used by the standard output CoreUARTapb instance for + * generating the UART's baud rate if you want a different baud rate from the + * default of 115200 baud + */ +#define MSCC_STDIO_BAUD_VALUE 115200 +#endif /*MSCC_STDIO_BAUD_VALUE*/ + +#endif /* end of MSCC_STDIO_THRU_CORE_UART_APB */ +/******************************************************************************* + * End of user edit section + */ +#endif /* FPGA_DESIGN_CONFIG_H_ */ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld b/applications/user-crypto/miv-rv32-ndrbg-services/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld new file mode 100644 index 0000000..8541db6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld @@ -0,0 +1,160 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-ram.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * debug image executing in SRAM. + * + * This linker script assumes that a RAM is connected at on Mi-V soft processor + * memory space pointed by the reset vector address. + * + * NOTE : Modify the memory section address and the size according to your + * Libero design. + * For example: + * 1) If you want to download and step debug at a different RAM memory address in + * your design (For example TCM base address) than the one provided in this file. + * 2) The MIV_RV32, when used with MIV_ESS IP, provides ways to copy the executable + * HEX file from external Non-Volatile memory into the TCM at reset. In this + * case your executable must be linked to the TCM address. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +MEMORY +{ + ram (rwx) : ORIGIN = 0x80000000, LENGTH = 64k + crypto_ram (rw) : ORIGIN = 0x61000000, LENGTH = 32k +} + +RAM_START_ADDRESS = 0x80000000; /* Must be the same value MEMORY region ram ORIGIN above. */ +RAM_SIZE = 64k; /* Must be the same value MEMORY region ram LENGTH above. */ +STACK_SIZE = 2k; /* needs to be calculated for your application */ +HEAP_SIZE = 0k; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > ram + + .text : ALIGN(0x10) + { + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } > ram + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } > ram + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } > ram + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram + + . = 0x61000000; + .crypto_data : ALIGN(0x10) + { + . = ALIGN(0x10); + *(.crypto_data) + } > crypto_ram +} + diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/aesf5200.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/aesf5200.h new file mode 100644 index 0000000..889dddd --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/aesf5200.h @@ -0,0 +1,104 @@ +/* ------------------------------------------------------------------- + $Rev: 1293 $ $Date: 2017-07-27 14:09:14 -0400 (Thu, 27 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for F5200 AES function hardware implementation for + CAL. + ------------------------------------------------------------------- */ + +#ifndef AESF5200_H +#define AESF5200_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef AESF5200_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATR aesf5200aes (SATSYMTYPE eSymType, SATSYMMODE eMode, + void *pIV, SATBOOL bLoadIV, const void *pSrc, void *pDest, SATUINT32_t uiLen, + SATBOOL bDecrypt); + +extern SATR aesf5200aesk (SATSYMTYPE eSymType, const SATUINT32_t *puiKey); + +extern SATR aesf5200gcm (SATSYMTYPE eSymType, SATSYMMODE eMode, void *pIV, + const void *pSrc, void *pDest, SATUINT32_t uiEncLen, + const void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, SATUINT32_t uiMACLen, + SATBOOL bDecrypt); + +extern SATR aesf5200gcmdma(SATSYMTYPE eSymType, SATSYMMODE eMode, void *pIV, + const void *pSrc, void *pDest, SATUINT32_t uiEncLen, const void *pAuth, + SATUINT32_t uiAuthLen, void *pMAC, SATUINT32_t uiMACLen, SATBOOL bDecrypt, + SATUINT32_t uiDMAChConfig); + +extern SATR aesf5200kw(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR aesf5200kwp(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR aesf5200kr(SATSYMTYPE eSymType, SATSYMMODE eMode, + const SATUINT32_t *puiKey, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKrf, SATBOOL bDecrypt); + +extern SATR aesf5200dma(SATSYMTYPE eSymType, SATSYMMODE eMode, void *pIV, + SATBOOL bLoadIV, const void *pExtSrc, void *pExtDest, SATUINT32_t uiLen, + SATUINT32_t uiDMAChConfig, SATBOOL bDecrypt); + +extern SATR aesf5200krdma(SATSYMTYPE eSymType, SATSYMMODE eMode, + const SATUINT32_t *puiKey, void *pIV, SATBOOL bLoadIV, const void *pExtSrc, + void *pExtDest, SATUINT32_t uiLen, SATUINT32_t uiKrf, + SATUINT32_t uiDMAChConfig, SATBOOL bDecrypt); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/calcontext.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/calcontext.h new file mode 100644 index 0000000..fc408c2 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/calcontext.h @@ -0,0 +1,88 @@ +/* ------------------------------------------------------------------- + $Rev: 1298 $ $Date: 2017-08-04 13:04:19 -0400 (Fri, 04 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL context management functions. + ------------------------------------------------------------------- */ + +#ifndef CALCONTEXT_H +#define CALCONTEXT_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* Function resource handle. */ +/* ----- ------ ------- ---- */ +#define SATRES_DEFAULT (SATRESHANDLE)0U +#define SATRES_CALSW (SATRESHANDLE)1U + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ +typedef struct{ + SATUINT32_t uiBase; + SATRESCONTEXTPTR pContext; + }SATRESHANDLESTRUCT; + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALCONTEXT_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATRESCONTEXTPTR CALContextCurrent(const SATRESHANDLE hResource); + +extern SATR CALContextLoad(const SATRESHANDLE hResource, + const SATRESCONTEXTPTR pContext); + +extern SATR CALContextRemove(const SATRESHANDLE hResource); + +extern SATR CALContextUnload(const SATRESHANDLE hResource); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern void init_reshandles(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/calenum.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/calenum.h new file mode 100644 index 0000000..6281f3f --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/calenum.h @@ -0,0 +1,289 @@ +/* ------------------------------------------------------------------- + $Rev: 1566 $ $Date: 2018-09-14 11:04:30 -0400 (Fri, 14 Sep 2018) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + This file defines common types in the CAL. + + Most CAL types and constants are defined with the "SAT" prefix to + reduce the chance of name space collisions with other users. + ------------------------------------------------------------------- */ + +#ifndef CALENUM_H +#define CALENUM_H + +/* -------- */ +/* Includes */ +/* -------- */ + +/* CAL base types. */ +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ +/* NULL definitions. */ +#define SAT_NULL 0 + +/* Boolean definitions. */ +#define SAT_TRUE ((SATBOOL)1) +#define SAT_FALSE ((SATBOOL)0) + + +/* Major cipher key/SSP type. */ +/* ----- ------ ------- ----- */ +#define SATSSPTYPE_NULL (SATSSPTYPE)0 +#define SATSSPTYPE_SYMKEY (SATSSPTYPE)1 +#define SATSSPTYPE_ASYMKEY (SATSSPTYPE)2 +/* Special marker for end of list. */ +#define SATSSPTYPE_LAST (SATSSPTYPE)3 + + +/* Asymmetric Ciphers */ +/* ---------- ------- */ +#define SATASYMTYPE_NULL (SATASYMTYPE)0U +#define SATASYMTYPE_DSA_SIGN (SATASYMTYPE)1U +#define SATASYMTYPE_DSA_VERIFY (SATASYMTYPE)2U +#define SATASYMTYPE_RSA_ENCRYPT (SATASYMTYPE)3U +#define SATASYMTYPE_RSA_DECRYPT (SATASYMTYPE)4U +#define SATASYMTYPE_DH (SATASYMTYPE)5U +#define SATASYMTYPE_ECDSA_SIGN (SATASYMTYPE)6U +#define SATASYMTYPE_ECDSA_VERIFY (SATASYMTYPE)7U +#define SATASYMTYPE_ECDH (SATASYMTYPE)8U +#define SATASYMTYPE_RSA_SIGN (SATASYMTYPE)9U +#define SATASYMTYPE_RSA_VERIFY (SATASYMTYPE)10U +/* Special marker for end of list. */ +#define SATASYMTYPE_LAST (SATASYMTYPE)11U + + +/* Encoding Types */ +/* -------- ----- */ +#define SATRSAENCTYPE_NULL (SATRSAENCTYPE)0U +#define SATRSAENCTYPE_PKCS (SATRSAENCTYPE)1U +#define SATRSAENCTYPE_ANSI (SATRSAENCTYPE)2U +#define SATRSAENCTYPE_PSS (SATRSAENCTYPE)3U +/* Special marker for end of list. */ +#define SATRSAENCTYPE_LAST (SATRSAENCTYPE)4U + + +/* Symmetric Ciphers */ +/* --------- ------- */ + +/* Cipher Type. */ +#define SATSYMTYPE_NULL (SATSYMTYPE)0U +#define SATSYMTYPE_AES128 (SATSYMTYPE)1U +#define SATSYMTYPE_AES192 (SATSYMTYPE)2U +#define SATSYMTYPE_AES256 (SATSYMTYPE)3U +#define SATSYMTYPE_AESKS128 (SATSYMTYPE)4U +#define SATSYMTYPE_AESKS192 (SATSYMTYPE)5U +#define SATSYMTYPE_AESKS256 (SATSYMTYPE)6U +/* Special marker for end of list. */ +#define SATSYMTYPE_LAST (SATSYMTYPE)7U + +/* Names for common cipher key lengths, in bits. */ +#define SATSYMKEYSIZE_AES128 (SATSYMKEYSIZE)128U +#define SATSYMKEYSIZE_AES192 (SATSYMKEYSIZE)192U +#define SATSYMKEYSIZE_AES256 (SATSYMKEYSIZE)256U +#define SATSYMKEYSIZE_AESKS128 (SATSYMKEYSIZE)256U +#define SATSYMKEYSIZE_AESKS192 (SATSYMKEYSIZE)384U +#define SATSYMKEYSIZE_AESKS256 (SATSYMKEYSIZE)512U + +/* Cipher Mode. */ +#define SATSYMMODE_NULL (SATSYMMODE)0U +#define SATSYMMODE_ECB (SATSYMMODE)1U +#define SATSYMMODE_CBC (SATSYMMODE)2U +#define SATSYMMODE_CFB (SATSYMMODE)3U +#define SATSYMMODE_OFB (SATSYMMODE)4U +#define SATSYMMODE_CTR (SATSYMMODE)5U +#define SATSYMMODE_GCM (SATSYMMODE)6U +#define SATSYMMODE_GHASH (SATSYMMODE)8U +/* Special marker for end of list. */ +#define SATSYMMODE_LAST (SATSYMMODE)9U + + +/* Hashes */ +/* ------ */ +#define SATHASHTYPE_NULL (SATHASHTYPE)0U +#define SATHASHTYPE_SHA1 (SATHASHTYPE)1U +#define SATHASHTYPE_SHA224 (SATHASHTYPE)2U +#define SATHASHTYPE_SHA256 (SATHASHTYPE)3U +#define SATHASHTYPE_SHA384 (SATHASHTYPE)4U +#define SATHASHTYPE_SHA512 (SATHASHTYPE)5U +#define SATHASHTYPE_SHA512_224 (SATHASHTYPE)6U +#define SATHASHTYPE_SHA512_256 (SATHASHTYPE)7U +/* Special marker for end of list. */ +#define SATHASHTYPE_LAST (SATHASHTYPE)8U + +/* Hash sizes defined in bits */ +#define SATHASHSIZE_NULL (SATHASHSIZE)0U +#define SATHASHSIZE_SHA1 (SATHASHSIZE)160U +#define SATHASHSIZE_SHA224 (SATHASHSIZE)224U +#define SATHASHSIZE_SHA256 (SATHASHSIZE)256U +#define SATHASHSIZE_SHA384 (SATHASHSIZE)384U +#define SATHASHSIZE_SHA512 (SATHASHSIZE)512U +#define SATHASHSIZE_SHA512_224 (SATHASHSIZE)224U +#define SATHASHSIZE_SHA512_256 (SATHASHSIZE)256U + +#define SATHASHSIZE_HASH160 (SATHASHSIZE)160U +#define SATHASHSIZE_HASH192 (SATHASHSIZE)192U +#define SATHASHSIZE_HASH224 (SATHASHSIZE)224U +#define SATHASHSIZE_HASH256 (SATHASHSIZE)256U +#define SATHASHSIZE_HASH320 (SATHASHSIZE)320U +#define SATHASHSIZE_HASH384 (SATHASHSIZE)384U +#define SATHASHSIZE_HASH512 (SATHASHSIZE)512U +#define SATHASHSIZE_HASH521 (SATHASHSIZE)521U + + +/* Message Authentication Codes */ +/* ------- -------------- ----- */ + +/* Message Authentication Types */ +#define SATMACTYPE_NULL (SATMACTYPE)0U +#define SATMACTYPE_SHA1 (SATMACTYPE)1U +#define SATMACTYPE_SHA224 (SATMACTYPE)2U +#define SATMACTYPE_SHA256 (SATMACTYPE)3U +#define SATMACTYPE_SHA384 (SATMACTYPE)4U +#define SATMACTYPE_SHA512 (SATMACTYPE)5U +#define SATMACTYPE_SHA512_224 (SATMACTYPE)6U +#define SATMACTYPE_SHA512_256 (SATMACTYPE)7U +#define SATMACTYPE_AESCMAC128 (SATMACTYPE)10U +#define SATMACTYPE_AESCMAC192 (SATMACTYPE)11U +#define SATMACTYPE_AESCMAC256 (SATMACTYPE)12U +#define SATMACTYPE_AESGMAC (SATMACTYPE)13U +/* Special marker for end of list. */ +#define SATMACTYPE_LAST (SATMACTYPE)14U + + +/* Message Authentication Flags */ +#define SATMACFLAG_OP (SATMACTYPEFLAG)0U +#define SATMACFLAG_FIRSTPASS (SATMACTYPEFLAG)1U +#define SATMACFLAG_FINALPASS (SATMACTYPEFLAG)2U +#define SATMACFLAG_IKEYFINAL (SATMACTYPEFLAG)4U +#define SATMACFLAG_OKEYFINAL (SATMACTYPEFLAG)8U + + +/* Non-deterministic Random Bit Generator */ +/* ------- -------------- ----- */ + +/* NRBG register write enables */ +#define SATNRBGCONFIG_NONE 0x0 +#define SATNRBGCONFIG_RNG_CSR 0x1 +#define SATNRBGCONFIG_RNG_CNTLIM 0x2 +#define SATNRBGCONFIG_RNG_VOTIMER 0X4 +#define SATNRBGCONFIG_RNG_FMSK 0X8 + +/* RNG_CSR access defines */ +#define SATNRBGCONFIG_CSR_RODIS 0x0 +#define SATNRBGCONFIG_CSR_ROEN 0x1 +#define SATNRBGCONFIG_CSR_ROFATAL 0x2 +#define SATNRBGCONFIG_CSR_ROFATALCLR 0X4 + +/* RNG_FMSK mask values */ +#define SATNRBGCONFIG_FMSK_ROOSCF 0xFF +#define SATNRBGCONFIG_FMSK_MONOBITF 0x10000 +#define SATNRBGCONFIG_FMSK_POKERF 0x20000 +#define SATNRBGCONFIG_FMSK_RUNSF 0x40000 +#define SATNRBGCONFIG_FMSK_LRUNSF 0x80000 +#define SATNRBGCONFIG_FMSK_F1401 0xF0000 +#define SATNRBGCONFIG_FMSK_REPCNTF 0x100000 +#define SATNRBGCONFIG_FMSK_APROPF 0x200000 +#define SATNRBGCONFIG_FMSK_SP800 0x300000 + +/* RNG_ROHEALTH mask values */ +#define SATNRBGCONFIG_HLTH_ROOSCF 0x3FC0 +#define SATNRBGCONFIG_HLTH_APROPF 0x20 +#define SATNRBGCONFIG_HLTH_REPCNTF 0x10 +#define SATNRBGCONFIG_HLTH_LRUNSF 0x8 +#define SATNRBGCONFIG_HLTH_RUNSF 0x4 +#define SATNRBGCONFIG_HLTH_POKERF 0x2 +#define SATNRBGCONFIG_HLTH_MONOBITF 0x1 + + +/* Return Codes */ +/* ------ ----- */ +#define SATR_SUCCESS (SATR)0U +#define SATR_FAIL (SATR)1U +#define SATR_BADPARAM (SATR)2U +#define SATR_VERIFYFAIL (SATR)3U +#define SATR_KEYSFULL (SATR)4U +#define SATR_BUSY (SATR)5U +#define SATR_ROFATAL (SATR)6U +#define SATR_PARITYFLUSH (SATR)7U +#define SATR_SIGNFAIL (SATR)8U +#define SATR_VALIDATEFAIL (SATR)9U +#define SATR_PAF (SATR)10U +#define SATR_VALPARMX (SATR)11U +#define SATR_VALPARMY (SATR)12U +#define SATR_VALPARMB (SATR)13U +#define SATR_DCMPPARMX (SATR)14U +#define SATR_DCMPPARMB (SATR)15U +#define SATR_DCMPPARMP (SATR)16U +#define SATR_SIGNPARMD (SATR)17U +#define SATR_SIGNPARMK (SATR)18U +#define SATR_VERPARMR (SATR)19U +#define SATR_VERPARMS (SATR)20U +#define SATR_MSBICV1 (SATR)21U +#define SATR_MSBICV2 (SATR)22U +#define SATR_PADLEN (SATR)23U +#define SATR_LSB0PAD (SATR)24U +#define SATR_BADLEN (SATR)25U +#define SATR_BADHASHTYPE (SATR)26U +#define SATR_BADTYPE (SATR)27U +#define SATR_BADMODE (SATR)28U +#define SATR_BADCONTEXT (SATR)29U +#define SATR_BADHASHLEN (SATR)30U +#define SATR_BADMACTYPE (SATR)31U +#define SATR_BADMACLEN (SATR)32U +#define SATR_BADHANDLE (SATR)33U +#define SATR_FNP (SATR)34U +#define SATR_HFAULT (SATR)35U +#define SATR_NOPEND (SATR)36U +#define SATR_BADRSAENC (SATR)37U +#define SATR_BADMOD (SATR)38U +/* Special marker for end of list. */ +#define SATR_LAST (SATR)39U + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* See caltypes.h for type definitions associated with defines above. */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALENUM_C +#ifdef __cplusplus +extern "C" { +#endif + +/* NOTE: this header file does not have an associated C file. */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/calini.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/calini.h new file mode 100644 index 0000000..62461d1 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/calini.h @@ -0,0 +1,69 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL initialization + ------------------------------------------------------------------- */ + +#ifndef CALINI_H +#define CALINI_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALINI_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALIni(void); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/calpolicy.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/calpolicy.h new file mode 100644 index 0000000..2a43445 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/calpolicy.h @@ -0,0 +1,183 @@ +/* ------------------------------------------------------------------- + $Rev: 1293 $ $Date: 2017-07-27 14:09:14 -0400 (Thu, 27 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file defining CAL policy for endianess, HW/SW, etc. + ------------------------------------------------------------------- */ + +#ifndef CALPOLICY_H +#define CALPOLICY_H + +/* -------- */ +/* Includes */ +/* -------- */ + +/* The following include provides a custom configuration header file when + CALCONFIGH is defined +*/ +#ifdef CALCONFIGH +# include CALCONFIGH +#else +# error "CALCONFIGH not defined. CAL requires a custom configuration header \ +defined by CALCONFIGH. Review CAL README." +#endif + +/* ------- */ +/* Defines */ +/* ------- */ + +/* Context switching */ +#ifndef MAXRESHANDLES +# define MAXRESHANDLES 1 +#endif + +/* Little Endian (default) / Big Endian */ +#ifndef SAT_LITTLE_ENDIAN +# define SAT_LITTLE_ENDIAN 1 +#endif + +/* PK SW Point Validate Checking */ +#ifndef PKSWCHKVALPT +# define PKSWCHKVALPT 1 +#endif + +/* DMA */ +#ifndef USE_X52EXEC_DMA +# define USE_X52EXEC_DMA 0 +#endif + +/* SHA */ +#define MAXHASHLEN 512 +#define MAXHMACKEYLEN 512 + +/* RNG */ +#define NRBGSIMNUMRO 16 +#define ENTROPYMEMBLOCKS 7 +#define BUFMEMBLOCKS 3 +#ifndef RNXBLKLEN +#define RNXBLKLEN 32 +#endif +#ifndef RNXBLKOUTLEN +#define RNXBLKOUTLEN 4 +#endif + +#ifndef USENRBGSW +# define USENRBGSW 0 +#endif + +/* PK */ +#ifndef PKX0_BASE +# define PKX0_BASE 0xE0000000u +#endif + +#if USEPKSW +# ifndef MAXMODSIZE +# define MAXMODSIZE 8192 +# endif +# ifndef PKSWBUFSIZE +# define PKSWBUFSIZE 15*(MAXMODSIZE/32) +# endif +#else +# define USEPKSW 0 +#endif + +/* Set default values for X52 configuration defines. */ +#ifndef X52_CFG_OPT +# define X52_CFG_OPT 0 +#endif +#ifndef X52_LIR_LEN +# define X52_LIR_LEN 0x800 +#endif +#ifndef X52_BER_LEN +# define X52_BER_LEN 0x400 +#endif +#ifndef X52_MMR_LEN +# define X52_MMR_LEN 0x400 +#endif +#ifndef X52_TSR_LEN +# define X52_TSR_LEN 0x400 +#endif +#ifndef X52_FPR_LEN +# define X52_FPR_LEN 0x400 +#endif +#if X52_LIR_ROM_LEN>0 && X52_LIR_LEN>X52_LIR_ROM_LEN +# define PKX_OFFSET 2048 +#else +# define PKX_OFFSET 0 +#endif + +/* X52 Configuration Options */ +#define AESPKX (X52_CFG_OPT&0x00000001u) +#define AESPKXGCM (X52_CFG_OPT&0x00000008u) +#define AESPKXFASTKEY (X52_CFG_OPT&0x01000000u) +#define SHAPKXOPT1 (X52_CFG_OPT&0x00000020u) +#define SHAPKXOPT224 (X52_CFG_OPT&0x00000040u) +#define SHAPKXOPT256 (X52_CFG_OPT&0x00000080u) +#define SHAPKXOPT384 (X52_CFG_OPT&0x00000100u) +#define SHAPKXOPT512 (X52_CFG_OPT&0x00000200u) +#define SHAPKXOPT5124 (X52_CFG_OPT&0x00400000u) +#define SHAPKXOPT5126 (X52_CFG_OPT&0x00800000u) + +/* Define the maximum number of return values that may be handled using + CAL*TrfRes() function(s). +*/ +#define CAL_MAXTRFS 4 + +/* Volatile pointer operations */ +/* These access macros are designed so that they may be redefined by a + user compiling CAL. +*/ +#ifndef CALREAD32 +# define CALREAD32(ptr) ( *(ptr) ) +#endif +#ifndef CALWRITE32 +# define CALWRITE32(ptr, val) ( *(ptr)=val ) +#endif +#ifndef CALPOLL32 +# define CALPOLL32(ptr, val, mask) while ((*(ptr) & (mask)) != (val)); +#endif + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +#ifndef CALPOLICY_C +#ifdef __cplusplus +extern "C" { +#endif + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +/* NOTE: this header file does not have an associated C file. */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/caltypes.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/caltypes.h new file mode 100644 index 0000000..3b2fe0b --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/caltypes.h @@ -0,0 +1,328 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + This file defines common types in the CAL. + + Since support for the C99 stdint.h integer types is not universal, + these are defined herein and may require customization from compiler + to compiler, or use of the stdint.h header, if present (recommended). + + C99 supports 64-bit types; however, support in older compilers is + spotty. For those that do not support it, the macro NO64BITINT may be + defined by the user to prevent defintion of 64-bit types. This is + generally safe with CAL-PK and CAL-SYM; however, this is incompatible + with CAL-SW. + + Most CAL types and constants are defined with the "SAT" prefix to + reduce the chance of name space collisions with other users. + ------------------------------------------------------------------- */ + +#ifndef CALTYPES_H +#define CALTYPES_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* Base Types */ +/* ---- ----- */ + +/* The user may compile using stdint.h instead of the definitions below + by defining the macro INC_STDINT_H. */ +#ifdef INC_STDINT_H +#include +#endif + +/* Integer type abstraction layer. */ +#ifndef INC_STDINT_H + +typedef unsigned char uint8_t; +typedef signed char int8_t; + +typedef unsigned short uint16_t; +typedef signed short int16_t; + +typedef unsigned int uint32_t; +typedef int int32_t; + +/* stdint.h is a C99 feature, and C99 supports 64-bit ints, so this is + immune to the macro used to disable 64-bit int support. +*/ +typedef unsigned long long uint64_t; +typedef long long int64_t; + +typedef long uintptr_t; + +#endif + +/* Boolean type. */ +typedef uint8_t SATBOOL; + +/* Unsigned integer type */ +typedef uint8_t SATUINT8_t; +typedef uint16_t SATUINT16_t; +typedef uint32_t SATUINT32_t; +#ifdef INC_STDINT_H +typedef uint64_t SATUINT64_t; +#else +#ifndef NO64BITINT +typedef uint64_t SATUINT64_t; +#endif +#endif + +/* Integer type */ +typedef int8_t SATINT8_t; +typedef int16_t SATINT16_t; +typedef int32_t SATINT32_t; +#ifdef INC_STDINT_H +typedef int64_t SATINT64_t; +#else +#ifndef NO64BITINT +typedef int64_t SATINT64_t; +#endif +#endif + +typedef uintptr_t SATUINTPTR_t; + +/* Major cipher key/SSP type. */ +/* ----- ------ ------- ----- */ +typedef uint8_t SATSSPTYPE; +typedef SATSSPTYPE * SATSSPTYPEPTR; + + +/* Asymmetric Ciphers */ +/* ---------- ------- */ + +/* Cipher type. */ +typedef uint8_t SATASYMTYPE; +typedef SATASYMTYPE * SATASYMTYPEPTR; + +/* Cipher size type. */ +typedef uint16_t SATASYMSIZE; +typedef SATASYMSIZE * SATASYMSIZEPTR; + +/* Cipher encoding */ +typedef uint8_t SATRSAENCTYPE; +typedef SATRSAENCTYPE * SATRSAENCTYPEPTR; + +/* DSA public/private key. */ +typedef struct { + uint16_t ui16PLen; /* Length of modulus p. */ + uint16_t ui16QLen; /* Length of prime divisor q. */ + uint32_t *pui32P; /* Prime modulus p. */ + uint32_t *pui32Q; /* Prime divisor q. */ + uint32_t *pui32G; /* Generator g, length==p. */ + uint32_t *pui32X; /* Private key x, length==p. */ + uint32_t *pui32Y; /* Private key y, length==q. */ +} SATASYMDSADOMAIN; +typedef SATASYMDSADOMAIN * SATASYMDSADOMAINPTR; + + +/* Symmetric Ciphers */ +/* --------- ------- */ + +/* Cipher type. */ +typedef uint8_t SATSYMTYPE; +typedef SATSYMTYPE * SATSYMTYPEPTR; + +/* Cipher key size type (in bits). */ +typedef uint16_t SATSYMKEYSIZE; +typedef SATSYMKEYSIZE * SATSYMKEYSIZEPTR; + +/* Cipher mode type. */ +typedef uint8_t SATSYMMODE; +typedef SATSYMMODE * SATSYMMODEPTR; + +/* Cipher key object. */ +/* Other fields are only valid when sstCipher!=SATSYMTYPE_NULL. */ +typedef struct { + SATSYMTYPE sstCipher; + SATSYMKEYSIZE ssksKeyLen; + uint32_t *pui32Key; +} SATSYMKEY; +typedef SATSYMKEY * SATSYMKEYPTR; + + +/* Hashes */ +/* ------ */ + +/* Hash type. */ +typedef uint8_t SATHASHTYPE; +typedef SATHASHTYPE * SATHASHTYPEPTR; + +/* Hash size type (in bits). */ +typedef uint16_t SATHASHSIZE; +typedef SATHASHSIZE * SATHASHSIZEPTR; + + +/* Context switching. */ +/* ----- ------ ------- ----- */ + +typedef uint32_t SATRESHANDLE; +typedef SATRESHANDLE * SATRESHANDLEPTR; + +typedef struct { + SATHASHTYPE sshashtype; + uint32_t uiRunLen; + uint32_t uiHash[MAXHASHLEN/32]; /* holds intermed hash */ +} SHACTX; + +typedef struct { + SATHASHTYPE sshashtype; + uint32_t uiRunLen; + uint32_t uiKeyLen; + uint32_t uiHash[MAXHASHLEN/32]; /* holds intermed hash */ + uint32_t uiKey[MAXHMACKEYLEN/32]; /* holds intermed key */ +} SHAHMACCTX; + +typedef struct { + uint8_t uiContextType; + union{ + SHACTX ctxSHA; + SHAHMACCTX ctxMAC; + }CTXUNION; +} SATRESCONTEXT; +typedef SATRESCONTEXT * SATRESCONTEXTPTR; + + +/* Message Authentication Codes */ +/* ------- -------------- ----- */ + +/* MAC type. */ +typedef uint8_t SATMACTYPE; +typedef SATMACTYPE * SATMACTYPEPTR; +typedef uint8_t SATMACTYPEFLAG; + + +/* Random Number Generator */ +/* ------ ------ --------- */ +typedef union { + uint32_t u32[4]; + uint8_t u8[16]; +} uint128_t; + +typedef struct { + uint128_t ui128V; + uint128_t ui128K[2]; + uint32_t uiReseedCnt; + uint32_t uiReseedLim; + uint32_t uiEntropyFactor; + SATSYMKEYSIZE eStrength; + SATBOOL bTesting; + +} DRBGCTX; + +typedef DRBGCTX * DRBGCTXPTR; + + +/* Function Return Code */ +/* -------- ------ ---- */ +typedef uint16_t SATR ; +typedef SATR * SATRPTR ; + + +/* Transfer Results */ +/* -------- ------- */ +typedef struct { + SATUINT32_t uiLen; + volatile SATUINT32_t* vpuiSrc; + void* pDest; +} SATDATATRF; + +typedef struct { + SATUINT32_t uiResType; + SATUINT32_t uiNumDataTrf; + SATDATATRF dtrfArray[CAL_MAXTRFS]; +} SATRESULT; + + +/* EC Ultra Structs */ +/* -- ----- ------- */ +typedef uint32_t SATECTYPE; + +typedef struct { + SATUINT32_t uiLen; + SATUINT32_t* puiX; + SATUINT32_t* puiY; +} SATECPOINT; + +typedef struct { + SATUINT32_t uiLen; + SATUINT32_t* puiMod; + SATUINT32_t* puiMontPrecompute; + SATUINT32_t* puiRSqd; +} SATECMONTMOD; + +typedef struct { + SATUINT32_t uiCurveSize; + SATECTYPE eCurveType; + SATECPOINT* pBasePoint; + SATECMONTMOD* pModP; + SATECMONTMOD* pModN; + SATUINT32_t* puiA; + SATUINT32_t* puiB; +} SATECCURVE; + +typedef struct { + SATUINT32_t uiLen; + SATUINT32_t* puiSigR; + SATUINT32_t* puiSigS; + SATUINT32_t* puiSigX; + SATUINT32_t* puiSigY; +} SATECDSASIG; + +typedef struct { + SATHASHSIZE sHashLen; + SATUINT32_t* puiHash; +} SATHASH; + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALTYPES_C +#ifdef __cplusplus +extern "C" { +#endif + +/* NOTE: this header file does not have an associated C file. */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/config_user.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/config_user.h new file mode 100644 index 0000000..3728565 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/config_user.h @@ -0,0 +1,44 @@ +/* ------------------------------------------------------------------- + $Rev: 727 $ $Date: 2017-10-20 16:50:53 -0400 (Fri, 20 Oct 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + + User configuration file to include/exclude CAL components. + ------------------------------------------------------------------- */ + +#ifndef CALCONFIG_F5200_H +#define CALCONFIG_F5200_H + +#include "x52cfg_user.h" +#include + +extern uint32_t g_user_crypto_base_addr; + +#define SAT_LITTLE_ENDIAN 1 +#define PKX0_BASE (g_user_crypto_base_addr) +#define USEPKX 1 +#define USEAESPKX 1 +#define USESHAPKX 1 +#define USEDRBGPKX 1 +#define USENRBGPKX 1 +#define USECALCTX 1 + +#endif diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/drbg.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/drbg.h new file mode 100644 index 0000000..dba16f7 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/drbg.h @@ -0,0 +1,91 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for DRBG functions for CAL + ------------------------------------------------------------------- */ + +#ifndef DRBG_H +#define DRBG_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ +#define CALDRBGENTROPYFACTOR 2 + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef DRBG_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALDRBGInstantiate(const SATUINT32_t *puiNonce, + SATUINT32_t uiNonceLen, const SATUINT32_t *puiPzStr, + SATUINT32_t uiPzStrLen, SATSYMKEYSIZE eStrength, + SATUINT32_t uiEntropyFactor, SATUINT32_t uiReseedLim, SATBOOL bTesting); + +extern SATR CALDRBGReseed(const SATUINT32_t *puiAddIn, SATUINT32_t uiAddInLen); + +extern SATR CALDRBGGenerate(const SATUINT32_t *puiAddIn, SATUINT32_t uiAddInLen, + SATBOOL bPredResist, SATUINT32_t *puiOut, SATUINT32_t uiOutBlocks); + +extern SATR CALDRBGUninstantiate(void); + +extern SATR CALDRBGGetCtx(DRBGCTXPTR drbgCtxExt); + +extern SATR CALDRBGLoadCtx(DRBGCTXPTR drbgCtxExt); + +extern SATR CALDRBGGetbInst(void); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +extern SATR CALDrbgTrfRes(SATBOOL bBlock); + +extern void CALDrbgIni(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/drbgf5200.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/drbgf5200.h new file mode 100644 index 0000000..d7f6c4c --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/drbgf5200.h @@ -0,0 +1,120 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for F5200 DRBG function hardware implementations + in CAL. + ------------------------------------------------------------------- */ + +#ifndef DRBGF5200_H +#define DRBGF5200_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ +#define RNXEFACTOR (X52BER+2) +#define RNXIRLEN (X52BER+2) +#define RNXKEYORD (X52BER+3) +#define RNXRESPRED (X52BER+4) +#define RNXTESTSEL (X52BER+5) +#define RNXBADDIN (X52BER+6) +#define RNXPPSTR (X52BER+7) +#define RNXPCTX (X52BER+8) +#define RNXPRENT (X52BER+13) +#define RNXITMP3 (X52BER+20) +#define RNXPCTX2 (X52BER+22) +/* These use same locs as tb generator, but can change */ +#define RNXRDATA (X52BER_ENDIAN+0x24) +#define RNXAIDATAOFF 0x0062 +#define RNXAIDATA (X52BER_ENDIAN+RNXAIDATAOFF) +#define RNXCTXOFF 0x0094 +#define RNXCTX (X52FPR+RNXCTXOFF) +#define RNXCTXV (X52FPR_ENDIAN+RNXCTXOFF+6) +#define RNXCTXVMMR (X52MMR_ENDIAN+RNXCTXOFF+6) +#define RNXTESTENT (X52TSR_ENDIAN+8) + +#define RNXCTXWORDS 18 +#define RNXBLENLOC (RNXCTX+RNXCTXWORDS) +#define RNXBOUTLENLOC (RNXCTX+RNXCTXWORDS+1) + +#define RNXMAXTESTENT32 512 +#define CALDRBGMAXADDINLEN X52_BER_LEN-RNXAIDATAOFF-4 +#define CALDRBGMAXPSNONCELEN X52_BER_LEN-RNXAIDATAOFF-4 + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef DRBGF5200_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATR drbgf5200Ini(void); + +extern SATR drbgf5200TrfRes(SATBOOL bBlock); + +extern SATR drbgf5200instantiate(const SATUINT32_t *puiNonce, + SATUINT32_t uiNonceLen, const SATUINT32_t *puiPzStr, SATUINT32_t uiPzStrLen, + SATSYMKEYSIZE eStrength, SATUINT32_t uiEntropyFactor, + SATUINT32_t uiReseedLim, SATBOOL bTesting); + +extern SATR drbgf5200reseed(const SATUINT32_t *puiAddIn, + SATUINT32_t uiAddInLen); + +extern SATR drbgf5200generate(const SATUINT32_t *puiAddIn, + SATUINT32_t uiAddInLen, SATBOOL bPredResist, SATUINT32_t uiReqLen, + SATUINT32_t *puiOut); + +extern SATR drbgf5200uninstantiate(void); + +extern SATR drbgf5200getctx(DRBGCTXPTR drbgCtxExt); + +extern SATR drbgf5200loadctx(DRBGCTXPTR drbgCtxExt); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/hash.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/hash.h new file mode 100644 index 0000000..f3fd6d4 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/hash.h @@ -0,0 +1,102 @@ +/* ------------------------------------------------------------------- + $Rev: 1293 $ $Date: 2017-07-27 14:09:14 -0400 (Thu, 27 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL hash functions. + ------------------------------------------------------------------- */ + +#ifndef HASH_H +#define HASH_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ +extern const SATHASHSIZE uiHashWordLen[SATHASHTYPE_LAST]; + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef HASH_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALHash(SATHASHTYPE eHashType, const void *pMsg, + SATUINT32_t uiMsgLen, void *pHash); + +extern SATR CALHashDMA(SATHASHTYPE eHashType, const void *pMsg, + SATUINT32_t uiMsgLen, void *pHash, SATUINT32_t uiDMAChConfig); + +extern SATR CALHashCtx(const SATRESHANDLE hResource, + const SATRESCONTEXTPTR pContext, const void *pMsg, SATUINT32_t uiMsgLen, + void *pHash, const SATBOOL bFinal); + +extern SATR CALHashCtxIni(const SATRESCONTEXTPTR pContext, + const SATHASHTYPE eHashType); + +extern SATR CALHashIni(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen); + +extern SATR CALHashWrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR CALHashRead(void *pHash); + +extern SATR CALKeyTree(SATBOOL bPathSizeSel, const SATUINT32_t* puiKey, + SATUINT8_t uiOpType, const SATUINT32_t* puiPath, SATUINT32_t* puiKeyOut); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATUINT32_t iGetHashLen(SATHASHTYPE eHashType); + +extern SATUINT32_t iGetBlockLen(SATHASHTYPE eHashType); + +extern SATR CALHashCtxLoad(const SATRESHANDLE hResource, + SATRESCONTEXTPTR const pContext, SATUINT32_t uiRunLen); + +extern SATUINT32_t iGetRunLen(SATRESCONTEXTPTR const pContext); + +extern SATR CALHashTypeIni(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/mac.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/mac.h new file mode 100644 index 0000000..acdc767 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/mac.h @@ -0,0 +1,95 @@ +/* ------------------------------------------------------------------- + $Rev: 1296 $ $Date: 2017-08-01 13:54:48 -0400 (Tue, 01 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL MAC functions. + ------------------------------------------------------------------- */ + +#ifndef MAC_H +#define MAC_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef MAC_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALMAC(SATMACTYPE eMACType, const SATUINT32_t *pKey, SATUINT32_t uiKeyLen, + const void *pMsg, SATUINT32_t uiMsgLen, void *pMAC); + +extern SATR CALMACDMA(SATMACTYPE eMACType, const SATUINT32_t *pKey, + SATUINT32_t uiKeyLen, const void *pMsg, SATUINT32_t uiMsgLen, + const void *pMAC, SATUINT32_t uiDMAChConfig); + +extern SATR CALMACIni(SATMACTYPE eMACType, const SATUINT32_t *pKey, + SATUINT32_t uiKeyLen, SATUINT32_t uiMsgLen); + +extern SATR CALMACCtx(const SATRESHANDLE hResource, + const SATRESCONTEXTPTR pContext, const void *pMsg, SATUINT32_t uiMsgLen, + void *pHash, const SATUINT8_t uiFlag); + +extern SATR CALMACCtxIni(const SATRESCONTEXTPTR pContext, const SATHASHTYPE eHashType, + const SATUINT32_t *pKey, SATUINT32_t uiKeyLen); + +extern SATR CALMACWrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR CALMACRead(void *pMAC); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATUINT32_t iGetMACKeyLen(SATMACTYPE eMACType); + +extern SATR CALMACCtxLoad(const SATRESHANDLE hResource, + SATRESCONTEXTPTR const pContext, SATUINT32_t uiRunLen); + +extern SATUINT32_t iGetMACRunLen(SATRESCONTEXTPTR const pContext); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/miv-rv32i-user-crypto-lib.a b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/miv-rv32i-user-crypto-lib.a new file mode 100644 index 0000000..5fda638 Binary files /dev/null and b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/miv-rv32i-user-crypto-lib.a differ diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/miv-rv32imc-user-crypto-lib.a b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/miv-rv32imc-user-crypto-lib.a new file mode 100644 index 0000000..ee7bcf4 Binary files /dev/null and b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/miv-rv32imc-user-crypto-lib.a differ diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/nrbg.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/nrbg.h new file mode 100644 index 0000000..d517065 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/nrbg.h @@ -0,0 +1,83 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for NRBG functions for CAL. + ------------------------------------------------------------------- */ + +#ifndef NRBG_H +#define NRBG_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef NRBG_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALNRBGSetTestEntropy(SATUINT32_t * puiEntropy, + SATUINT32_t uiEntLen32); + +extern SATR CALNRBGGetEntropy(SATUINT32_t * puiEntropy, SATUINT32_t uiEntLen32, + SATBOOL bTesting); + +extern SATR CALNRBGConfig(SATUINT32_t uiWriteEn, SATUINT32_t uiCSR, + SATUINT32_t uiCntLim, SATUINT32_t uiVoTimer, SATUINT32_t uiFMsk, + SATUINT32_t* puiStatus); + +extern SATUINT32_t CALNRBGHealthStatus(void); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATUINT32_t CALNRBGGetTestEntLen(void); + +extern SATR nrbgpkxgetentropy(SATUINT32_t * puiEntropy, + SATUINT32_t uiEntLen32); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/pk.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/pk.h new file mode 100644 index 0000000..5983d9a --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/pk.h @@ -0,0 +1,302 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for for CAL PK. + ------------------------------------------------------------------- */ + +#ifndef PK_H +#define PK_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef PK_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALPKTrfRes(SATBOOL bBlock); + +extern SATR CALDSASign(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALDSASignCM(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALDSASignHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, const SATUINT32_t* puiK, + const SATUINT32_t* puiX, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, SATUINT32_t uiN, + SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALDSASignHashCM(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, const SATUINT32_t* puiK, + const SATUINT32_t* puiX, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, SATUINT32_t uiN, + SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALDSAVerify(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiY, const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, + const SATUINT32_t* puiQMu, SATUINT32_t uiN, SATUINT32_t uiL); + +extern SATR CALDSAVerifyHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, const SATUINT32_t* puiY, + const SATUINT32_t* puiR, const SATUINT32_t* puiS, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALECDHC(const SATUINT32_t* puiS, const SATUINT32_t* puiWx, + const SATUINT32_t* puiWy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t* puiK, const SATUINT32_t* puiR, + const SATUINT32_t* puiRMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiZ); + +extern SATR CALECDSASign(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALECDSASignTwist(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALECDSASignCM(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALECDSASignTwistCM(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALECDSASignHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiK, const SATUINT32_t* puiD, const SATUINT32_t* puiB, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSASignHashCM(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiK, const SATUINT32_t* puiD, const SATUINT32_t* puiB, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSASignTwistHash(const SATUINT32_t* puiMsg, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSAVerify(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS,const + SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress); + +extern SATR CALECDSAVerifyTwist(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALECDSAVerifyHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSAVerifyTwistHash(const SATUINT32_t* puiMsg, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALECMult(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECMultCM(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t* puiN, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress, SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECMultTwist(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiLen, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECMultTwistCM(const SATUINT32_t* puiMul, + const SATUINT32_t* puiPx, const SATUINT32_t* puiPy, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiMod,const SATUINT32_t* puiMu, + const SATUINT32_t* puiN, SATUINT32_t uiLen, SATUINT32_t* puiRx, + SATUINT32_t* puiRy); + +extern SATR CALECMultAdd(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiB, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen, SATUINT32_t uiPtPCompress, SATUINT32_t uiPtQCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECPtValidate(const SATUINT32_t* puiPx, const SATUINT32_t* puiPy, + const SATUINT32_t* puiB, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen); + +extern SATR CALECKeyPairGen(const SATUINT32_t* puiC, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + const SATUINT32_t* puiNM1, const SATUINT32_t* puiNM1Mu, const SATUINT32_t* puiB, + SATUINT32_t* puiD, SATUINT32_t* puiQx, SATUINT32_t* puiQy, SATUINT32_t uiLen); + +extern SATR CALExpo(const SATUINT32_t* puiBase, const SATUINT32_t* puiExpo, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALExpoCM(const SATUINT32_t* puiBase, const SATUINT32_t* puiExpo, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALMMult(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALMMultAdd(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiC, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALModRed(const SATUINT32_t* puiA, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiALen, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPreCompute(const SATUINT32_t* puiMod, SATUINT32_t* puiMu, + SATUINT32_t uiModLen); + +extern SATR CALRSACRT(const SATUINT32_t* puiCipher, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ,const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiLen, SATUINT32_t* puiPlain); + +extern SATR CALRSACRTCM(const SATUINT32_t* puiCipher, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t * puiE, const SATUINT32_t* puiP, + const SATUINT32_t* puiQ, const SATUINT32_t * puiN, + const SATUINT32_t * puiNMu, SATUINT32_t uiLen, SATUINT32_t uiELen, + SATUINT32_t* puiPlain); + +extern SATR CALRSACRTSign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + const SATUINT32_t* puiN, SATUINT32_t uiLen, SATUINT32_t* puiSig); + +extern SATR CALRSACRTSignCM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, const SATUINT32_t* puiQ, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSig); + +extern SATR CALRSACRTSignHash(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ,const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + const SATUINT32_t* puiN, SATUINT32_t uiMsgLen, SATUINT32_t uiModLen, + SATUINT32_t* puiSig, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALRSACRTSignHashCM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, const SATUINT32_t* puiQ, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, SATUINT32_t* puiSig, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALRSASign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiD, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, SATUINT32_t* puiSig); + +extern SATR CALRSASignHash(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiD, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, SATUINT32_t uiModLen, + SATUINT32_t* puiSig, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALRSAVerify(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, + const SATUINT32_t* puiSig); + +extern SATR CALRSAVerifyHash(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiE, SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, const SATUINT32_t* puiSig, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPurge52(SATBOOL bVerify); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/pkx.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/pkx.h new file mode 100644 index 0000000..c23dda4 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/pkx.h @@ -0,0 +1,409 @@ +/* ------------------------------------------------------------------- + $Rev: 1298 $ $Date: 2017-08-04 13:04:19 -0400 (Fri, 04 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for for CAL PK. + ------------------------------------------------------------------- */ + +#ifndef PKX_H +#define PKX_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* X5200 Addressing */ +#define X52BER ((volatile SATUINT32_t *) (PKX0_BASE + 0x00000000u)) +#define X52MMR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00001000u)) +#define X52TSR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00002000u)) +#define X52FPR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00003000u)) +#define X52LIR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00004000u)) +#define X52CSR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00007F80u)) +#define X52CSRMERRS ((volatile SATUINT32_t *) (PKX0_BASE + 0x00007F8Cu)) +#define X52CSRMERRT0 ((volatile SATUINT32_t *) (PKX0_BASE + 0x00007F94u)) + +#if SAT_LITTLE_ENDIAN +#define X52BER_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00008000u)) +#define X52MMR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00009000u)) +#define X52TSR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x0000A000u)) +#define X52FPR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x0000B000u)) +#define X52DMACONFIG_ENDIAN 0x8 +#else +#define X52BER_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00000000u)) +#define X52MMR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00001000u)) +#define X52TSR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00002000u)) +#define X52FPR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00003000u)) +#define X52DMACONFIG_ENDIAN 0x0 +#endif + +/* X5200 Macros */ +#define X52GO(x) (0x10 | ((x)<<8)) + +/* Counter Measures */ +#define RANDLEN 4 + +/* X5200 CSRMAIN bit field masks. */ +#define X52CSRMAINRST 1 +#define X52CSRMAINCCMPLT 2 +#define X52CSRMAINCMPLT 4 +#define X52CSRMAINBUSY 8 +#define X52CSRMAINGO 0x10 +#define X52CSRMAINPURGE 0x20 +#define X52CSRMAINECDIS 0x40 +#define X52CSRMAINALARM 0x80 +#define X52CSRMAINLIRA ((0xFFF) << 8) +#define X52CSRMERRSSEC ((0x2) << 24) +#define X52CSRMERRSA 0x1FFF + +/* Address pointers for ROM'd P-curve moduli */ +#define P192_MOD (&uiROMMods[0]) +#define P224_MOD (&uiROMMods[1]) +#define P256_MOD (&uiROMMods[2]) +#define P384_MOD (&uiROMMods[3]) +#define P521_MOD (&uiROMMods[4]) + +/* X5200 Addressing Flags */ +#define X52BYTEREVERSE_FLAG 1 +#define X52WORDREVERSE_FLAG 2 +#define X52BYTEREVERSE 0x00002000 +#define X52WORDREVERSE 0x00004000 +#define X52ADDRESSRANGE 0x2000 + +/* X5200 DMA channel configuration constants. */ +#define X52CCR_DEFAULT 0 /* BSIZE=auto, ESWP=none, PROT=user, INC=inc */ +#define X52CCR_BSIZEAUTO 0 /* BSIZE=auto */ +#define X52CCR_BSIZEBYTE 0x10 /* BSIZE=byte */ +#define X52CCR_BSIZEHWORD 0x20 /* BSIZE=half word */ +#define X52CCR_BSIZEWORD 0x30 /* BSIZE=word */ +#define X52CCR_ESWPNONE 0 /* ESWP=none */ +#define X52CCR_ESWPWORD 0x8 /* ESWP=swap bytes in word [0123]->[3210] */ +#define X52CCR_PROTUSER 0 /* PROT=user */ +#define X52CCR_PROTPRIV 0x2 /* PROT=priv */ +#define X52CCR_INCADDR 0 /* INC=inc */ +#define X52CCR_NOINCADDR 0x1 /* INC=non-inc */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef PKX_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern void CALPKXIni(void); + +extern void CALPKMem32Load(volatile SATUINT32_t * puiDst, + const SATUINT32_t * puiSrc, SATUINT32_t uiNum ); + +extern SATR CALPKXTrfRes(SATBOOL bBlock); + +extern SATR CALPKXPreCompute(const SATUINT32_t* puiMod, SATUINT32_t* puiMu, + SATUINT32_t uiModLen); + +extern SATR CALPKXExpo(const SATUINT32_t* puiBase, const SATUINT32_t* puiExpo, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALPKXExpoCM(const SATUINT32_t* puiBase, + const SATUINT32_t* puiExpo, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPKXDSASign(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXDSASignCM(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXDSASHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATUINT32_t uiDMAChConfig, const SATBOOL bCM); + +extern SATR CALPKXDSAVerify(const SATUINT32_t *puiHash, + const SATUINT32_t *puiG, const SATUINT32_t *puiY, + const SATUINT32_t *puiSigR, const SATUINT32_t *puiSigS, + const SATUINT32_t *puiP, const SATUINT32_t *puiPMu, + const SATUINT32_t *puiQ, const SATUINT32_t *puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL); + +extern SATR CALPKXDSAVHDMA(const SATUINT32_t *puiExtInput, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t *puiG, const SATUINT32_t *puiY, + const SATUINT32_t *puiSigR, const SATUINT32_t *puiSigS, + const SATUINT32_t *puiP, const SATUINT32_t *puiPMu, const SATUINT32_t *puiQ, + const SATUINT32_t *puiQMu, SATUINT32_t uiN, SATUINT32_t uiL, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXModRed(const SATUINT32_t* puiA, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiALen, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPKXMMult(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPKXMMultAdd(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiC, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALPKXECMult(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECMultTwist(const SATUINT32_t* puiMul, + const SATUINT32_t* puiPx,const SATUINT32_t* puiPy, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen, SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECMultCM(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t * puiN, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress, SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECMultTwistCM(const SATUINT32_t* puiMul, + const SATUINT32_t* puiPx, const SATUINT32_t* puiPy, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + const SATUINT32_t * puiN, SATUINT32_t uiLen, SATUINT32_t* puiRx, + SATUINT32_t* puiRy); + +extern SATR CALPKXECMultAdd(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiB, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen, SATUINT32_t uiPtPCompress, SATUINT32_t uiPtQCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECDSASign(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASignTwist(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx,const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASignCM(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASignTwistCM(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASH(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + const SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASHCM(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + const SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, SATUINT32_t uiDMAChConfig, + const SATBOOL bCM); + +extern SATR CALPKXECDSASTwistH(const SATUINT32_t* puiHash, + const SATHASHTYPE eHashType, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiK, const SATUINT32_t* puiD, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, const SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASTwistHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECDSAVerify(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVerifyTwist(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVH(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB,const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + const SATUINT32_t uiLen, const SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB,const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECDSAVTwistH(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, const SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVTwistHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECDHC(const SATUINT32_t* puiS, const SATUINT32_t* puiWx, + const SATUINT32_t* puiWy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t* puiK, const SATUINT32_t* puiR, + const SATUINT32_t* puiRMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiZ); + +extern SATR CALPKXRSACRT(const SATUINT32_t* puiCipher, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, SATUINT32_t uiLen, + SATUINT32_t* puiPlain); + +extern SATR CALPKXRSACRTCM(const SATUINT32_t* puiCipher, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiE, + const SATUINT32_t* puiP, const SATUINT32_t* puiQ, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, const SATUINT32_t uiLen, const SATUINT32_t uiELen, + SATUINT32_t* puiPlain); + +extern SATR CALPKXRSACRTSign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiCipher, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, + const SATUINT32_t* puiQMu, const SATUINT32_t* puiN, SATUINT32_t uiLen, + SATUINT32_t* puiS); + +extern SATR CALPKXRSACRTSignCM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, + const SATUINT32_t* puiP, const SATUINT32_t* puiQ, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSig); + +extern SATR CALPKXRSACRTSHDMA(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + const SATUINT32_t* puiN, SATUINT32_t uiMsgLen, SATUINT32_t uiModLen, + SATUINT32_t* puiSig, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXRSACRTSHDMACM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, + const SATUINT32_t* puiP, const SATUINT32_t* puiQ, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, SATUINT32_t uiLen, + SATUINT32_t* puiSig, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXRSASign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiD, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, SATUINT32_t* puiSig); + +extern SATR CALPKXRSASHDMA(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiD, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, SATUINT32_t* puiSig, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXRSAVerify(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, + const SATUINT32_t* puiS); + +extern SATR CALPKXRSAVHDMA(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiE,SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, const SATUINT32_t* puiS, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECPtValidate(const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiLen); + +extern SATR CALPKXECKeyPairGen(const SATUINT32_t* puiC, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + const SATUINT32_t* puiNM1, const SATUINT32_t* puiNM1Mu, const SATUINT32_t* puiB, + SATUINT32_t* puiD, SATUINT32_t* puiQx, SATUINT32_t* puiQy, SATUINT32_t uiLen); + +extern SATR CALPKXPurge52(SATBOOL bVerify); + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ +extern SATRESULT SATResults; + +/* -------- ------ --------- */ +/* External Global Constants */ +/* -------- ------ --------- */ +extern const SATUINT32_t uiROMMods[]; + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/pkxlib.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/pkxlib.h new file mode 100644 index 0000000..fb4c0fc --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/pkxlib.h @@ -0,0 +1,95 @@ +/* ------------------------------------------------------------------- + $Rev: 1434 $ $Date: 2017-10-20 16:46:16 -0400 (Fri, 20 Oct 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for PKX-5200 Library. + ------------------------------------------------------------------- */ + +#ifndef PKXLIB_H +#define PKXLIB_H + +#include "caltypes.h" +#include "calpolicy.h" + +#define PKX_JMP_NONE (0xFFFFu + PKX_OFFSET) + +/* jump table entry points: starting PC value */ +#define PKX_JMP_RECIP_PRECOMPUTE (0x0000 + PKX_OFFSET) +#define PKX_JMP_MOD_EXP (0x0002 + PKX_OFFSET) +#define PKX_JMP_RSA_CRT (0x0004 + PKX_OFFSET) +#define PKX_JMP_EC_PTMUL (0x0006 + PKX_OFFSET) +#define PKX_JMP_EC_DSA_SIGN (0x0008 + PKX_OFFSET) +#define PKX_JMP_EC_DSA_VERIFY (0x000A + PKX_OFFSET) +#define PKX_JMP_DSA_SIGN (0x000C + PKX_OFFSET) +#define PKX_JMP_DSA_VERIFY (0x000E + PKX_OFFSET) +#define PKX_JMP_MOD_MULT (0x0010 + PKX_OFFSET) +#define PKX_JMP_MOD_RED (0x0012 + PKX_OFFSET) +#define PKX_JMP_EC_PTDECOMP (0x0014 + PKX_OFFSET) +#define PKX_JMP_EC_DHC (0x0016 + PKX_OFFSET) +#define PKX_JMP_MOD_MULT_ADD (0x0018 + PKX_OFFSET) +#define PKX_JMP_EC_PTMUL_ADD (0x001A + PKX_OFFSET) +#define PKX_JMP_EC_PTVALIDATE (0x001C + PKX_OFFSET) +#define PKX_JMP_F5200_SHA (0x001E + PKX_OFFSET) +#define PKX_JMP_F5200_AES (0x0020 + PKX_OFFSET) +#define PKX_JMP_F5200_AESK (0x0022 + PKX_OFFSET) +#define PKX_JMP_F5200_GCM (0x0024 + PKX_OFFSET) +#define PKX_JMP_F5200_GHA (0x0026 + PKX_OFFSET) +#define PKX_JMP_F5200_AESKW (0x0028 + PKX_OFFSET) +#define PKX_JMP_F5200_AESKWP (0x002A + PKX_OFFSET) +#define PKX_JMP_RNG_INSTANTIATE (0x002C + PKX_OFFSET) +#define PKX_JMP_RNG_RESEED (0x002E + PKX_OFFSET) +#define PKX_JMP_RNG_GENERATE (0x0030 + PKX_OFFSET) +#define PKX_JMP_RNG_UNINSTANTIATE (0x0032 + PKX_OFFSET) +#define PKX_JMP_RNG_GETENTROPY (0x0034 + PKX_OFFSET) +#define PKX_JMP_F5200_SHA_HMAC (0x0036 + PKX_OFFSET) +#define PKX_JMP_F5200_AES_DMA (0x0038 + PKX_OFFSET) +#define PKX_JMP_RNG_CTRLSTATUS (0x003A + PKX_OFFSET) +#define PKX_JMP_F5200_SHA_DMA (0x003C + PKX_OFFSET) +#define PKX_JMP_SHX_KEYTREE (0x003E + PKX_OFFSET) +#define PKX_JMP_PKX_DSA_DMA (0x0040 + PKX_OFFSET) +#define PKX_JMP_PKX_RSACRT_SIGN (0x0042 + PKX_OFFSET) +#define PKX_JMP_PKX_RSA_SIGN (0x0044 + PKX_OFFSET) +#define PKX_JMP_PKX_RSA_VERIFY (0x0046 + PKX_OFFSET) +#define PKX_JMP_PKX_EC_DSA_DMA (0x0048 + PKX_OFFSET) +#define PKX_JMP_F5200_AES_KEYROLL (0x004A + PKX_OFFSET) +#define PKX_JMP_EXPM (0x004C + PKX_OFFSET) +#define PKX_JMP_RSACRTM (0x004E + PKX_OFFSET) +#define PKX_JMP_EC_PTMULM (0x0050 + PKX_OFFSET) +#define PKX_JMP_DSA_SIGN_M (0x0052 + PKX_OFFSET) +#define PKX_JMP_EC_DSA_SIGN_M (0x0054 + PKX_OFFSET) +#define PKX_JMP_EC_KEYPAIRGEN (0x0056 + PKX_OFFSET) +#define PKX_JMP_RSACRTCM_SIGN (0x0058 + PKX_OFFSET) +#define PKX_JMP_F5200_GCM_NEW (0x005A + PKX_OFFSET) +/* PKX PKRev 2180 */ +/* PKX SHARev 2160 */ +/* PKX AESRev 2135 */ +/* Hex Checksum: 0xd0d79866 */ + +extern const SATUINT32_t uiPKX_Flags; +extern const SATUINT32_t uiPKX_BERWords; +extern const SATUINT32_t uiPKX_LIRWords; +extern const SATUINT32_t uiPKX_Rev; +extern const SATUINT32_t uiPKX_LibSize; +extern const SATUINT32_t uiPKX_LibChksum; +extern const SATUINT32_t uiPKX_Lib[]; +extern SATBOOL bMPF300TS_ES; + +#endif diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/shaf5200.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/shaf5200.h new file mode 100644 index 0000000..da598d1 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/shaf5200.h @@ -0,0 +1,101 @@ +/* ------------------------------------------------------------------- + $Rev: 1296 $ $Date: 2017-08-01 13:54:48 -0400 (Tue, 01 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for SHA function hardware implementation for CAL. + ------------------------------------------------------------------- */ + +#ifndef SHAF5200_H +#define SHAF5200_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef SHAF5200_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATR shapkxctx(SATRESCONTEXTPTR const pContext, const void *pBuffer, + SATUINT32_t uiBufLen,void *pHash, const SATBOOL bFinal); + +extern SATR shapkxhmacctx(SATRESCONTEXTPTR const pContext, const void *pBuffer, + SATUINT32_t uiBufLen, void *pHash, const SATUINT8_t uiFlag); + +extern SATR shapkxctxload(SATRESCONTEXTPTR const pContext); + +extern void shapkxctxunload(SATRESCONTEXTPTR const pContext); + +extern SATR shapkxini(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen); + +extern SATR shapkxhmacini(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, + const void *pKey, SATUINT32_t uiKeyLen); + +extern SATR shapkxwrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR shapkxhmacwrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR shapkxread(void *pHash, SATUINT32_t uiRevFlag); + +extern SATR shapkxkeytree(SATBOOL bPathSizeSel, const SATUINT32_t* puiKey, + SATUINT8_t uiOpType, const SATUINT32_t* puiPath, SATUINT32_t* puiKeyOut); + +extern SATR shapkxdma(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, + const void *pExtSrc, const void *pExtDest, SATUINT32_t uiDMAChConfig); + +extern SATR shapkxhmacdma(SATMACTYPE eMACType, const SATUINT32_t *pKey, + SATUINT32_t uiKeyLen, const void *pMsg, SATUINT32_t uiMsgLen, + const void *pMAC, SATUINT32_t uiDMAChConfig); + +extern SATR shapkxhashtypeini(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/sym.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/sym.h new file mode 100644 index 0000000..2e07faa --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/sym.h @@ -0,0 +1,129 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for Symmetric Key Cryptography in CAL. + ------------------------------------------------------------------- */ + +#ifndef SYM_H +#define SYM_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef SYM_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALSymTrfRes(SATBOOL bBlock); + +extern SATR CALSymEncrypt(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen); + +extern SATR CALSymDecrypt(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen); + +extern SATR CALSymEncryptDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymDecryptDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymEncryptKR(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF); + +extern SATR CALSymDecryptKR(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF); + +extern SATR CALSymEncryptKRDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymDecryptKRDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymEncAuth(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen); + +extern SATR CALSymDecVerify(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen); + +extern SATR CALSymKw(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR CALSymKwp(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR CALSymEncAuthDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymDecVerifyDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen, SATUINT32_t uiDMAChConfig); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/utils.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/utils.h new file mode 100644 index 0000000..91474f0 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/utils.h @@ -0,0 +1,93 @@ +/* ------------------------------------------------------------------- + $Rev: 1300 $ $Date: 2017-08-07 11:36:02 -0400 (Mon, 07 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL utility functions. + ------------------------------------------------------------------- */ + +#ifndef UTILS_H +#define UTILS_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef UTILS_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern void CALMemCopy(void *pDst, const void *pSrc, SATUINT32_t uiNum8); + +extern void CALMemClear( void * pLoc, SATUINT32_t uiNum ); + +extern void CALMemClear32( SATUINT32_t* puiLoc, SATUINT32_t uiLen32 ); + +extern SATBOOL CALMemCmp(const void *pA, const void *pB, SATUINT32_t uiNum); + +extern void CALVol32MemLoad(volatile SATUINT32_t * puiDst, const void * pSrc, + SATUINT32_t uiNum32); + +extern void CALVol32MemRead(void * pDst, volatile SATUINT32_t * puiSrc, + SATUINT32_t uiNum32); + +extern void CALByteReverse(SATUINT32_t* puiArray, SATINT32_t iNumberBytes); + +extern void CALByteReverseWord(SATUINT32_t* puiArray, SATINT32_t iNumberWords); + +extern void CALWordReverse(SATUINT32_t *puiArray, SATINT32_t iNumberWords); + +extern void vAppendNonzero(void *puiArray, SATUINT32_t uiLen, + SATUINT32_t uiBlockSize); + +extern void vAppendZero(void *puiArray, SATUINT32_t uiLen, + SATUINT32_t uiBlockSize); + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/x52cfg_user.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/x52cfg_user.h new file mode 100644 index 0000000..c8d8648 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/middleware/cal/x52cfg_user.h @@ -0,0 +1,72 @@ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ +/* X5200 configuration */ +/* $Date: 2015-07-23 14:30:19 -0400 (Thu, 23 Jul 2015) $ $Rev: 2093 $ */ +/* ------------------------------------------------------------------- + Options: + * LIR ROM size : 4096 + * LIR RAM size : 2048 + * BER size : 1024 + * MMR size : 1024 + * TSR size : 1024 + * FPR size : 1024 + * Single error correct, dual error detect (SECDED) memory parity + * DMA enabled + * FPGA multipliers disabled + * AES enabled + - Fast key schedule generation + - GCM/GHASH enabled + - AES countermeasures enabled + * RNG enabled + * External PRNG disabled + * SHA enabled + - Fast SHA enabled + - SHA-1 enabled + - SHA-224 enabled + - SHA-256 enabled + - SHA-384 enabled + - SHA-512 enabled + - SHA-512/224 enabled + - SHA-512/256 enabled + - SHA countermeasures enabled + * P-curves populated in FCR: + - P-192 populated + - P-224 populated + - P-256 populated + - P-384 populated + - P-521 populated + * Data memory scrambling enabled + + ------------------------------------------------------------------- */ + +#ifndef X52CFG_H +#define X52CFG_H + +#define X52_CFG_MODEL 0xf5200 +#define X52_CFG_DATE 0x15072720 +#define X52_CFG_REV 0x0000082e +#define X52_CFG_OPT 0x0fd87ff9 +#define X52_CFG_OPT2 0xc0000000 +#define X52_LIR_LEN 0x1800 +#define X52_LIR_ROM_LEN 0x1000 +#define X52_LIR_RAM_LEN 0x0800 +#define X52_BER_LEN 0x400 +#define X52_MMR_LEN 0x400 +#define X52_TSR_LEN 0x400 +#define X52_FPR_LEN 0x400 + +#endif diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/README.md b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/README.md new file mode 100644 index 0000000..f7f6030 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/README.md @@ -0,0 +1,27 @@ +# Mi-V soft processor platform source code + +## Repo organization + +``` + + | + |-- drivers + | |- fpga_ip + | | | CoreGPIO + | | | CoreSysServices_PF + | | | CoreUARTapb + | | + | |- off_chip + | | | . + | | | . + | | + |-- hal + | | + |-- miv_rv32_hal + + +``` + +The drivers published here are compatible with the improved SoftConsole project folder structure being used in the latest [example projects](https://github.com/Mi-V-Soft-RISC-V/miv-rv32-bare-metal-examples). +These drivers can also be used with the legacy folder structure (projects released via Firmware Catalog) by defining the **LEGACY_DIR_STRUCTURE** macro in the SoftConsole project settings. + diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c new file mode 100644 index 0000000..1a0073f --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c @@ -0,0 +1,533 @@ +/******************************************************************************* + * (c) Copyright 2008-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file core_gpio.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreGPIO bare metal driver implementation. + * + */ +#include "coregpio_regs.h" +#include "core_gpio.h" + +/*-------------------------------------------------------------------------*//** + * + */ +#define GPIO_INT_ENABLE_MASK (uint32_t)0x00000008UL +#define OUTPUT_BUFFER_ENABLE_MASK 0x00000004UL + + +#define NB_OF_GPIO 32 + +#define CLEAR_ALL_IRQ32 (uint32_t)0xFFFFFFFF +#define CLEAR_ALL_IRQ16 (uint16_t)0xFFFF +#define CLEAR_ALL_IRQ8 (uint8_t)0xFF + +/*-------------------------------------------------------------------------*//** + * GPIO_init() + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_init +( + gpio_instance_t * this_gpio, + addr_t base_addr, + gpio_apb_width_t bus_width +) +{ + uint8_t i = 0; + addr_t cfg_reg_addr = base_addr; + + this_gpio->base_addr = base_addr; + this_gpio->apb_bus_width = bus_width; + + /* Clear configuration. */ + for( i = 0, cfg_reg_addr = base_addr; i < NB_OF_GPIO; ++i ) + { + HW_set_8bit_reg( cfg_reg_addr, 0 ); + cfg_reg_addr += 4; + } + /* Clear any pending interrupts */ + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, CLEAR_ALL_IRQ32 ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, (uint16_t)CLEAR_ALL_IRQ16 ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, (uint16_t)CLEAR_ALL_IRQ16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, (uint8_t)CLEAR_ALL_IRQ8 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_config + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_config +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint32_t config +) +{ + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + uint32_t cfg_reg_addr = this_gpio->base_addr; + cfg_reg_addr += (port_id * 4); + HW_set_32bit_reg( cfg_reg_addr, config ); + + /* + * Verify that the configuration was correctly written. Failure to read + * back the expected value may indicate that the GPIO port was configured + * as part of the hardware flow and cannot be modified through software. + * It may also indicate that the base address passed as parameter to + * GPIO_init() was incorrect. + */ + HAL_ASSERT( HW_get_32bit_reg( cfg_reg_addr ) == config ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_set_outputs + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_set_outputs +( + gpio_instance_t * this_gpio, + uint32_t value +) +{ + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, GPIO_OUT, value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, GPIO_OUT0, (uint16_t)value ); + HAL_set_16bit_reg( this_gpio->base_addr, GPIO_OUT1, (uint16_t)(value >> 16) ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT0, (uint8_t)value ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT1, (uint8_t)(value >> 8) ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT2, (uint8_t)(value >> 16) ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT3, (uint8_t)(value >> 24) ); + break; + + default: + HAL_ASSERT(0); + break; + } + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( GPIO_get_outputs( this_gpio ) == value ); +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_inputs + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_inputs +( + gpio_instance_t * this_gpio +) +{ + uint32_t gpio_in = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + gpio_in = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_IN ); + break; + + case GPIO_APB_16_BITS_BUS: + gpio_in |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_IN0 ); + gpio_in |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_IN1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + gpio_in |= HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN0 ); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN1 ) << 8); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN2 ) << 16); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return gpio_in; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_outputs + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_outputs +( + gpio_instance_t * this_gpio +) +{ + uint32_t gpio_out = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + gpio_out = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ); + break; + + case GPIO_APB_16_BITS_BUS: + gpio_out |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT0 ); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + gpio_out |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT0 ); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT1 ) << 8); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT2 ) << 16); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return gpio_out; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_set_output + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_set_output +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint8_t value +) +{ + HAL_ASSERT( port_id < NB_OF_GPIO ); + + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + { + uint32_t outputs_state; + + outputs_state = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ); + if ( 0 == value ) + { + outputs_state &= ~(1 << port_id); + } + else + { + outputs_state |= 1 << port_id; + } + HAL_set_32bit_reg( this_gpio->base_addr, GPIO_OUT, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ) == outputs_state ); + } + break; + + case GPIO_APB_16_BITS_BUS: + { + uint16_t outputs_state; + uint32_t gpio_out_reg_addr = this_gpio->base_addr + GPIO_OUT_REG_OFFSET + ((port_id >> 4) * 4); + + outputs_state = HW_get_16bit_reg( gpio_out_reg_addr ); + if ( 0 == value ) + { + outputs_state &= ~(1 << (port_id & 0x0F)); + } + else + { + outputs_state |= 1 << (port_id & 0x0F); + } + HW_set_16bit_reg( gpio_out_reg_addr, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HW_get_16bit_reg( gpio_out_reg_addr ) == outputs_state ); + } + break; + + case GPIO_APB_8_BITS_BUS: + { + uint8_t outputs_state; + uint32_t gpio_out_reg_addr = this_gpio->base_addr + GPIO_OUT_REG_OFFSET + ((port_id >> 3) * 4); + + outputs_state = HW_get_8bit_reg( gpio_out_reg_addr ); + if ( 0 == value ) + { + outputs_state &= ~(1 << (port_id & 0x07)); + } + else + { + outputs_state |= 1 << (port_id & 0x07); + } + HW_set_8bit_reg( gpio_out_reg_addr, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HW_get_8bit_reg( gpio_out_reg_addr ) == outputs_state ); + } + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_drive_inout + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_drive_inout +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + gpio_inout_state_t inout_state +) +{ + uint32_t config; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + switch( inout_state ) + { + case GPIO_DRIVE_HIGH: + /* Set output high */ + GPIO_set_output( this_gpio, port_id, 1 ); + + /* Enable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config |= OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + case GPIO_DRIVE_LOW: + /* Set output low */ + GPIO_set_output( this_gpio, port_id, 0 ); + + /* Enable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config |= OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + case GPIO_HIGH_Z: + /* Disable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config &= ~OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_enable_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_enable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t cfg_value; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + cfg_reg_addr += (port_id * 4); + cfg_value = HW_get_8bit_reg( cfg_reg_addr ); + cfg_value |= GPIO_INT_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, cfg_value ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_disable_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_disable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t cfg_value; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + cfg_reg_addr += (port_id * 4); + cfg_value = HW_get_8bit_reg( cfg_reg_addr ); + cfg_value &= ~GPIO_INT_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, cfg_value ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_clear_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_clear_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t irq_clr_value = ((uint32_t)1) << ((uint32_t)port_id); + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, irq_clr_value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, irq_clr_value >> 16 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, irq_clr_value >> 24 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_irq_sources + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_irq_sources +( + gpio_instance_t * this_gpio +) +{ + uint32_t intr_src = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + intr_src = HAL_get_32bit_reg( this_gpio->base_addr, IRQ ); + break; + + case GPIO_APB_16_BITS_BUS: + intr_src |= HAL_get_16bit_reg( this_gpio->base_addr, IRQ0 ); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + intr_src |= HAL_get_16bit_reg( this_gpio->base_addr, IRQ0 ); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ1 ) << 8); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ2 ) << 16); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return intr_src; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_clear_all_irq_sources + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_clear_all_irq_sources +( + gpio_instance_t * this_gpio, + uint32_t bitmask +) +{ + uint32_t irq_clr_value = bitmask; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, irq_clr_value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, irq_clr_value >> 16 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, irq_clr_value >> 24 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h new file mode 100644 index 0000000..88ba178 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h @@ -0,0 +1,722 @@ +/******************************************************************************* + * (c) Copyright 2008-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file core_gpio.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreGPIO bare metal driver public API. + * + */ + +/*=========================================================================*//** + @mainpage CoreGPIO Bare Metal Driver. + + @section intro_sec Introduction + The CoreGPIO hardware IP includes up to 32 general-purpose input/output GPIOs. + This driver provides a set of functions for controlling the GPIOs as part of a + bare-metal system where no operating system is available. These drivers + can be adapted for use as part of an operating system, but the implementation + of the adaptation layer between this driver and the operating system's driver + model is outside the scope of this driver. + + @section driver_configuration Driver Configuration + The individual IOs of CoreGPIO can be configured either in the hardware flow + or as part of the software application through calls to the GPIO_config() + function. GPIOs configured as part of the hardware are fixed and cannot be + modified using a call to the GPI_config() function. + + @section theory_op Theory of Operation + The CoreGPIO driver uses the Actel Hardware Abstraction Layer (HAL) to access + hardware registers. You must ensure that the Actel HAL is included as part of + your software project. The Actel HAL is available through the Actel Firmware + Catalog. + + The CoreGPIO driver functions are logically grouped into the following groups: + - Initialization + - Configuration + - Reading and writing GPIO state + - Interrupt control + + The CoreGPIO driver is initialized through a call to the GPIO_init() function. + The GPIO_init() function must be called before any other GPIO driver functions + can be called. + + Each GPIO port is individually configured through a call to the + GPIO_config() function. Configuration includes deciding if a GPIO port is + going to be used as input, output, or both. GPIO ports configured as inputs + are further configured to generate interrupts based on the state of input. + Interrupts is either level- or edge-sensitive. + Note that a CoreGPIO hardware instance is generated as part of the hardware + flow with a fixed configuration for some or all of its IOs. + Attempting to modify the configuration of such a hardware-configured IO using + the GPIO_config() function has no effect. + + The state of the GPIO ports can be read and written using the following + functions: + - GPIO_get_inputs() + - GPIO_get_outputs() + - GPIO_set_outputs() + - GPIO_drive_inout() + + Interrupts generated by GPIO ports configured as inputs are controlled using + the following functions: + - GPIO_enable_irq() + - GPIO_disable_irq() + - GPIO_clear_irq() + - GPIO_get_irq_sources() + - GPIO_clear_all_irq_sources() + + *//*=========================================================================*/ +#ifndef CORE_GPIO_H_ +#define CORE_GPIO_H_ + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + The gpio_id_t enumeration is used to identify GPIOs as part of the + parameter to functions: + - GPIO_config(), + - GPIO_drive_inout(), + - GPIO_enable_int(), + - GPIO_disable_int(), + - GPIO_clear_int() + */ +typedef enum __gpio_id_t +{ + GPIO_0 = 0, + GPIO_1 = 1, + GPIO_2 = 2, + GPIO_3 = 3, + GPIO_4 = 4, + GPIO_5 = 5, + GPIO_6 = 6, + GPIO_7 = 7, + GPIO_8 = 8, + GPIO_9 = 9, + GPIO_10 = 10, + GPIO_11 = 11, + GPIO_12 = 12, + GPIO_13 = 13, + GPIO_14 = 14, + GPIO_15 = 15, + GPIO_16 = 16, + GPIO_17 = 17, + GPIO_18 = 18, + GPIO_19 = 19, + GPIO_20 = 20, + GPIO_21 = 21, + GPIO_22 = 22, + GPIO_23 = 23, + GPIO_24 = 24, + GPIO_25 = 25, + GPIO_26 = 26, + GPIO_27 = 27, + GPIO_28 = 28, + GPIO_29 = 29, + GPIO_30 = 30, + GPIO_31 = 31 +} gpio_id_t; + +/*-------------------------------------------------------------------------*//** + Possible width of the APB bus + */ +typedef enum __gpio_apb_width_t +{ + GPIO_APB_8_BITS_BUS = 0, + GPIO_APB_16_BITS_BUS = 1, + GPIO_APB_32_BITS_BUS = 2, + GPIO_APB_UNKNOWN_BUS_WIDTH = 3 +} gpio_apb_width_t; + +/*-------------------------------------------------------------------------*//** + Structure instance holding all data regarding the CoreGPIO + */ +typedef struct __gpio_instance_t +{ + addr_t base_addr; + gpio_apb_width_t apb_bus_width; +} gpio_instance_t; + +/*-------------------------------------------------------------------------*//** + GPIO ports definitions used to identify GPIOs as part of the parameter to + function GPIO_set_outputs(). + These definitions are also be used to identity GPIO through logical operations + on the return value of function GPIO_get_inputs(). + # GPIO_0_MASK + # GPIO_1_MASK + # GPIO_2_MASK + # GPIO_3_MASK + # GPIO_4_MASK + # GPIO_5_MASK + # GPIO_6_MASK + # GPIO_7_MASK + # GPIO_8_MASK + # GPIO_9_MASK + # GPIO_10_MASK + # GPIO_11_MASK + # GPIO_12_MASK + # GPIO_13_MASK + # GPIO_14_MASK + # GPIO_15_MASK + # GPIO_16_MASK + # GPIO_17_MASK + # GPIO_18_MASK + # GPIO_19_MASK + # GPIO_20_MASK + # GPIO_21_MASK + # GPIO_22_MASK + # GPIO_23_MASK + # GPIO_24_MASK + # GPIO_25_MASK + # GPIO_26_MASK + # GPIO_27_MASK + # GPIO_28_MASK + # GPIO_29_MASK + # GPIO_30_MASK + # GPIO_31_MASK + */ +#define GPIO_0_MASK 0x00000001UL +#define GPIO_1_MASK 0x00000002UL +#define GPIO_2_MASK 0x00000004UL +#define GPIO_3_MASK 0x00000008UL +#define GPIO_4_MASK 0x00000010UL +#define GPIO_5_MASK 0x00000020UL +#define GPIO_6_MASK 0x00000040UL +#define GPIO_7_MASK 0x00000080UL +#define GPIO_8_MASK 0x00000100UL +#define GPIO_9_MASK 0x00000200UL +#define GPIO_10_MASK 0x00000400UL +#define GPIO_11_MASK 0x00000800UL +#define GPIO_12_MASK 0x00001000UL +#define GPIO_13_MASK 0x00002000UL +#define GPIO_14_MASK 0x00004000UL +#define GPIO_15_MASK 0x00008000UL +#define GPIO_16_MASK 0x00010000UL +#define GPIO_17_MASK 0x00020000UL +#define GPIO_18_MASK 0x00040000UL +#define GPIO_19_MASK 0x00080000UL +#define GPIO_20_MASK 0x00100000UL +#define GPIO_21_MASK 0x00200000UL +#define GPIO_22_MASK 0x00400000UL +#define GPIO_23_MASK 0x00800000UL +#define GPIO_24_MASK 0x01000000UL +#define GPIO_25_MASK 0x02000000UL +#define GPIO_26_MASK 0x04000000UL +#define GPIO_27_MASK 0x08000000UL +#define GPIO_28_MASK 0x10000000UL +#define GPIO_29_MASK 0x20000000UL +#define GPIO_30_MASK 0x40000000UL +#define GPIO_31_MASK 0x80000000UL + +/*-------------------------------------------------------------------------*//** + * GPIO modes + * # GPIO_INPUT_MODE + * # GPIO_OUTPUT_MODE + * # GPIO_INOUT_MODE + */ +#define GPIO_INPUT_MODE 0x0000000002UL +#define GPIO_OUTPUT_MODE 0x0000000005UL +#define GPIO_INOUT_MODE 0x0000000003UL + +/*-------------------------------------------------------------------------*//** + * Possible GPIO inputs interrupt configurations. + * # GPIO_IRQ_LEVEL_HIGH + * # GPIO_IRQ_LEVEL_LOW + * # GPIO_IRQ_EDGE_POSITIVE + * # GPIO_IRQ_EDGE_NEGATIVE + * # GPIO_IRQ_EDGE_BOTH + */ +#define GPIO_IRQ_LEVEL_HIGH 0x0000000000UL +#define GPIO_IRQ_LEVEL_LOW 0x0000000020UL +#define GPIO_IRQ_EDGE_POSITIVE 0x0000000040UL +#define GPIO_IRQ_EDGE_NEGATIVE 0x0000000060UL +#define GPIO_IRQ_EDGE_BOTH 0x0000000080UL + +/*-------------------------------------------------------------------------*//** + * Possible states for GPIO configured as INOUT + */ +typedef enum gpio_inout_state +{ + GPIO_DRIVE_LOW = 0, + GPIO_DRIVE_HIGH, + GPIO_HIGH_Z +} gpio_inout_state_t; + +/*-------------------------------------------------------------------------*//** + The GPIO_init() function initializes a CoreGPIO hardware instance and the data + structure associated with the CoreGPIO hardware instance. + Note that a CoreGPIO hardware instance is generated with a fixed configuration + for some or all of its IOs as part of the hardware flow. + Attempting to modify the configuration of such a hardware-configured IO using + the GPIO_config() function has no effect. + + @param this_gpio + Pointer to the gpio_instance_t data structure instance holding all data + regarding the CoreGPIO hardware instance being initialized. A pointer to the + same data structure is used in subsequent calls to the CoreGPIO driver + functions in order to identify the CoreGPIO instance that must perform the + operation implemented by the called driver function. + + @param base_addr + The base_addr parameter is the base address in the memory map of the + processor for the registers of the GPIO instance being initialized. + + @param bus_width + The bus_width parameter informs the driver of the APB bus width selected + during the hardware flow configuration of the CoreGPIO hardware instance. It + indicates to the driver whether the CoreGPIO hardware registers are visible + as 8, 16, or 32-bits registers. Allowed values are: + - GPIO_APB_8_BITS_BUS + - GPIO_APB_16_BITS_BUS + - GPIO_APB_32_BITS_BUS + + @return + none. + + @example + @code + #define COREGPIO_BASE_ADDR 0xC2000000 + + gpio_instance_t g_gpio; + + void system_init( void ) + { + GPIO_init( &g_gpio, COREGPIO_BASE_ADDR, GPIO_APB_32_BITS_BUS ); + } + @endcode + */ +void GPIO_init +( + gpio_instance_t * this_gpio, + addr_t base_addr, + gpio_apb_width_t bus_width +); + +/*-------------------------------------------------------------------------*//** + The GPIO_config() function is used to configure an individual GPIO port. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO port to be configured. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @param config + The config parameter specifies the configuration to be applied to the GPIO + port identified by the first parameter. It is a logical OR of GPIO mode and + interrupt mode. The interrupt mode is only relevant if the GPIO is + configured as an input. + - Possible modes are: + - GPIO_INPUT_MODE, + - GPIO_OUTPUT_MODE, + - GPIO_INOUT_MODE. + - Possible interrupt modes are: + - GPIO_IRQ_LEVEL_HIGH, + - GPIO_IRQ_LEVEL_LOW, + - GPIO_IRQ_EDGE_POSITIVE, + - GPIO_IRQ_EDGE_NEGATIVE, + - GPIO_IRQ_EDGE_BOTH + + @return + none. + + @example + For example, the following call configures GPIO 4 as an input that generates + interrupts on a low-to-high transition of the input: + @code + GPIO_config( &g_gpio, GPIO_4, GPIO_INPUT_MODE | GPIO_IRQ_EDGE_POSITIVE ); + @endcode + */ +void GPIO_config +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint32_t config +); + +/*-------------------------------------------------------------------------*//** + The GPIO_set_outputs() function is used to set the state of the GPIO ports + configured as outputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param value + The value parameter specifies the state of the GPIO ports configured as + outputs. It is a bit mask of the form (GPIO_n_MASK | GPIO_m_MASK), where n + and m are numbers identifying GPIOs. + For example, (GPIO_0_MASK | GPIO_1_MASK | GPIO_2_MASK ) specifies that the + first, second, and third GPIO must be set high and all other outputs set + low. + + @return + none. + + @example + Set GPIO 0 and 8 outputs high and all other GPIO outputs low. + @code + GPIO_set_outputs( &g_gpio, GPIO_0_MASK | GPIO_8_MASK ); + @endcode + + @example + Set GPIO 2 and 4 outputs low without affecting the other GPIO outputs. + @code + uint32_t gpio_outputs; + gpio_outputs = GPIO_get_outputs( &g_gpio ); + gpio_outputs &= ~( GPIO_2_MASK | GPIO_4_MASK ); + GPIO_set_outputs( &g_gpio, gpio_outputs ); + @endcode + + @see GPIO_get_outputs() + */ +void GPIO_set_outputs +( + gpio_instance_t * this_gpio, + uint32_t value +); + +/*-------------------------------------------------------------------------*//** + The GPIO_set_output() function is used to set the state of a single GPIO port + configured as an output. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter specifies the GPIO port that has its output set by a + call to this function. + + @param value + The value parameter specifies the desired state for the GPIO output. A value + of 0 sets the output low, and a value of 1 sets the port high. + + @return + none. + */ +void GPIO_set_output +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint8_t value +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_inputs() function is used to read the state of all GPIOs + configured as inputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @return + This function returns a 32-bit unsigned integer, where each bit represents + the state of an input. The least significant bit represents the state of + GPIO 0, and the most significant bit represents the state of GPIO 31. + */ +uint32_t GPIO_get_inputs +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_outputs() function is used to read the current state of all + GPIO outputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @return + This function returns a 32-bit unsigned integer where each bit represents + the state of an output. The least significant bit represents the state + of GPIO 0, and the most significant bit represents the state of GPIO 31. + */ +uint32_t GPIO_get_outputs +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_drive_inout() function is used to set the output state of a + GPIO configured as INOUT. An INOUT GPIO is in one of three states: + - high + - low + - high impedance + + An INOUT output is typically be used where several devices drive the state of + a signal. The high and low states are equivalent to the high and low states of + a GPIO configured as an output. The high impedance state is used to prevent + the GPIO from driving the state of the output and therefore allow reading the + state of the GPIO as an input. + Note that the GPIO port you wish to use as INOUT through this function + must be configurable through software. Therefore, the GPIO ports used as INOUT + must not have a fixed configuration selected as part of the hardware flow. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO for which this function will + change the output state. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @param inout_state + The inout_state parameter specifies the state of the I/O identified by the + first parameter. Possible states are: + - GPIO_DRIVE_HIGH, + - GPIO_DRIVE_LOW, + - GPIO_HIGH_Z (high impedance) + + @return + none. + + @example + The call to GPIO_drive_inout() below will set the GPIO 7 output to + high impedance state. + @code + GPIO_drive_inout( &g_gpio, GPIO_7, GPIO_HIGH_Z ); + @endcode + */ +void GPIO_drive_inout +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + gpio_inout_state_t inout_state +); + +/*-------------------------------------------------------------------------*//** + The GPIO_enable_irq() function is used to enable an interrupt to be + generated based on the state of the input identified as a parameter. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO input that the call to + GPIO_enable_irq() enables to generate interrupts. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + @example + The call to GPIO_enable_irq() below allows GPIO 8 to generate interrupts. + + @code + GPIO_enable_irq( &g_gpio, GPIO_8 ); + @endcode + */ +void GPIO_enable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_disable_irq() function is used to disable interrupts from being + generated based on the state of the input specified as a parameter. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO input that the call to + GPIO_disable_irq() disables from generating interrupts. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + @example + The call to GPIO_disable_irq() below prevents GPIO 8 from generating + interrupts. + @code + GPIO_disable_irq( &g_gpio, GPIO_8 ); + @endcode + */ +void GPIO_disable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_clear_irq() function is used to clear the interrupt generated by + the GPIO specified as a parameter. The GPIO_clear_irq() function must be + called as part of a GPIO interrupt service routine (ISR) in order to prevent + the same interrupt event from re-triggering a call to the GPIO ISR. + Note that interrupts may also need to be cleared in the processor's + interrupt controller. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO input for which to clear the + interrupt. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + @example + The example below demonstrates the use of the GPIO_clear_irq() function as + part of the GPIO-9 interrupt service routine. + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + GPIO_clear_irq( &g_gpio, GPIO_9 ); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +void GPIO_clear_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_irq_sources() function is used to identify the source of the + interrupt. i.e. to That is the GPIO input line, whose state change triggered + the interrupt. The GPIO_get_irq_sources() function must be called as part of + a GPIO interrupt service routine (ISR) in order to determine the interrupt + source. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @return + This function returns a 32-bit unsigned integer, where each bit represents + the pin number of a GPIO. + + @example + The example below demonstrates the use of the GPIO_get_irq_sources() + function as part of the GPIO-9 interrupt service routine. + + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + GPIO_clear_all_irq_sources(g_p_mygpio, GPIO_get_irq_sources(g_p_mygpio)); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +uint32_t GPIO_get_irq_sources +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_clear_all_irq_sources() function is used to clear all the active + interrupts generated by the GPIO specified as a parameter. The + GPIO_clear_all_irq_sources() function must be called as part of a GPIO + interrupt service routine (ISR) in order to prevent the same interrupt event + from re-triggering a call to the GPIO ISR. + Note that interrupts may also need to be cleared in the processor's + interrupt controller. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param bitmask + This bitmask parameter is a 32-bit unsigned integer where each bit + represents the GPIO pin used to clear the interrupt bit register of the + corresponding GPIO bit. The least significant bit represents the status of + GPIO 0, and the most significant bit represents the status of GPIO 31. + + @return + none. + + @example + The example below demonstrates the use of the GPIO_clear_all_irq_sources() + function as part of the GPIO-9 interrupt service routine. + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + do_interrupt_processing(); + + GPIO_clear_all_irq_sources(g_p_mygpio, GPIO_get_irq_sources(g_p_mygpio)); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +void GPIO_clear_all_irq_sources +( + gpio_instance_t * this_gpio, + uint32_t bitmask +); + +#ifdef __cplusplus +} +#endif + +#endif /* CORE_GPIO_H_ */ diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h new file mode 100644 index 0000000..41f5b7c --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h @@ -0,0 +1,45 @@ +/******************************************************************************* + * (c) Copyright 2008-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file coregpio_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreGPIO register definitions + * + */ + +#ifndef __CORE_GPIO_REGISTERS_H +#define __CORE_GPIO_REGISTERS_H 1 + +/*------------------------------------------------------------------------------ + * + */ +#define IRQ_REG_OFFSET 0x80 + +#define IRQ0_REG_OFFSET 0x80 +#define IRQ1_REG_OFFSET 0x84 +#define IRQ2_REG_OFFSET 0x88 +#define IRQ3_REG_OFFSET 0x8C + +/*------------------------------------------------------------------------------ + * + */ +#define GPIO_IN_REG_OFFSET 0x90 + +#define GPIO_IN0_REG_OFFSET 0x90 +#define GPIO_IN1_REG_OFFSET 0x94 +#define GPIO_IN2_REG_OFFSET 0x98 +#define GPIO_IN3_REG_OFFSET 0x9C + +/*------------------------------------------------------------------------------ + * + */ +#define GPIO_OUT_REG_OFFSET 0xA0 + +#define GPIO_OUT0_REG_OFFSET 0xA0 +#define GPIO_OUT1_REG_OFFSET 0xA4 +#define GPIO_OUT2_REG_OFFSET 0xA8 +#define GPIO_OUT3_REG_OFFSET 0xAC + +#endif /* __CORE_GPIO_REGISTERS_H */ diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c new file mode 100644 index 0000000..1fd3dd6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c @@ -0,0 +1,1495 @@ +/******************************************************************************* + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * CoreI2C software driver implementation. + * + */ + +#include "core_smbus_regs.h" +#include "core_i2c.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * I2C transaction direction. + */ +#define WRITE_DIR 0u +#define READ_DIR 1u + +/* -- TRANSACTIONS TYPES -- */ +#define NO_TRANSACTION 0u +#define MASTER_WRITE_TRANSACTION 1u +#define MASTER_READ_TRANSACTION 2u +#define MASTER_RANDOM_READ_TRANSACTION 3u +#define WRITE_SLAVE_TRANSACTION 4u +#define READ_SLAVE_TRANSACTION 5u + +/* -- SMBUS H/W STATES -- */ +/* -- MASTER STATES -- */ +#define ST_BUS_ERROR 0x00u /* Bus error during MST or selected slave modes */ +#define ST_I2C_IDLE 0xF8u /* No activity and no interrupt either... */ +#define ST_START 0x08u /* start condition sent */ +#define ST_RESTART 0x10u /* repeated start */ +#define ST_SLAW_ACK 0x18u /* SLA+W sent, ack received */ +#define ST_SLAW_NACK 0x20u /* SLA+W sent, nack received */ +#define ST_TX_DATA_ACK 0x28u /* Data sent, ACK'ed */ +#define ST_TX_DATA_NACK 0x30u /* Data sent, NACK'ed */ +#define ST_LOST_ARB 0x38u /* Master lost arbitration */ +#define ST_SLAR_ACK 0x40u /* SLA+R sent, ACK'ed */ +#define ST_SLAR_NACK 0x48u /* SLA+R sent, NACK'ed */ +#define ST_RX_DATA_ACK 0x50u /* Data received, ACK sent */ +#define ST_RX_DATA_NACK 0x58u /* Data received, NACK sent */ +#define ST_RESET_ACTIVATED 0xD0u /* Master reset is activated */ +#define ST_STOP_TRANSMIT 0xE0u /* Stop has been transmitted */ + +/* -- SLAVE STATES -- */ +#define ST_SLAVE_SLAW 0x60u /* SLA+W received */ +#define ST_SLAVE_SLAR_ACK 0xA8u /* SLA+R received, ACK returned */ +#define ST_SLV_LA 0x68u /* Slave lost arbitration */ +#define ST_GCA 0x70u /* GCA received */ +#define ST_GCA_LA 0x78u /* GCA lost arbitration */ +#define ST_RDATA 0x80u /* Data received */ +#define ST_SLA_NACK 0x88u /* Slave addressed, NACK returned */ +#define ST_GCA_ACK 0x90u /* Previously addresses with GCA, data ACKed */ +#define ST_GCA_NACK 0x98u /* GCA addressed, NACK returned */ +#define ST_RSTOP 0xA0u /* Stop received */ +#define ST_SLARW_LA 0xB0u /* Arbitration lost */ +#define ST_RACK 0xB8u /* Byte sent, ACK received */ +#define ST_SLAVE_RNACK 0xC0u /* Byte sent, NACK received */ +#define ST_FINAL 0xC8u /* Final byte sent, ACK received */ +#define ST_SLV_RST 0xD8u /* Slave reset state */ + + +/* I2C Channel base offset */ +#define CHANNEL_BASE_SHIFT 5u +#define CHANNEL_MASK 0x1E0u + +/* + * Maximum address offset length in slave write-read transactions. + * A maximum of two bytes will be interpreted as address offset within the slave + * tx buffer. + */ +#define MAX_OFFSET_LENGTH 2u + +/*------------------------------------------------------------------------------ + * I2C interrupts control functions implemented "i2c_interrupt.c". + * the implementation of these functions depend on the underlying hardware + * design and how the CoreI2C interrupt line is connected to the system's + * interrupt controller. + */ +void I2C_enable_irq( i2c_instance_t * this_i2c ); +void I2C_disable_irq( i2c_instance_t * this_i2c ); +static void enable_slave_if_required(i2c_instance_t * this_i2c); + +/*------------------------------------------------------------------------------ + * I2C_init() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_init +( + i2c_instance_t * this_i2c, + addr_t base_address, + uint8_t ser_address, + i2c_clock_divider_t ser_clock_speed +) +{ + psr_t saved_psr; + uint_fast16_t clock_speed = (uint_fast16_t)ser_clock_speed; + + /* + * We need to disable ints while doing this as there is no guarantee we + * have not been called already and the ISR is active. + */ + saved_psr = HAL_disable_interrupts(); + + /* + * Initialize all items of the this_i2c data structure to zero. This + * initializes all state variables to their init value. It relies on + * the fact that NO_TRANSACTION, I2C_SUCCESS and I2C_RELEASE_BUS all + * have an actual value of zero. + */ + memset(this_i2c, 0, sizeof(i2c_instance_t)); + + /* + * Set base address of I2C hardware used by this instance. + */ + this_i2c->base_address = base_address; + + /* + * Update Serial address of the device + */ + this_i2c->ser_address = ((uint_fast8_t)ser_address << 1u); + + /* + * Configure hardware. + */ + HAL_set_8bit_reg_field(this_i2c->base_address, ENS1, 0x00); /* Reset I2C hardware. */ + HAL_set_8bit_reg_field(this_i2c->base_address, ENS1, 0x01); /* set enable bit */ + HAL_set_8bit_reg_field(this_i2c->base_address, CR2, ( (clock_speed >> 2) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c->base_address, CR1, ( (clock_speed >> 1) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c->base_address, CR0, ( clock_speed & 0x01) ); + + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS, this_i2c->ser_address); + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, this_i2c->ser_address); + + /* + * Finally safe to enable interrupts. + */ + HAL_restore_interrupts( saved_psr ); +} +/*------------------------------------------------------------------------------ + * I2C_channel_init() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_channel_init +( + i2c_instance_t * this_i2c_channel, + i2c_instance_t * this_i2c, + i2c_channel_number_t channel_number, + i2c_clock_divider_t ser_clock_speed +) +{ + psr_t saved_psr; + uint_fast16_t clock_speed = (uint_fast16_t)ser_clock_speed; + + HAL_ASSERT(channel_number < I2C_MAX_CHANNELS); + HAL_ASSERT(I2C_CHANNEL_0 != channel_number); + + /* + * Cannot allow channel 0 in this function as we will trash the hardware + * base address and slave address. + */ + if ((channel_number < I2C_MAX_CHANNELS) && + (I2C_CHANNEL_0 != channel_number)) + { + /* + * We need to disable ints while doing this as the hardware should already + * be active at this stage. + */ + saved_psr = HAL_disable_interrupts(); + + /* + * Initialize channel data. + */ + memset(this_i2c_channel, 0, sizeof(i2c_instance_t)); + + this_i2c_channel->base_address = + ((this_i2c->base_address) & ~((addr_t)CHANNEL_MASK)) + | (((addr_t)channel_number) << CHANNEL_BASE_SHIFT); + + this_i2c_channel->ser_address = this_i2c->ser_address; + + HAL_set_8bit_reg_field(this_i2c_channel->base_address, ENS1, 0x00); /* Reset I2C channel hardware. */ + HAL_set_8bit_reg_field(this_i2c_channel->base_address, ENS1, 0x01); /* set enable bit */ + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR2, ( (clock_speed >> 2) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR1, ( (clock_speed >> 1) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR0, ( clock_speed & 0x01) ); + /* + * Finally safe to enable interrupts. + */ + HAL_restore_interrupts( saved_psr ); + } +} + +/*------------------------------------------------------------------------------ + * I2C_write() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_write +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * write_buffer, + uint16_t write_size, + uint8_t options +) +{ + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + saved_psr = HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_WRITE_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_WRITE_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + this_i2c->dir = WRITE_DIR; + this_i2c->master_tx_buffer = write_buffer; + this_i2c->master_tx_size = write_size; + this_i2c->master_tx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_read() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +) +{ + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + saved_psr = HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_READ_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_READ_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + + this_i2c->dir = READ_DIR; + + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_write_read() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_write_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * addr_offset, + uint16_t offset_size, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +) +{ + HAL_ASSERT(offset_size > 0u); + HAL_ASSERT(addr_offset != (uint8_t *)0); + HAL_ASSERT(read_size > 0u); + HAL_ASSERT(read_buffer != (uint8_t *)0); + + this_i2c->master_status = I2C_FAILED; + + if((read_size > 0u) && (offset_size > 0u)) + { + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + saved_psr = HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_RANDOM_READ_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_RANDOM_READ_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + + this_i2c->dir = WRITE_DIR; + + this_i2c->master_tx_buffer = addr_offset; + this_i2c->master_tx_size = offset_size; + this_i2c->master_tx_idx = 0u; + + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + + HAL_restore_interrupts( saved_psr ); + } +} + +/*------------------------------------------------------------------------------ + * I2C_get_status() + * See "core_i2c.h" for details of how to use this function. + */ +i2c_status_t I2C_get_status +( + i2c_instance_t * this_i2c +) +{ + i2c_status_t i2c_status ; + + i2c_status = this_i2c->master_status ; + + return i2c_status; +} + +/*------------------------------------------------------------------------------ + * I2C_wait_complete() + * See "core_i2c.h" for details of how to use this function. + */ +i2c_status_t I2C_wait_complete +( + i2c_instance_t * this_i2c, + uint32_t timeout_ms +) +{ + i2c_status_t i2c_status; + psr_t saved_psr; + /* + * Because we have no idea of what CPU we are supposed to be running on + * we need to guard this write to the timeout value to avoid ISR/user code + * interaction issues. Checking the status below should be fine as only a + * single byte should change in that. + */ + saved_psr = HAL_disable_interrupts(); + this_i2c->master_timeout_ms = timeout_ms; + HAL_restore_interrupts( saved_psr ); + + /* Run the loop until state returns I2C_FAILED or I2C_SUCESS*/ + do { + i2c_status = this_i2c->master_status; + } while(I2C_IN_PROGRESS == i2c_status); + return i2c_status; +} + +/*------------------------------------------------------------------------------ + * I2C_system_tick() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_system_tick +( + i2c_instance_t * this_i2c, + uint32_t ms_since_last_tick +) +{ + if(this_i2c->master_timeout_ms != I2C_NO_TIMEOUT) + { + if(this_i2c->master_timeout_ms > ms_since_last_tick) + { + this_i2c->master_timeout_ms -= ms_since_last_tick; + } + else + { + psr_t saved_psr; + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + /* + * Mark current transaction as having timed out. + */ + this_i2c->master_status = I2C_TIMED_OUT; + this_i2c->transaction = NO_TRANSACTION; + this_i2c->is_transaction_pending = 0; + + HAL_restore_interrupts( saved_psr ); + + /* + * Make sure we do not incorrectly signal a timeout for subsequent + * transactions. + */ + this_i2c->master_timeout_ms = I2C_NO_TIMEOUT; + } + } +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_tx_buffer() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_tx_buffer +( + i2c_instance_t * this_i2c, + const uint8_t * tx_buffer, + uint16_t tx_size +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + this_i2c->slave_tx_buffer = tx_buffer; + this_i2c->slave_tx_size = tx_size; + this_i2c->slave_tx_idx = 0u; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_rx_buffer() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_rx_buffer +( + i2c_instance_t * this_i2c, + uint8_t * rx_buffer, + uint16_t rx_size +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + this_i2c->slave_rx_buffer = rx_buffer; + this_i2c->slave_rx_size = rx_size; + this_i2c->slave_rx_idx = 0u; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_mem_offset_length() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_mem_offset_length +( + i2c_instance_t * this_i2c, + uint8_t offset_length +) +{ + HAL_ASSERT(offset_length <= MAX_OFFSET_LENGTH); + + /* + * Single byte update, should be interrupt safe + */ + if(offset_length > MAX_OFFSET_LENGTH) + { + this_i2c->slave_mem_offset_length = MAX_OFFSET_LENGTH; + } + else + { + this_i2c->slave_mem_offset_length = offset_length; + } +} + +/*------------------------------------------------------------------------------ + * I2C_register_write_handler() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_register_write_handler +( + i2c_instance_t * this_i2c, + i2c_slave_wr_handler_t handler +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + this_i2c->slave_write_handler = handler; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_enable_slave() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_enable_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register and slave mode flag without the I2C ISR interrupting + * us. + */ + saved_psr = HAL_disable_interrupts(); + + /* Set the Assert Acknowledge bit. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + /* Enable slave mode */ + this_i2c->is_slave_enabled = 1u; + + HAL_restore_interrupts( saved_psr ); + + /* Enable I2C IRQ*/ + I2C_enable_irq( this_i2c ); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_slave() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_disable_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + /* Reset the assert acknowledge bit. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + + /* Disable slave mode with IRQ blocked to make whole change atomic */ + this_i2c->is_slave_enabled = 0u; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * + */ +static void enable_slave_if_required +( + i2c_instance_t * this_i2c +) +{ + /* + * This function is only called from within the ISR and so does not need + * guarding on the register access. + */ + if( 0 != this_i2c->is_slave_enabled ) + { + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x01u ); + } +} +/*------------------------------------------------------------------------------ + * I2C_set_slave_second_addr() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_slave_second_addr +( + i2c_instance_t * this_i2c, + uint8_t second_slave_addr +) +{ + uint8_t second_slave_address; + + /* + This function does not support CoreI2C hardware configured with a fixed + second slave address. The current implementation of the ADDR1[0] register + bit makes it difficult for the driver to support both programmable and + fixed second slave address, so we choose to support programmable only. + With the programmable configuration, ADDR1[0] and ADDR0[0] both control + enable/disable of GCA recognition, as an effective OR of the 2 bit fields. + Therefore we set ADDR1[0] to 0 here, so that only ADDR0[0] controls GCA. + */ + second_slave_address = (uint8_t)((second_slave_addr << 1u) & (~SLAVE1_EN_MASK)); + + /* + * Single byte register write, should be interrupt safe + */ + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, second_slave_address); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_slave_second_addr() + * See "i2c.h" for details of how to use this function. + */ +void I2C_disable_slave_second_addr +( + i2c_instance_t * this_i2c +) +{ + /* + We are disabling the second slave address by setting the value of the 2nd + slave address to the primary slave address. The reason for using this method + of disabling 2nd slave address is that ADDRESS1[0] has different meaning + depending on hardware configuration. Its use would likely interfere with + the intended GCA setting. + */ + /* + * Single byte register write, should be interrupt safe + */ + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, this_i2c->ser_address); +} + +/*------------------------------------------------------------------------------ + * i2C_set_gca() + * See "i2c.h" for details of how to use this function. + */ + +void I2C_set_gca +( + i2c_instance_t * this_i2c +) +{ + /* + * This read modify write access should be interrupt safe as the address + * register is not written to in the ISR. + */ + /* accept GC addressing. */ + HAL_set_8bit_reg_field(this_i2c->base_address, GC, 0x01u); +} + +/*------------------------------------------------------------------------------ + * I2C_clear_gca() + * See "i2c.h" for details of how to use this function. + */ +void I2C_clear_gca +( + i2c_instance_t * this_i2c +) +{ + /* + * This read modify write access should be interrupt safe as the address + * register is not written to in the ISR. + */ + /* Clear GC addressing. */ + HAL_set_8bit_reg_field(this_i2c->base_address, GC, 0x00u); +} + +/*------------------------------------------------------------------------------ + * I2C_isr() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_isr +( + i2c_instance_t * this_i2c +) +{ + volatile uint8_t status; + uint8_t data; + uint8_t hold_bus; + uint8_t clear_irq = 1u; + + status = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + + switch( status ) + { + /************** MASTER TRANSMITTER / RECEIVER *******************/ + + case ST_START: /* start has been xmt'd */ + case ST_RESTART: /* repeated start has been xmt'd */ + HAL_set_8bit_reg_field( this_i2c->base_address, STA, 0x00u); + HAL_set_8bit_reg( this_i2c->base_address, DATA, this_i2c->target_addr); /* write call address */ + HAL_set_8bit_reg_field( this_i2c->base_address, DIR, this_i2c->dir); /* set direction bit */ + if(this_i2c->dir == WRITE_DIR) + { + this_i2c->master_tx_idx = 0u; + } + else + { + this_i2c->master_rx_idx = 0u; + } + + /* + * Clear the pending transaction. This condition will be true if the slave + * has acquired the bus to carry out pending master transaction which + * it had received during its slave transmission or reception mode. + */ + if(this_i2c->is_transaction_pending) + { + this_i2c->is_transaction_pending = 0u; + } + + /* + * Make sure to update proper transaction after master START + * or RESTART + */ + if(this_i2c->transaction != this_i2c->pending_transaction) + { + this_i2c->transaction = this_i2c->pending_transaction; + } + break; + + case ST_LOST_ARB: + /* Set start bit. Let's keep trying! Don't give up! */ + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + break; + + case ST_STOP_TRANSMIT: + /* Stop has been transmitted. Do nothing */ + break; + + /******************* MASTER TRANSMITTER *************************/ + case ST_SLAW_NACK: + /* SLA+W has been transmitted; not ACK has been received - let's stop. */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_FAILED; + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + case ST_SLAW_ACK: + case ST_TX_DATA_ACK: + /* data byte has been xmt'd with ACK, time to send stop bit or repeated start. */ + if (this_i2c->master_tx_idx < this_i2c->master_tx_size) + { + HAL_set_8bit_reg(this_i2c->base_address, DATA, (uint_fast8_t)this_i2c->master_tx_buffer[this_i2c->master_tx_idx++]); + } + else if ( this_i2c->transaction == MASTER_RANDOM_READ_TRANSACTION ) + { + /* We are finished sending the address offset part of a random read transaction. + * It is is time to send a restart in order to change direction. */ + this_i2c->dir = READ_DIR; + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + else /* done sending. let's stop */ + { + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + hold_bus = this_i2c->options & I2C_HOLD_BUS; + + /* Store the information of current I2C bus status in the bus_status*/ + this_i2c->bus_status = hold_bus; + if ( hold_bus == 0u ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); /*xmt stop condition */ + enable_slave_if_required(this_i2c); + } + else + { + I2C_disable_irq( this_i2c ); + clear_irq = 0u; + } + this_i2c->master_status = I2C_SUCCESS; + } + break; + + case ST_TX_DATA_NACK: + /* data byte SENT, ACK to be received + * In fact, this means we've received a NACK (This may not be + * obvious, but if we've rec'd an ACK then we would be in state + * 0x28!) hence, let's send a stop bit + */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u);/* xmt stop condition */ + this_i2c->master_status = I2C_FAILED; + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + /********************* MASTER (or slave?) RECEIVER *************************/ + + /* STATUS codes 08H, 10H, 38H are all covered in MTX mode */ + case ST_SLAR_ACK: /* SLA+R tx'ed. */ + /* Let's make sure we ACK the first data byte received (set AA bit in CTRL) unless + * the next byte is the last byte of the read transaction. + */ + if(this_i2c->master_rx_size > 1u) + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + } + else if(1u == this_i2c->master_rx_size) + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + else /* this_i2c->master_rx_size == 0u */ + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_SUCCESS; + this_i2c->transaction = NO_TRANSACTION; + } + break; + + case ST_SLAR_NACK: /* SLA+R tx'ed; let's release the bus (send a stop condition) */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_FAILED; + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + case ST_RX_DATA_ACK: /* Data byte received, ACK returned */ + /* First, get the data */ + this_i2c->master_rx_buffer[this_i2c->master_rx_idx++] = HAL_get_8bit_reg(this_i2c->base_address, DATA); + if( this_i2c->master_rx_idx >= (this_i2c->master_rx_size - 1u)) + { + /* If we're at the second last byte, let's set AA to 0 so + * we return a NACK at the last byte. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + break; + + case ST_RX_DATA_NACK: /* Data byte received, NACK returned */ + /* Get the data, then send a stop condition */ + this_i2c->master_rx_buffer[this_i2c->master_rx_idx] = HAL_get_8bit_reg(this_i2c->base_address, DATA); + + hold_bus = this_i2c->options & I2C_HOLD_BUS; + + /* Store the information of current I2C bus status in the bus_status*/ + this_i2c->bus_status = hold_bus; + if ( hold_bus == 0u ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); /*xmt stop condition */ + + /* Bus is released, now we can start listening to bus, if it is slave */ + enable_slave_if_required(this_i2c); + } + else + { + I2C_disable_irq( this_i2c ); + clear_irq = 0u; + } + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + this_i2c->master_status = I2C_SUCCESS; + break; + + /******************** SLAVE RECEIVER **************************/ + case ST_GCA_NACK: /* NACK after, GCA addressing */ + case ST_SLA_NACK: /* Re-enable AA (assert ack) bit for future transmissions */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + this_i2c->transaction = NO_TRANSACTION; + this_i2c->slave_status = I2C_SUCCESS; + + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + break; + + case ST_GCA_LA: /* Arbitr. lost (GCA rec'd) */ + case ST_SLV_LA: /* Arbitr. lost (SLA rec'd) */ + /* + * We lost arbitration and either the GCE or our address was the + * one received so pend the master operation we were starting. + */ + this_i2c->is_transaction_pending = 1u; + /* Fall through to normal ST processing as we are now in slave mode */ + + case ST_GCA: /* General call address received, ACK returned */ + case ST_SLAVE_SLAW: /* SLA+W received, ACK returned */ + this_i2c->transaction = WRITE_SLAVE_TRANSACTION; + this_i2c->slave_rx_idx = 0u; + this_i2c->random_read_addr = 0u; + /* + * If Start Bit is set clear it, but store that information since it is because of + * pending transaction + */ + if(HAL_get_8bit_reg_field(this_i2c->base_address, STA)) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + this_i2c->is_transaction_pending = 1u; + } + this_i2c->slave_status = I2C_IN_PROGRESS; +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + /* Fall through to put address as first byte in payload buffer */ +#else + /* Only break from this case if the slave address must NOT be included at the + * beginning of the received write data. */ + break; +#endif + case ST_GCA_ACK: /* DATA received; ACK sent after GCA */ + case ST_RDATA: /* DATA received; must clear DATA register */ + if((this_i2c->slave_rx_buffer != (uint8_t *)0) + && (this_i2c->slave_rx_idx < this_i2c->slave_rx_size)) + { + data = HAL_get_8bit_reg(this_i2c->base_address, DATA); + this_i2c->slave_rx_buffer[this_i2c->slave_rx_idx++] = data; + +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + if((ST_RDATA == status) || (ST_GCA_ACK == status)) + { + /* Ignore the slave address byte in the random read address + computation in the case where INCLUDE_SLA_IN_RX_PAYLOAD + is defined. */ +#endif + this_i2c->random_read_addr = (this_i2c->random_read_addr << 8) + data; +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + } +#endif + } + + if(this_i2c->slave_rx_idx >= this_i2c->slave_rx_size) + { + /* Rx buffer is full. NACK next received byte. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + break; + + case ST_RSTOP: + /* STOP or repeated START occurred. */ + /* We cannot be sure if the transaction has actually completed as + * this hardware state reports that either a STOP or repeated START + * condition has occurred. We assume that this is a repeated START + * if the transaction was a write from the master to this point.*/ + if ( this_i2c->transaction == WRITE_SLAVE_TRANSACTION ) + { + if ( this_i2c->slave_rx_idx == this_i2c->slave_mem_offset_length ) + { + this_i2c->slave_tx_idx = this_i2c->random_read_addr; + } + /* Call the slave's write transaction handler if it exists. */ + if ( this_i2c->slave_write_handler != 0u ) + { + i2c_slave_handler_ret_t h_ret; + h_ret = this_i2c->slave_write_handler( this_i2c, this_i2c->slave_rx_buffer, (uint16_t)this_i2c->slave_rx_idx ); + if ( I2C_REENABLE_SLAVE_RX == h_ret ) + { + /* There is a small risk that the write handler could + * call I2C_disable_slave() but return + * I2C_REENABLE_SLAVE_RX in error so we only enable + * ACKs if still in slave mode. */ + enable_slave_if_required(this_i2c); + } + else + { + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x0u ); + /* Clear slave mode flag as well otherwise in mixed + * master/slave applications, the AA bit will get set by + * subsequent master operations. */ + this_i2c->is_slave_enabled = 0u; + } + } + else + { + /* Re-enable address acknowledge in case we were ready to nack the next received byte. */ + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x01u ); + } + } + else /* A stop or repeated start outside a write/read operation */ + { + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * See if we need to re-enable acknowledgement as some error conditions, such + * as a master prematurely ending a transfer, can see us get here with AA set + * to 0 which will disable slave operation if we are not careful. + */ + enable_slave_if_required(this_i2c); + } + + /* Mark any previous master write transaction as complete. */ + this_i2c->slave_status = I2C_SUCCESS; + + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + + break; + + case ST_SLV_RST: /* SMBUS ONLY: timeout state. must clear interrupt */ + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction. + */ + this_i2c->transaction = NO_TRANSACTION; + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * Clear status to I2C_FAILED only if there was an operation in progress. + */ + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->slave_status = I2C_FAILED; + } + + enable_slave_if_required(this_i2c); /* Make sure AA is set correctly */ + + break; + + /****************** SLAVE TRANSMITTER **************************/ + case ST_SLAVE_SLAR_ACK: /* SLA+R received, ACK returned */ + case ST_SLARW_LA: /* Arbitration lost, and: */ + case ST_RACK: /* Data tx'ed, ACK received */ + if ( status == ST_SLAVE_SLAR_ACK ) + { + this_i2c->transaction = READ_SLAVE_TRANSACTION; + this_i2c->random_read_addr = 0u; + this_i2c->slave_status = I2C_IN_PROGRESS; + /* If Start Bit is set clear it, but store that information since it is because of + * pending transaction + */ + if(HAL_get_8bit_reg_field(this_i2c->base_address, STA)) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + this_i2c->is_transaction_pending = 1u; + } + } + if (this_i2c->slave_tx_idx >= this_i2c->slave_tx_size) + { + /* Ensure 0xFF is returned to the master when the slave specifies + * an empty transmit buffer. */ + HAL_set_8bit_reg(this_i2c->base_address, DATA, 0xFFu); + } + else + { + /* Load the data the data byte to be sent to the master. */ + HAL_set_8bit_reg(this_i2c->base_address, DATA, (uint_fast8_t)this_i2c->slave_tx_buffer[this_i2c->slave_tx_idx++]); + } + /* Determine if this is the last data byte to send to the master. */ + if (this_i2c->slave_tx_idx >= this_i2c->slave_tx_size) /* last byte? */ + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + /* Next read transaction will result in slave's transmit buffer + * being sent from the first byte. */ + this_i2c->slave_tx_idx = 0u; + } + break; + + case ST_SLAVE_RNACK: /* Data byte has been transmitted; not-ACK has been received. */ + case ST_FINAL: /* Last Data byte tx'ed, ACK received */ + /* We assume that the transaction will be stopped by the master. + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. */ + this_i2c->slave_tx_idx = 0u; + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + /* Mark previous state as complete */ + this_i2c->slave_status = I2C_SUCCESS; + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + + break; + + /* Master Reset has been activated Wait 35 ms for interrupt to be set, + * clear interrupt and proceed to 0xF8 state. */ + case ST_RESET_ACTIVATED: + case ST_BUS_ERROR: /* Bus error during MST or selected slave modes */ + default: + /* Some undefined state has encountered. Clear Start bit to make + * sure, next good transaction happen */ + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction. + */ + this_i2c->transaction = NO_TRANSACTION; + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * Clear statuses to I2C_FAILED only if there was an operation in progress. + */ + if(I2C_IN_PROGRESS == this_i2c->master_status) + { + this_i2c->master_status = I2C_FAILED; + } + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->slave_status = I2C_FAILED; + } + + break; + } + + if ( clear_irq ) + { + /* clear interrupt. */ + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + /* Read the status register to ensure the last I2C registers write took place + * in a system built around a bus making use of posted writes. */ + status = HAL_get_8bit_reg( this_i2c->base_address, STATUS); +} + +/*------------------------------------------------------------------------------ + * I2C_smbus_init() + * See "i2c.h" for details of how to use this function. + */ + +/* + * SMBSUS_NO = 1 + * SMBALERT_NO = 1 + * SMBus enable = 1 + */ +#define INIT_AND_ENABLE_SMBUS 0x54u +void I2C_smbus_init +( + i2c_instance_t * this_i2c +) +{ + /* + * Single byte register write, should be interrupt safe + */ + /* Enable SMBUS */ + HAL_set_8bit_reg(this_i2c->base_address, SMBUS, INIT_AND_ENABLE_SMBUS); +} + +/*------------------------------------------------------------------------------ + * I2C_enable_smbus_irq() + * See "i2c.h" for details of how to use this function. + */ +void I2C_enable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + if ( irq_type & I2C_SMBALERT_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_IE, 0x01u); + } + if ( irq_type & I2C_SMBSUS_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_IE, 0x01u); + } + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_smbus_irq() + * See "i2c.h" for details of how to use this function. + */ +void I2C_disable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + if ( irq_type & I2C_SMBALERT_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_IE, 0x00u); + } + if (irq_type & I2C_SMBSUS_IRQ ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_IE, 0x00u); + } + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_suspend_smbus_slave() + * See "i2c.h" for details of how to use this function. + */ +void I2C_suspend_smbus_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_NO_CONTROL, 0x00u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_resume_smbus_slave() + * See "i2c.h" for details of how to use this function. + */ +void I2C_resume_smbus_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_NO_CONTROL, 0x01u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_reset_smbus() + * See "i2c.h" for details of how to use this function. + */ +void I2C_reset_smbus +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + HAL_set_8bit_reg_field(this_i2c->base_address, SMBUS_MST_RESET, 0x01u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_smbus_alert() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_smbus_alert +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_NO_CONTROL, 0x00u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_clear_smbus_alert() + * See "i2c.h" for details of how to use this function. + */ +void I2C_clear_smbus_alert +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_NO_CONTROL, 0x01u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_get_irq_status() + * See "i2c.h" for details of how to use this function. + */ +uint8_t I2C_get_irq_status +( + i2c_instance_t * this_i2c +) +{ + uint8_t status ; + uint8_t irq_type = I2C_NO_IRQ ; + + status = HAL_get_8bit_reg(this_i2c->base_address, SMBUS); + + if( status & (uint8_t)SMBALERT_NI_STATUS_MASK ) + { + irq_type |= I2C_SMBALERT_IRQ ; + } + + if( status & (uint8_t)SMBSUS_NI_STATUS_MASK ) + { + irq_type |= I2C_SMBSUS_IRQ ; + } + + status = HAL_get_8bit_reg(this_i2c->base_address, CONTROL); + + if( status & (uint8_t)SI_MASK ) + { + irq_type |= I2C_INTR_IRQ ; + } + return(irq_type); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_addr2() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_user_data +( + i2c_instance_t * this_i2c, + void * p_user_data +) +{ + this_i2c->p_user_data = p_user_data ; +} + +/*------------------------------------------------------------------------------ + * I2C_get_user_data() + * See "i2c.h" for details of how to use this function. + */ +void * I2C_get_user_data +( + i2c_instance_t * this_i2c +) +{ + return( this_i2c->p_user_data); +} + +#ifdef __cplusplus +} +#endif + diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h new file mode 100644 index 0000000..3891ce0 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h @@ -0,0 +1,2306 @@ +/***************************************************************************//** + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * CoreI2C software driver Application Programming Interface. + * This file contains defines and function declarations allowing to interface + * with the CoreI2C software driver. + * + */ +/*=========================================================================*//** + @mainpage CoreI2C Bare Metal Driver. + The CoreI2C bare metal software driver supports I2C master and slave + operations. + + ============================================================================== + Introduction + ============================================================================== + The CoreI2C driver provides a set of functions for controlling the Microchip + CoreI2C hardware IP. The driver supports up to 16 separate I2C channels per + CoreI2C instance, with common slave address settings shared between channels + on a device. + + Optional features of the CoreI2C allow it to operate with I2C based protocols + such as System Management Bus (SMBus), Power Management Bus (PMBus), and + Intelligent Platform Management Interface (IPMI). This driver provides support + for these features when enabled in the CoreI2C IP. + + The major features provided by CoreI2C driver: + - Provides support to configuring the I2C channels of each CoreI2C peripheral device. + - I2C master operations. + - I2C slave operations. + - SMBus related operations. + + This driver is used as part of a bare metal system where no operating + system is available. The driver gets adapted as a part of an operating system, + but the implementation of the adaptation layer between the driver and the operating + system's driver model is outside the scope of this driver. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + Your application software should configure the CoreI2C driver through + calls to the I2C_init() function for each CoreI2C instance in the + hardware design. The configuration parameters include the CoreI2C hardware + instance base address and other runtime parameters, such as the I2C serial + clock frequency and the I2C device address. + + Once channel 0 of a CoreI2C peripheral has been initialized by I2C_init(), + any additional channels present should be configured by calling + I2C_channel_init() for each of the remaining channels. + + Apart from the CoreI2C hardware instance base address, no CoreI2C hardware configuration + parameters are used by the driver. Hence, no additional configuration files are required + to use the driver. + + -------------------------------- + Interrupt Control + -------------------------------- + The CoreI2C driver has to enable and disable the generation of interrupts by + CoreI2C at various times when it is operating. This enabling and disabling of + interrupts must be done through the system’s interrupt controller. For that + reason, the method of controlling the CoreI2C interrupt is system specific + and it is necessary to customize the I2C_enable_irq() and I2C_disable_irq() + functions. These functions are available in the i2c_interrupt.c file. + The default implementation calls HAL_ASSERT(0) to indicate to the application + developer that a suitable implementations for these functions must be provided. + + The implementation of the I2C_enable_irq() function should permit interrupts + generated by a CoreI2C instance to interrupt the processor. The implementation + of the I2C_disable_irq() function should prevent interrupts generated by a + CoreI2C instance from interrupting the processor. See the provided example + projects for a working implementation of these functions. + + The I2C_register_write_handler() function registers a write handler + function with the CoreI2C driver that calls on completion of an I2C write + transaction by the CoreI2C slave. It is your responsibility to create and + register the implementation of this handler function that processes or + trigger the processing of the received data. + + The SMBSUS and SMBALERT interrupts are related to the SMBus interface and are + enabled and disabled through I2C_enable_smbus_irq() and + I2C_disable_smbus_irq() respectively. It is your responsibility to create + interrupt handler functions in your application to get the desired response + for the SMBus interrupts. + + Note: You must include the path to any application header files that are + included in the i2c_interrupt.c file, as an include path in your + project's compiler settings. The details of how to do this will depend + on your development software. + + -------------------------------- + SMBus Logic Options + -------------------------------- + SMBus related APIs does not have any effect if the "Generate SMBus Logic" + is not enabled in the CoreI2C hardware configuration. Following are API's + that does not give the desired results if SMBus Logic is disabled. + + - I2C_smbus_init() + - I2C_reset_smbus() + - I2C_enable_smbus_irq() + - I2C_disable_smbus_irq() + - I2C_suspend_smbus_slave() + - I2C_resume_smbus_slave() + - I2C_set_smsbus_alert() + - I2C_clear_smsbus_alert() + - I2C_get_irq_status() + + -------------------------------- + Fixed Baud Rate Values + -------------------------------- + The serial clock frequency parameter passed to the I2C_init() and + I2C_channel_init() functions may not have any effect if fixed values were + selected for Baud rate in the hardware configuration of CoreI2C. When fixed + values are selected for these baud rates, the driver cannot overwrite + the fixed values. + + ----------------------------------- + Fixed Slave Address Options Values + ----------------------------------- + The primary slave address parameter passed to the I2C_init() function and + secondary address value passed to the I2C_set_slave_second_addr() function, + may not have the desired effect if fixed values were selected for the slave 0 + address and slave 1 address respectively. Proper operation of this version of + the driver requires the slave addresses to be programmable. + + ============================================================================== + Theory of Operation + ============================================================================== + The CoreI2C software driver is designed to allow the control of multiple + instances of CoreI2C with one or more I2C channels. Each channel in an + instance of CoreI2C in the hardware design is associated with a single + instance of the i2c_instance_t structure in the software. You must allocate + memory for one unique i2c_instance_t structure instance for each channel of + each CoreI2C hardware instance. The contents of these data structures are + initialised by calling I2C_init() and if necessary I2C_channel_init(). + A pointer to the structure is passed to the subsequent driver functions in order + to identify the CoreI2C hardware instance and channel to perform the + requested operation. + + Note: Do not attempt to directly manipulate the contents of i2c_instance_t + structures. These structures are only intended to be modified by the driver + functions. + + The CoreI2C driver functions are grouped into the following categories: + - Initialization and configuration functions + - Interrupt control + - I2C slave addressing functions + - I2C master operations functions to handle write, read, and write-read + transactions + - I2C slave operations functions to handle write, read, and write-read + transactions + - Mixed master-slave operations + - SMBus interface configuration and control + + -------------------------------- + Initialization and Configuration + -------------------------------- + The CoreI2C device is first initialized by calling the I2C_init() + function. Since each CoreI2C peripheral supports up to 16 channels, an + additional function, I2C_channel_init(), is required to initialize the + remaining channels with their own data structures. + + I2C_init() function initializes channel 0 of a CoreI2C and the i2c_instance_t + for channel 0 acts as the basis for further channel initialization as the + hardware base address and I2C serial address are same across all the channels. + Ensure to call I2C_init() function before calling any other I2C driver function + calls. The I2C_init() call for each CoreI2C takes the I2C serial address assigned + to the I2C and the serial clock divider to generate its I2C clock as configuration + parameters. + + I2C_channel_init() function takes as input parameters a pointer to the CoreI2C + i2c_instance_t which has been initialized by calling the I2C_init() and a pointer + to a separate i2c_instance_t which represents this new channel. Another input + parameter which is required by this function is serial clock divider which generates + its I2C clock. + + -------------------------------- + Interrupt Control + -------------------------------- + The CoreI2C driver is interrupt driven and it uses each channels INT + interrupt to drive the state machine which is at the heart of the driver. + The application is responsible for providing the link between the interrupt + generating hardware and the CoreI2C interrupt handler and must ensure that + the I2C_isr() function is called with the correct i2c_instance_t structure + pointer for the CoreI2C channel initiating the interrupt. + + The driver enables and disables the generation of INT interrupts by CoreI2C + at various times when it is operating through the user supplied + I2C_enable_irq() and I2C_disable_irq() functions. + + The I2C_register_write_handler() function is used to register a write + handler function with the CoreI2C driver which is called on completion + of an I2C write transaction by the CoreI2C slave. It is the user + applications responsibility to create and register the implementation of + this handler function that processes or triggers the processing of the + received data. + + The other two interrupt sources in the CoreI2C are related to SMBus + operation and are enabled and disabled through I2C_enable_smbus_irq() and + I2C_disable_smbus_irq() respectively. Due to the application specific + nature of the response to SMBus interrupts, you must design interrupt + handler functions in the application to get the desired behaviour for + SMBus related interrupts. + + If enabled, the SMBA_INT signal from the CoreI2C is asserted if an + SMBALERT condition is signalled on the SMBALERT_NI input for the channel. + + If enabled, the SMBS_INT signal from the CoreI2C is asserted if an + SMBSUSPEND condition is signalled on the SMBSUS_NI input for the channel. + + ## I2C Slave Addressing Functions + A CoreI2C peripheral responds to the following three slave addresses: + - Slave address 0 - This is the primary slave address that accesses + a CoreI2C channel when it acts as a slave in + I2C transactions. You must configure the primary slave + address using I2C_init(). + + - Slave address 1 - This is the secondary slave address which might be + required in certain application specific scenarios. + The secondary slave address is configured by + I2C_set_slave_second_addr() and is disabled by + I2C_disable_slave_second_addr(). + + - General call address - A CoreI2C slave can be configured to respond to + a broadcast command by a master transmitting the + general call address of 0x00. Use the I2C_set_gca() + function to enable the slave to respond to the general + call address. If the CoreI2C slave is not required to + respond to the general call address, disable this + address by calling I2C_clear_gca(). + + Note: All channels on a CoreI2C instance share the same slave address logic. + This means that they cannot have separate slave addresses and rely on + the separate physical I2C bus connections to distinguish them. + + -------------------------------- + Transaction Types + -------------------------------- + The I2C driver is designed to handle three types of I2C transaction: + - Write transactions + - Read transactions + - Write-read transactions + + ## Write Transaction + The master I2C device initiates a write transaction by sending a START bit + as soon as the bus becomes free. The START bit is followed by the 7-bit + serial address of the target slave device followed by the read/write bit + indicating the direction of the transaction. The slave acknowledges the + receipt of it's address with an acknowledge bit. The master sends data one + byte at a time to the slave, which must acknowledge the receipt of each byte + for the next byte to be sent. The master sends a STOP bit to complete the + transaction. The slave can abort the transaction by replying with a + non-acknowledge bit instead of an acknowledge bit. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ## Read Transaction + The master I2C device initiates a read transaction by sending a START bit + as soon as the bus becomes free. The START bit is followed by the 7-bit + serial address of the target slave device followed by the read/write bit + indicating the direction of the transaction. The slave acknowledges the + receipt of it's slave address with an acknowledge bit. The slave sends + data one byte at a time to the master, which must acknowledge the receipt of + each byte for the next byte to be sent. The master sends a non-acknowledge + bit following the last byte it wishes to read followed by a STOP bit. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ## Write-Read Transaction + The write-read transaction is a combination of a write transaction + immediately followed by a read transaction. There is no STOP bit in between + the write and read phases of a write-read transaction. A repeated START + bit is sent between the write and read phases. + + Whilst the write handler is being executed, the slave holds the clock line + low to stretch the clock until the response is ready. + + The write-read transaction is typically used to send a command or offset + in the write transaction specifying the logical data to be transferred + during the read phase. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ## Master Operations + The application can use the I2C_write(), I2C_read(), and I2C_write_read() + functions to initiate an I2C bus transaction. The application can then wait + for the transaction to complete using the I2C_wait_complete() function + or poll the status of the I2C transaction using the I2C_get_status() + function until it returns a value different from I2C_IN_PROGRESS. The + I2C_system_tick() function is used to set a time base for the + I2C_wait_complete() function's time out delay. + + ## Slave Operations + To configure the I2C driver to operate as an I2C slave requires the use + of the following functions: + - I2C_set_slave_tx_buffer() + - I2C_set_slave_rx_buffer() + - I2C_set_slave_mem_offset_length() + - I2C_register_write_handler() + - I2C_enable_slave() + + Use of all functions is not required if the slave I2C does not need to support + all types of I2C read transactions. The subsequent sections list the functions + that must be used to support each transaction type. + + ## Responding to Read Transactions + The following functions are used to configure the CoreI2C driver to + respond to I2C read transactions: + • I2C_set_slave_tx_buffer() + • I2C_enable_slave() + + The I2C_set_slave_tx_buffer() function specifies the data buffer that + is transmitted when the I2C slave is the target of an I2C read + transaction. It is then up to the application to manage the content of + that buffer to control the data that will be transmitted to the I2C + master as a result of the read transaction. + + The I2C_enable_slave() function enables the I2C hardware instance + to respond to the I2C transactions. It must be called after the I2C driver + has been configured to respond to the required transaction types. + + ## Responding to Write Transactions + The following functions are used to configure the I2C driver to respond + to I2C write transactions: + • I2C_set_slave_rx_buffer() + • I2C_register_write_handler() + • I2C_enable_slave() + + The I2C_set_slave_rx_buffer() function specifies the data buffer that + stored the data received by the I2C slave when it targets an I2C write + transaction. + + The I2C_register_write_handler() function specifies the handler function + that must be called on completion of the I2C write transaction. It is this + handler function that processes or triggers the processing of the received + data. + + The I2C_enable_slave() function enables the I2C hardware instance + to respond to I2C transactions. It must be called after the I2C driver + has been configured to respond to the required transaction types. + + ## Responding to Write-Read Transactions + The following functions are used to configure the CoreI2C driver to + respond to write-read transactions: + - I2C_set_slave_mem_offset_length() + - I2C_set_slave_tx_buffer() + - I2C_set_slave_rx_buffer() + - I2C_register_write_handler() + - I2C_enable_slave() + + The I2C_set_slave_mem_offset_length() function specifies the number of + bytes expected by the I2C slave during the write phase of the write-read + transaction. + + The I2C_set_slave_tx_buffer() function specifies the data that is + transmitted to the I2C master during the read phase of the write-read + transaction. The value received by the I2C slave during the write phase of + the transaction will be used as an index into the transmit buffer + specified by this function. It decides which part of the transmit buffer + will be transmitted to the I2C master as part of the read phase of the + write-read transaction. + + The I2C_set_slave_rx_buffer() function specifies the data buffer that + stores the data received by the I2C slave during the write phase of + the write-read transaction. This buffer must be large enough to accommodate + the number of bytes specified through the I2C_set_slave_mem_offset_length() + function. + + The I2C_register_write_handler() function can optionally be used to + specify a handler function that is called on completion of the write phase + of the I2C write-read transaction. If a handler function is registered, it + is responsible for processing the received data in the slave receive + buffer and populating the slave transmit buffer with the data that will be + transmitted to the I2C master as part of the read phase of the write-read + transaction. + + The I2C_enable_slave() function enables the CoreI2C hardware instance to + respond to the I2C transactions. It must be called after configuring the + CoreI2C driver to respond to the required transaction types. + + ## Mixed Master-Slave Operations + The CoreI2C device supports mixed master and slave operations. If the + CoreI2C slave has a transaction in progress and your application attempts to + begin a master mode transaction, the CoreI2C driver queues the master mode + transaction until the bus is released and the CoreI2C can switch to master + mode and acquire the bus. The CoreI2C master then starts the previously + queued master transaction. + + ## SMBus Control + The CoreI2C driver enables the CoreI2C peripheral’s SMBus functionality + using the I2C_smbus_init() function. + + The I2C_suspend_smbus_slave() function is used with a master mode CoreI2C + to force slave devices on the SMBus to enter their Power-Down/Suspend mode. + The I2C_resume_smbus_slave() function is used to end the suspend operation + on the SMBus. + + The I2C_reset_smbus() function is used with a master mode CoreI2C to force + all devices on the SMBus to reset their SMBUs interface. + + The I2C_set_smsbus_alert() function is used by a slave mode CoreI2C to + force communication with the SMBus master. Once communications with the + master is initiated, the I2C_clear_smsbus_alert() function clears the alert + condition. + + The I2C_enable_smbus_irq() and I2C_disable_smbus_irq() functions are used to + enable and disable the SMBSUS and SMBALERT SMBus interrupts. + + *//*=========================================================================*/ + +#ifndef CORE_I2C_H_ +#define CORE_I2C_H_ + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#include "hal_assert.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + I2C_RELEASE_BUS + ======================================= + The I2C_RELEASE_BUS constant is used to specify the options parameter to + functions I2C_read(), I2C_write() and I2C_write_read() to indicate + that a STOP bit must be generated at the end of the I2C transaction to release + the bus. + */ +#define I2C_RELEASE_BUS 0x00u + +/*-------------------------------------------------------------------------*//** + I2C_HOLD_BUS + ======================================= + The I2C_HOLD_BUS constant specify the options parameter to functions I2C_read(), + I2C_write(), and I2C_write_read() to indicate that a STOP bit must not be + generated at the end of the I2C transaction in order to retain the bus ownership. + This causes the next transaction to begin with a repeated START bit and no STOP + bit between the transactions. + */ +#define I2C_HOLD_BUS 0x01u + +/*-------------------------------------------------------------------------*//** + Interrupt Identifier Number + ======================================= + The following constants specify the interrupt identifier number which is + solely used by the driver API. This has nothing to do with hardware interrupt + line. I2C_INTR_IRQ is the primary interrupt signal which drives the state machine + of the CoreI2C driver. The I2C_SMBALERT_IRQ and I2C_SMBSUS_IRQ are used by + SMBus interrupt enable and disable functions. These IRQ numbers are also used + by I2C_get_irq_status(). + + | Constant | Description | + |--------------------|--------------------------------------------------------| + | I2C_NO_IRQ | No interrupt | + | I2C_SMBALERT_IRQ | Used by SMBus interrupt enable functions | + | I2C_SMBSUS_IRQ | Used by SMBus interrupt disable functions | + | I2C_INTR_IRQ | Primary interrupt signal which drives the state machine| + + */ +#define I2C_NO_IRQ 0x00u +#define I2C_SMBALERT_IRQ 0x01u +#define I2C_SMBSUS_IRQ 0x02u +#define I2C_INTR_IRQ 0x04u + +/*-------------------------------------------------------------------------*//** + I2C_NO_TIMEOUT + ======================================= + The I2C_wait_complete() function uses I2C_NO_TIMEOUT constant as a parameter + to indicate that the wait for completion of the transaction should not time out. + */ +#define I2C_NO_TIMEOUT 0u + +/***************************************************************************//** + The i2c_channel_number_t type is used to specify the channel number of a + CoreI2C instance. + */ +typedef enum i2c_channel_number { + I2C_CHANNEL_0 = 0u, + I2C_CHANNEL_1, + I2C_CHANNEL_2, + I2C_CHANNEL_3, + I2C_CHANNEL_4, + I2C_CHANNEL_5, + I2C_CHANNEL_6, + I2C_CHANNEL_7, + I2C_CHANNEL_8, + I2C_CHANNEL_9, + I2C_CHANNEL_10, + I2C_CHANNEL_11, + I2C_CHANNEL_12, + I2C_CHANNEL_13, + I2C_CHANNEL_14, + I2C_CHANNEL_15, + I2C_MAX_CHANNELS = 16u +} i2c_channel_number_t; + +/***************************************************************************//** + The i2c_clock_divider_t type specifies the divider to be applied + to the I2C PCLK or BCLK signal in order to generate the I2C clock. + The I2C_BCLK_DIV_8 value selects a clock frequency based on division of BCLK, + all other values select a clock frequency based on division of PCLK. + */ +typedef enum i2c_clock_divider { + I2C_PCLK_DIV_256 = 0u, + I2C_PCLK_DIV_224, + I2C_PCLK_DIV_192, + I2C_PCLK_DIV_160, + I2C_PCLK_DIV_960, + I2C_PCLK_DIV_120, + I2C_PCLK_DIV_60, + I2C_BCLK_DIV_8 +} i2c_clock_divider_t; + +/***************************************************************************//** + The i2c_status_t type is used to report the status of I2C transactions. + */ +typedef enum i2c_status +{ + I2C_SUCCESS = 0u, + I2C_IN_PROGRESS, + I2C_FAILED, + I2C_TIMED_OUT +} i2c_status_t; + +/***************************************************************************//** + The i2c_slave_handler_ret_t type is used by slave write handler functions + to indicate whether or not the received data buffer should be released. + */ +typedef enum i2c_slave_handler_ret { + I2C_REENABLE_SLAVE_RX = 0u, + I2C_PAUSE_SLAVE_RX = 1u +} i2c_slave_handler_ret_t; + +/***************************************************************************//** + This structure identifies various CoreI2C hardware instances in the system + and the I2C channels within them. The application software should declare + one instance of this structure for each channel of each instance of CoreI2C + in your system. I2C_init() and I2C_channel_init() functions initialize this + structure depending on whether it is channel 0 or one of the additional + channels, respectively. A pointer to an initialized instance of the + structure should be passed as the first parameter to the CoreI2C driver + functions, to identify which CoreI2C hardware instance and channel should + perform the requested operation. + + The contents of this data structure should not be modified or used outside of + the CoreI2C driver. Software using the CoreI2C driver should only need to + create one single instance of this data structure for each channel of each + CoreI2C hardware instance in the system then pass a pointer to these data + structures with each call to the CoreI2C driver in order to identify which + CoreI2C hardware instance to use. + */ +typedef struct i2c_instance i2c_instance_t ; +/***************************************************************************//* + Slave write handler functions prototype +/***************************************************************************//** + This defines the function prototype that must be followed by I2C slave write + handler functions. These functions are registered with the CoreI2C driver + through the I2C_register_write_handler() function. + + Declaring and Implementing Slave Write Handler Functions: + + Slave write handler functions should follow the following prototype: + @code + i2c_slave_handler_ret_t write_handler + ( + i2c_instance_t *instance, uint8_t * data, uint16_t size + ); + @endcode + + The instance parameter is a pointer to the i2c_instance_t for which this + slave write handler has been declared. + + The data parameter is a pointer to a buffer (received data buffer) holding + the data written to the I2C slave. + + Define the INCLUDE_SLA_IN_RX_PAYLOAD macro for the driver to insert the + actual address used to access the slave as the first byte in the buffer. + This allows the applications to tailor their response based on the actual + address used to access the slave (primary address, secondary address, or GCA). + + The size parameter is the number of bytes held in the received data buffer. + Handler functions must return one of the following values: + - I2C_REENABLE_SLAVE_RX + - I2C_PAUSE_SLAVE_RX + + If the handler function returns I2C_REENABLE_SLAVE_RX, the driver releases + the received data buffer and allows further I2C write transactions to the + I2C slave. + + If the handler function returns I2C_PAUSE_SLAVE_RX, the I2C slave responds + to subsequent write requests with a non-acknowledge bit (NACK), until the + received data buffer content gets processed by some other part of the + software application. + + Call the I2C_enable_slave() after returning the I2C_PAUSE_SLAVE_RX to release + the received data buffer in order to store the data received by the subsequent + I2C write transactions. + */ +typedef i2c_slave_handler_ret_t (*i2c_slave_wr_handler_t)(i2c_instance_t *instance, uint8_t *, uint16_t ); + +/***************************************************************************//** + This structure is used to identify the various CoreI2C hardware instances in + your system and the I2C channels within them. Your application software should + declare one instance of this structure for each channel of each instance of + CoreI2C in your system. The functions I2C_init() and I2C_channel_init() + initialize this structure depending on whether it is channel 0 or one of the + additional channels respectively. A pointer to an initialized instance of the + structure should be passed as the first parameter to the CoreI2C driver + functions, to identify which CoreI2C hardware instance and channel should + perform the requested operation. + + The contents of this data structure should not be modified or used outside of + the CoreI2C driver. Software using the CoreI2C driver should only need to + create one single instance of this data structure for each channel of each + CoreI2C hardware instance in the system then pass a pointer to these data + structures with each call to the CoreI2C driver in order to identify the + CoreI2C hardware instance it wishes to use. + */ +struct i2c_instance +{ + addr_t base_address; + uint_fast8_t ser_address; + + /* Transmit related info:*/ + uint_fast8_t target_addr; + + /* Current transaction type (WRITE, READ, RANDOM_READ)*/ + uint8_t transaction; + + uint_fast16_t random_read_addr; + + uint8_t options; + + /* Master TX INFO: */ + const uint8_t * master_tx_buffer; + uint_fast16_t master_tx_size; + uint_fast16_t master_tx_idx; + uint_fast8_t dir; + + /* Master RX INFO: */ + uint8_t * master_rx_buffer; + uint_fast16_t master_rx_size; + uint_fast16_t master_rx_idx; + + /* Master Status */ + volatile i2c_status_t master_status; + uint32_t master_timeout_ms; + + /* Slave TX INFO */ + const uint8_t * slave_tx_buffer; + uint_fast16_t slave_tx_size; + uint_fast16_t slave_tx_idx; + + /* Slave RX INFO */ + uint8_t * slave_rx_buffer; + uint_fast16_t slave_rx_size; + uint_fast16_t slave_rx_idx; + /* Slave Status */ + volatile i2c_status_t slave_status; + + /* Slave data: */ + uint_fast8_t slave_mem_offset_length; + i2c_slave_wr_handler_t slave_write_handler; + uint8_t is_slave_enabled; + + /* user specific data */ + void *p_user_data ; + + /* I2C bus status */ + uint8_t bus_status; + + /* Is transaction pending flag */ + uint8_t is_transaction_pending; + + /* I2C Pending transaction */ + uint8_t pending_transaction; +}; + +/*------------------------Public Function-------------------------------------*/ + +/***************************************************************************//** + The I2C_init() function configures channel 0 of a CoreI2C instance. It sets + the base hardware address which is used to locate the CoreI2C instance + in memory and also used internally by I2C_channel_init() to calculate the + register addresses for any additional channels. The slave serial address set + is shared by all channels on a CoreI2C instance. + + If only one channel is configured in a CoreI2C, the address of the + i2c_instance_t used in I2C_Init() will also be used in subsequent calls to the + CoreI2C driver functions. If more than one channel is configured in the + CoreI2C, I2C_channel_init() will be called after I2C_init(), which initializes + the i2c_instance_t data structure for a specific channel. + + @param this_i2c + Pointer to the i2c_instance_t data structure that holds all the data + related to channel 0 of the CoreI2C instance is initialized. A pointer + to this structure is used in all subsequent calls to the CoreI2C driver + functions which operates on channel 0 of this CoreI2C instance. + + @param base_address + Base address in the processor's memory map of the registers of the CoreI2C + instance being initialized. + + @param ser_address + This parameter sets the primary I2C serial address (SLAVE0 address) for the + CoreI2C to initialize. It is the principal I2C bus address to which the + CoreI2C instance will respond. CoreI2C can operate in master mode or slave + mode and the serial address is significant only in the case of I2C slave + mode. In master mode, CoreI2C does not require a serial address and the + value of this parameter is not important. If you do not intend to use the + CoreI2C device in slave mode, then provide any dummy slave address value + to this parameter. However, in systems where the CoreI2C is expected to + switch from master mode to slave mode, it is advisable to initialize the + CoreI2C device with a valid serial slave address. Call the I2C_init() + function whenever it is required to change the primary slave address as + there is no separate function to set the primary slave address of the + I2C device. The serial address initialized through this function is + basically the primary slave address or slave address0. + I2C_set_slave_second_addr() is used to set the secondary slave address + or slave address 1. + Note : ser_address parameter does not have any affect if fixed slave + address is enabled in CoreI2C hardware design. CoreI2C will + be always addressed with the hardware configured fixed slave + address. + Note : ser_address parameter will not have any affect if the CoreI2C + instance is only used in master mode. + + @param ser_clock_speed + This parameter sets the I2C serial clock frequency. It selects the divider + that generates the serial clock from the APB PCLK or from the BCLK. + It can be one of the following: + - I2C_PCLK_DIV_256 + - I2C_PCLK_DIV_224 + - I2C_PCLK_DIV_192 + - I2C_PCLK_DIV_160 + - I2C_PCLK_DIV_960 + - I2C_PCLK_DIV_120 + - I2C_PCLK_DIV_60 + - I2C_BCLK_DIV_8 + Note: serial_clock_speed value does not have any affect if the fixed baud + rate is enabled in CoreI2C hardware instance configuration dialogue + window. The fixed baud rate divider value overrides the value passed + as parameter in this function. + Note: serial_clock_speed value is not critical for devices that only operate + as slaves and can be set to any of the above values. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void system_init( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + } + @endcode + */ +void I2C_init +( + i2c_instance_t * this_i2c, + addr_t base_address, + uint8_t ser_address, + i2c_clock_divider_t ser_clock_speed +); + +/***************************************************************************//** + The I2C_channel_init() function initializes and configures hardware and data + structures of one of the additional channels of a CoreI2C instance. + I2C_init() must be called before calling this function to set the CoreI2C + instance hardware base address and I2C serial address. I2C_channel_init() also + initializes I2C serial clock divider to set the serial clock baud rate. + The pointer to data structure i2c_instance_t used for a particular channel + is used as an input parameter to subsequent CoreI2C driver functions + which operate on this channel. + + @param this_i2c_channel + Pointer to the i2c_instance_t data structure that holds all data related to + the CoreI2C channel gets initialized. A pointer to the same data structure + is used in subsequent calls to the CoreI2C driver functions in order to + identify the CoreI2C channel instance that should perform the operation + implemented by the called driver function. + + @param this_i2c + This is a pointer to an i2c_instance_t structure, previously initialized by + I2C_init(). It holds information regarding the hardware base address and + I2C serial address for the CoreI2C containing the channel to be + initialized. This information is required by I2C_channel_init() to + initialize the i2c_instance_t structure pointed by this_i2c_channel as + all channels in a CoreI2C instance share the same base address and serial + address. It is very important that the i2c_instance_t structure pointed + by this_i2c must be previously initialized by calling I2C_init(). + + @param channel_number + This parameter of type i2c_channel_number_t identifies the channel to be + initialized. + + @param ser_clock_speed + This parameter sets the I2C serial clock frequency. It selects the divider + that is used to generate the serial clock from the APB PCLK or from + the BCLK. It can be one of the following: + - I2C_PCLK_DIV_256 + - I2C_PCLK_DIV_224 + - I2C_PCLK_DIV_192 + - I2C_PCLK_DIV_160 + - I2C_PCLK_DIV_960 + - I2C_PCLK_DIV_120 + - I2C_PCLK_DIV_60 + - I2C_BCLK_DIV_8 + Note: serial_clock_speed value does not have any affect if the fixed baud + rate is enabled in CoreI2C hardware instance configuration dialogue + window. The fixed baud rate divider value will supersede the value + passed as parameter in this function. + Note: ser_clock_speed value is not critical for devices that only operate + as slaves and can be set to any of the above values. + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_SER_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + i2c_instance_t g_i2c_channel_1_inst; + + uint8_t tx_buffer[DATA_LENGTH]; + uint8_t write_length = DATA_LENGTH; + + void system_init( void ) + { + uint8_t target_slave_addr = 0x12; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize CoreI2C channel 1 with different clock speed + I2C_channel_init( &g_i2c_channel_1_inst, &g_i2c_inst, I2C_CHANNEL_1, + I2C_PCLK_DIV_224 ); + + // Write data to Channel 1 of CoreI2C instance. + I2C_write( &g_i2c_channel_1_inst, target_slave_addr, tx_buffer, + write_length, I2C_RELEASE_BUS ); + } + @endcode + +*/ +void I2C_channel_init +( + i2c_instance_t * this_i2c_channel, + i2c_instance_t * this_i2c, + i2c_channel_number_t channel_number, + i2c_clock_divider_t ser_clock_speed +); + +/***************************************************************************//** + The I2C_isr function is the CoreI2C interrupt service routine. User must + call this function from their application level CoreI2C interrupt handler + function. This function runs the I2C state machine based on previous and + current status. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREINTERRUPT_BASE_ADDR 0xCC000000u + #define COREI2C_SER_ADDR 0x10u + #define I2C_IRQ_NB 2u + + i2c_instance_t g_i2c_inst; + + void core_i2c_isr( void ) + { + I2C_isr( &g_i2c_inst ); + } + + void main( void ) + { + CIC_init( COREINTERRUPT_BASE_ADDR ); + NVIC_init(); + CIC_set_irq_handler( I2C_IRQ_NB, core_i2c_isr ); + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + NVIC_enable_interrupt( NVIC_IRQ_0 ); + } + @endcode + */ +void I2C_isr +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//* + #Master Specific Functions + + The following functions are only used within an I2C master's implementation. +/***************************************************************************//** + This function initiates an I2C master write transaction. This function returns + immediately after initiating the transaction. The content of the write buffer + passed as parameter should not be modified until the write transaction + completes. It also means that the memory allocated for the write buffer should + not be freed or should not go out of scope before the write completes. You can + check for the write transaction completion using the I2C_status() function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr + This parameter specifies the serial address of the target I2C device. + + @param write_buffer + This parameter is a pointer to a buffer holding the data to be written to + the target I2C device. Do not to release the memory used by this buffer + before the write transaction completes. For example, it is not appropriate + to return from a function allocating this buffer as an auto array variable + before the write transaction completes as this would result in the buffer's + memory being de-allocated from the stack when the function returns. This + memory could then be subsequently reused and modified causing unexpected + data to be written to the target I2C device. + + @param write_size + Number of bytes held in the write_buffer to be written to the target I2C + device. + + @param options + The options parameter is used to indicate if the I2C bus should be released + on completion of the write transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the write transaction causing the bus to be released for other I2C + devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the write + transaction, preventing other I2C devices from initiating a bus transaction. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t tx_buffer[DATA_LENGTH]; + uint8_t write_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Write data to Channel 0 of CoreI2C instance. + I2C_write( &g_i2c_inst, target_slave_addr, tx_buffer, write_length, + I2C_RELEASE_BUS ); + + // Wait for completion and record the outcome + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_write +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * write_buffer, + uint16_t write_size, + uint8_t options +); + +/***************************************************************************//** + This function initiates an I2C master read transaction. This function returns + immediately after initiating the transaction. + The contents of the read buffer passed as parameter should not be modified + until the read transaction completes. It also means that the memory allocated + for the read buffer should not be freed or should not go out of scope before + the read completes. You can check for the read transaction completion using + the I2C_status() function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr + This parameter specifies the serial address of the target I2C device. + + @param read_buffer + This is a pointer to a buffer where the data received from the target device + gets stored. Do not to release the memory used by this buffer before the read + transaction completes. For example, it is not appropriate to return from a + function allocating this buffer as an auto array variable before the read + transaction completes as this would result in the buffer's memory being + de-allocated from the stack when the function returns. This memory could + then be subsequently reallocated resulting in the read transaction + corrupting the newly allocated memory. + + @param read_size + This parameter specifies the number of bytes to read from the target device. + This size must not exceed the size of the read_buffer buffer. + + @param options + The options parameter is used to indicate if the I2C bus should be released + on completion of the read transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the read transaction causing the bus to be released for other I2C + devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the read transaction, + preventing other I2C devices from initiating a bus transaction. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t rx_buffer[DATA_LENGTH]; + uint8_t read_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Read data from target slave Channel 0 of CoreI2C instance. + I2C_read( &g_i2c_inst, target_slave_addr, rx_buffer, read_length, + I2C_RELEASE_BUS ); + + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +); + +/***************************************************************************//** + This function initiates an I2C write-read transaction where data is first + written to the target device before issuing a restart condition and changing + the direction of the I2C transaction in order to read from the target device. + + The same warnings about buffer allocation in I2C_write() and I2C_read() + applies to this function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr + This parameter specifies the serial address of the target I2C device. + + @param addr_offset + This parameter is a pointer to the buffer containing the data that is sent + to the slave during the write phase of the write-read transaction. This + data is typically used to specify an address offset specifying to the I2C + slave device what data it must return during the read phase of the + write-read transaction. + + @param offset_size + This parameter specifies the number of offset bytes to be written during the + write phase of the write-read transaction. This is typically the size of the + buffer pointed by the addr_offset parameter. + + @param read_buffer + This parameter is a pointer to the buffer where the data read from the I2C + slave will be stored. + + @param read_size + This parameter specifies the number of bytes to read from the target I2C + slave device. This size must not exceed the size of the buffer pointed by + the read_buffer parameter. + + @param options + The options parameter is used to indicate if the I2C bus should be released + on completion of the write-read transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the write-read transaction causing the bus to be released for other + I2C devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the write-read + transaction, preventing other I2C devices from initiating a bus transaction. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define TX_LENGTH 16u + #define RX_LENGTH 8u + + i2c_instance_t g_i2c_inst; + uint8_t rx_buffer[RX_LENGTH]; + uint8_t read_length = RX_LENGTH; + uint8_t tx_buffer[TX_LENGTH]; + uint8_t write_length = TX_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + I2C_write_read( &g_i2c_inst, target_slave_addr, tx_buffer, write_length, + rx_buffer, read_length, I2C_RELEASE_BUS ); + + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_write_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * addr_offset, + uint16_t offset_size, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +); + +/***************************************************************************//** + This function indicates the current state of a CoreI2C channel. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + The return value indicates the current state of a CoreI2C channel or the + outcome of the previous transaction if no transaction is in progress. + Following are the return values are: + - I2C_SUCCESS + The last I2C transaction has completed successfully. + - I2C_IN_PROGRESS + There is an I2C transaction in progress. + - I2C_FAILED + The last I2C transaction failed. + - I2C_TIMED_OUT + The request has failed to complete in the allotted time. + + @example + @code + i2c_instance_t g_i2c_inst; + + while( I2C_IN_PROGRESS == I2C_get_status( &g_i2c_inst ) ) + { + // Do something useful while waiting for I2C operation to complete + our_i2c_busy_task(); + } + + if( I2C_SUCCESS != I2C_get_status( &g_i2c_inst ) ) + { + // Something went wrong... + our_i2c_error_recovery( &g_i2c_inst ); + } + @endcode + */ +i2c_status_t I2C_get_status +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + This function waits for the current I2C transaction to complete. The return + value indicates whether the last I2C transaction was successful or not. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + @param timeout_ms + The timeout_ms parameter specifies the delay within which the current I2C + transaction should complete. The time out delay is given in + milliseconds. I2C_wait_complete() will return I2C_TIMED_OUT if the current + transaction has not completed after the time out delay has expired. This + parameter can be set to I2C_NO_TIMEOUT to indicate that I2C_wait_complete() + must not time out. + + @return + The return value indicates the outcome of the last I2C transaction. It can + be one of the following: + - I2C_SUCCESS + The last I2C transaction has completed successfully. + - I2C_FAILED + The last I2C transaction failed. + - I2C_TIMED_OUT + The last transaction failed to complete within the time out delay given + as second parameter. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t rx_buffer[DATA_LENGTH]; + uint8_t read_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Read data from Channel 0 of CoreI2C instance. + I2C_read( &g_i2c_inst, target_slave_addr, rx_buffer, read_length, + I2C_RELEASE_BUS ); + + // Wait for completion and record the outcome + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +i2c_status_t I2C_wait_complete +( + i2c_instance_t * this_i2c, + uint32_t timeout_ms +); + +/***************************************************************************//** + This function is used to control the expiration of the time out delay + specified as a parameter to the I2C_wait_complete() function. It must be + called from the interrupt service routine of a periodic interrupt source such + as the SysTick timer interrupt. It takes the period of the interrupt + source as its ms_since_last_tick parameter and uses it as the time base for + the I2C_wait_complete() function's time out delay. + + Note: This function does not need to be called if the I2C_wait_complete() + function is called with a timeout_ms value of I2C_NO_TIMEOUT. + + Note: If this function is not called then the I2C_wait_complete() function + will behave as if its timeout_ms was specified as I2C_NO_TIMEOUT and it + will not time out. + + Note: If this function is being called from an interrupt handler (for example, + SysTick) it is important that the calling interrupt have a lower priority + than the CoreI2C interrupt(s) to ensure any updates to the shared data are + protected. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + @param ms_since_last_tick + The ms_since_last_tick parameter specifies the number of milliseconds that + elapsed since the last call to I2C_system_tick(). This parameter would + typically be a constant specifying the interrupt rate of a timer used to + generate system ticks. + + @return None. + + @example + The following example shows how the I2C_system_tick() function. I2C_system_tick() + is called for each I2C channel from the SysTick timer interrupt service routine. + The following example shows how the SysTick is configured to generate an interrupt + in every 10 milliseconds. + @code + #define SYSTICK_INTERVAL_MS 10 + + void SysTick_Handler(void) + { + I2C_system_tick(&g_core_i2c0, SYSTICK_INTERVAL_MS); + I2C_system_tick(&g_core_i2c2, SYSTICK_INTERVAL_MS); + } + @endcode + */ +void I2C_system_tick +( + i2c_instance_t * this_i2c, + uint32_t ms_since_last_tick +); + +/***************************************************************************//* + #Slave Specific Functions + + The following functions are only used within the implementation of an I2C slave device. + +/***************************************************************************//** + This function specifies the memory buffer holding the data that will be sent + to the I2C master when this CoreI2C channel is the target of an I2C read or + write-read transaction. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param tx_buffer + This parameter is a pointer to the memory buffer holding the data to be + returned to the I2C master when this CoreI2C channel is the target of an + I2C read or write-read transaction. + + @param tx_size + Size of the transmit buffer pointed by the tx_buffer parameter. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Specify the transmit buffer containing the data that will be + // returned to the master during read and write-read transactions. + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + } + @endcode + */ +void I2C_set_slave_tx_buffer +( + i2c_instance_t * this_i2c, + const uint8_t * tx_buffer, + uint16_t tx_size +); + +/***************************************************************************//** + This function specifies the memory buffer that is used by the CoreI2C channel + to receive data when it is a slave. This buffer is the memory where data gets + stored when the CoreI2C channel is the target of an I2C master write + transaction (that is, when it is the slave). + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param rx_buffer + This parameter is a pointer to the memory buffer allocated by the caller + software to be used as a slave receive buffer. + + @param rx_size + Size of the slave receive buffer. This is the amount of memory allocated + to the buffer pointed by rx_buffer. + Note: Indirectly, this buffer size specifies the maximum I2C write + transaction length this CoreI2C channel targets. This is because + this CoreI2C channel responds to further received bytes with + a non-acknowledge bit (NACK) as soon as its receive buffer is + full. This causes the write transaction to fail. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_RX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_rx_buffer[SLAVE_RX_BUFFER_SIZE]; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Specify the buffer used to store the data written by the I2C master. + I2C_set_slave_rx_buffer( &g_i2c_inst, g_slave_rx_buffer, + sizeof(g_slave_rx_buffer) ); + } + @endcode + */ +void I2C_set_slave_rx_buffer +( + i2c_instance_t * this_i2c, + uint8_t * rx_buffer, + uint16_t rx_size +); + +/***************************************************************************//** + This function is used as part of the configuration of a CoreI2C channel to + operate as a slave supporting write-read transactions. It specifies the + number of bytes expected as part of the write phase of a write-read + transaction. The bytes received during the write phase of a write-read + transaction will be interpreted as an offset into the slave's transmit buffer. + This allows random access into the I2C slave transmit buffer from a remote + I2C master. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param offset_length + The offset_length parameter configures the number of bytes to be interpreted + by the CoreI2C slave as a memory offset value during the write phase of + write-read transactions. The maximum value for the offset_length parameter + is two. The value of offset_length has the following effect on the + interpretation of the received data. + • If offset_length is 0, the offset into the transmit buffer is fixed at 0. + • If offset_length is 1, a single byte of received data is interpreted as an + unsigned 8-bit offset value in the range 0 to 255. + • If offset_length is 2, 2 bytes of received data are interpreted as an + unsigned 16-bit offset value in the range 0 to 65535. The first byte + received in this case provides the high order bits of the offset and + the second byte provides the low order bits. + If the number of bytes received does not match the non 0 value of + offset_length, the transmit buffer offset is set to 0. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + I2C_set_slave_mem_offset_length( &g_i2c_inst, 1 ); + } + @endcode + */ +void I2C_set_slave_mem_offset_length +( + i2c_instance_t * this_i2c, + uint8_t offset_length +); + +/***************************************************************************//** + Register the function that is called to process the data written to this + CoreI2C channel when it is the slave in an I2C write transaction. + + Note: If a write handler is registered, it is called on completion of the + write phase of a write-read transaction and responsible for processing + the received data in the slave receive buffer and populating the slave + transmit buffer with the data that is transmitted to the I2C master + as part of the read phase of the write-read transaction. If a write + handler is not registered, the write data of a write-read transaction is + interpreted as an offset into the slave’s transmit buffer and handled by + the driver. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param handler + Pointer to the function that processes the I2C write request. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + // local function prototype + void slave_write_handler + ( + i2c_instance_t * this_i2c, + uint8_t * p_rx_data, + uint16_t rx_size + ); + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + I2C_set_slave_mem_offset_length( &g_i2c_inst, 1 ); + I2C_register_write_handler( &g_i2c_inst, slave_write_handler ); + } + @endcode +*/ +void I2C_register_write_handler +( + i2c_instance_t * this_i2c, + i2c_slave_wr_handler_t handler +); + +/***************************************************************************//** + This function enables slave mode operation for a CoreI2C channel. It enables + the CoreI2C slave to receive data when it is the target of an I2C read, write, + or write-read transaction. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + // Enable I2C slave + I2C_enable_slave( &g_i2c_inst ); + @endcode + */ +void I2C_enable_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + This function disables the slave mode operation for a CoreI2C channel. It stops + the CoreI2C slave that acknowledges the I2C read, write, or write-read + transactions targeted at it. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + // Disable I2C slave + I2C_disable_slave( &g_i2c_inst ); + @endcode + */ +void I2C_disable_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_slave_second_addr() function sets the secondary slave address for + a CoreI2C slave device. This is an additional slave address required in certain + applications, for example, to enable fail-safe operation in a system. As the + CoreI2C device supports 7-bit addressing, the highest value assigned to second + slave address is 127 (0x7F). + + Note: This function does not support CoreI2C hardware configured with a fixed + second slave address. The current implementation of the ADDR1[0] register + bit makes it difficult for the driver to support both programmable and + fixed second slave address, so we choose to support programmable only. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param second_slave_addr + The second_slave_addr parameter is the secondary slave address of the I2C + device. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SECOND_SLAVE_ADDR 0x20u + + i2c_instance_t g_i2c_inst; + void main( void ) + { + // Initialize the CoreI2C driver with its base address, primary I2C + // serial address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_second_addr( &g_i2c_inst, SECOND_SLAVE_ADDR ); + } + @endcode + */ +void I2C_set_slave_second_addr +( + i2c_instance_t * this_i2c, + uint8_t second_slave_addr +); + +/***************************************************************************//** + The I2C_disable_slave_second_addr() function disables the secondary slave + address of the CoreI2C slave device. + + Note: This version of the driver only supports CoreI2C hardware configured + with a programmable second slave address. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + i2c_instance_t g_i2c_inst; + I2C_disable_slave_second_addr( &g_i2c_inst); + @endcode + */ +void I2C_disable_slave_second_addr +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_gca() function is used to set the general call acknowledgement bit + of a CoreI2C slave device. This allows all channels of the CoreI2C slave + device to respond to a general call or broadcast message from an I2C master. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + i2c_instance_t g_i2c_inst; + + // Enable recognition of the General Call Address + I2C_set_gca( &g_i2c_inst ); + @endcode + */ +void I2C_set_gca +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_clear_gca() function is used to clear the general call acknowledgement + bit of a CoreI2C slave device. This will stop all channels of the I2C slave + device responding to any general call or broadcast message from the master. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + i2c_instance_t g_i2c_inst; + + // Disable recognition of the General Call Address + I2C_clear_gca( &g_i2c_inst ); + @endcode + */ + +void I2C_clear_gca +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//* + #I2C SMBUS Specific APIs + +/***************************************************************************//** + The I2C_smbus_init() function enables SMBus timeouts and status logic for a + CoreI2C channel. + + Note: This and any of the other SMBus related functionality will only have an + effect if the CoreI2C was instantiated with the Generate SMBus Logic + option checked. + + Note: If the CoreI2C was instantiated with the Generate IPMI Logic option + checked this function then enables the IPMI 3mS SCL low timeout but + none of the other SMBus functions will have any effect. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void system_init( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst); + } + @endcode + */ +void I2C_smbus_init +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_enable_smbus_irq() function is used to enable the CoreI2C channel’s + SMBSUS and SMBALERT SMBus interrupts. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param irq_type + The irq_type specify the SMBUS interrupt(s) which will be enabled. + The two possible interrupts are: + - I2C_SMBALERT_IRQ + - I2C_SMBSUS_IRQ + To enable both interrupts in one call, use I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ. + + @return + None + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both I2C_SMBALERT_IRQ & I2C_SMBSUS_IRQ interrupts + I2C_enable_smbus_irq( &g_i2c_inst, + (uint8_t)(I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ) ); + } + @endcode + */ +void I2C_enable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +); + +/***************************************************************************//** + The I2C_disable_smbus_irq() function disable the CoreI2C channel’s SMBSUS and + SMBALERT SMBus interrupts. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param irq_type + The irq_type specifies the SMBUS interrupt(s) which are disabled. + The two possible interrupts are: + • I2C_SMBALERT_IRQ + • I2C_SMBSUS_IRQ + To disable both ints in one call, use I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both SMBALERT & SMBSUS interrupts + I2C_enable_smbus_irq( &g_i2c_inst, + (uint8_t)(I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ)); + + ... + + // Disable the SMBALERT interrupt + I2C_disable_smbus_irq( &g_i2c_inst, I2C_SMBALERT_IRQ ); + } + @endcode + */ +void I2C_disable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +); + +/***************************************************************************//** + The I2C_suspend_smbus_slave() function forces any SMBUS slave devices + connected to a CoreI2C channel into Power-Down or Suspend mode by asserting + the channel's SMBSUS signal. The CoreI2C channel is the SMBus master in this + case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // suspend SMBus slaves + I2C_suspend_smbus_slave( &g_i2c_inst ); + + ... + + // Re-enable SMBus slaves + I2C_resume_smbus_slave( &g_i2c_inst ); + } + @endcode + */ +void I2C_suspend_smbus_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_resume_smbus_slave() function de-asserts the CoreI2C channel's SMBSUS + signal to take any connected slave devices out of the Suspend mode. The CoreI2C + channel is the SMBus master in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // suspend SMBus slaves + I2C_suspend_smbus_slave( &g_i2c_inst ); + + ... + + // Re-enable SMBus slaves + I2C_resume_smbus_slave( &g_i2c_inst ); + } + @endcode + */ +void I2C_resume_smbus_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_reset_smbus() function resets the CoreI2C channel's SMBus connection + by forcing SCLK low for 35 mS. The reset that automatically cleares after 35 ms + gets elapsed. The CoreI2C channel is the SMBus master in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Make sure the SMBus channel is in a known state by resetting it + I2C_reset_smbus( &g_i2c_inst ); + } + @endcode + */ +void I2C_reset_smbus +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_smbus_alert() function is used to force master communication with + an I2C slave device by asserting the CoreI2C channel's SMBALERT signal. The + CoreI2C channel is the SMBus slave in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Get the SMBus masters attention + I2C_set_smbus_alert( &g_i2c_inst ); + + ... + + // Once we are happy, drop the alert + I2C_clear_smbus_alert( &g_i2c_inst ); + } + @endcode + */ +void I2C_set_smbus_alert +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_clear_smbus_alert() function is used to de-assert the CoreI2C channel's + SMBALERT signal once a slave device gets a response from the master. The + CoreI2C channel is the SMBus slave in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Get the SMBus masters attention + I2C_set_smbus_alert( &g_i2c_inst ); + + ... + + // Once we are happy, drop the alert + I2C_clear_smbus_alert( &g_i2c_inst ); + } + @endcode + */ +void I2C_clear_smbus_alert +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_get_irq_status function returns information about which interrupts are + currently pending in a CoreI2C channel. + The interrupts supported by CoreI2C are: + • SMBUSALERT + • SMBSUS + • INTR + + The macros I2C_NO_IRQ, I2C_SMBALERT_IRQ, I2C_SMBSUS_IRQ, and I2C_INTR_IRQ are + provided to use with this function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + This function returns the status of the CoreI2C channel's interrupts as a + single byte bitmap where a bit is set to indicate a pending interrupt. + The following are the bit positions associated with each interrupt type: + Bit 0 - SMBUS_ALERT_IRQ + Bit 1 - SMBSUS_IRQ + Bit 2 - INTR_IRQ + It returns 0, if there are no pending interrupts. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + uint8_t irq_to_enable = I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ; + uint8_t pending_irq = 0u; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both I2C_SMBALERT_IRQ & I2C_SMBSUS_IRQ irq + I2C_enable_smbus_irq( &g_i2c_inst, irq_to_enable ); + + // Get I2C IRQ type + pending_irq = I2C_get_irq_status( &g_i2c_inst ); + + // Let's assume, in system, INTR and SMBALERT IRQ is pending. + // So pending_irq will return status of both the IRQs + + if( pending_irq & I2C_SMBALERT_IRQ ) + { + // if true, it means SMBALERT_IRQ is there in pending IRQ list + } + if( pending_irq & I2C_INTR_IRQ ) + { + // if true, it means I2C_INTR_IRQ is there in pending IRQ list + } + } + @endcode + */ +uint8_t I2C_get_irq_status +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_user_data() function allows the association of a block of application + specific data with a CoreI2C channel. The composition of the data block is an + application matter and the driver simply provides the means for the application + to set and retrieve the pointer. For example, this is used to provide additional + channel specific information to the slave write handler. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param p_user_data + The p_user_data parameter is a pointer to the user specific data block for + this channel. It is defined as void * as the driver does not know the actual + type of data being pointed to and simply stores the pointer for later + retrieval by the application. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + app_data_t channel_xdata; + + void main( void ) + { + app_data_t *p_xdata; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Store location of user data in instance structure + I2C_set_user_data( &g_i2c_inst, (void *)&channel_xdata ); + + ... + + // Retrieve location of user data and do some work on it + p_xdata = (app_data_t *)I2C_get_user_data( &g_i2c_inst ); + if( NULL != p_xdata ) + { + p_xdata->foo = 123; + } + } + @endcode + */ +void I2C_set_user_data +( + i2c_instance_t * this_i2c, + void * p_user_data +); + +/***************************************************************************//** + The I2C_get_user_data() function is used to allows the retrieval of the address + of a block of application specific data associated with a CoreI2C channel. + The composition of the data block is an application matter and the driver + simply provides the means for the application to set and retrieve the pointer. + For example, this is used to provide additional channel specific information + to the slave write handler. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + This function returns a pointer to the user specific data block for this + channel. It is defined as void * as the driver does not know the actual type + of data being pointed. If no user data has been registered for this channel + a NULL pointer is returned. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + app_data_t channel_xdata; + + void main( void ) + { + app_data_t *p_xdata; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Store location of user data in instance structure + I2C_set_user_data( &g_i2c_inst, (void *)&channel_xdata ); + + ... + + // Retrieve location of user data and do some work on it + p_xdata = (app_data_t *)I2C_get_user_data( &g_i2c_inst ); + if( NULL != p_xdata ) + { + p_xdata->foo = 123; + } + } + @endcode + */ +void * I2C_get_user_data +( + i2c_instance_t * this_i2c +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h new file mode 100644 index 0000000..b1d872d --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h @@ -0,0 +1,190 @@ +/******************************************************************************* + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + */ + +#ifndef __CORE_SMBUS_REGISTERS +#define __CORE_SMBUS_REGISTERS 1 + +/*------------------------------------------------------------------------------ + * CONTROL register details + */ +#define CONTROL_REG_OFFSET 0x00u + +/* + * CR0 bits. + */ +#define CR0_OFFSET 0x00u +#define CR0_MASK 0x01u +#define CR0_SHIFT 0u + +/* + * CR1 bits. + */ +#define CR1_OFFSET 0x00u +#define CR1_MASK 0x02u +#define CR1_SHIFT 1u + +/* + * AA bits. + */ +#define AA_OFFSET 0x00u +#define AA_MASK 0x04u +#define AA_SHIFT 2u + +/* + * SI bits. + */ +#define SI_OFFSET 0x00u +#define SI_MASK 0x08u +#define SI_SHIFT 3u + +/* + * STO bits. + */ +#define STO_OFFSET 0x00u +#define STO_MASK 0x10u +#define STO_SHIFT 4u + +/* + * STA bits. + */ +#define STA_OFFSET 0x00u +#define STA_MASK 0x20u +#define STA_SHIFT 5u + +/* + * ENS1 bits. + */ +#define ENS1_OFFSET 0x00u +#define ENS1_MASK 0x40u +#define ENS1_SHIFT 6u + +/* + * CR2 bits. + */ +#define CR2_OFFSET 0x00u +#define CR2_MASK 0x80u +#define CR2_SHIFT 7u + +/*------------------------------------------------------------------------------ + * STATUS register details + */ +#define STATUS_REG_OFFSET 0x04u + +/*------------------------------------------------------------------------------ + * DATA register details + */ +#define DATA_REG_OFFSET 0x08u + +/* + * TARGET_ADDR bits. + */ +#define TARGET_ADDR_OFFSET 0x08u +#define TARGET_ADDR_MASK 0xFEu +#define TARGET_ADDR_SHIFT 1u + +/* + * DIR bit. + */ +#define DIR_OFFSET 0x08u +#define DIR_MASK 0x01u +#define DIR_SHIFT 0u + + +/*------------------------------------------------------------------------------ + * ADDRESS register details + */ +#define ADDRESS_REG_OFFSET 0x0Cu + +/* + * GC bits. + */ +#define GC_OFFSET 0x0Cu +#define GC_MASK 0x01u +#define GC_SHIFT 0u + +/* + * ADR bits. + */ +#define OWN_SLAVE_ADDR_OFFSET 0x0Cu +#define OWN_SLAVE_ADDR_MASK 0xFEu +#define OWN_SLAVE_ADDR_SHIFT 1u + +/*------------------------------------------------------------------------------ + * SMBUS register details + */ +#define SMBUS_REG_OFFSET 0x10u + +/* + * SMBALERT_IE bits. + */ +#define SMBALERT_IE_OFFSET 0x10u +#define SMBALERT_IE_MASK 0x01u +#define SMBALERT_IE_SHIFT 0u + +/* + * SMBSUS_IE bits. + */ +#define SMBSUS_IE_OFFSET 0x10u +#define SMBSUS_IE_MASK 0x02u +#define SMBSUS_IE_SHIFT 1u + +/* + * SMB_IPMI_EN bits. + */ +#define SMB_IPMI_EN_OFFSET 0x10u +#define SMB_IPMI_EN_MASK 0x04u +#define SMB_IPMI_EN_SHIFT 2u + +/* + * SMBALERT_NI_STATUS bits. + */ +#define SMBALERT_NI_STATUS_OFFSET 0x10u +#define SMBALERT_NI_STATUS_MASK 0x08u +#define SMBALERT_NI_STATUS_SHIFT 3u + +/* + * SMBALERT_NO_CONTROL bits. + */ +#define SMBALERT_NO_CONTROL_OFFSET 0x10u +#define SMBALERT_NO_CONTROL_MASK 0x10u +#define SMBALERT_NO_CONTROL_SHIFT 4u + +/* + * SMBSUS_NI_STATUS bits. + */ +#define SMBSUS_NI_STATUS_OFFSET 0x10u +#define SMBSUS_NI_STATUS_MASK 0x20u +#define SMBSUS_NI_STATUS_SHIFT 5u + +/* + * SMBSUS_NO_CONTROL bits. + */ +#define SMBSUS_NO_CONTROL_OFFSET 0x10u +#define SMBSUS_NO_CONTROL_MASK 0x40u +#define SMBSUS_NO_CONTROL_SHIFT 6u + +/* + * SMBUS_MST_RESET bits. + */ +#define SMBUS_MST_RESET_OFFSET 0x10u +#define SMBUS_MST_RESET_MASK 0x80u +#define SMBUS_MST_RESET_SHIFT 7u + +/*------------------------------------------------------------------------------ + * SLAVE ADDRESS 1 register details + */ + +#define ADDRESS1_REG_OFFSET 0x1Cu + +/* + * SLAVE1_EN bit of Slave Address 1 . + */ +#define SLAVE1_EN_OFFSET 0x1Cu +#define SLAVE1_EN_MASK 0x01u +#define SLAVE1_EN_SHIFT 0u + +#endif /* __CORE_SMBUS_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c new file mode 100644 index 0000000..12e352d --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * CoreI2C driver interrupt control. + * + */ +#include "core_i2c.h" + +/*------------------------------------------------------------------------------ + * This function must be modified to enable interrupts generated from the + * CoreI2C instance identified as parameter. + */ +void I2C_enable_irq( i2c_instance_t * this_i2c ) +{ + HAL_ASSERT(0) +} + +/*------------------------------------------------------------------------------ + * This function must be modified to disable interrupts generated from the + * CoreI2C instance identified as parameter. + */ +void I2C_disable_irq( i2c_instance_t * this_i2c ) +{ + HAL_ASSERT(0) +} diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.c b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.c new file mode 100644 index 0000000..2e11750 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.c @@ -0,0 +1,1345 @@ +/***************************************************************************//** + * Copyright 2013-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * CoreSPI bare metal driver implementation for CoreSPI. + * + * This Core SPI driver provides functions for implementing SPI master or + * SPI slave operations with the CoreSPI version 4.2.xxx It is not compatible + * with CoreSPI version 3.0.xxx. + * + * @file core_spi.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreSPI software configuration + * + */ + +#include "core_spi.h" +#include "corespi_regs.h" +#include + +/******************************************************************************* + * Null parameters with appropriate type definitions + */ +#define NULL_ADDR ( ( addr_t ) 0u ) +#define NULL_INSTANCE ( ( spi_instance_t * ) 0u ) +#define NULL_BUFF ( ( uint8_t * ) 0u ) +#define NULL_FRAME_HANDLER ( ( spi_frame_rx_handler_t ) 0u ) +#define NULL_BLOCK_HANDLER ( ( spi_block_rx_handler_t ) 0u ) +#define NULL_SLAVE_TX_UPDATE_HANDLER ( ( spi_slave_frame_tx_handler_t ) 0u ) +#define NULL_SLAVE_CMD_HANDLER NULL_BLOCK_HANDLER + +#define SPI_ALL_INTS (0xFFu) /* For clearing all active interrupts */ + +/******************************************************************************* + * Possible states for different register bit fields + */ + +#define DISABLE 0u +#define ENABLE 1u + + +/******************************************************************************* + * Function return values + */ +enum { + FAILURE = 0u, + SUCCESS = 1u +}; + +/******************************************************************************* + * Local function declarations + */ +static void fill_slave_tx_fifo( spi_instance_t * this_spi ); +static void read_slave_rx_fifo( spi_instance_t * this_spi ); +static void recover_from_rx_overflow( const spi_instance_t * this_spi ); + +/******************************************************************************* + * SPI_init() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_init +( + spi_instance_t * this_spi, + addr_t base_addr, + uint16_t fifo_depth +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( NULL_ADDR != base_addr ); + HAL_ASSERT( SPI_MAX_FIFO_DEPTH >= fifo_depth ); + HAL_ASSERT( SPI_MIN_FIFO_DEPTH <= fifo_depth ); + + if( ( NULL_INSTANCE != this_spi ) && ( base_addr != NULL_ADDR ) ) + { + /* + * Initialize all transmit / receive buffers and handlers + * + * Relies on the fact that byte filling with 0x00 will equate + * to 0 for any non byte sized items too. + */ + + /* First fill struct with 0s */ + memset( this_spi, 0, sizeof(spi_instance_t) ); + + /* Configure CoreSPI instance attributes */ + this_spi->base_addr = (addr_t)base_addr; + + /* Store FIFO depth or fall back to minimum if out of range */ + if( ( SPI_MAX_FIFO_DEPTH >= fifo_depth ) && ( SPI_MIN_FIFO_DEPTH <= fifo_depth ) ) + { + this_spi->fifo_depth = fifo_depth; + } + else + { + this_spi->fifo_depth = SPI_MIN_FIFO_DEPTH; + } + /* Make sure the CoreSPI is disabled while we configure it */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Ensure all slaves are deselected */ + HAL_set_8bit_reg( this_spi->base_addr, SSEL, 0u ); + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Ensure RXAVAIL, TXRFM, SSEND and CMDINT are disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, 0u ); + /* + * Enable the CoreSPI in the reset default of master mode + * with TXUNDERRUN, RXOVFLOW and TXDONE interrupts disabled. + * The driver does not currently use interrupts in master mode. + */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL1, ENABLE | CTRL1_MASTER_MASK ); + } +} + +/***************************************************************************//** + * SPI_configure_slave_mode() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_configure_slave_mode +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Don't yet know what slave transfer mode will be used */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_NONE; + + /* Make sure the CoreSPI is disabled while we configure it */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Ensure RXAVAIL, TXRFM, SSEND and CMDINT are disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, 0u ); + /* + * Enable the CoreSPI in slave mode with TXUNDERRUN, RXOVFLOW and TXDONE + * interrupts disabled. The appropriate interrupts will be enabled later + * on when the transfer mode is configured. + */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL1, ENABLE ); + } +} + +/***************************************************************************//** + * SPI_configure_master_mode() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_configure_master_mode +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Disable the CoreSPI for a little while, while we configure the CoreSPI */ + HAL_set_8bit_reg_field(this_spi->base_addr, CTRL1_ENABLE, DISABLE); + + /* Reset slave transfer mode to unknown in case it has been set previously */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_NONE; + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Ensure RXAVAIL, TXRFM, SSEND and CMDINT are disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, 0u ); + + /* Enable the CoreSPI in master mode with TXUNDERRUN, RXOVFLOW and TXDONE interrupts disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL1, ENABLE | CTRL1_MASTER_MASK ); + } +} + +/***************************************************************************//** + * SPI_set_slave_select() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +) +{ + spi_slave_t temp = (spi_slave_t)(0x00u) ; + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( SPI_MAX_NB_OF_SLAVES > slave ); + + if( ( NULL_INSTANCE != this_spi ) && ( SPI_MAX_NB_OF_SLAVES > slave ) ) + { + /* This function is only intended to be used with an SPI master */ + if( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW ) ) + { + recover_from_rx_overflow( this_spi ); + } + /* Set the correct slave select bit */ + temp = (spi_slave_t)( HAL_get_8bit_reg( this_spi->base_addr, SSEL ) | ((uint32_t)1u << (uint32_t)slave) ); + HAL_set_8bit_reg( this_spi->base_addr, SSEL, (uint_fast8_t)temp ); + } + } +} + +/***************************************************************************//** + * SPI_clear_slave_select() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_clear_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +) +{ + spi_slave_t temp = (spi_slave_t) (0x00u) ; + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( SPI_MAX_NB_OF_SLAVES > slave ); + + if( ( NULL_INSTANCE != this_spi ) && ( SPI_MAX_NB_OF_SLAVES > slave ) ) + { + /* This function is only intended to be used with an SPI master. */ + if( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW) ) + { + recover_from_rx_overflow( this_spi ); + } + /* Clear the correct slave select bit */ + temp = (spi_slave_t)( HAL_get_8bit_reg( this_spi->base_addr, SSEL ) & ~((uint32_t)1u << (uint32_t)slave) ); + HAL_set_8bit_reg( this_spi->base_addr, SSEL, (uint_fast8_t)temp ) ; + } + } +} + +/***************************************************************************//** + * SPI_transfer_frame() + * See "core_spi.h" for details of how to use this function. + */ +uint32_t SPI_transfer_frame +( + spi_instance_t * this_spi, + uint32_t tx_bits +) +{ + volatile uint32_t rx_data = 0u; /* Ensure consistent return value if in slave mode */ + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI master. */ + if( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Flush the receive and transmit FIFOs by resetting both */ + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK); + + /* Send frame. */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, tx_bits ); + + /* Wait for frame Tx to complete. */ + while ( ENABLE != HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_DONE ) ) + { + ; + } + + /* Read received frame. */ + rx_data = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + } + } + + /* Finally, return the frame we received from the slave or 0 */ + return( rx_data ); +} + + +/***************************************************************************//** + * SPI_transfer_block() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_transfer_block +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_buffer, + uint16_t rx_byte_size +) +{ + uint32_t transfer_size = 0U; /* Total number of bytes to transfer. */ + uint16_t transfer_idx = 0U; /* Number of bytes transferred so far */ + uint16_t tx_idx = 0u; /* Number of valid data bytes sent */ + uint16_t rx_idx = 0u; /* Number of valid response bytes received */ + uint16_t transit = 0U; /* Number of bytes "in flight" to avoid FIFO errors */ + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI master. */ + if( ( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) && + /* Check for empty transfer as well */ + ( 0u != ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) ) ) + { + /* + * tansfer_size is one less than the real amount as we have to write + * the last frame separately to trigger the slave deselect in case + * the SPS option is in place. + */ + transfer_size = ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) - 1u; + /* Flush the receive and transmit FIFOs */ + HAL_set_8bit_reg(this_spi->base_addr, CMD, (uint32_t)(CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK )); + + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW) ) + { + recover_from_rx_overflow( this_spi ); + } + + /* Disable the Core SPI for a little bit, while we load the TX FIFO */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + while( ( tx_idx < transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out 0s to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + } + ++transit; + ++tx_idx; + } + + /* If room left to put last frame in before the off, then do it */ + if( ( tx_idx == transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data, not expecting any reply this time */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out last 0 to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + } + + ++transit; + ++tx_idx; + } + + /* FIFO is all loaded up so enable Core SPI to start transfer */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + + /* Perform the remainder of the transfer by sending a byte every time a byte + * has been received. This should ensure that no Rx overflow can happen in + * case of an interrupt occurring during this function. + * + * We break the transfer down into stages to minimise the processing in + * each loop as the SPI interface is very demanding at higher clock rates. + * This works well with FIFOs but might be less efficient if there is only + * a single frame buffer. + * + * First stage transfers remaining command bytes (if any). + * At this stage anything in the RX FIFO can be discarded as it is + * not part of a valid response. + */ + while( tx_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + /* Send another byte. */ + if( tx_idx == transfer_size ) /* Last frame is special... */ + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Read and discard. */ + HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now, we are writing dummy bytes to push through the response from + * the slave but we still have to keep discarding any read data that + * corresponds with one of our command bytes. + */ + while( transfer_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + if( tx_idx < transfer_size ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Read and discard. */ + HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now we are now only sending dummy data to push through the + * valid response data which we store in the response buffer. + */ + while( tx_idx < transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received byte. */ + rx_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* If we still need to send the last frame */ + while( tx_idx == transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received byte. */ + rx_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* + * Finally, we are now finished sending data and are only reading + * valid response data which we store in the response buffer. + */ + while( transfer_idx <= transfer_size ) + { + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received byte. */ + rx_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + } + } + } + } +} + +/***************************************************************************//** + * SPI_transfer_block_store_all_resp() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_transfer_block_store_all_resp +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_data_buffer, + uint16_t rx_byte_size, + uint8_t * cmd_response_buffer +) +{ + uint32_t transfer_size = 0U; /* Total number of bytes to transfer. */ + uint16_t transfer_idx = 0U; /* Number of bytes transferred so far */ + uint16_t tx_idx = 0u; /* Number of valid data bytes sent */ + uint16_t rx_idx = 0u; /* Number of valid response bytes received */ + uint16_t transit = 0U; /* Number of bytes "in flight" to avoid FIFO errors */ + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI master. */ + if( ( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) && + /* Check for empty transfer as well */ + ( 0u != ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) ) ) + { + /* + * tansfer_size is one less than the real amount as we have to write + * the last frame separately to trigger the slave deselect in case + * the SPS option is in place. + */ + transfer_size = ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) - 1u; + /* Flush the receive and transmit FIFOs */ + HAL_set_8bit_reg(this_spi->base_addr, CMD, (uint32_t)(CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK )); + + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW) ) + { + recover_from_rx_overflow( this_spi ); + } + + /* Disable the Core SPI for a little bit, while we load the TX FIFO */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + while( ( tx_idx < transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out 0s to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + } + ++transit; + ++tx_idx; + } + + /* If room left to put last frame in before the off, then do it */ + if( ( tx_idx == transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data, not expecting any reply this time */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out last 0 to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + } + + ++transit; + ++tx_idx; + } + + /* FIFO is all loaded up so enable Core SPI to start transfer */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + + /* Perform the remainder of the transfer by sending a byte every time a byte + * has been received. This should ensure that no Rx overflow can happen in + * case of an interrupt occurring during this function. + * + * We break the transfer down into stages to minimise the processing in + * each loop as the SPI interface is very demanding at higher clock rates. + * This works well with FIFOs but might be less efficient if there is only + * a single frame buffer. + * + * First stage transfers remaining command bytes (if any). + * At this stage anything in the RX FIFO can be discarded as it is + * not part of a valid response. + */ + while( tx_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + /* Send another byte. */ + if( tx_idx == transfer_size ) /* Last frame is special... */ + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received command byte. */ + cmd_response_buffer[transfer_idx] = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now, we are writing dummy bytes to push through the response from + * the slave, which we store in the command response buffer. + */ + while( transfer_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + if( tx_idx < transfer_size ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received command byte. */ + cmd_response_buffer[transfer_idx] = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now we are now only sending dummy data to push through the + * valid response data which we store in the data response buffer. + */ + while( tx_idx < transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received data byte. */ + rx_data_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* If we still need to send the last frame */ + while( tx_idx == transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received data byte. */ + rx_data_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* + * Finally, we are now finished sending data and are only reading + * valid response data which we store in the data response buffer. + */ + while( transfer_idx <= transfer_size ) + { + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received data byte. */ + rx_data_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + } + } + } + } +} +/***************************************************************************//** + * SPI_set_frame_rx_handler() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_frame_rx_handler +( + spi_instance_t * this_spi, + spi_frame_rx_handler_t rx_handler +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if(NULL_INSTANCE != this_spi) + { + /* This function is only intended to be used with an SPI slave. */ + if(DISABLE == HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER)) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Disable SSEND and CMD interrupts as we are not doing block transfers */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTSSEND, DISABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + + /* Disable block Rx handler as they are mutually exclusive. */ + this_spi->block_rx_handler = 0U; + + /* Keep a copy of the pointer to the Rx handler function. */ + this_spi->frame_rx_handler = rx_handler; + + if( SPI_SLAVE_XFER_FRAME != this_spi->slave_xfer_mode ) + { + /* + * Either just coming from init or were previously in block mode + * so no tx frame handler is set at this point in time... + * + * Don't allow TXDONE interrupts. + */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXDONE, DISABLE ); + } + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK); + + /* Enable Rx and FIFO error interrupts */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTRXOVFLOW, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXURUN, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTRXDATA, ENABLE ); + + /* Make sure correct mode is selected */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_FRAME; + + /* Finally re-enable the CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } + } +} + +/***************************************************************************//** + * SPI_set_slave_tx_frame() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_slave_tx_frame +( + spi_instance_t * this_spi, + uint32_t frame_value, + spi_slave_frame_tx_handler_t slave_tx_frame_handler +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI slave. */ + if( DISABLE == HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Disable SSEND and CMD interrupts as we are not doing block transfers */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTSSEND, DISABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + + if( SPI_SLAVE_XFER_FRAME != this_spi->slave_xfer_mode ) + { + /* + * Either just coming from init or were previously in block mode + * so no rx frame handler is set at this point in time... + * + * Don't allow RXDATA interrupts. + */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTRXDATA, DISABLE ); + } + + /* Disable slave block tx buffer as it is mutually exclusive with frame + * level handling. */ + this_spi->slave_tx_buffer = NULL_BUFF; + this_spi->slave_tx_size = 0U; + this_spi->slave_tx_idx = 0U; + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK); + + /* Assign the slave frame update handler - NULL_SLAVE_TX_UPDATE_HANDLER for none */ + this_spi->slave_tx_frame_handler = slave_tx_frame_handler; + + /* Keep a copy of the slave Tx frame value. */ + this_spi->slave_tx_frame = frame_value; + + /* Load one frame into Tx data register. */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, this_spi->slave_tx_frame ); + + /* Enable Tx Done interrupt in order to reload the slave Tx frame after each + * time it has been sent. */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXDONE, ENABLE ); + + /* Make sure correct mode is selected */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_FRAME; + + /* Ready to go so enable CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } + } +} + +/***************************************************************************//** + * SPI_set_slave_block_buffers() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_slave_block_buffers +( + spi_instance_t * this_spi, + const uint8_t * tx_buffer, + uint32_t tx_buff_size, + uint8_t * rx_buffer, + uint32_t rx_buff_size, + spi_block_rx_handler_t block_rx_handler +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI slave. */ + if( DISABLE == HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Make sure correct mode is selected */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_BLOCK; + /* + * No command handler should be setup at this stage so fake this + * to ensure 0 padding works. + */ + this_spi->cmd_done = 1u; + + /* Disable frame handlers as they are mutually exclusive with block Rx handler. */ + this_spi->frame_rx_handler = NULL_FRAME_HANDLER; + this_spi->slave_tx_frame_handler = NULL_SLAVE_TX_UPDATE_HANDLER; + + /* Keep a copy of the pointer to the block Rx handler function. */ + this_spi->block_rx_handler = block_rx_handler; + + /* Assign slave receive buffer */ + this_spi->slave_rx_buffer = rx_buffer; + this_spi->slave_rx_size = rx_buff_size; + this_spi->slave_rx_idx = 0U; + + /* Assign slave transmit buffer*/ + this_spi->slave_tx_buffer = tx_buffer; + this_spi->slave_tx_size = tx_buff_size; + this_spi->slave_tx_idx = 0U; + + /* Flush the receive and transmit FIFOs */ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Preload the transmit FIFO. */ + while( !(HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_TXFULL)) && + ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->slave_tx_buffer[this_spi->slave_tx_idx] ); + ++this_spi->slave_tx_idx; + } + /* + * Disable TXDATA interrupt as we will look after transmission in rx handling + * because we know that once we have read a frame it is safe to send another one. + */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTTXDATA, DISABLE ); + + /* Enable Rx, FIFO error and SSEND interrupts */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTRXOVFLOW, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXURUN, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTRXDATA, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTSSEND, ENABLE ); + + /* Disable command handler until it is set explicitly */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + + /* Now enable the CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } + } +} + +/***************************************************************************//** + * SPI_set_cmd_handler() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_cmd_handler +( + spi_instance_t * this_spi, + spi_block_rx_handler_t cmd_handler, + uint32_t cmd_size +) +{ + uint32_t ctrl2 = 0u; + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( NULL_SLAVE_CMD_HANDLER != cmd_handler ); + HAL_ASSERT( 0u < cmd_size ); + + if( ( NULL_INSTANCE != this_spi ) && ( 0u < cmd_size ) && + ( NULL_SLAVE_CMD_HANDLER != cmd_handler ) ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + /* + * Note we don't flush the FIFOs as this has been done already when + * block mode was configured. + * + * Clear this flag so zero padding is disabled until command response + * has been taken care of. + */ + this_spi->cmd_done = 0u; + + /* Assign user handler for Command received interrupt */ + this_spi->cmd_handler = cmd_handler; + + /* Configure the command size and Enable Command received interrupt */ + ctrl2 = HAL_get_8bit_reg( this_spi->base_addr, CTRL2 ); + + /* First clear the count field then insert count and int enables */ + ctrl2 &= ~(uint32_t)CTRL2_CMDSIZE_MASK; + ctrl2 |= (uint32_t)((cmd_size & CTRL2_CMDSIZE_MASK) | CTRL2_INTCMD_MASK | CTRL2_INTRXDATA_MASK); + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, ctrl2 ); + + /* Now enable the CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } +} + +/***************************************************************************//** + * SPI_set_cmd_response() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_cmd_response +( + spi_instance_t * this_spi, + const uint8_t * resp_tx_buffer, + uint32_t resp_buff_size +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( NULL_BUFF != resp_tx_buffer ); + HAL_ASSERT( 0u < resp_buff_size ); + + if( ( NULL_INSTANCE != this_spi ) && ( 0u < resp_buff_size ) && + ( NULL_BUFF != resp_tx_buffer ) ) + { + this_spi->resp_tx_buffer = resp_tx_buffer; + this_spi->resp_buff_size = resp_buff_size; + this_spi->resp_buff_tx_idx = 0u; + + fill_slave_tx_fifo(this_spi); + } +} + + +/***************************************************************************//** + * SPI_enable() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_enable +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } +} + + +/***************************************************************************//** + * SPI_disable() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_disable +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + } +} + + +/***************************************************************************//** + * SPI interrupt service routine. + */ +void SPI_isr +( + spi_instance_t * this_spi +) +{ + uint32_t rx_frame; + int32_t guard; + +/* + * The assert and the NULL check here can be commented out to reduce the interrupt + * latency once you are sure the interrupt vector code is correct. + */ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + if( NULL_INSTANCE != this_spi ) + { + /* Handle receive. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_RXDATA ) ) + { + /* + * Service receive data according to transfer mode in operation. + * + * We check block mode first as this is most likely to have back to back + * transfers with multiple bytes. + * + * Note the order of the checks here will effect interrupt latency and + * for critical timing the mode you are using most often should probably be + * be the first checked. + */ + if( SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode ) /* Block handling mode. */ + { + while( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Read irrespective to clear the RX IRQ */ + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + if( this_spi->slave_rx_idx < this_spi->slave_rx_size ) + { + this_spi->slave_rx_buffer[this_spi->slave_rx_idx] = (uint8_t)rx_frame; + } + ++this_spi->slave_rx_idx; + } + /* + * Now handle updating of tx FIFO to keep the data flowing. + * First see if there is anything in slave_tx_buffer to send. + */ + while( ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) + && ( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->slave_tx_buffer[this_spi->slave_tx_idx] ); + ++this_spi->slave_tx_idx; + } + /* + * Next see if there is anything in resp_tx_buffer to send. + */ + if( this_spi->slave_tx_idx >= this_spi->slave_tx_size ) + { + while( ( this_spi->resp_buff_tx_idx < this_spi->resp_buff_size ) + && ( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->resp_tx_buffer[this_spi->resp_buff_tx_idx] ); + ++this_spi->resp_buff_tx_idx; + } + } + /* + * Lastly, see if we are ready to pad with 0s . + */ + if( this_spi->cmd_done && ( this_spi->slave_tx_idx >= this_spi->slave_tx_size ) && + ( this_spi->resp_buff_tx_idx >= this_spi->resp_buff_size ) ) + { + guard = 1 + ((int32_t)this_spi->fifo_depth / 4); + while( ( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) + && ( 0 != guard ) ) + { + /* + * Pad TX FIFO with 0s for consistent behaviour if the master + * tries to transfer more than we expected. + */ + HAL_set_32bit_reg(this_spi->base_addr, TXDATA, 0x00u); + /* + * We use the guard count to cover the event that we are never + * seeing the TX FIFO full because the data is being pulled + * out as fast as we can stuff it in. In this case we never spend + * more than our allocated time spinning here. + */ + guard--; + } + } + } + else if( SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode ) /* Single frame handling mode. */ + { + while( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + if( NULL_FRAME_HANDLER != this_spi->frame_rx_handler ) + { + this_spi->frame_rx_handler( rx_frame ); + } + } + } + else /* Slave transfer mode not set up so discard anything in RX FIFO */ + { + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_RXFIFORST_MASK ); + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_RXDATA, ENABLE ); + } + + /* Handle transmit. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_TXDONE ) ) + { + /* + * Note, the driver only currently uses the txdone interrupt when + * in frame transmit mode. In block mode all TX handling is done by the + * receive interrupt handling code as we know that for every frame received + * a frame must be placed in the TX FIFO. + */ + if( SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode ) + { + /* Execute the user callback to update the slave_tx_frame */ + if( NULL_SLAVE_TX_UPDATE_HANDLER != this_spi->slave_tx_frame_handler ) + { + this_spi->slave_tx_frame_handler ( this_spi ); + } + + /* Reload slave tx frame into Tx data register. */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, this_spi->slave_tx_frame ); + } + else if( SPI_SLAVE_XFER_BLOCK != this_spi->slave_xfer_mode ) + { + /* Slave transfer mode not set up so discard anything in TX FIFO */ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK ); + } + else + { + /* Nothing to do, no slave mode configured */ + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_TXDONE, ENABLE ); + } + + + /* Handle receive overflow. */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, INTMASK_RXOVERFLOW)) + { + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_RXFIFORST_MASK); + HAL_set_8bit_reg_field(this_spi->base_addr, INTCLR_RXOVERFLOW, ENABLE); + } + + /* Handle transmit under run. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_TXUNDERRUN ) ) + { + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK ); + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_TXUNDERRUN, ENABLE ); + } + + /* Handle command interrupt. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_CMDINT ) ) + { + read_slave_rx_fifo( this_spi ); + + /* + * Call the command handler if one exists. + */ + if( NULL_SLAVE_CMD_HANDLER != this_spi->cmd_handler ) + { + this_spi->cmd_handler( this_spi->slave_rx_buffer, this_spi->slave_rx_idx ); + } + this_spi->cmd_done = 1u; + /* Disable command interrupt until slave select becomes de-asserted to avoid retriggering. */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_CMDINT, ENABLE ); + } + + /* Handle slave select becoming de-asserted. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_SSEND) ) + { + /* Only supposed to do all this if transferring blocks... */ + if(SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode) + { + uint32_t rx_size; + + /* Empty any remaining bytes in RX FIFO */ + read_slave_rx_fifo( this_spi ); + rx_size = this_spi->slave_rx_idx; + /* + * Re-enable command interrupt if required. + * Must be done before re loading FIFO to ensure stale response + * data is not pushed into the FIFO. + */ + if(NULL_SLAVE_CMD_HANDLER != this_spi->cmd_handler) + { + this_spi->cmd_done = 0u; + this_spi->resp_tx_buffer = 0u; + this_spi->resp_buff_size = 0u; + this_spi->resp_buff_tx_idx = 0u; + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_CMDINT, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, ENABLE ); + } + /* + * Reset the transmit index to 0 to restart transmit at the start of the + * transmit buffer in the next transaction. This also requires flushing + * the Tx FIFO and refilling it with the start of Tx data buffer. + */ + this_spi->slave_tx_idx = 0u; + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + fill_slave_tx_fifo( this_spi ); + + /* Prepare to receive next packet. */ + this_spi->slave_rx_idx = 0u; + /* + * Call the receive handler if one exists. + */ + if( NULL_BLOCK_HANDLER != this_spi->block_rx_handler ) + { + this_spi->block_rx_handler( this_spi->slave_rx_buffer, rx_size ); + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_RXDATA, ENABLE ); + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_SSEND, ENABLE ); + } + } +} + +/******************************************************************************* + * Local function definitions + */ + +/***************************************************************************//** + * Fill the transmit FIFO (used for slave block transfers). + */ +static void fill_slave_tx_fifo +( + spi_instance_t * this_spi +) +{ + /* First see if slave_tx_buffer needs transmitting */ + while( ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) && + !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->slave_tx_buffer[this_spi->slave_tx_idx] ); + ++this_spi->slave_tx_idx; + } + + /* Then see if it is safe to look at putting resp_tx_buffer in FIFO? */ + if( this_spi->slave_tx_idx >= this_spi->slave_tx_size ) + { + while( ( this_spi->resp_buff_tx_idx < this_spi->resp_buff_size ) && + !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->resp_tx_buffer[this_spi->resp_buff_tx_idx] ); + ++this_spi->resp_buff_tx_idx; + } + } +} + +/***************************************************************************//** + * + */ +static void read_slave_rx_fifo +( + spi_instance_t * this_spi +) +{ + uint32_t rx_frame; + + if( SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode ) /* Block handling mode. */ + { + while( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); /* Read irresepective to clear the RX IRQ */ + if( this_spi->slave_rx_idx < this_spi->slave_rx_size ) + { + this_spi->slave_rx_buffer[this_spi->slave_rx_idx] = (uint8_t)rx_frame; + } + ++this_spi->slave_rx_idx; + } + } + else if( SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode ) /* Frame handling mode */ + { + while( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Single frame handling mode. */ + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + if( NULL_FRAME_HANDLER != this_spi->frame_rx_handler ) + { + this_spi->frame_rx_handler( rx_frame ); + } + } + } + else /* Slave transfer mode not set up so discard anything in RX FIFO */ + { + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_RXFIFORST_MASK ); + } +} + +/***************************************************************************//** + * This function is to recover the CoreSPI from receiver overflow. + * It temporarily disables the CoreSPI from interacting with external world, flushes + * the transmit and receiver FIFOs, clears all interrupts and then re-enables + * the CoreSPI instance referred by this_spi parameter. + */ +static void recover_from_rx_overflow +( + const spi_instance_t * this_spi +) +{ + /* Disable CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Reset TX and RX FIFOs */ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Enable CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); +} + + diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.h new file mode 100644 index 0000000..c6873f7 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.h @@ -0,0 +1,1324 @@ +/***************************************************************************//** + * Copyright 2013-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Core SPI bare metal software driver public API. + * + * This Core SPI driver provides functions for implementing SPI master or + * SPI slave operations with the CoreSPI version 4.2.xxx It is not compatible + * with CoreSPI version 3.0.xxx. + * + * The Core SPI driver supports two classes of data transfer operation: + * SPI frame operation or SPI block transfer operations. + * + * Frame operations allow transferring individual SPI frames from 4 to 32-bits + * in length. Block operations allow transferring blocks of data organized as + * 8-bit frames. + * + * @file core_spi.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreSPI prototypes + * + */ + +/*=========================================================================*//** + @mainpage Core SPI Bare Metal Driver. + + ============================================================================== + Introduction + ============================================================================== + CoreSPI is an IP component that implements a full-duplex, synchronous, and + configurable serial peripheral interface (SPI) with frame sizes from 4 to 32 + bits and bus interface sizes of 8-, 16-, or 32-bit. Each CoreSPI instance + communicates with up to eight slave devices. + + This driver provides a set of functions for controlling CoreSPI as part of + the bare metal system where no operating system is available. These drivers + can be adapted to be used as a part of an operating system, but the + implementation of the adaptation layer between driver and the operating + system's driver model is outside the scope of this User's Guide. + + ============================================================================== + Driver Configuration + ============================================================================== + Your application software should configure the CoreSPI driver through calls + to the SPI_init() function for each CoreSPI instance in the hardware design. + This function configures a default set of parameters that include a CoreSPI + hardware instance base address and the depth of the FIFOs for this instance. + + The CoreSPI instance is configured at the time of instantiation in hardware + design for APB width, frame size, FIFO depth, serial clock speed, serial + clock polarity, serial clock phase, and slave select state parameters. + + CoreSPI can communicate with up to eight different slave devices that match + the CoreSPI configuration at the time of hardware instantiation. + + The functions SPI_configure_slave_mode() and SPI_configure_master_mode() are + used to configure the CoreSPI instance as a master or slave as required by + the application. + + When CoreSPI wishes to communicate with a specific slave device, call + the SPI_set_slave_select() function with the slave number as an argument. + This function selects the slave device. A previously selected slave gets + unselected by calling the SPI_clear_slave_select() function. + + ============================================================================== + Theory of Operation + ============================================================================== + The CoreSPI driver functions are grouped into the following categories: + • Initialization + • Configuration for either master or slave operations + • SPI master frame transfer control + • SPI master block transfer control + • SPI slave frame transfer control + • SPI slave block transfer control + + Frame transfers allow CoreSPI to write or read up to 32-bits of data in a + single SPI transaction. For example, a frame transfer of 12-bits might be used + to read the result of an ADC conversion from a SPI analog to digital converter. + + Block transfers allow CoreSPI to write and/or read a number of bytes in a single + SPI transaction. With the driver as is, block transfer transactions allow data + transfers in multiples of 8-bits (8, 16, 24, 32, 40,...) and the CoreSPI instance + has to be configured for 8-bit frames. For other frame sizes, the + SPI_transfer_block() code can act as a template for developing a frame block + transfer function. + Block transfers are typically used with byte oriented devices like SPI + FLASH devices. + + Note: The CoreSPI instance in the hardware design must be configured for + the frame size required by the application; configuration by driver is + not possible. + + -------------------------------- + Initialization + -------------------------------- + The CoreSPI driver is initialized through a call to the SPI_init() function. + The SPI_init() function takes a pointer to the global CoreSPI instance data + structure of type spi_instance_t and the base address of the CoreSPI instance + as defined by the hardware design. The CoreSPI instance global data structure + is used by the driver to store state information for each CoreSPI instance. + A pointer to these data structures is also used as the first parameter to + any of the driver functions to identify which CoreSPI will be used by the + called function. It is the responsibility of the application programmer to + create and maintain these global CoreSPI instance data structures. Any call + to a CoreSPI driver function should be of the form SPI_function_name + ( &g_core_spi0, ... ). + The SPI_init() function resets the transmit and receives FIFOs of CoreSPI + instance being initialized. + The SPI_init() function must be called before any other CoreSPI driver + functions can be called. + + ---------------------------------------------------- + Configuration + ---------------------------------------------------- + A CoreSPI instance can operate either as a master or as a slave SPI device. + There are two distinct functions for configuring a CoreSPI instance for + master or slave operations. + + ## Master Configuration + The SPI_configure_master_mode() function configures the specified CoreSPI + block for operations as an SPI master. This function must be called once + before the CoreSPI block communicates with an SPI slave device. + + ## Slave Configuration + The SPI_configure_slave_mode() function configures the specified CoreSPI + block for operations as a SPI slave. This function must be called after + calling the SPI_init() to configure the CoreSPI instance referred by this_spi + parameter to operate in the slave mode. + + ------------------------------------- + SPI Master Frame Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI master frame transfers: + • SPI_set_slave_select() + • SPI_transfer_frame() + • SPI_clear_slave_select() + + The master must first select the target slave or slaves to be addressed by + calling the SPI_set_slave_select() function. This causes the relevant select + line(s) to become asserted while data is clocked out onto the SPI data line. + + A function call is then made to SPI_transfer_frame() specifying the value + of the data frame to be sent and returning the value read. + + After the transfer is complete, use the SPI_clear_slave_select() function + to prevent this slave select line from being asserted during subsequent SPI + transactions. A call to this function is required only if the master is + communicating with multiple slave devices. + + ------------------------------------- + SPI Master Block Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI master block transfers: + • SPI_set_slave_select() + • SPI_transfer_block() + • SPI_clear_slave_select() + + The master must first select the target slave or slaves by calling + SPI_set_slave_select(). This causes the relevant slave select line(s) to + become asserted while data is clocked out onto the SPI data line. + Alternatively, a general purpose input/output (GPIO) can be used to control + the state of the target slave device's chip select signal. + + A call is then made to the SPI_transfer_block() function. The parameters of + this function specify the following: + • The number of bytes to be transmitted + • A pointer to the buffer containing the data to be transmitted + • The number of bytes to be received + • A pointer to the buffer where the received data gets stored + + The number of bytes to be transmitted can be set to zero to indicate that the + transfer is purely a block read transfer. The number of bytes to be received + can be set to zero to specify that the transfer is purely a block write + transfer. + + Block mode transfers as implemented by the driver are effectively half duplex + as we do not store the values received from the slave device whilst we are + transmitting. If full duplex operation is required, the driver + SPI_transfer_block() function can serve as a starting point for implementing + full duplex block transfers. + + The SPI_clear_slave_select() function can be used after the transfer is + complete to prevent this slave select line from being asserted during + subsequent SPI transactions. A call to this function is only required if + the master is communicating with multiple slave devices. + + ------------------------------------- + SPI Slave Frame Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI slave frame transfers: + • SPI_set_frame_rx_handler() + • SPI_set_slave_tx_frame() + + The SPI_set_frame_rx_handler() function specifies the receive handler + function that is called when a frame of data has been received by the + SPI when it is configured as a slave. The receive handler function specified + through this call processes the frame data written over the SPI bus to the + SPI slave by the remote SPI master. The receive handler function must be + implemented as part of the application. It is only required if the SPI slave + is the target of SPI frame write transactions. + + The SPI_set_slave_tx_frame() function specifies the frame data that is + returned to the SPI master. The frame data specified through this function + is the value that will be read over the SPI bus by the remote SPI master, + when it initiates a transaction. Call the SPI_set_slave_tx_frame() function + only if the SPI slave is the target of SPI read transactions. That is, if + data is meant to be read over CoreSPI. + + If both frame handlers are required, call the SPI_set_frame_rx_handler() + first, otherwise the initial TX frame gets discarded when SPI_set_frame_rx_handler() + clears the FIFOs as part of its initialization. + + ------------------------------------- + SPI Slave Block Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI slave block transfers: + • SPI_set_slave_block_buffers() + • SPI_set_cmd_handler() + • SPI_set_cmd_response() + + The SPI_set_slave_block_buffers() function is used to configure an SPI slave + for block transfer operations. It specifies the following: + • The buffer containing the data that will be returned to the remote SPI + master + • The buffer where data received from the remote SPI master will be + stored + • The optional handler function that will be called after the receive + buffer is filled + + The SPI_set_cmd_handler() function specifies a command handler function that + is called by the driver once a specific number of frames have been + received after the SPI chip select signal becomes active. The number of + bytes making up the command part of the transaction is specified as part of + the parameters to the SPI_set_cmd_handler() function. The command handler + function is implemented as a part of the application making use of the SPI + driver and typically calls the SPI_set_cmd_response() function. + + The SPI_set_cmd_response() function specifies the data that gets returned + to the master. Typically, the SPI_set_slave_block_buffers() function is + called as a part of the system initialisation to specify the data sent to + the master while the command bytes are being received. The transmit buffer + specified through calling the SPI_set_slave_block_buffers() function would + also typically include one or more bytes allowing the turn around time + for the command handler function to execute and call the + SPI_set_cmd_response() function. + + *//*=========================================================================*/ +#ifndef CORE_SPI_H_ +#define CORE_SPI_H_ + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#include "hal_assert.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + SPI FIFO Depth + ======================================= + SPI_MAX_FIFO_DEPTH & SPI_MIN_FIFO_DEPTH constants define the maximum and minimum + FIFO depths allowed for the CoreSPI instance. User need to inform the driver of + the FIFO depth for each CoreSPI instance to ensure that the FIFOs are managed correctly. + + | Constant | Description | + |--------------------|----------------------------------------------------| + | SPI_MAX_FIFO_DEPTH | Maximum FIFO depth allowed for the CoreSPI instance| + | SPI_MIN_FIFO_DEPTH | Minimum FIFO depth allowed for the CoreSPI instance| + + */ +#define SPI_MAX_FIFO_DEPTH 32u +#define SPI_MIN_FIFO_DEPTH 1u + +/***************************************************************************//** + Instances of this structure are used to identify the specific CoreSPI hardware + instances. A pointer to an instance of the spi_instance_t structure is passed + as the first parameter to the CoreSPI driver functions to identify which SPI + performs the requested operation. + */ +typedef struct spi_instance spi_instance_t; + +/***************************************************************************//** + This function pointer type is to assign a callback function for TX interrupt + when slave wants to send the next updated frame. + + Declaring and Implementing Slave Frame Transmit Handler Functions: + Slave transmit frame update handler functions should follow the following + prototype: + void slave_tx_frame_update_handler ( spi_instance_t * this_spi ); + The actual name of the transmit handler is unimportant. You can use any name + of your choice for the frame update handler. + + A common handler function may be used when multiple CoreSPI instances are + configured as slave, as the particular slave device currently requiring + service is indicated by the function parameter. + */ +typedef void (*spi_slave_frame_tx_handler_t)( spi_instance_t * this_spi ); + +/***************************************************************************//** + This defines the function prototype that must be followed by the SPI slave + frame receive handler functions. These functions are registered with the SPI + driver through the SPI_set_frame_rx_handler() function. + + Declaring and Implementing the Slave Frame Receive Handler Functions: + The Slave frame receive handler functions should follow the following + prototype: + void slave_frame_receive_handler(uint32_t rx_frame); + The actual name of the receive handler is unimportant. You can use any name + of your choice for the receive frame handler. The rx_frame parameter contains + the value of the received frame. + + Separate handler functions are required for each slave instance as there is + no indication of the slave requiring service passed to the handler. + + */ +typedef void (*spi_frame_rx_handler_t)( uint32_t rx_frame ); + +/***************************************************************************//** + This defines the function prototype that must be followed by SPI slave + block receive handler functions. These functions are registered with the + SPI driver through the SPI_set_slave_block_buffers() function. + + Declaring and Implementing Slave Block Receive Handler Functions: + Slave block receive handler functions should follow the following prototype: + void spi_block_rx_handler ( uint8_t * rx_buff, uint16_t rx_size ); + The actual name of the receive handler is unimportant. You can use any name + of your choice for the receive frame handler. The rx_buff parameter contains + a pointer to the start of the received block. The rx_size parameter contains + the number of bytes of the received block. + + Separate handler functions are required for each slave instance as there is + no indication of the slave requiring service passed to the handler. + + */ +typedef void (*spi_block_rx_handler_t)( uint8_t * rx_buff, uint32_t rx_size ); + +/***************************************************************************//** + This enumeration is used to select a specific SPI slave device (0 to 7). It is + used as a parameter to the SPI_configure_master_mode(), SPI_set_slave_select(), + and SPI_clear_slave_select() functions. + */ +typedef enum __spi_slave_t +{ + SPI_SLAVE_0 = 0, + SPI_SLAVE_1 = 1, + SPI_SLAVE_2 = 2, + SPI_SLAVE_3 = 3, + SPI_SLAVE_4 = 4, + SPI_SLAVE_5 = 5, + SPI_SLAVE_6 = 6, + SPI_SLAVE_7 = 7, + SPI_MAX_NB_OF_SLAVES = 8 +} spi_slave_t; + +/***************************************************************************//** + This enumeration is used to indicate the current slave mode transfer type so + that we are not relying on buffer comparisons to dictate the logic of the driver. + */ +typedef enum __spi_sxfer_mode_t +{ + SPI_SLAVE_XFER_NONE = 0, /* Not configured yet */ + SPI_SLAVE_XFER_BLOCK = 1, /* Block transfers, with SSEND delimiting end of block */ + SPI_SLAVE_XFER_FRAME = 2 /* Single frame transfers */ +} spi_sxfer_mode_t; + +/***************************************************************************//** + There is one instance of this structure for each of the core SPIs. Instances + of this structure are used to identify a specific SPI. A pointer to an + instance of the spi_instance_t structure is passed as the first parameter to + SPI driver functions to identify which SPI should perform the requested operation. + */ +struct spi_instance{ + + /* Base address in the processor's memory map for the + registers of the CoreSPI instance being initialized */ + addr_t base_addr; /* Base address of SPI hardware instance */ + + uint32_t rx_frame; /* received data */ + + /* Internal transmit state: */ + const uint8_t * slave_tx_buffer; /* Pointer to slave transmit buffer */ + uint32_t slave_tx_size; /* Size of slave transmit buffer */ + uint32_t slave_tx_idx; /* Current index into slave transmit buffer */ + + /* Slave command response buffer: */ + const uint8_t * resp_tx_buffer; + uint32_t resp_buff_size; + uint32_t resp_buff_tx_idx; + spi_block_rx_handler_t cmd_handler; + uint32_t cmd_done; /* Flag which indicates response has been set up and + it is safe to pad with 0s once the response is sent */ + + /* Internal receive state: */ + uint8_t * slave_rx_buffer; /* Pointer to buffer where data received by a slave will be stored */ + uint32_t slave_rx_size; /* Slave receive buffer size */ + uint32_t slave_rx_idx; /* Current index into slave receive buffer */ + + /* Slave received frame handler: */ + spi_frame_rx_handler_t frame_rx_handler; /* Pointer to function that will be called when a frame + is received when the SPI block is configured as slave */ + /* Slave transmitted frame handler: */ + uint32_t slave_tx_frame; /* Value of the data frame that will be transmitted + when the SPI block is configured as slave */ + spi_slave_frame_tx_handler_t slave_tx_frame_handler; /* Callback function pointer to update slave_tx_frame */ + + /* Slave block rx handler: */ + spi_block_rx_handler_t block_rx_handler; /* Pointer to the function that will be called when a data block has been received */ + + /* Per instance specific hardware information that the driver needs to know */ + uint16_t fifo_depth; /* Depth of RX and TX FIFOs in frames */ + + /* How we are expecting to deal with slave transfers */ + spi_sxfer_mode_t slave_xfer_mode; /* Current slave mode transfer configuration */ +}; + +/*------------------------Public Function-------------------------------------*/ + +/***************************************************************************//** + The SPI_init() function initializes the hardware and data structures of a + CoreSPI instance referenced by this_spi parameter. This function must be + called for each CoreSPI instance with a unique this_spi and base_addr + parameter combination. The SPI_init() function must be called before any + other CoreSPI driver functions are called. + + After calling the SPI_init() the CoreSPI is configured as a master, + all interrupt sources will be masked and all the slaves are deselected. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to be initialized. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @param base_addr + The base_addr parameter is the base address in the processor's memory map for + the registers of the CoreSPI instance being initialized. It is assumed that + any non NULL value passed in here points to a valid instance of a CoreSPI as + the driver has no way of verifying this. Failure to pass in a valid address + can result in system instability. + + @param fifo_depth + The fifo_depth parameter specifies the number of frames in the receive + and transmit FIFOs of the CoreSPI instance being initialized. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + @endcode + */ +void SPI_init +( + spi_instance_t * this_spi, + addr_t base_addr, + uint16_t fifo_depth +); + +/***************************************************************************//** + The SPI_configure_slave_mode() function is used when a CoreSPI instance is + to be configured as a SPI slave. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to be configured. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + + int main(void) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_slave_mode ( &g _spi0 ); + } + @endcode + */ +void SPI_configure_slave_mode +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_configure_master_mode() function is used when a CoreSPI instance is + to be configured as a SPI master. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to be configured. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + + int main(void) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_master_mode ( &g _spi0 ); + } + @endcode + */ +void SPI_configure_master_mode +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_set_slave_select() function is used by a CoreSPI master to select a + specific slave. This function causes the relevant slave select signal to be + asserted while data is clocked out onto the SPI data line. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param slave + The slave parameter is one of the spi_slave_t enumerated constants + identifying a slave. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + const uint32_t master_tx_frame = 0x0100A0E1; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0 ); + SPI_transfer_frame( &g_spi0, master_tx_frame ); + SPI_clear_slave_select( &g_spi0, SPI_SLAVE_0 ); + + @endcode + */ +void SPI_set_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +); + +/***************************************************************************//** + The SPI_clear_slave_select() function is used by a CoreSPI master to + deselect a specific slave. This function causes the relevant slave select + signal to be de-asserted. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param slave + The slave parameter is one of the spi_slave_t enumerated constants + identifying a slave. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + const uint32_t master_tx_frame = 0x0100A0E1; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0 ); + SPI_transfer_frame( &g_spi0, master_tx_frame ); + SPI_clear_slave_select( &g_spi0, SPI_SLAVE_0 ); + @endcode + */ +void SPI_clear_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +); + +/***************************************************************************//** + The SPI_transfer_frame() function is used by a SPI master to transmit and + receive a single frame of the size that has been configured at the time of + CoreSPI hardware instantiation. This function is typically used for + transactions with a SPI slave where the number of transmit and receive bits + are not divisible by 8 or where full duplex exchange of frames is required. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param tx_bits + The tx_bits parameter is a 32-bit word containing the value that will be + transmitted. If the frame size configured for the CoreSPI is less than 32-bits, + the upper bits will be ignored. + Note: The bit length of the value to be transmitted to the slave is + set when the CoreSPI is instantiated in the hardware design. + + @return + This function returns a 32-bit word containing the value that is received + from the slave. If the frame size configured for the CoreSPI in question is + less that 32-bits, the upper bits will be 0. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + const uint32_t master_tx_frame = 0x0100A0E1; + uint32_t master_rx; + + SPI_init(&g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ); + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0 ); + master_rx = SPI_transfer_frame( &g_spi0, master_tx_frame ); + SPI_clear_slave_select( &g_spi0, SPI_SLAVE_0 ); + @endcode + */ +uint32_t SPI_transfer_frame +( + spi_instance_t * this_spi, + uint32_t tx_bits +); + +/***************************************************************************//** + The SPI_transfer_block() function is used by the SPI master to transmit and + receive blocks of data organized as a specified number of 8-bit frames. It + can be used for the following: + • Writing a data block to a slave + • Reading a data block from a slave + • Sending a command to a slave followed by reading the outcome of + the command in a single SPI transaction. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param cmd_buffer + The cmd_buffer parameter is a pointer to the buffer that contains the data + sent by the master from the beginning of the transfer. This pointer can be + null (0) if the master does not need to send a command before reading data. + + @param cmd_byte_size + The cmd_byte_size parameter specifies the number of bytes in cmd_buffer that + will be sent. A value ‘0’ indicates that no data needs to be sent to the slave. + + @param rx_buffer + The rx_buffer parameter is a pointer to the buffer that stores the data received + from the slave after sending the command. This pointer can be null (0) if the + master does not receive any data from the slave. + + @param rx_byte_size + The rx_byte_size parameter specifies the number of bytes received from + the slave and stored in the rx_buffer. A value ‘0’ indicates that no data is + to be read from the slave. + + @return + This function does not return any value. + + @example + @code + Polled write transfer example + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + + uint8_t master_tx_buffer[MASTER_TX_BUFFER] = + { + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A + }; + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0) ; + SPI_transfer_block + ( + &g_spi0, + master_tx_buffer, + sizeof(master_tx_buffer), + 0, + 0 + ); + SPI_clear_slave_select(&g_spi0, SPI_SLAVE_0 ); + @endcode + */ +void SPI_transfer_block +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_buffer, + uint16_t rx_byte_size +); + +/***************************************************************************//** + The SPI_transfer_block_store_all_resp() function is used by the SPI master + to transmit and receive blocks of data organized as a specified number + of 8-bit frames. It can be used for the following: + • Writing a data block to a slave + • Reading a data block from a slave + • Sending a command to a slave followed by reading the outcome of + the command in a single SPI transaction + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param cmd_buffer + The cmd_buffer parameter is a pointer to the buffer that contains the data sent by + the master from the beginning of the transfer. This pointer can be null (0) + if the master does not need to send a command before reading data. + + @param cmd_byte_size + The cmd_byte_size parameter specifies the number of bytes contained in + cmd_buffer that will be sent. A value ‘0’ indicates that no data needs + to be sent to the slave. + + @param rx_data_buffer + The rx_data_buffer parameter is a pointer to the buffer that stores the data received + from the slave after sending the command. This pointer can be null (0) if the + master does not receive any data from the slave. + + @param rx_byte_size + The rx_byte_size parameter specifies the number of bytes received from + the slave and stores in the rx_buffer. A value ‘0’ indicates that no data is + to be read from the slave. + + @param cmd_response_buffer + The cmd_response_buffer parameter is a pointer to the buffer which stores the + command response from the slave, while the master is transmitting the number + of bytes indicated by cmd_byte_size parameter. + + @return + This function does not return any value. + + @example + @code + Polled write transfer example + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + + uint8_t master_tx_buffer[MASTER_TX_BUFFER] = + { + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A + }; + + uint8_t cmd_rx_buffer[CMD_RX_BUFFER]={0}; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0) ; + SPI_transfer_block_store_all_resp + ( + &g_spi0, + master_tx_buffer, + sizeof(master_tx_buffer), + 0, + 0, + cmd_response_buffer + ); + SPI_clear_slave_select(&g_spi0, SPI_SLAVE_0 ); + @endcode + */ +void SPI_transfer_block_store_all_resp +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_data_buffer, + uint16_t rx_byte_size, + uint8_t * cmd_response_buffer +); + +/***************************************************************************//** + The SPI_set_frame_rx_handler() function is used by the SPI slaves to specify + the receive handler function that is called by the SPI driver interrupt + handler when a frame of data is received by the SPI slave. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param rx_handler + The rx_handler parameter is a pointer to the frame receive handler that must + be called when a frame is received by the CoreSPI slave. Passing in a NULL + pointer disables the receive handler but does enable the receive interrupt to + ensure the RX FIFO is empty each time a frame is received. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + uint32_t g_slave_rx_frame = 0; + spi_instance_t g_spi0; + + void slave_frame_handler(uint32_t rx_frame) + { + g_slave_rx_frame = rx_frame; + } + int setup_slave( void ) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_slave_mode( &g_spi0 ); + SPI_set_frame_rx_handler( &g_spi0, slave_frame_handler ); + } + @endcode + */ +void SPI_set_frame_rx_handler +( + spi_instance_t * this_spi, + spi_frame_rx_handler_t rx_handler +); + +/***************************************************************************//** + The SPI_set_slave_tx_frame() function is used by the SPI slaves to specify + the frame that gets transmitted when a transaction is initiated by the SPI + master. This function allows you to assign a slave_tx_frame_handler function, + which will be executed upon transmit interrupt when the SPI is in slave mode. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param frame_value + The frame_value parameter contains the value of the frame to be sent to the + master. + Note: The bit length of the value to be transmitted to the master is + set when the CoreSPI is instantiated in the hardware design. + + @param slave_tx_frame_handler + The slave_tx_frame_handler function pointer is executed upon occurrence of + transmit interrupt when CoreSPI is operating in slave mode. This parameter + is optional and if set to NULL it is assumed that the frame value is static or + updated asynchronously. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + const uint32_t slave_tx_frame[2] = { 0x0110F761, 0x0110F671 }; + uint32_t master_rx; + uint32_t slave_frame_idx = 0 ; + + slave_frame_update( spi_instance_t * this_spi ) + { + this_spi->slave_tx_frame = slave_tx_frame[slave_frame_idx++]; + if( slave_frame_idx > 2 ) + slave_frame_idx = 0; + } + main() + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ) ; + SPI_set_slave_tx_frame( &g_spi0, slave_tx_frame[slave_frame_idx++], + &slave_frame_update ); + } + @endcode + */ +void SPI_set_slave_tx_frame +( + spi_instance_t * this_spi, + uint32_t frame_value, + spi_slave_frame_tx_handler_t slave_tx_frame_handler +); + +/***************************************************************************//** + The SPI_set_slave_block_buffers() function is used to configure an SPI slave + for block transfer operations. It specifies one or more of the following: + • The data that is transmitted when accessed by a master. + • The buffer where the data received from a master is stored. + • The handler function that must be called after the receive buffer has + been filled. + • The number of bytes that must be received from the master before calling + the recieve handler function. + These parameters allow the following use cases: + • Slave performing an action after receiving a block of data from a + master containing a command. This action is performed by the + receive handler based on the content of the receive data buffer. + • Slave returning a block of data to the master. The type of information + is always the same but the actual values change over time. For example, + returning the voltage of a predefined set of analog inputs. + • Slave returning data based on a command contained in the first part of + the SPI transaction. For example, reading the voltage of the analog + input specified by the first data byte by the master. This is achieved + by using the SPI_set_slave_block_buffers() function in conjunction with + functions SPI_set_cmd_handler() and SPI_set_cmd_response(). + + See the SPI_set_cmd_handler() function description for details of + this use case. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param tx_buffer + The tx_buffer parameter is a pointer to a buffer containing the data that + will be sent to the master. This parameter can be set to ‘0’ if the SPI + slave is not intended to be the target of SPI read transactions. + + @param tx_buff_size + The tx_buff_size parameter specifies the number of bytes that are + transmitted by the SPI slave. It is the number of bytes contained in the + tx_buffer. This parameter can be set to ‘0’ if the SPI slave is not + intended to be the target of SPI read transactions. The driver returns 0s + to the master if there is no buffer specified or the master reads beyond the + end of the buffer. + Note: If SPI_transfer_block() is used to read from this slave and there is + no command handler involved, the buffer size here must be at least the + combined length of the command and response specified by the master. + On receiving this data, the master discards the data bytes equal to + command length bytes from the start of the received buffer. + + @param rx_buffer + The rx_buffer parameter is a pointer to the buffer where data received + from the master is stored. This parameter can be set to ‘0’ if the + SPI slave is not intended to be the target of SPI write or write-read + transactions. + + @param rx_buff_size + The rx_buff_size parameter specifies the size of the receive buffer. It is + also the number of bytes that must be received before the receive handler + is called, if a receive handler is specified using the block_rx_handler + parameter. Any bytes received in excess of the size specified by the + rx_buff_size parameter are discarded. This parameter can be set to ‘0’ + if the SPI slave is not intended to be the target of SPI write or + write-read transactions. + + @param block_rx_handler + The block_rx_handler parameter is a pointer to a function that is called + when receive buffer has been filled or the slave select has been de-asserted. + This parameter can be set to ‘0’ if the SPI slave is not intended to be the + target of SPI write or write-read transactions. + + @return + This function does not return any value. + + @example + @code + Slave Performing Operation Based on Master Command: + In this example the SPI slave is configured to receive 10 bytes of data + or command from the SPI slave, and process the data received from the master. + + #define SPI0_BASE_ADDR 0xC2000000 + + uint32_t nb_of_rx_handler_calls = 0; + spi_instance_t g_spi0; + + void spi1_block_rx_handler_b + ( + uint8_t * rx_buff, + uint16_t rx_size + ) + { + ++nb_of_rx_handler_calls; + } + + void setup_slave( void ) + { + uint8_t slave_rx_buffer[10] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_slave_mode( &g_spi0 ); + + SPI_set_slave_block_buffers + ( + &g_spi0, + 0, + 0, + slave_rx_buffer, + sizeof( master_tx_buffer ), + spi1_block_rx_handler_b + ); + } + @endcode + */ +void SPI_set_slave_block_buffers +( + spi_instance_t * this_spi, + const uint8_t * tx_buffer, + uint32_t tx_buff_size, + uint8_t * rx_buffer, + uint32_t rx_buff_size, + spi_block_rx_handler_t block_rx_handler +); + +/***************************************************************************//** + The SPI_isr() function is the top level interrupt handler function for the + CoreSPI driver. You must call SPI_isr() from the system level + (CoreInterrupt and NVIC level) interrupt handler assigned to the interrupt + triggered by the CoreSPI SPIINT signal. Your system level interrupt handler + must also clear the system level interrupt triggered by the CoreSPI SPIINT + signal before returning, to prevent a re-assertion of the same interrupt. + + This function supports all types of interrupt triggered by CoreSPI. It is not + a complete interrupt handler by itself; rather, it is a top level wrapper that + abstracts CoreSPI command interrupt and slave mode transmit interrupt handling + by calling lower level handler functions specific to each type of CoreSPI + interrupt. You must create the lower level handler functions to suit your + application and register them with the driver through calling the + SPI_set_cmd_handler(), SPI_set_cmd_response(), and SPI_set_slave_tx_frame() + functions. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + + @example + @code + + Example of configuring a CoreInterrupt connected to the Fabric Interrupt on a + SmartFusion device to handle CoreSPI interrupt. + + #define #define SPI1_INT_IRQ_NB 0 + spi_instance_t g_spi0; + + Void CIC_irq1_handler(void) + { + SPI_isr( &g_spi0 ); + } + + void Fabric_IRQHandler( void ) + { + // Call the CoreInterrupt driver ISR to determine the source of the + // interrupt and call the relevant ISR registered to it. + CIC_irq_handler(); + + // Clear NVIC interrupt status to allow further interrupts + NVIC_ClearPendingIRQ( Fabric_IRQn ); + } + + main() + { + ... + + CIC_init( CIC_BASE_ADDR ); + + // Install handler for SPI IRQ + CIC_set_irq_handler( SPI0_INT_IRQ_NB, CIC_irq1_handler ); + + NVIC_ClearPendingIRQ( Fabric_IRQn ); + NVIC_EnableIRQ( Fabric_IRQn ); + + CIC_enable_irq( SPI1_INT_IRQ_NB ); + + ... + } + @endcode + */ +void SPI_isr +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_set_cmd_handler() function specifies a command handler function that + will be called when the number of bytes received reaches the command size + specified as cmd_size parameter. + + This function is used by the SPI slaves performing block transfers. Its + purpose is to allow an SPI slave to decide the data that will be returned to + the master while an SPI transaction is taking place. Typically, one or more + command bytes are sent by the master to request some specific data. The slave + interprets the command byte(s) while one or more turn-around bytes are + transmitted. The slave adjusts its transmit data buffer based on the command + during the turn around time. + + The following table provides an example of the use of this function where the + SPI slave returns data bytes D0 to D6 based on the value of a command. The + 3 bytes long command is made up of a command opcode byte followed by an + address byte followed by a size byte. The cmd_handler() function specified + through an earlier call to SPI_set_cmd_handler() is called by the CoreSPI + driver once the third byte is received. The cmd_handler() function + interprets the command bytes and calls SPI_set_cmd_response() to set the SPI + slave's response transmit buffer with the data to be transmitted after the + turnaround bytes (T0 to T3). The number of turnaround bytes must be + sufficient to give enough time for the cmd_handler() to execute. The number + of turnaround bytes is specified by the protocol used on top of the SPI + transport layer so that master and slave agree on the number of turn around + bytes. + +|Timestamp| SPI Transaction | Bytes | Comments | +|---------|-------------|----------------------|---------------| +| t0|COMMAND|C A S |C - command opcode byte, A - address byte, S - size byte| +|t1| TURN-AROUND|T0 T1 |cmd_handler() called here (T0 to T3 are TURN-AROUND bytes)| +|t2|TURN-AROUND|T2 T3|SPI_set_cmd_response() called here by implementation of cmd_handler() +|| | |to set the data that will be transmitted by the SPI slave.| +|t3| DATA | D0 D1 D2 D3 D4 D5 D6 |Data transmition (SPI slave return data bytes)| + + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure identifying + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @param cmd_handler + The cmd_handler parameter is a pointer to a function with the prototype: + void cmd_handler(uint8_t * rx_buff, uint32_t rx_size); + It specifies the function that will be called when the number of bytes + specified by the cmd_size parameter has been received. + + @param cmd_size + The cmd_size parameter specifies the number of bytes that must be received + before calling the command handler function specified by the cmd_handler. + The CoreSPI supports cmd_size values in the range 1 to 7. + + @return + This function does not return any value. + + @example + @code + The following example demonstrates how to configure CoreSPI to implement + the protocol given as an example above. The configure_slave() function + configures CoreSPI. It sets receive and transmit buffers. The transmit + buffer specified through the call to SPI_set_slave_block_buffers() function + specifies the data that will be returned to the master in bytes between + t0 and t3. These bytes will be sent to the master while the master transmits + the command and dummy bytes. The spi_slave_cmd_handler() function will be + called by the driver at time t1 after the 3 command bytes have been received. + The spi_block_rx_handler() function will be called by the driver at time t4, + when the transaction completes and the slave select signal becomes + de-asserted. + + #define SPI0_BASE_ADDR 0xC2000000 + #define COMMAND_SIZE 3 + #define NB_OF_DUMMY_BYTES 4 + #define MAX_TRANSACTION_SIZE 16 + + spi_instance_t g_spi0; + uint8_t slave_tx_buffer[COMMAND_SIZE + NB_OF_DUMMY_BYTES]; + uint8_t slave_rx_buffer[MAX_TRANSACTION_SIZE]; + + void configure_slave( void ) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_slave_mode( &g_spi0 ); + SPI_set_slave_block_buffers + ( + &g_spi0, + slave_tx_buffer, + COMMAND_SIZE + NB_OF_DUMMY_BYTES, + slave_rx_buffer, + sizeof(slave_rx_buffer), + spi_block_rx_handler + ); + + SPI_set_cmd_handler + ( + &g_spi0, + spi_slave_cmd_handler, + COMMAND_SIZE + ); + } + + void spi_slave_cmd_handler + ( + uint8_t * rx_buff, + uint32_t rx_size + ) + { + uint8_t command; + uint8_t address; + uint8_t size; + uint8_t * p_response; + uint32_t response_size; + + command = rx_buff[0]; + address = rx_buff[1]; + size = rx_buff[2]; + + p_response = get_response_data( command, address, size, &response_size ); + SPI_set_cmd_response( &g_spi0, p_response, response_size ); + } + + void spi_block_rx_handler + ( + uint8_t * rx_buff, + uint32_t rx_size + ) + { + process_rx_data( rx_buff, rx_size ); + } + @endcode + */ +void SPI_set_cmd_handler +( + spi_instance_t * this_spi, + spi_block_rx_handler_t cmd_handler, + uint32_t cmd_size +); + +/***************************************************************************//** + The SPI_set_cmd_response() function specifies the data that will be returned + to the master. See the description of SPI_set_cmd_handler() for details. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param resp_tx_buffer + The resp_tx_buffer parameter is a pointer to the buffer containing the data + that must be returned to the host in the data phase of an SPI transaction. + + @param resp_buff_size + The resp_buff_size parameter specifies the size of the buffer pointed by the + resp_tx_buffer parameter. + + @return + This function does not return any value. + */ +void SPI_set_cmd_response +( + spi_instance_t * this_spi, + const uint8_t * resp_tx_buffer, + uint32_t resp_buff_size +); + +/***************************************************************************//** + The SPI_enable() function enables the CoreSPI and allows it to respond to the external + signals. It is usually called to re-enable a CoreSPI instance which has been + disabled previously via by calling the SPI_disable() as the normal state of a CoreSPI + after enabling the initialization. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + */ +void SPI_enable +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_disable() function disables the CoreSPI and stops responding to the + external signals. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + */ +void SPI_disable +( + spi_instance_t * this_spi +); + +#ifdef __cplusplus +} +#endif + +#endif /* CORE_SPI_H_*/ diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreSPI/corespi_regs.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreSPI/corespi_regs.h new file mode 100644 index 0000000..a3e5b2a --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreSPI/corespi_regs.h @@ -0,0 +1,270 @@ +/***************************************************************************//** + * Copyright 2011-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file corespi_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreSPI memory map + * + */ + +#ifndef CORESPI_REGS_H_ +#define CORESPI_REGS_H_ + +/******************************************************************************* + * Control register 1: + *------------------------------------------------------------------------------ + */ +#define CTRL1_REG_OFFSET 0x00u + +#define CTRL1_ENABLE_OFFSET 0x00u +#define CTRL1_ENABLE_MASK 0x01u +#define CTRL1_ENABLE_SHIFT 0x00 + +#define CTRL1_MASTER_OFFSET 0x00u +#define CTRL1_MASTER_MASK 0x02u +#define CTRL1_MASTER_SHIFT 0x01 + +#define CTRL1_INTRXDATA_OFFSET 0x00u +#define CTRL1_INTRXDATA_MASK 0x04u +#define CTRL1_INTRXDATA_SHIFT 0x02 + +#define CTRL1_INTTXDONE_OFFSET 0x00u +#define CTRL1_INTTXDONE_MASK 0x08u +#define CTRL1_INTTXDONE_SHIFT 0x03 + +#define CTRL1_INTRXOVFLOW_OFFSET 0x00u +#define CTRL1_INTRXOVFLOW_MASK 0x10u +#define CTRL1_INTRXOVFLOW_SHIFT 0x04 + +#define CTRL1_INTTXURUN_OFFSET 0x00u +#define CTRL1_INTTXURUN_MASK 0x20u +#define CTRL1_INTTXURUN_SHIFT 0x05 + +#define CTRL1_FRAMEURUN_OFFSET 0x00u +#define CTRL1_FRAMEURUN_MASK 0x40u +#define CTRL1_FRAMEURUN_SHIFT 0x06 + +#define CTRL1_OENOFF_OFFSET 0x00u +#define CTRL1_OENOFF_MASK 0x80u +#define CTRL1_OENOFF_SHIFT 0x07 + +/******************************************************************************* + * Interrupt clear register: + *------------------------------------------------------------------------------ + */ +#define INTCLR_REG_OFFSET 0x04u + +#define INTCLR_TXDONE_OFFSET 0x04u +#define INTCLR_TXDONE_MASK 0x01u +#define INTCLR_TXDONE_SHIFT 0x00 + +#define INTCLR_RXDONE_OFFSET 0x04u +#define INTCLR_RXDONE_MASK 0x02u +#define INTCLR_RXDONE_SHIFT 0x01 + +#define INTCLR_RXOVERFLOW_OFFSET 0x04u +#define INTCLR_RXOVERFLOW_MASK 0x04u +#define INTCLR_RXOVERFLOW_SHIFT 0x02 + +#define INTCLR_TXUNDERRUN_OFFSET 0x04u +#define INTCLR_TXUNDERRUN_MASK 0x08u +#define INTCLR_TXUNDERRUN_SHIFT 0x03 + +#define INTCLR_CMDINT_OFFSET 0x04u +#define INTCLR_CMDINT_MASK 0x10u +#define INTCLR_CMDINT_SHIFT 0x04 + +#define INTCLR_SSEND_OFFSET 0x04u +#define INTCLR_SSEND_MASK 0x20u +#define INTCLR_SSEND_SHIFT 0x05 + +#define INTCLR_RXDATA_OFFSET 0x04u +#define INTCLR_RXDATA_MASK 0x40u +#define INTCLR_RXDATA_SHIFT 0x06 + +#define INTCLR_TXDATA_OFFSET 0x04u +#define INTCLR_TXDATA_MASK 0x80u +#define INTCLR_TXDATA_SHIFT 0x07 + +/******************************************************************************* + * Receive data register: + *------------------------------------------------------------------------------ + */ +#define RXDATA_REG_OFFSET 0x08u + +/******************************************************************************* + * Transmit data register: + *------------------------------------------------------------------------------ + */ +#define TXDATA_REG_OFFSET 0x0Cu + +/******************************************************************************* + * Masked interrupt status register: + *------------------------------------------------------------------------------ + */ +#define INTMASK_REG_OFFSET 0x10u + +#define INTMASK_TXDONE_OFFSET 0x10u +#define INTMASK_TXDONE_MASK 0x01u +#define INTMASK_TXDONE_SHIFT 0x00 + +#define INTMASK_RXDONE_OFFSET 0x10u +#define INTMASK_RXDONE_MASK 0x02u +#define INTMASK_RXDONE_SHIFT 0x01 + +#define INTMASK_RXOVERFLOW_OFFSET 0x10u +#define INTMASK_RXOVERFLOW_MASK 0x04u +#define INTMASK_RXOVERFLOW_SHIFT 0x02 + +#define INTMASK_TXUNDERRUN_OFFSET 0x10u +#define INTMASK_TXUNDERRUN_MASK 0x08u +#define INTMASK_TXUNDERRUN_SHIFT 0x03 + +#define INTMASK_CMDINT_OFFSET 0x10u +#define INTMASK_CMDINT_MASK 0x10u +#define INTMASK_CMDINT_SHIFT 0x04 + +#define INTMASK_SSEND_OFFSET 0x10u +#define INTMASK_SSEND_MASK 0x20u +#define INTMASK_SSEND_SHIFT 0x05 + +#define INTMASK_RXDATA_OFFSET 0x10u +#define INTMASK_RXDATA_MASK 0x40u +#define INTMASK_RXDATA_SHIFT 0x06 + +#define INTMASK_TXDATA_OFFSET 0x10u +#define INTMASK_TXDATA_MASK 0x80u +#define INTMASK_TXDATA_SHIFT 0x07 + +/******************************************************************************* + * Raw interrupt status register: + *------------------------------------------------------------------------------ + */ +#define INTRAW_REG_OFFSET 0x14u + +#define INTRAW_TXDONE_OFFSET 0x14u +#define INTRAW_TXDONE_MASK 0x01u +#define INTRAW_TXDONE_SHIFT 0x00 + +#define INTRAW_RXDONE_OFFSET 0x14u +#define INTRAW_RXDONE_MASK 0x02u +#define INTRAW_RXDONE_SHIFT 0x01 + +#define INTRAW_RXOVERFLOW_OFFSET 0x14u +#define INTRAW_RXOVERFLOW_MASK 0x04u +#define INTRAW_RXOVERFLOW_SHIFT 0x02 + +#define INTRAW_TXUNDERRUN_OFFSET 0x14u +#define INTRAW_TXUNDERRUN_MASK 0x08u +#define INTRAW_TXUNDERRUN_SHIFT 0x03 + +#define INTRAW_CMDINT_OFFSET 0x14u +#define INTRAW_CMDINT_MASK 0x10u +#define INTRAW_CMDINT_SHIFT 0x04 + +#define INTRAW_SSEND_OFFSET 0x14u +#define INTRAW_SSEND_MASK 0x20u +#define INTRAW_SSEND_SHIFT 0x05 + +#define INTRAW_RXDATA_OFFSET 0x14u +#define INTRAW_RXDATA_MASK 0x40u +#define INTRAW_RXDATA_SHIFT 0x06 + +#define INTRAW_TXDATA_OFFSET 0x14u +#define INTRAW_TXDATA_MASK 0x80u +#define INTRAW_TXDATA_SHIFT 0x07 + +/******************************************************************************* + * Control register 2: + *------------------------------------------------------------------------------ + */ +#define CTRL2_REG_OFFSET 0x18u + +#define CTRL2_CMDSIZE_OFFSET 0x18u +#define CTRL2_CMDSIZE_MASK 0x07u +#define CTRL2_CMDSIZE_SHIFT 0x00 + +#define CTRL2_INTCMD_OFFSET 0x18u +#define CTRL2_INTCMD_MASK 0x10u +#define CTRL2_INTCMD_SHIFT 0x04 + +#define CTRL2_INTSSEND_OFFSET 0x18u +#define CTRL2_INTSSEND_MASK 0x20u +#define CTRL2_INTSSEND_SHIFT 0x05 + +#define CTRL2_INTRXDATA_OFFSET 0x18u +#define CTRL2_INTRXDATA_MASK 0x40u +#define CTRL2_INTRXDATA_SHIFT 0x06 + +#define CTRL2_INTTXDATA_OFFSET 0x18u +#define CTRL2_INTTXDATA_MASK 0x80u +#define CTRL2_INTTXDATA_SHIFT 0x07 + +/******************************************************************************* + * Command register: + *------------------------------------------------------------------------------ + */ +#define CMD_REG_OFFSET 0x1Cu + +#define CMD_RXFIFORST_OFFSET 0x1Cu +#define CMD_RXFIFORST_MASK 0x01u +#define CMD_RXFIFORST_SHIFT 0x00 + +#define CMD_TXFIFORST_OFFSET 0x1Cu +#define CMD_TXFIFORST_MASK 0x02u +#define CMD_TXFIFORST_SHIFT 0x01 + +/******************************************************************************* + * Status register: + *------------------------------------------------------------------------------ + */ +#define STATUS_REG_OFFSET 0x20u + +#define STATUS_FIRSTFRAME_OFFSET 0x20u +#define STATUS_FIRSTFRAME_MASK 0x01u +#define STATUS_FIRSTFRAME_SHIFT 0x00 + +#define STATUS_DONE_OFFSET 0x20u +#define STATUS_DONE_MASK 0x02u +#define STATUS_DONE_SHIFT 0x01 + +#define STATUS_RXEMPTY_OFFSET 0x20u +#define STATUS_RXEMPTY_MASK 0x04u +#define STATUS_RXEMPTY_SHIFT 0x02 + +#define STATUS_TXFULL_OFFSET 0x20u +#define STATUS_TXFULL_MASK 0x08u +#define STATUS_TXFULL_SHIFT 0x03 + +#define STATUS_RXOVFLOW_OFFSET 0x20u +#define STATUS_RXOVFLOW_MASK 0x10u +#define STATUS_RXOVFLOW_SHIFT 0x04 + +#define STATUS_TXUNDERRUN_OFFSET 0x20u +#define STATUS_TXUNDERRUN_MASK 0x20u +#define STATUS_TXUNDERRUN_SHIFT 0x05 + +#define STATUS_SSEL_OFFSET 0x20u +#define STATUS_SSEL_MASK 0x40u +#define STATUS_SSEL_SHIFT 0x06 + +#define STATUS_ACTIVE_OFFSET 0x20u +#define STATUS_ACTIVE_MASK 0x80u +#define STATUS_ACTIVE_SHIFT 0x07 + +/******************************************************************************* + * Slave select register: + *------------------------------------------------------------------------------ + */ +#define SSEL_REG_OFFSET 0x24u + +/******************************************************************************* + * Transmit data last register: + *------------------------------------------------------------------------------ + */ +#define TXLAST_REG_OFFSET 0x28u + + +#endif /*CORESPI_REGS_H_*/ diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.c b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.c new file mode 100644 index 0000000..b8adaed --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.c @@ -0,0 +1,889 @@ +/******************************************************************************* + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * PF_System_Services driver implementation. See file "core_syservices_pf.h" for + * description of the functions implemented in this file. + * + */ + +#include "core_sysservices_pf.h" +#include "coresysservicespf_regs.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define NULL_BUFFER (( uint8_t* ) 0) + +static uint8_t execute_ss_command +( + uint8_t cmd_opcode, + const uint8_t* cmd_data, + uint16_t cmd_data_size, + const uint8_t* p_response, + uint16_t response_size, + uint16_t mb_offset, + uint16_t response_offset +); + +uint32_t g_css_pf_base_addr = 0u; + +/***************************************************************************//** + * SYS_init() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +void +SYS_init +( + uint32_t base_addr +) +{ + g_css_pf_base_addr = base_addr; +} + +/***************************************************************************//** + * SYS_get_serial_number() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_serial_number +( + const uint8_t * p_serial_number, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if (p_serial_number == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(SERIAL_NUMBER_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_serial_number, + SERIAL_NUMBER_RESP_LEN, + mb_offset, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_get_user_code() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_user_code +( + const uint8_t * p_user_code, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_user_code == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(USERCODE_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_user_code, + USERCODE_RESP_LEN, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_get_design_info() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_design_info +( + const uint8_t * p_design_info, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_design_info == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(DESIGN_INFO_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_design_info, + DESIGN_INFO_RESP_LEN, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_get_device_certificate() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_device_certificate +( + const uint8_t * p_device_certificate, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_device_certificate == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(DEVICE_CERTIFICATE_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_device_certificate, + DEVICE_CERTIFICATE_RESP_LEN, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_read_digest() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_read_digest +( + const uint8_t * p_digest, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_digest == NULL_BUFFER) + { + return status; + } + +#ifndef CORESYSSERVICES_MPFS + status = execute_ss_command(READ_DIGEST_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_digest, + READ_DIGEST_RESP_LEN, + mb_offset, + 0u); +#else + status = execute_ss_command(READ_DIGEST_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_digest, + READ_DIGEST_MPFS_RESP_LEN, + mb_offset, + 0u); +#endif + return status; + +} + +/***************************************************************************//** + * SYS_query_security() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_query_security +( + uint8_t * p_security_locks, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint8_t idx = 0u; + + if(p_security_locks == NULL_BUFFER) + { + return status; + } + +#ifndef CORESYSSERVICES_MPFS + uint8_t buf[12] = {0}; + /* Actual QUERY_SECURITY_RESP_LEN is 9 or 33 but PF_System_Services core + * needs number of words instead of number of bytes to be written to or read + * from MailBox */ + status = execute_ss_command(QUERY_SECURITY_REQUEST_CMD, + NULL_BUFFER, + 0u, + buf, + (QUERY_SECURITY_RESP_LEN + 3u), + mb_offset, + 0u); + + for (idx = 0u; idx < 9u; idx++) + { + *(p_security_locks+idx) = buf[idx]; + } + +#else + uint8_t buf[36] = {0}; + + status = execute_ss_command(QUERY_SECURITY_REQUEST_CMD, + NULL_BUFFER, + 0u, + buf, + (QUERY_SECURITY_MPFS_RESP_LEN + 3u), + mb_offset, + 0u); + + for (idx = 0u; idx < 33u; idx++) + { + *(p_security_locks+idx) = buf[idx]; + } + +#endif + + return status; +} + +/***************************************************************************//** + * SYS_read_debug_info() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_read_debug_info +( + const uint8_t * p_debug_info, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_debug_info == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(READ_DEBUG_INFO_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_debug_info, + READ_DEBUG_INFO_RESP_LEN, + mb_offset, + 0u); + return status; +} + +#ifdef CORESYSSERVICES_MPFS +/***************************************************************************//** + * SYS_read_envm_parameter() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_read_envm_parameter +( + uint8_t * p_envm_param, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_envm_param == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(READ_ENVM_PARAM_REQUEST_CMD, + NULL_BUFFER, + 0, + p_envm_param, + READ_ENVM_PARAM_RESP_LEN, + mb_offset, + 0); + return status; +} + +#endif + +/***************************************************************************//** + * SYS_puf_emulation_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_puf_emulation_service +( + const uint8_t * p_challenge, + uint8_t op_type, + uint8_t* p_response, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint8_t mb_format[20] = {0x00}; + uint8_t index = 0u; + + if((p_response == NULL_BUFFER) || (p_challenge == NULL_BUFFER)) + { + return status; + } + + /* Frame the data required for mailbox */ + mb_format[index] = op_type; + + for (index = 4u; index < 20u; index++) + { + mb_format[index] = p_challenge[index - 4u]; + } + + status = execute_ss_command(PUF_EMULATION_SERVICE_REQUEST_CMD, + mb_format, + PUF_EMULATION_SERVICE_CMD_LEN, + p_response, + PUF_EMULATION_SERVICE_RESP_LEN, + mb_offset, + 5u); /* mentioning offset to number of words instead of bytes */ + + return status; +} + +/***************************************************************************//** + * SYS_digital_signature_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_digital_signature_service +( + const uint8_t* p_hash, + uint8_t format, + uint8_t* p_response, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if((p_hash == NULL_BUFFER) || (p_response == NULL_BUFFER)) + { + return status; + } + + if (format == DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD) + { + status = execute_ss_command(DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD, + p_hash, + DIGITAL_SIGNATURE_HASH_LEN, + p_response, + DIGITAL_SIGNATURE_RAW_FORMAT_RESP_SIZE, + mb_offset, + 12u); /* mentioning offset to number of words instead of bytes */ + } + else + { + status = execute_ss_command(DIGITAL_SIGNATURE_DER_FORMAT_REQUEST_CMD, + p_hash, + DIGITAL_SIGNATURE_HASH_LEN, + p_response, + DIGITAL_SIGNATURE_DER_FORMAT_RESP_SIZE, + mb_offset, + 12u); /* mentioning offset to number of words instead of bytes */ + } + + return status; +} + +/***************************************************************************//** + * SYS_secure_nvm_write() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_secure_nvm_write +( + uint8_t format, + uint8_t snvm_module, + const uint8_t* p_data, + const uint8_t* p_user_key, + uint16_t mb_offset +) +{ + uint8_t frame[256] = {0x00}; + uint8_t* p_frame = &frame[0]; + uint16_t index = 0u; + uint8_t status = SYS_PARAM_ERR; + + HAL_ASSERT(!(NULL_BUFFER == p_data)); + HAL_ASSERT(!(snvm_module >= 221u)); + if (format != SNVM_NON_AUTHEN_TEXT_REQUEST_CMD) + { + HAL_ASSERT(!(NULL_BUFFER == p_user_key)); + } + + if ((p_data == NULL_BUFFER) || (snvm_module >= 221)) + { + return status; + } + + if ((format != SNVM_NON_AUTHEN_TEXT_REQUEST_CMD) + && (p_user_key == NULL_BUFFER)) + { + return status; + } + + if ((format != SNVM_NON_AUTHEN_TEXT_REQUEST_CMD) + && (format != SNVM_AUTHEN_TEXT_REQUEST_CMD) + && (format != SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD)) + { + return status; + } + + *p_frame = snvm_module; /* SNVMADDR - SNVM module */ + + p_frame += 4u; /* Next 3 bytes RESERVED - For alignment */ + + /* Copy user key and send the command/data to mailbox. */ + if ((format == SNVM_AUTHEN_TEXT_REQUEST_CMD) || + (format == SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD)) + { + /* Copy user data */ + for (index = 0u; index < (AUTHENTICATED_TEXT_DATA_LEN - USER_SECRET_KEY_LEN - 4u); index++) + { + *p_frame = p_data[index]; + p_frame++; + } + + /* Copy user key */ + for (index = 0u; index < USER_SECRET_KEY_LEN; index++) + { + *p_frame = p_user_key[index]; + p_frame++; + } + + status = execute_ss_command(format, + &frame[0], + AUTHENTICATED_TEXT_DATA_LEN, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + } + else + { + /* Copy user data */ + for (index = 0u; index < (NON_AUTHENTICATED_TEXT_DATA_LEN - 4u); index++) + { + *(p_frame+index) = p_data[index]; + } + + status = execute_ss_command(format, + &frame[0], + NON_AUTHENTICATED_TEXT_DATA_LEN, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + } + + return status; +} + +/***************************************************************************//** + * SYS_secure_nvm_read() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_secure_nvm_read +( + uint8_t snvm_module, + const uint8_t* p_user_key, + uint8_t* p_admin, + uint8_t* p_data, + uint16_t data_len, + uint16_t mb_offset +) +{ + /* Frame the message. */ + uint8_t frame[16] = {0x00u}; + uint8_t* p_frame = &frame[0u]; + uint8_t status = SYS_PARAM_ERR; + uint8_t response[256] = {0x00u}; + uint16_t index = 0u; + + HAL_ASSERT(!(NULL_BUFFER == p_data)); + HAL_ASSERT(!(NULL_BUFFER == p_admin)); + HAL_ASSERT(!(snvm_module > 221u)); + + HAL_ASSERT(data_len == 236u || data_len == 252u); + + if((p_data == NULL_BUFFER) || + (snvm_module >= 221) || + (p_admin == NULL_BUFFER)) + { + return status; + } + + *p_frame = snvm_module; /* SNVMADDR - SNVM module */ + + p_frame += 4u; /* RESERVED - For alignment */ + + /* Copy user key */ + if (236u == data_len) + { + HAL_ASSERT(p_user_key != NULL_BUFFER); + + if(p_user_key == NULL_BUFFER) + { + return status; + } + + for (index = 0u; index < 12u; index++) + { + *p_frame = p_user_key[index]; + p_frame++; + } + } + else + { + p_frame += 12u; + } + + status = execute_ss_command(SNVM_READ_REQUEST_CMD, + &frame[0], + 16u, + response, + (data_len + 4u), + mb_offset, + 4u); /* mentioning offset to number of words instead of bytes */ + + if (SYS_SUCCESS == status) + { + for (index = 0u; index < 4u; index++) + { + *(p_admin+index) = (uint32_t)response[index]; + } + + + /* Copy data into user buffer. */ + for (index = 4u; index < (data_len + 4u); index++) + { + *(p_data + (index - 4u)) = response[index]; + } + } + else + { + ; + } + + return status; +} + +/***************************************************************************//** + * SYS_nonce_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_nonce_service +( + const uint8_t * p_nonce, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if((p_nonce == NULL_BUFFER)) + { + return status; + } + + status = execute_ss_command(NONCE_SERVICE_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_nonce, + NONCE_SERVICE_RESP_LEN, + mb_offset, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_bitstream_authenticate_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_bitstream_authenticate_service +( + uint32_t spi_flash_address, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint32_t l_spi_flash_address = spi_flash_address; + status = execute_ss_command(BITSTREAM_AUTHENTICATE_CMD, + (uint8_t* )&l_spi_flash_address, + 4u, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_IAP_image_authenticate_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_IAP_image_authenticate_service +( + uint8_t spi_idx +) +{ + uint8_t status = SYS_PARAM_ERR; + + HAL_ASSERT(!(spi_idx == 1u)); + + if (spi_idx == 1u) + { + return status; + } + + status = execute_ss_command(IAP_BITSTREAM_AUTHENTICATE_CMD, + NULL_BUFFER, + 0u, + NULL_BUFFER, + 0u, + spi_idx, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_digest_check_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_digest_check_service +( + uint32_t options, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint32_t l_options = options; + + status = execute_ss_command(DIGEST_CHECK_CMD, + (uint8_t* )&l_options, + 4u, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_iap_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_iap_service +( + uint8_t iap_cmd, + uint32_t spiaddr, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint16_t l_mb_offset = 0u; + uint16_t cmd_data_size = 0u; + uint8_t* cmd_data = NULL_BUFFER; + bool invalid_param = false; + + if (((IAP_PROGRAM_BY_SPIIDX_CMD == iap_cmd) + || (IAP_VERIFY_BY_SPIIDX_CMD == iap_cmd)) + && (1u == spiaddr)) + { + invalid_param = true; + HAL_ASSERT(!invalid_param); + } + + if (!invalid_param) + { + switch(iap_cmd) + { + case IAP_PROGRAM_BY_SPIIDX_CMD: + case IAP_VERIFY_BY_SPIIDX_CMD: + /*In SPI_IDX based program and verify commands, + * Mailbox is not Required. Instead of mailbox offset + * SPI_IDX is passed as parameter.*/ + l_mb_offset = (uint16_t)(0xFFu & spiaddr); + break; + + case IAP_PROGRAM_BY_SPIADDR_CMD: + case IAP_VERIFY_BY_SPIADDR_CMD: + /*In SPI_ADDR based program and verify commands, + * Mailbox is Required*/ + l_mb_offset = mb_offset; + /*command data size is four bytes holding the + * SPI Address in it.*/ + cmd_data_size = 4u; + cmd_data = (uint8_t*)&spiaddr; + break; + + case IAP_AUTOUPDATE_CMD: + /*In auto update command Mailbox is not Required*/ + l_mb_offset = 0u; + break; + + default: + l_mb_offset = 0u; + + } + + status = execute_ss_command( + (uint8_t)iap_cmd, + cmd_data, + cmd_data_size, + NULL_BUFFER, + 0, + (uint16_t)l_mb_offset, + 0); + } + + return status; +} + +/***************************************************************************//** + Internal functions. +*/ +/* +This function executes the SS command. If Mailbox input data is required by the +it will first load it from cmd_data into the Mailbox. If the service requires +the response data to be read from mailbox, it will do so and store it in p_response. +*/ +static uint8_t execute_ss_command +( + uint8_t cmd_opcode, + const uint8_t* cmd_data, + uint16_t cmd_data_size, + const uint8_t* p_response, + uint16_t response_size, + uint16_t mb_offset, + uint16_t response_offset +) +{ + /* Pointer used during Writing to Mailbox memory. */ + uint32_t status = 0u; + uint16_t idx = 0u; + uint16_t ss_command = 0u; + uint32_t* word_buf; + uint16_t timeout_count = SS_TIMEOUT_COUNT; + + /* making sure that the system controller is not executing any service i.e. + SS_USER_BUSY is gone 0 */ + + while (1u == HAL_get_32bit_reg_field(g_css_pf_base_addr, SS_USER_BUSY)) + { + --timeout_count; + + if (timeout_count == 0) + { + return SS_USER_BUSY_TIMEOUT; + } + } + + /* Form the SS command: bit 0to6 is the opcode, bit 7to15 is the Mailbox offset + For some services this field has another meaning + (e.g. for IAP bitstream auth. it means spi_idx) */ + ss_command = ((mb_offset << 7u) | (cmd_opcode & 0x7Fu)); + + /* Load the command register with the SS request command code*/ + HAL_set_32bit_reg(g_css_pf_base_addr, SS_CMD, ss_command); + + if (cmd_data_size > 0u) + { + HAL_ASSERT(!(NULL_BUFFER == cmd_data)); + HAL_ASSERT(!(cmd_data_size % 4u)); + + /* Load the MBX_WCNT register with number of words */ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_WCNT, (cmd_data_size/4u)); + + /* Load the MBX_WADDR register with offset of input data (write to Mailbox) + For all the services this offset remains either 0 or Not applicable + for the services in which no Mailbox write is required.*/ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_WADDR, (0x00u + mb_offset)); + + } + + if (response_size > 0u) + { + HAL_ASSERT(!(NULL_BUFFER == p_response)); + HAL_ASSERT(!(response_size % 4u)); + + /* + Load the MBX_RWCNT register with number of words to be read from Mailbox + */ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_RCNT, (response_size/4u)); + + /* + Load the MBX_RADRDESC register with offset address within the mailbox + format for that particular service. + It will be 0 for the services where there is no output data from G5CONTROL + is expected. + This function assumes that this value is pre-calculated by service specific + functions as this value is fixed for each service. + */ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_RADDR, (response_offset + mb_offset)); + } + + /*Set the request bit in SYS_SERV_REQ register to start the service*/ + HAL_set_32bit_reg_field(g_css_pf_base_addr, SS_REQ_REQ, 0x01u); + + if (cmd_data_size > 0u) + { + word_buf = (uint32_t*)cmd_data; + + /* Write the user data into mail box. */ + for (idx = 0u; idx < (cmd_data_size/4u); idx++) + { + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_WDATA, word_buf[idx]); + } + } + + timeout_count = SS_TIMEOUT_COUNT; + if (response_size > 0u) + { + word_buf = (uint32_t*)p_response; + + for (idx = 0u; idx < (response_size/4u); idx++) + { + while (0u == HAL_get_32bit_reg_field(g_css_pf_base_addr, + SS_USER_RDVLD)) + { + --timeout_count; + + if (timeout_count == 0) + { + return SS_USER_RDVLD_TIMEOUT; + } + } + word_buf[idx] = HAL_get_32bit_reg(g_css_pf_base_addr, MBX_RDATA); + } + } + + timeout_count = SS_TIMEOUT_COUNT; + /* make sure that service is complete i.e. SS_USER_BUSY is gone 0 */ + while (1u == HAL_get_32bit_reg_field(g_css_pf_base_addr, SS_USER_BUSY)) + { + --timeout_count; + + if (timeout_count == 0) + { + return SS_USER_RDVLD_TIMEOUT; + } + } + + /* Read the status returned by System Controller */ + status = HAL_get_32bit_reg(g_css_pf_base_addr, SS_STAT); + + return (uint8_t)status; +} + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h new file mode 100644 index 0000000..8e0ebb6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h @@ -0,0 +1,1249 @@ +/******************************************************************************* + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the + * CoreSysServices_PF bare metal driver. + */ +/*=========================================================================*//** + @mainpage CoreSysServices_PF Bare Metal Driver. + + @section intro_sec Introduction + The PolarFire System Services (PF_SYSTEM_SERVICES) SgCore enables executing + the system services on the PolarFire and PolarFire SoC device. The system services + are the system controller actions initiated by the System Controller's System + Service Interface (SSI). The PolarFire System Services "SgCore" provides a + method to initiate these system services. The PF_SYSTEM_SERVICES interacts + with the system controller on SSI and Mailbox interface to initiate system + services, exchange data required for that services, and to know the successful + completion or error status. + + The PF_SYSTEM_SERVICES provides an APB interface for controlling the registers + functions for controlling the PF_SYSTEM_SERVICES as part of a bare metal system + register implemented within it. This software driver provides a set of where no + part of an operating system but the implementation of the adaptation layer + operating system is available. This driver is adapted for use in + between this driver and the operating system's driver model is outside the + scope of this driver. + + ## Features + The CoreSysServices_PF driver provides the following features: + - Executing device and design information services + - Executing design services + - Executing data security services + - Executing Fabric services + + The CoreSysServices_PF driver is provided as C source code. + + @section Driver Configuration + The application software should configure the CoreSysServices_PF driver through + calling the SYS_init() function. Only one instance of PF_SYSTEM_SERVICES SgCore is + supported. No additional configuration files are required to use the driver. + If using this driver on RT PolarFire device FPGA, define RT_DEVICE_FAMILY + macro in application. + + @section theory_op Theory of Operation + The CoreSysServices_PF driver provides access to the PolarFire system services. + These system services are grouped into the following categories: + + Device and Design Information Service + - Serial Number Service + - USERCODE Service + - Design Info Service + - Device Certificate Services + - Read Digests + - Query Security + - Read Debug Info + - Read eNVM param + + Design Services + - Bitstream authentication service + - IAP bitstream authentication service + + Data Security Services + - Digital Signature Service + - Secure NVM (SNVM) Functions + - PUF Emulation Service + - Nonce Service + + Fabric Services + - Digest Check Service + - In Application programming(IAP)/Auto-Update service + + Initialization and Configuration + + The CoreSysServices_PF driver is initialized by calling the SYS_init() + function. The SYS_init() function must be called before calling any other + CoreSysServices_PF driver functions. + + Device and Design Information Services + + The CoreSysServices_PF driver is used to read information about the device + and the design using the following functions: + - SYS_get_serial_number() + - SYS_get_user_code() + - SYS_get_design_info() + - SYS_get_device_certificate() + - SYS_read_digest() + - SYS_query_security() + - SYS_read_debug_info() + + Design Authentication Services + + The CoreSysServices_PF driver is used to execute design services using the + following functions: + - SYS_bitstream_authenticate_service() + - SYS_IAP_image_authenticate_service() + + Data Security Services + + The CoreSysServices_PF driver is used to execute data security services + using the following functions: + - SYS_digital_signature_service() + - SYS_secure_nvm_write() + - SYS_secure_nvm_read() + - SYS_puf_emulation_service () + - SYS_nonce_service () + + Executing Fabric Services + + The CoreSysServices_PF driver is used to execute fabric services using the + following functions: + - SYS_digest_check_service() + - SYS_iap_service() + + All the service execution functions return the 8-bit status, which is returned + by the system controller on executing the given service. A '0' value indicates + successful execution of that service. A non-zero value indicates error. + The error codes for each service are different. See individual function + description to know the exact meanings of the error codes for each service. + + The function descriptions in this file mainly focus on the details required + by the user to use the APIs provided by this driver to execute the services. + To know the complete details of the system services, see the + PolarFire FPGA and PolarFire SoC FPGA System Services [document](https://onlinedocs.microchip.com/pr/GUID-1409CF11-8EF9-4C24-A94E-70979A688632-en-US-3/index.html) + + *//*=========================================================================*/ +#ifndef __CORE_SYSSERV_PF_H +#define __CORE_SYSSERV_PF_H 1 + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#include "hal_assert.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** +* # Service Execution Success and Error Status Codes +* +* The following status codes are the return values from the system service functions. +* For any service, a return value '0' indicates that the service was executed +* successfully. A non-zero return value indicates that the service was not +* executed successfully. For all the services, the return value represents the +* status code returned by the system controller for the respective service, +* except the values SYS_PARAM_ERR, SS_USER_BUSY_TIMEOUT, and SS_USER_RDVLD_TIMEOUT. +* These three values indicate the error conditions detected by this driver and +* they do not overlap with the status code returned by the system controller for +* any of the system service. +* +* SYS_SUCCESS +* System service executed successfully +* +* SYS_PARAM_ERR +* System service cannot be executed as one or more parameters are not as +* expected by this driver. No read/write access is performed with the +* IP. +* +* SS_USER_BUSY_TIMEOUT +* The System service request is initiated and the driver timed-out while +* waiting for the system service to complete. The System Service +* completion is indicated by de-assertion of the SS_USER_BUSY bit by the +* IP. +* +* SS_USER_RDVLD_TIMEOUT +* The System service request is initiated and the driver timed-out while +* waiting for SS_USER_RDVLD bit, which indicates availability of data to +* be read from the mailbox, to become active. +*/ +#define SYS_SUCCESS 0u +#define SYS_PARAM_ERR 0xFFu +#define SS_USER_BUSY_TIMEOUT 0xFAu +#define SS_USER_RDVLD_TIMEOUT 0xFBu + +/** +* # System Service Timeout Count +* +* The SS_TIMEOUT_COUNT value is used by the driver as a timeout count +* while waiting for either the SS_USER_BUSY or SS_USER_RDVLD. This empirical +* value is sufficiently large so that the operations are falsely +* timeout in the normal circumstance. It is provided as a way to provide +* more debug information to the application in case there are some +* unforeseen issues. You may change this value for your need based on your +* system design. +*/ +#define SS_TIMEOUT_COUNT 40000u +/* + * SYS_DCF_DEVICE_MISMATCH + * Public key or FSN do not match device + * + * + * SYS_DCF_INVALID_SIGNATURE + * Certificate signature is invalid + * + * SYS_DCF_SYSTEM_ERROR + * PUF or storage failure + */ +#define SYS_DCF_DEVICE_MISMATCH 1u +#define SYS_DCF_INVALID_SIGNATURE 2u +#define SYS_DCF_SYSTEM_ERROR 3u + +/* + * SYS_NONCE_PUK_FETCH_ERROR + * Error fetching PUK + * + * SYS_NONCE_SEED_GEN_ERROR + * Error generating seed + */ +#define SYS_NONCE_PUK_FETCH_ERROR 1u +#define SYS_NONCE_SEED_GEN_ERROR 2u + +/** + * # Secure Nvm Write Error Codes + * + * SNVM_WRITE_INVALID_SNVMADDR + * Illegal page address + * + * SNVM_WRITE_FAILURE + * PNVM program/verify failed + * + * SNVM_WRITE_SYSTEM_ERROR + * PUF or storage failure + * + * SNVM_WRITE_NOT_PERMITTED + * Write is not permitted + */ +#define SNVM_WRITE_INVALID_SNVMADDR 1u +#define SNVM_WRITE_FAILURE 2u +#define SNVM_WRITE_SYSTEM_ERROR 3u +#define SNVM_WRITE_NOT_PERMITTED 4u + +/** + * # Secure Nvm Read Error Codes + * + * SNVM_READ_INVALID_SNVMADDR + * Illegal page address + * + * SNVM_READ_AUTHENTICATION_FAILURE + * Storage corrupt or incorrect USK + * + * SNVM_READ_SYSTEM_ERROR + * PUF or storage failure + * + */ +#define SNVM_READ_INVALID_SNVMADDR 1u +#define SNVM_READ_AUTHENTICATION_FAILURE 2u +#define SNVM_READ_SYSTEM_ERROR 3u + +/** + * # Digital Signature Service Error Codes + * + * DIGITAL_SIGNATURE_FEK_FAILURE_ERROR + * Error retrieving FEK + * + * DIGITAL_SIGNATURE_DRBG_ERROR + * Failed to generate nonce + * + * DIGITAL_SIGNATURE_ECDSA_ERROR + * ECDSA failed + */ +#define DIGITAL_SIGNATURE_FEK_FAILURE_ERROR 1u +#define DIGITAL_SIGNATURE_DRBG_ERROR 2u +#define DIGITAL_SIGNATURE_ECDSA_ERROR 3u + +/** + * # Digest Check Error Codes + * + * NOTE: When these error occur, the DIGEST tamper flag is triggered. + * + * DIGEST_CHECK_FABRICERR + * Fabric digest check error + * + * DIGEST_CHECK_CCERR + * UFS Fabric Configuration (CC) segment digest check error + * + * DIGEST_CHECK_SNVMERR + * ROM digest in SNVM segment digest check error + * + * DIGEST_CHECK_ULERR + * UFS UL segment digest check error + * + * DIGEST_CHECK_UK0ERR + * UKDIGEST0 in User Key segment digest check error + * + * DIGEST_CHECK_UK1ERR + * UKDIGEST1 in User Key segment digest check error + * + * DIGEST_CHECK_UK2ERR + * UKDIGEST2 in User Key segment (UPK1) digest check error + * + * DIGEST_CHECK_UK3ERR + * UKDIGEST3 in User Key segment (UK1) digest check error + * + * DIGEST_CHECK_UK4ERR + * UKDIGEST4 in User Key segment (DPK) digest check error + * + * DIGEST_CHECK_UK5ERR + * UKDIGEST5 in User Key segment (UPK2) digest check error + * + * DIGEST_CHECK_UK6ERR + * UKDIGEST6 in User Key segment (UK2) digest check error + * + * DIGEST_CHECK_UPERR + * UFS Permanent Lock (UPERM) segment digest check error + * + * DIGEST_CHECK_SYSERR + * M3 ROM, Factory and Factory Key Segments digest check error + * + */ +#define DIGEST_CHECK_FABRICERR 0x00u +#define DIGEST_CHECK_CCERR 0x01u +#define DIGEST_CHECK_SNVMERR 0x02u +#define DIGEST_CHECK_ULERR 0x03u +#define DIGEST_CHECK_UK0ERR 0x04u +#define DIGEST_CHECK_UK1ERR 0x05u +#define DIGEST_CHECK_UK2ERR 0x06u +#define DIGEST_CHECK_UK3ERR 0x07u +#define DIGEST_CHECK_UK4ERR 0x08u +#define DIGEST_CHECK_UK5ERR 0x09u +#define DIGEST_CHECK_UK6ERR 0x10u +#define DIGEST_CHECK_UPERR 0x11u +#define DIGEST_CHECK_SYSERR 0x12u + +/** + * # Bitstream Authentication and Iap Bitstream Authentication Return Status + * + * BSTREAM_AUTH_CHAINING_MISMATCH_ERR + * Validator or hash chaining mismatch. Incorrectly constructed bitstream or + * wrong key used. + * + * BSTREAM_AUTH_UNEXPECTED_DATA_ERR + * Unexpected data received. + * Additional data received after end of EOB component. + * + * BSTREAM_AUTH_INVALID_ENCRY_KEY_ERR + * Invalid/corrupt encryption key. + * The requested key mode is disabled or the key could not be read/reconstructed. + * + * BSTREAM_AUTH_INVALID_HEADER_ERR + * Invalid component header + * + * BSTREAM_AUTH_BACK_LEVEL_NOT_SATISFIED_ERR + * Back level not satisfied + * + * BSTREAM_AUTH_ILLEGAL_BITSTREAM_MODE_ERR + * Illegal bitstream mode. + * Requested bitstream mode is disabled by user security. + * + * BSTREAM_AUTH_DNS_BINDING_MISMATCH_ERR + * DSN binding mismatch + * + * BSTREAM_AUTH_ILLEGAL_COMPONENT_SEQUENCE_ERR + * Illegal component sequence + * + * BSTREAM_AUTH_INSUFF_DEVICE_CAPAB_ERR + * Insufficient device capabilities + * + * BSTREAM_AUTH_INCORRECT_DEVICEID_ERR + * Incorrect DEVICEID + * + * BSTREAM_AUTH_PROTOCOL_VERSION_ERR + * Unsupported bitstream protocol version (regeneration required) + * + * BSTREAM_AUTH_VERIFY_ERR + * Verify not permitted on this bitstream + * + * BSTREAM_AUTH_INVALID_DEV_CERT_ERR + * Invalid Device Certificate. + * Device SCAC is invalid or not present. + * + * BSTREAM_AUTH_INVALID_DIB_ERR + * Invalid DIB + * + * BSTREAM_AUTH_SPI_NOT_MASTER_ERR + * Device not in SPI Master Mode. + * Error may occur only when bitstream is executed through IAP mode. + * + * BSTREAM_AUTH_AUTOIAP_NO_VALID_IMAGE_ERR + * No valid images found. + * Error may occur when bitstream is executed through Auto Update mode. + * Occurs when no valid image pointers are found. + * + * BSTREAM_AUTH_INDEXIAP_NO_VALID_IMAGE_ERR + * No valid images found. + * Error may occur when bitstream is executed through IAP mode via Index Mode. + * Occurs when No valid image pointers are found. + * + * BSTREAM_AUTH_NEWER_DESIGN_VERSION_ERR + * Programmed design version is newer than AutoUpdate image found. + * Error may occur when bitstream is executed through Auto Update mode. + * + * BSTREAM_AUTH_INVALID_IMAGE_ERR + * Selected image was invalid and no recovery was performed due to valid design + * in device. + * Error may occur only when bitstream is executed through Auto Update or IAP mode + * (This error is here for completeness but only can be observed by running the + * READ_DEBUG_INFO instruction and looking at IAP Error code field). + * + * BSTREAM_AUTH_IMAGE_PROGRAM_FAILED_ERR + * Selected and Recovery image failed to program. + * Error may occur only when bitstream is executed through Auto Update or + * IAP mode + * (This error is here for completeness but only can be observed by running the + * READ_DEBUG_INFO instruction and looking at IAP Error code field). + * + * BSTREAM_AUTH_ABORT_ERR + * Abort. + * Non-bitstream instruction executed during bitstream loading. + * + * BSTREAM_AUTH_NVMVERIFY_ERR + * Fabric/UFS verification failed (min or weak limit) + * + * BSTREAM_AUTH_PROTECTED_ERR + * Device security prevented modification of non-volatile memory + * + * BSTREAM_AUTH_NOTENA + * Programming mode not enabled + * + * BSTREAM_AUTH_PNVMVERIFY + * pNVM verify operation failed + * + * BSTREAM_AUTH_SYSTEM + * System hardware error (PUF or DRBG) + * + * BSTREAM_AUTH_BADCOMPONENT + * An internal error was detected in a component payload + * + * BSTREAM_AUTH_HVPROGERR + * HV programming subsystem failure (pump failure) + * + * BSTREAM_AUTH_HVSTATE + * HV programming subsystem in unexpected state (internal error) + * + */ +#define BSTREAM_AUTH_CHAINING_MISMATCH_ERR 1 +#define BSTREAM_AUTH_UNEXPECTED_DATA_ERR 2 +#define BSTREAM_AUTH_INVALID_ENCRY_KEY_ERR 3 +#define BSTREAM_AUTH_INVALID_HEADER_ERR 4 +#define BSTREAM_AUTH_BACK_LEVEL_NOT_SATISFIED_ERR 5 +#define BSTREAM_AUTH_ILLEGAL_BITSTREAM_MODE_ERR 6 +#define BSTREAM_AUTH_DNS_BINDING_MISMATCH_ERR 7 +#define BSTREAM_AUTH_ILLEGAL_COMPONENT_SEQUENCE_ERR 8 +#define BSTREAM_AUTH_INSUFF_DEVICE_CAPAB_ERR 9 +#define BSTREAM_AUTH_INCORRECT_DEVICEID_ERR 10 +#define BSTREAM_AUTH_PROTOCOL_VERSION_ERR 11 +#define BSTREAM_AUTH_VERIFY_ERR 12 +#define BSTREAM_AUTH_INVALID_DEV_CERT_ERR 13 +#define BSTREAM_AUTH_INVALID_DIB_ERR 14 +#define BSTREAM_AUTH_SPI_NOT_MASTER_ERR 21 +#define BSTREAM_AUTH_AUTOIAP_NO_VALID_IMAGE_ERR 22 +#define BSTREAM_AUTH_INDEXIAP_NO_VALID_IMAGE_ERR 23 +#define BSTREAM_AUTH_NEWER_DESIGN_VERSION_ERR 24 +/* 25 Reserved */ +#define BSTREAM_AUTH_INVALID_IMAGE_ERR 26 +#define BSTREAM_AUTH_IMAGE_PROGRAM_FAILED_ERR 27 +#define BSTREAM_AUTH_ABORT_ERR 127 +#define BSTREAM_AUTH_NVMVERIFY_ERR 128 +#define BSTREAM_AUTH_PROTECTED_ERR 129 +#define BSTREAM_AUTH_NOTENA 130 +#define BSTREAM_AUTH_PNVMVERIFY 131 +#define BSTREAM_AUTH_SYSTEM 132 +#define BSTREAM_AUTH_BADCOMPONENT 133 +#define BSTREAM_AUTH_HVPROGERR 134 +#define BSTREAM_AUTH_HVSTATE 135 + +/***************************************************************************//** + * # Mailbox ECC Status + * Provides ECC status when the mailbox is read. The values are as follows: + * 00: No ECC errors detected, data is correct. + * 01: Exactly one bit error occurred and has been corrected. + * 10: Exactly two bits error occurred and no correction performed. + * 11: Reserved. + */ +#define SYS_MBOX_ECC_NO_ERROR_MASK 0x00u +#define SYS_MBOX_ONEBIT_ERROR_CORRECTED_MASK 0x40u +#define SYS_MBOX_TWOBIT_ERROR_MASK 0xC0u + +/***************************************************************************//** + * Service request command opcodes: +*/ +#define SERIAL_NUMBER_REQUEST_CMD 0x00u +#define USERCODE_REQUEST_CMD 0x01u +#define DESIGN_INFO_REQUEST_CMD 0x02u +#define DEVICE_CERTIFICATE_REQUEST_CMD 0x03u +#define READ_DIGEST_REQUEST_CMD 0x04u +#define QUERY_SECURITY_REQUEST_CMD 0x05u +#define READ_DEBUG_INFO_REQUEST_CMD 0x06u +#define READ_ENVM_PARAM_REQUEST_CMD 0x07u +#define SNVM_NON_AUTHEN_TEXT_REQUEST_CMD 0x10u +#define SNVM_AUTHEN_TEXT_REQUEST_CMD 0x11u +#define SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD 0x12u +#define SNVM_READ_REQUEST_CMD 0x18u +#define DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD 0x19u +#define PUF_EMULATION_SERVICE_REQUEST_CMD 0x20u +#define NONCE_SERVICE_REQUEST_CMD 0x21u +#define DIGITAL_SIGNATURE_DER_FORMAT_REQUEST_CMD 0x1Au + +#define BITSTREAM_AUTHENTICATE_CMD 0x23u +#define IAP_BITSTREAM_AUTHENTICATE_CMD 0x22u + +#define DIGEST_CHECK_CMD 0x47u + +#define IAP_PROGRAM_BY_SPIIDX_CMD 0x42u +#define IAP_VERIFY_BY_SPIIDX_CMD 0x44u +#define IAP_PROGRAM_BY_SPIADDR_CMD 0x43u +#define IAP_VERIFY_BY_SPIADDR_CMD 0x45u +#define IAP_AUTOUPDATE_CMD 0x46u + +/***************************************************************************//** + * Service request Mailbox return data length + */ +#define SERIAL_NUMBER_RESP_LEN 16u +#define USERCODE_RESP_LEN 4u +#define DESIGN_INFO_RESP_LEN 36u +#define DEVICE_CERTIFICATE_RESP_LEN 1024u +#define READ_DIGEST_RESP_LEN 416u +#define QUERY_SECURITY_RESP_LEN 9u +#define READ_DEBUG_INFO_RESP_LEN 76u +#define READ_ENVM_PARAM_RESP_LEN 256u +#define NONCE_SERVICE_RESP_LEN 32u + +#define PUF_EMULATION_SERVICE_CMD_LEN 20u +#define PUF_EMULATION_SERVICE_RESP_LEN 32u + +#define DIGITAL_SIGNATURE_HASH_LEN 48u +#define DIGITAL_SIGNATURE_RAW_FORMAT_RESP_SIZE 96u +#define DIGITAL_SIGNATURE_DER_FORMAT_RESP_SIZE 104u + +#define USER_SECRET_KEY_LEN 12u + +/* Same driver can be used on PolarFire SoC platform and the response length + * is different for PolarFire SoC. Constants defined below are used only when the + * PF System services driver is used with PolarFire SoC Platform. + */ +#define READ_DIGEST_MPFS_RESP_LEN 576u +#define QUERY_SECURITY_MPFS_RESP_LEN 33u + +/* SNVM Input data length from sNVM write. */ +#ifndef RT_DEVICE_FAMILY +/* SNVMADDR + RESERVED + PT + USK */ +#define NON_AUTHENTICATED_TEXT_DATA_LEN 256u + +/* SNVMADDR + RESERVED + PT */ +#define AUTHENTICATED_TEXT_DATA_LEN 252u +#else +/* SNVMADDR + RESERVED + PT + USK */ +#define NON_AUTHENTICATED_TEXT_DATA_LEN 224u + +/* SNVMADDR + RESERVED + PT */ +#define AUTHENTICATED_TEXT_DATA_LEN 220u +#endif + +/** + * # Digest Check Input Options + * + * DIGEST_CHECK_FABRIC + * Carry out digest check on Fabric + * + * DIGEST_CHECK_CC + * Carry out digest check on UFS Fabric Configuration (CC) segment + * + * DIGEST_CHECK_SNVM + * Carry out digest check on ROM digest in SNVM segment + * + * DIGEST_CHECK_UL + * Carry out digest check on UFS UL segment + * + * DIGEST_CHECK_UKDIGEST0 + * Carry out digest check on UKDIGEST0 in User Key segment + * + * DIGEST_CHECK_UKDIGEST1 + * Carry out digest check on UKDIGEST1 in User Key segment + * + * DIGEST_CHECK_UKDIGEST2 + * Carry out digest check on UKDIGEST2 in User Key segment (UPK1) + * + * DIGEST_CHECK_UKDIGEST3 + * Carry out digest check on UKDIGEST3 in User Key segment (UK1) + * + * DIGEST_CHECK_UKDIGEST4 + * Carry out digest check on UKDIGEST4 in User Key segment (DPK) + * + * DIGEST_CHECK_UKDIGEST5 + * Carry out digest check on UKDIGEST5 in User Key segment (UPK2) + * + * DIGEST_CHECK_UKDIGEST6 + * Carry out digest check on UKDIGEST6 in User Key segment (UK2) + * + * DIGEST_CHECK_UPERM + * Carry out digest check on UFS Permanent lock (UPERM) segment + * + * DIGEST_CHECK_SYS + * Carry out digest check on Factory and Factory Key Segments + * + */ +#define DIGEST_CHECK_FABRIC (0x01<<0x00u) /*Fabric digest*/ +#define DIGEST_CHECK_CC (0x01<<0x01u) /*UFS Fabric Configuration (CC) segment*/ +#define DIGEST_CHECK_SNVM (0x01<<0x02u) /*ROM digest in SNVM segment*/ +#define DIGEST_CHECK_UL (0x01<<0x03u) /*UFS UL segment*/ +#define DIGEST_CHECK_UKDIGEST0 (0x01<<0x04u) /*UKDIGEST0 in User Key segment*/ +#define DIGEST_CHECK_UKDIGEST1 (0x01<<0x05u) /*UKDIGEST1 in User Key segment*/ +#define DIGEST_CHECK_UKDIGEST2 (0x01<<0x06u) /*UKDIGEST2 in User Key segment (UPK1)*/ +#define DIGEST_CHECK_UKDIGEST3 (0x01<<0x07u) /*UKDIGEST3 in User Key segment (UK1)*/ +#define DIGEST_CHECK_UKDIGEST4 (0x01<<0x08u) /*UKDIGEST4 in User Key segment (DPK)*/ +#define DIGEST_CHECK_UKDIGEST5 (0x01<<0x09u) /*UKDIGEST5 in User Key segment (UPK2)*/ +#define DIGEST_CHECK_UKDIGEST6 (0x01<<0x0au) /*UKDIGEST6 in User Key segment (UK2)*/ +#define DIGEST_CHECK_UPERM (0x01<<0x0bu) /*UFS Permanent lock (UPERM) segment*/ +#define DIGEST_CHECK_SYS (0x01<<0x0cu) /*Factory and Factory Key Segments.*/ + +/***************************************************************************//** + * The function SYS_init() is used to initialize the internal data structures of + * this driver. Currently this function is empty. + * + * @param base_addr The base_addr parameter specifies the base address of the + * PF_System_services core. + * + * @return This function does not return a value. + */ +void +SYS_init +( + uint32_t base_addr +); + +/***************************************************************************//** + * The function SYS_get_serial_number() is used to execute "serial number" system + * service. + * + * @param p_serial_number The p_serial_number parameter is a pointer to a buffer + * in which the data returned by system controller + * is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t +SYS_get_serial_number +( + const uint8_t * p_serial_number, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_get_user_code() is used to execute "USERCODE" system + * service. + * @param p_user_code The p_user_code parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t +SYS_get_user_code +( + const uint8_t * p_user_code, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_get_design_info() is used to execute "Get Design Info" system + * service. + * + * @param p_design_info The p_design_info parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. Total size of debug information is 36 bytes. + * The data from the system controller includes the 256-bit + * user-defined design ID, 16-bit design version, and 16-bit + * design back level. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t +SYS_get_design_info +( + const uint8_t * p_design_info, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_get_device_certificate() is used to execute "Get Device + * Certificate" system service. + * + * @param p_device_certificate The p_device_certificate parameter is a pointer + * to a buffer in which the data returned by the + * system controller is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code means that + * the service was executed successfully. + * + */ +uint8_t +SYS_get_device_certificate +( + const uint8_t * p_device_certificate, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_read_digest() is used to execute "Read Digest" system service. + * + * @param p_digest The p_digest parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t SYS_read_digest +( + const uint8_t * p_digest, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_query_security() is used to execute "Query Security" system + * service. + * + * @param p_security_locks The p_security_locks parameter is a pointer to a buffer + * in which the data returned by system controller is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code means that + * the service was executed successfully. + */ +uint8_t SYS_query_security +( + uint8_t * p_security_locks, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_read_debug_info() is used to execute "Read Debug info" system + * service. + * + * @param p_debug_info The p_debug_info parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t SYS_read_debug_info +( + const uint8_t * p_debug_info, + uint16_t mb_offset +); + +#ifdef CORESYSSERVICES_PFSOC +/***************************************************************************//** + * The function SYS_read_envm_parameter() is used to retrieve all parameters needed + * for the eNVM operation and programming. + * + * NOTE: This service is available only on PolarFire SoC Platform. + * This service is not yet supported by PF_SYSTEM_SERVICES 3.0.100. + * + * @param p_envm_param The p_envm_param parameter is a pointer to a buffer + * in which the data returned by system controller is copied. + * This buffer stores all the eNVM parameters. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_read_envm_parameter service will return zero if the + * service executed successfully, otherwise, it will return + * one indicating error. + */ +uint8_t SYS_read_envm_parameter +( + uint8_t * p_envm_param, + uint16_t mb_offset +); +#endif +/***************************************************************************//** + * The function SYS_puf_emulation_service() is used to authenticate a device. + * + * The SYS_puf_emulation_service() function accept a challenge comprising a + * 8-bit optype and 128-bit challenge and return a 256-bit response unique to + * the given challenge and the device. + * + * @param p_challenge The p_challenge parameter specifies the 128-bit challenge + * to generate the 256-bits unique response. + * + * @param op_type The op_type parameter specifies the operational parameter + * to generate the 256-bits unique response. + * + * @param p_response The p_response parameter is a pointer to a buffer where + * the data returned which is the response by system controller + * is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_puf_emulation_service function will return zero + * if the service executed successfully, otherwise, it will + * return one indicating error. + */ +uint8_t SYS_puf_emulation_service +( + const uint8_t * p_challenge, + uint8_t op_type, + uint8_t* p_response, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_digital_signature_service() function is used to generate P-384 ECDSA + * signature based on SHA384 hash value. + * + * @param p_hash The p_hash parameter is a pointer to the buffer which + * contain the 48 bytes SHA384 Hash value (input value). + * + * @param format The format parameter specifies the output format of + * generated SIGNATURE field. The different types of output + * signature formats are as follow: + * - DIGITAL_SIGNATURE_RAW_FORMAT + * - DIGITAL_SIGNATURE_DER_FORMAT + * + * @param p_response The p_response parameter is a pointer to a buffer that + * contains the generated ECDSA signature. The field may be + * 96 bytes or 104 bytes depending upon the output format. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digital_signature_service function returns + * zero if the service executed successfully, otherwise, it + * returns non-zero values indicating error. + */ +uint8_t SYS_digital_signature_service +( + const uint8_t* p_hash, + uint8_t format, + uint8_t* p_response, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_secure_nvm_write() function writes data in the sNVM region. + * Data gets stored in the following format: + * - Non-authenticated plaintext + * - Authenticated plaintext + * - Authenticated ciphertext + * + * Note: If you are executing this function with Authenticated plaintext + * or Authenticated ciphertext on a device whose sNVM was never previously + * written to, then the service may fail. For it to work, you must first write + * Authenticated data to the sNVM using Libero along with USK client and + * custom security. This flow generates the SMK. See UG0753 PolarFire FPGA + * Security User Guide for further details. + + * @param format The format parameter specifies the format used to write + * data in sNVM region. The different type of text formats + * are as follow: + * - NON_AUTHENTICATED_PLAINTEXT_FORMAT + * - AUTHENTICATED_PLAINTEXT_FORMAT + * - AUTHENTICATED_CIPHERTEXT_FORMAT + * + * @param snvm_module The snvm_module parameter specifies the the sNVM module + * in which the data need to be written. + * + * @param p_data The p_data parameter is a pointer to a buffer which + * contains the data to be stored in sNVM region. The data + * length to be written is fixed depending on the format + * parameter. If NON_AUTHENTICATED_PLAINTEXT_FORMAT is + * selected, then you can write 252 bytes in the sNVM module. + * For other two formats the data length is 236 bytes. + * + * @param p_user_key The p_user_key parameter is a pointer to a buffer which + * contain the 96-bit key USK (user secret key). This user + * secret key will enhance the security when authentication + * is used. That is, when Authenticated plaintext and + * Authenticated ciphertext format is selected. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digital_signature_service function returns + * zero if the service executed successfully, otherwise, it + * returns non-zero values indicating error. + */ +uint8_t SYS_secure_nvm_write +( + uint8_t format, + uint8_t snvm_module, + const uint8_t* p_data, + const uint8_t* p_user_key, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_secure_nvm_read() function is used to read data present in sNVM region. + * User should provide USK key, if the data was programmed using authentication. + * If the data was written in the sNVM using the authenticated plaintext or the + * authenticated ciphertext service option then this service will return the + * valid data only when authentication is successful. For more details, see + * SYS_secure_nvm_write() function. If the data was written in + * the sNVM using the authenticated plaintext or the authenticated ciphertext + * service option then this service will return the valid data only when + * authentication is successful. For more details, see SYS_secure_nvm_write() + * function and its parameter description. + * + * @param snvm_module The snvm_module parameter specifies the sNVM module + * from which the data need to be read. + * + * @param p_user_key The p_user_key parameter is a pointer to a buffer which + * contain the 96-bit key USK (user secret key). User should + * provide same secret key which is previously used for + * authentication while writing data in sNVM region. + * + * @param p_admin The p_admin parameter is a pointer to the buffer where + * the output page admin data is stored. The page admin + * data is 4 bytes long. + * + * @param p_data The p_data parameter is a pointer to a buffer which + * contains the data read from sNVM region. User should + * provide the buffer large enough to store the read data. + * + * @param data_len The data_len parameter specifies the number of bytes to be + * read from sNVM. + * The application should know whether the data written in the + * chose sNVM module was previously stored using Authentication + * or not. + * The data_len should be 236 bytes, for authenticated data. + * For not authenticated data the data_len should be 252 bytes. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digital_signature_service function returns + * zero if the service executed successfully, otherwise, it + * returns non-zero values indicating error. + */ +uint8_t SYS_secure_nvm_read +( + uint8_t snvm_module, + const uint8_t* p_user_key, + uint8_t* p_admin, + uint8_t* p_data, + uint16_t data_len, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_nonce_service() is used to issue "Nonce Service" system + * service to the system controller. + * + * @param p_nonce The p_nonce parameter is a pointer to a buffer + * in which the data returned by system controller is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code means + * that the service was executed successfully and a non-zero + * value indicates error. See the document link + * provided in the theory of operation section to know more + * about the service and service response. + */ +uint8_t SYS_nonce_service +( + const uint8_t * p_nonce, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_bitstream_authenticate_service() function is used to authenticate + * the Bitstream which is located in SPI through a system service routine. Prior + * to using the IAP service, it may be required to first validate the new + * bitstream before committing the device to reprogramming, thus avoiding the + * need to invoke recovery procedures if the bitstream is invalid. + * + * This service is applicable to bitstreams stored in SPI Flash memory only. + * + * @param spi_flash_address + * The spi_flash_address parameter specifies the address within + * SPI Flash memory where the bit-stream is stored. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_bitstream_authenticate_service function will return + * zero if the service executed successfully and the non-zero + * response from system controller indicates error. See + * the document link provided in the theory of + * operation section to know more about the service and service + * response. + */ +uint8_t SYS_bitstream_authenticate_service +( + uint32_t spi_flash_address, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_IAP_image_authenticate_service() function is used to authenticate + * the IAP image which is located in SPI through a system service routine. The + * service checks the image descriptor and the referenced bitstream and optional + * initialization data. If the image is authenticated successfully, then the + * image is guaranteed to be valid when used by an IAP function. + * + * This service is applicable to bitstreams stored in SPI Flash memory only. + * + * @param spi_idx + * The spi_idx parameter specifies the index in the SPI directory to + * be used where the IAP bit-stream is stored. + * Note: To support recovery SPI_IDX=1 should be an empty slot and the recovery + * image should be located in SPI_IDX=0. Since SPI_IDX=1 should be an + * empty slot, it shouldn’t be passed into the system service. + * + * @return The SYS_IAP_image_authenticate_service function will return + * zero if the service executed successfully the non-zero + * response from system controller indicates error. Please + * refer to the document link provided in the theory of + * operation section to know more about the service and service + * response. + */ +uint8_t SYS_IAP_image_authenticate_service +( + uint8_t spi_idx +); + +/***************************************************************************//** + * The SYS_digest_check_service() function is used to Recalculates and compares + * digests of selected non-volatile memories. If the fabric digest is to be + * checked, then the user design must follow all prerequisite steps for the + * FlashFreeze service before invoking this service. + * This service is applicable to bitstreams stored in SPI Flash memory only. + * @param options + * The options parameter specifies the digest check options which + * indicate the area on which the digest check should be performed. + * Below is the list of options. You can OR these options to indicate + * to perform digest check on multiple segments. + * Note: The options parameter is of 2 bytes when used with PF + * device and 4 bytes when used with PolarFire SoC device. + * Options[i] | Description + * ---------------|---------------------------------- + * 0x01 | Fabric digest + * 0x02 | Fabric Configuration (CC) segment + * 0x04 | ROM digest in SNVM segment + * 0x08 | UL segment + * 0x10 | UKDIGEST0 in User Key segment + * 0x20 | UKDIGEST1 in User Key segment + * 0x40 | UKDIGEST2 in User Key segment (UPK1) + * 0x80 | UKDIGEST3 in User Key segment (UK1) + * 0x100 | UKDIGEST4 in User Key segment (DPK) + * 0x200 | UKDIGEST5 in User Key segment (UPK2) + * 0x400 | UKDIGEST6 in User Key segment (UK2) + * 0x800 | UFS Permanent lock (UPERM) segment + * 0x1000 | Factory and Factory Key Segments. + * 0x2000 | UKDIGEST7 in User Key segment (HWM) (PFSoC) + * 0x4000 | ENVMDIGEST (PFSoC only) + * 0x8000 | UKDIGEST8 for MSS Boot Info (PFSoC only) + * 0x10000 | SNVM_RW_ACCESS_MAP Digest (PFSoC only) + * 0x20000 | SBIC revocation digest (PFSoC only) + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digest_check_service function will return + * zero if the service executed successfully the non-zero + * response from system controller indicates error. Pleaes + * refer to the document link provided in the theory of + * operation section to know more about the service and service + * response. + */ +uint8_t SYS_digest_check_service +( + uint32_t options, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_iap_service() function is used to IAP service. The IAP service allows + * the user to reprogram the device without the need for an external master. The + * user design writes the bitstream to be programmed into a SPI Flash connected + * to the SPI port. When the service is invoked, the System Controller + * automatically reads the bitstream from the SPI flash and programs the device. + * The service allows the image to be executed in either VERIFY or PROGRAM modes. + * Another option for IAP is to perform the auto-update sequence. In this case + * the newest image of the first two images in the SPI directory is chosen to be + * programmed. + * + * @param iap_cmd + * The iap_cmd parameter specifies the specific IAP command which + * depends upon VERIFY or PROGRAM modes and the SPI address method. + * iap_cmd | Description + * -----------------------|------------ + * IAP_PROGRAM_BY_SPIIDX_CMD | IAP program. + * IAP_VERIFY_BY_SPIIDX_CMD | Fabric Configuration (CC) segment + * IAP_PROGRAM_BY_SPIADDR_CMD | ROM digest in SNVM segment + * IAP_VERIFY_BY_SPIADDR_CMD | UL segment + * IAP_AUTOUPDATE_CMD | UKDIGEST0 in User Key segment + * + * @param spiaddr + * The spiaddr parameter specifies either the index + * in the SPI directory or the SPI address in the SPI Flash memory. + * Below is the list of the possible meaning of spiaddr parameter + * in accordance with the iap_cmd parameter. + * iap_cmd | spiaddr + * ----------------------|----------------- + * IAP_PROGRAM_BY_SPIIDX_CMD | Index in the SPI directory. + * IAP_VERIFY_BY_SPIIDX_CMD | Index in the SPI directory. + * IAP_PROGRAM_BY_SPIADDR_CMD | SPI address in the SPI Flash memory + * IAP_VERIFY_BY_SPIADDR_CMD | SPI address in the SPI Flash memory + * IAP_AUTOUPDATE_CMD | spiaddr is ignored as No index/address required for this command. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * Note: For the IAP services with command IAP_PROGRAM_BY_SPIIDX_CMD and + * IAP_VERIFY_BY_SPIIDX_CMD To support recovery SPI_IDX=1 should be an + * empty slot and the recovery image should be located in SPI_IDX=0. + * Since SPI_IDX=1 should be an empty slot it shouldn’t be passed into + * the system service. + * + * @return The SYS_iap_service function will return zero if the service + * executed successfully and the non-zero response from system + * controller indicates error. Please refer to the document + * link provided in the theory of operation section to know + * more about the service and service response. + */ +uint8_t SYS_iap_service +( + uint8_t iap_cmd, + uint32_t spiaddr, + uint16_t mb_offset +); + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_SYSSERV_PF_H */ diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h new file mode 100644 index 0000000..8b14b7e --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h @@ -0,0 +1,149 @@ +/******************************************************************************* + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Register bit offsets and masks definitions for CoreSysServices_PF driver. + */ + +#ifndef __CORE_SYSSERV_PF_REGISTERS +#define __CORE_SYSSERV_PF_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * SYS_SERV_CMD (offset 0x04) register details + */ +#define SS_CMD_REG_OFFSET 0x04u + +#define SS_CMD_OFFSET 0x04 +#define SS_CMD_MASK 0x0000FFFFu +#define SS_CMD_SHIFT 0u + +/*------------------------------------------------------------------------------ + * SYS_SERV_STAT (offset 0x08) register details + */ +#define SS_STAT_REG_OFFSET 0x08u + +#define SS_STAT_OFFSET 0x08 +#define SS_STAT_MASK 0x0000FFFFu +#define SS_STAT_SHIFT 0u + +/*------------------------------------------------------------------------------ + * SYS_SERV_REQ (offset 0x0C) register details + */ +#define SS_REQ_REG_OFFSET 0x0Cu + + +#define SS_REQ_REQ_OFFSET 0x0Cu +#define SS_REQ_REQ_MASK 0x00000001UL +#define SS_REQ_REQ_SHIFT 0u + +#define SS_REQ_ABUSY_OFFSET 0x0Cu +#define SS_REQ_ABUSY_MASK 0x00000002UL +#define SS_REQ_ABUSY_SHIFT 1u + +#define SS_REQ_NABUSY_OFFSET 0x0Cu +#define SS_REQ_NABUSY_MASK 0x00000004UL +#define SS_REQ_NABUSY_SHIFT 2u + +#define SS_REQ_SSBUSY_OFFSET 0x0Cu +#define SS_REQ_SSBUSY_MASK 0x00000008UL +#define SS_REQ_SSBUSY_SHIFT 3u + +#define SS_REQ_AREQ_OFFSET 0x0Cu +#define SS_REQ_AREQ_MASK 0x00000010UL +#define SS_REQ_AREQ_SHIFT 4u + +#define SS_REQ_NAREQ_OFFSET 0x0Cu +#define SS_REQ_NAREQ_MASK 0x00000020UL +#define SS_REQ_NAREQ_SHIFT 5u +/*------------------------------------------------------------------------------ + * MBX_ECCSTATUS (offset 0x10) register details + */ +#define MBX_ECCSTATUS_REG_OFFSET 0x10u + +#define MBX_ECCSTATUS_OFFSET 0x10 +#define MBX_ECCSTATUS_MASK 0x03u +#define MBX_ECCSTATUS_SHIFT 0u + + +/*------------------------------------------------------------------------------ + * MBX_WCNT (offset 0x14) register details + */ +#define MBX_WCNT_REG_OFFSET 0x14u + +#define MBX_WCNT_OFFSET 0x14 +#define MBX_WCNT_MASK 0x000001FFu +#define MBX_WCNT_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_RWCNT (offset 0x18) register details + */ +#define MBX_RCNT_REG_OFFSET 0x18u + +#define MBX_RCNT_OFFSET 0x18 +#define MBX_RCNT_MASK 0x000001FFu +#define MBX_RCNT_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_WADRDESC (offset 0x1C) register details + */ +#define MBX_WADDR_REG_OFFSET 0x1Cu + +#define MBX_WADDR_OFFSET 0x1C +#define MBX_WADDR_MASK 0x000001FFu +#define MBX_WADDR_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_RADRDESC (offset 0x20) register details + */ +#define MBX_RADDR_REG_OFFSET 0x20u + +#define MBX_RADDR_OFFSET 0x20 +#define MBX_RADDR_MASK 0x000001FFu +#define MBX_RADDR_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_WDATA (offset 0x28) register details + */ +#define MBX_WDATA_REG_OFFSET 0x28u + +#define MBX_WDATA_OFFSET 0x28 +#define MBX_WDATA_MASK 0xFFFFFFFFu +#define MBX_WDATA_SHIFT 0u + + +/*------------------------------------------------------------------------------ + * MBX_RDATA (offset 0x2C) register details + */ +#define MBX_RDATA_REG_OFFSET 0x2Cu + +#define MBX_RDATA_OFFSET 0x2C +#define MBX_RDATA_MASK 0xFFFFFFFFu +#define MBX_RDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * SS_USER (offset 0x30) register details + */ +#define SS_USER_REG_OFFSET 0x30u + +#define SS_USER_BUSY_OFFSET 0x30 +#define SS_USER_BUSY_MASK 0x00000001u +#define SS_USER_BUSY_SHIFT 0u + +#define SS_USER_RDVLD_OFFSET 0x30 +#define SS_USER_RDVLD_MASK 0x00000002u +#define SS_USER_RDVLD_SHIFT 1u + +#define SS_USER_CMDERR_OFFSET 0x30 +#define SS_USER_CMDERR_MASK 0x00000004u +#define SS_USER_CMDERR_SHIFT 2u + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_SYSSERV_PF_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c new file mode 100644 index 0000000..0c0a866 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c @@ -0,0 +1,297 @@ +/******************************************************************************* + * (c) Copyright 2007-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file core_uart_apb.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreUARTapb driver implementation. See file "core_uart_apb.h" for + * description of the functions implemented in this file. + * + */ + +#include "coreuartapb_regs.h" +#include "core_uart_apb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define NULL_INSTANCE ( ( UART_instance_t* ) 0 ) +#define NULL_BUFFER ( ( uint8_t* ) 0 ) + +#define MAX_LINE_CONFIG ( ( uint8_t )( DATA_8_BITS | ODD_PARITY ) ) +#define MAX_BAUD_VALUE ( ( uint16_t )( 0x1FFF ) ) +#define STATUS_ERROR_MASK ( ( uint8_t )( STATUS_PARITYERR_MASK | \ + STATUS_OVERFLOW_MASK | \ + STATUS_FRAMERR_MASK ) ) +#define BAUDVALUE_LSB ( (uint16_t) (0x00FF) ) +#define BAUDVALUE_MSB ( (uint16_t) (0xFF00) ) +#define BAUDVALUE_SHIFT ( (uint8_t) (5) ) + +#define STATUS_ERROR_OFFSET STATUS_PARITYERR_SHIFT + +/***************************************************************************//** + * UART_init() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_init +( + UART_instance_t * this_uart, + addr_t base_addr, + uint16_t baud_value, + uint8_t line_config +) +{ + uint8_t rx_full; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( line_config <= MAX_LINE_CONFIG ) + HAL_ASSERT( baud_value <= MAX_BAUD_VALUE ) + + if( ( this_uart != NULL_INSTANCE ) && + ( line_config <= MAX_LINE_CONFIG ) && + ( baud_value <= MAX_BAUD_VALUE ) ) + { + /* + * Store lower 8-bits of baud value in CTRL1. + */ + HAL_set_8bit_reg( base_addr, CTRL1, (uint_fast8_t)(baud_value & + BAUDVALUE_LSB ) ); + + /* + * Extract higher 5-bits of baud value and store in higher 5-bits + * of CTRL2, along with line configuration in lower 3 three bits. + */ + HAL_set_8bit_reg( base_addr, CTRL2, (uint_fast8_t)line_config | + (uint_fast8_t)((baud_value & + BAUDVALUE_MSB) >> BAUDVALUE_SHIFT ) ); + + this_uart->base_address = base_addr; +#ifndef NDEBUG + { + uint8_t config; + uint8_t temp; + uint16_t baud_val; + baud_val = HAL_get_8bit_reg( this_uart->base_address, CTRL1 ); + config = HAL_get_8bit_reg( this_uart->base_address, CTRL2 ); + /* + * To resolve operator precedence between & and << + */ + temp = ( config & (uint8_t)(CTRL2_BAUDVALUE_MASK ) ); + baud_val |= (uint16_t)( (uint16_t)(temp) << BAUDVALUE_SHIFT ); + config &= (uint8_t)(~CTRL2_BAUDVALUE_MASK); + HAL_ASSERT( baud_val == baud_value ); + HAL_ASSERT( config == line_config ); + } +#endif + + /* + * Flush the receive FIFO of data that may have been received before the + * driver was initialized. + */ + rx_full = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_RXFULL_MASK; + while ( rx_full ) + { + HAL_get_8bit_reg( this_uart->base_address, RXDATA ); + rx_full = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_RXFULL_MASK; + } + + /* + * Clear status of the UART instance. + */ + this_uart->status = (uint8_t)0; + } +} + +/***************************************************************************//** + * UART_send() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_send +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +) +{ + size_t char_idx; + uint8_t tx_ready; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( tx_buffer != NULL_BUFFER ) + HAL_ASSERT( tx_size > 0 ) + + if( (this_uart != NULL_INSTANCE) && + (tx_buffer != NULL_BUFFER) && + (tx_size > (size_t)0) ) + { + for ( char_idx = (size_t)0; char_idx < tx_size; char_idx++ ) + { + /* Wait for UART to become ready to transmit. */ + do { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( !tx_ready ); + /* Send next character in the buffer. */ + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)tx_buffer[char_idx] ); + } + } +} + +/***************************************************************************//** + * UART_fill_tx_fifo() + * See "core_uart_apb.h" for details of how to use this function. + */ +size_t +UART_fill_tx_fifo +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +) +{ + uint8_t tx_ready; + size_t size_sent = 0u; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( tx_buffer != NULL_BUFFER ) + HAL_ASSERT( tx_size > 0 ) + + /* Fill the UART's Tx FIFO until the FIFO is full or the complete input + * buffer has been written. */ + if( (this_uart != NULL_INSTANCE) && + (tx_buffer != NULL_BUFFER) && + (tx_size > 0u) ) + { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + if ( tx_ready ) + { + do { + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)tx_buffer[size_sent] ); + size_sent++; + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( (tx_ready) && ( size_sent < tx_size ) ); + } + } + return size_sent; +} + +/***************************************************************************//** + * UART_get_rx() + * See "core_uart_apb.h" for details of how to use this function. + */ +size_t +UART_get_rx +( + UART_instance_t * this_uart, + uint8_t * rx_buffer, + size_t buff_size +) +{ + uint8_t new_status; + uint8_t rx_full; + size_t rx_idx = 0u; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( rx_buffer != NULL_BUFFER ) + HAL_ASSERT( buff_size > 0 ) + + if( (this_uart != NULL_INSTANCE) && + (rx_buffer != NULL_BUFFER) && + (buff_size > 0u) ) + { + rx_idx = 0u; + new_status = HAL_get_8bit_reg( this_uart->base_address, STATUS ); + this_uart->status |= new_status; + rx_full = new_status & STATUS_RXFULL_MASK; + while ( ( rx_full ) && ( rx_idx < buff_size ) ) + { + rx_buffer[rx_idx] = HAL_get_8bit_reg( this_uart->base_address, + RXDATA ); + rx_idx++; + new_status = HAL_get_8bit_reg( this_uart->base_address, STATUS ); + this_uart->status |= new_status; + rx_full = new_status & STATUS_RXFULL_MASK; + } + } + return rx_idx; +} + +/***************************************************************************//** + * UART_polled_tx_string() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_polled_tx_string +( + UART_instance_t * this_uart, + const uint8_t * p_sz_string +) +{ + uint32_t char_idx; + uint8_t tx_ready; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( p_sz_string != NULL_BUFFER ) + + if( ( this_uart != NULL_INSTANCE ) && ( p_sz_string != NULL_BUFFER ) ) + { + char_idx = 0U; + while( 0U != p_sz_string[char_idx] ) + { + /* Wait for UART to become ready to transmit. */ + do { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( !tx_ready ); + /* Send next character in the buffer. */ + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)p_sz_string[char_idx] ); + char_idx++; + } + } +} + +/***************************************************************************//** + * UART_get_rx_status() + * See "core_uart_apb.h" for details of how to use this function. + */ +uint8_t +UART_get_rx_status +( + UART_instance_t * this_uart +) +{ + uint8_t status = UART_APB_INVALID_PARAM; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + /* + * Extract UART error status and place in lower bits of "status". + * Bit 0 - Parity error status + * Bit 1 - Overflow error status + * Bit 2 - Frame error status + */ + if( this_uart != NULL_INSTANCE ) + { + status = ( ( this_uart->status & STATUS_ERROR_MASK ) >> + STATUS_ERROR_OFFSET ); + /* + * Clear the sticky status for this instance. + */ + this_uart->status = (uint8_t)0; + } + return status; +} + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h new file mode 100644 index 0000000..c016403 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h @@ -0,0 +1,451 @@ +/******************************************************************************* + * (c) Copyright 2007-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file core_uart_apb.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief This file contains the application programming interface for the + * CoreUARTapb bare metal driver. + * + */ +/*=========================================================================*//** + @mainpage CoreUARTapb Bare Metal Driver. + + @section intro_sec Introduction + CoreUARTapb is an implementation of the Universal Asynchronous + Receiver/Transmitter aimed at minimal FPGA tile usage within a Microchip FPGA. + The CoreUARTapb bare metal software driver is designed to be used in systems + with no operating system. + + The CoreUARTapb driver provides functions for basic polled transmitting and + receiving operations. It also provide functions that allow the use of the + CoreUARTapb in interrupt-driven mode but leaves the management of interrupts + to the calling application, as interrupt enabling and disabling are not + controlled through the CoreUARTapb registers. The CoreUARTapb driver is + provided as C source code. + + @section driver_configuration Driver Configuration + Your application software should configure the CoreUARTapb driver by calling + the UART_init() function for each CoreUARTapb instance in the hardware design. + The configuration parameters include the CoreUARTapb hardware instance base + address and other runtime parameters, such as baud rate, bit width, and + parity. No CoreUARTapb hardware configuration parameters are needed by the + driver, apart from the CoreUARTapb hardware instance base address. Hence, no + additional configuration files are required to use the driver. + + A CoreUARTapb hardware instance is generated with fixed baud rate, character + size, and parity configuration settings as part of the hardware flow. The + baud_value and line_config parameter values passed to the UART_init() function + have no effect if fixed values were selected for the baud rate, character + size, and parity in the hardware configuration of CoreUARTapb. When fixed + values are selected for these hardware configuration parameters, the driver is + unable to overwrite the fixed values in the CoreUARTapb control registers, + CTRL1 and CTRL2. + + @section theory_op Theory of Operation + The CoreUARTapb software driver is designed to allow the control of multiple + instances of CoreUARTapb. Each instance of CoreUARTapb in the hardware design + is associated with a single instance of the UART_instance_t structure in the + software. You need to allocate memory for one unique UART_instance_t structure + instance for each CoreUARTapb hardware instance. The contents of these data + structures are initialized while calling the UART_init() function. A pointer + to the structure is passed to the subsequent driver functions in order to + identify the CoreUARTapb hardware instance you wish to perform the requested + operation on. + + Note: Do not attempt to directly manipulate the content of UART_instance_t + structures. This structure is only intended to be modified by the driver + function. + + Once initialized, the driver transmits and receives data. Transmit is + performed using the UART_send() function. If this function blocks, then it + returns only when the data passed to it has been sent to the CoreUARTapb + hardware. Data received by the CoreUARTapb hardware is read by the user + application using the UART_get_rx() function. + + The UART_fill_tx_fifo() function is also provided as a part of the + interrupt-driven transmit. This function fills the CoreUARTapb hardware + transmit FIFO with the content of a data buffer passed as a parameter before + returning. The control of the interrupts must be implemented outside the + driver, as the CoreUARTapb hardware does not provide the ability to enable + or disable its interrupt sources. + + The UART_polled_tx_string() function is provided to transmit a NULL-terminated + string in polled mode. If this function blocks, then it returns only when the + data passed to it has been sent to the CoreUARTapb hardware. + + The UART_get_rx_status() function returns the error status of the CoreUARTapb + receiver. This is used by applications to take appropriate action in case of + receiver errors. +*//*=========================================================================*/ +#ifndef __CORE_UART_APB_H +#define __CORE_UART_APB_H 1 + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + Data Bits Length Defines + ======================== + These constants define the data length in a UART packet. + | Constant | Description | + |-------------|---------------------------------------| + | DATA_7_BITS | Data length is 7-bits | + | DATA_8_BITS | Data length is 8-bits | + */ +#define DATA_7_BITS 0x00u +#define DATA_8_BITS 0x01u + +/***************************************************************************//** + Parity Defines + ============== + These constants define parity check options. + | Constant | Description | + |-------------|---------------------------------------| + | NO_PARITY | No Parity bit | + | EVEN_PARITY | Even Parity bit | + | ODD_PARITY | ODD Parity bit | + */ +#define NO_PARITY 0x00u +#define EVEN_PARITY 0x02u +#define ODD_PARITY 0x06u + +/***************************************************************************//** + Error Status Definitions + ======================== + These constants define the different types of possible errors in UART + transmission of data. + | Constant | Description | + |-------------------------|---------------------------------------| + | UART_APB_PARITY_ERROR | Data parity error | + | UART_APB_OVERFLOW_ERROR | Data overflow error | + | UART_APB_FRAMING_ERROR | Data framing error | + | UART_APB_NO_ERROR | No error | + | UART_APB_INVALID_PARAM | Invalid parameter | + */ +#define UART_APB_PARITY_ERROR 0x01u +#define UART_APB_OVERFLOW_ERROR 0x02u +#define UART_APB_FRAMING_ERROR 0x04u +#define UART_APB_NO_ERROR 0x00u +#define UART_APB_INVALID_PARAM 0xFFu + +/***************************************************************************//** + * There should be one instance of this structure for each instance of + * CoreUARTapb in your system. This structure instance identifies various UARTs + * in a system and should be passed as first parameter to UART functions to + * identify which UART performs the requested operation. The 'status' element in + * the structure is used to provide sticky status information. + */ +typedef struct +{ + addr_t base_address; + uint8_t status; +} UART_instance_t; + +/***************************************************************************//** + * The UART_init() function initializes the UART with the configuration passed + * as parameters. The configuration parameters are the baud_value that generates + * the baud rate and the line configuration (bit length and parity). + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data regarding + * this instance of the CoreUARTapb. This pointer is used to + * identify the target CoreUARTapb hardware instance in + * subsequent calls to the CoreUARTapb functions. + * @param base_addr The base_address parameter is the base address in the + * processor's memory map for the registers of the + * CoreUARTapb instance being initialized. + * @param baud_value The baud_value parameter selects the baud rate for the + * UART. The baud value is calculated from the frequency of + * the system clock in hertz and the desired baud rate using + * the following equation: + * baud_value = (clock / (baud_rate * 16)) - 1. + * The baud_value parameter must be a value in the range 0 + * to 8191 (or 0x0000 to 0x1FFF). + * @param line_config This parameter is the line configuration, specifies the + * bit length and parity settings. This is the logical OR of: + * - DATA_7_BITS + * - DATA_8_BITS + * - NO_PARITY + * - EVEN_PARITY + * - ODD_PARITY + * For example, 8 bits even parity would be specified as + * (DATA_8_BITS | EVEN_PARITY). + * @return This function does not return a value. + * @example + * @code + * #define BAUD_VALUE_57600 25 + * + * #define COREUARTAPB0_BASE_ADDR 0xC3000000UL + * + * UART_instance_t g_uart; + * int main() + * { + * UART_init(&g_uart, COREUARTAPB0_BASE_ADDR, + BAUD_VALUE_57600, (DATA_8_BITS | EVEN_PARITY)); + * } + * @endcode + */ +void +UART_init +( + UART_instance_t * this_uart, + addr_t base_addr, + uint16_t baud_value, + uint8_t line_config +); + +/***************************************************************************//** + * The UART_send() function is used to transmit data. It transfers the content + * of the transmitter data buffer, passed as a function parameter, into the + * UART's hardware transmitter FIFO. It returns when the full content of the + * transmitter data buffer has been transferred to the UART's transmitter FIFO. + * + * Note: You should not assume that the data you are sending using this function + * has been received at the other end by the time this function returns. The + * actual transmission over the serial connection is still be taking place at + * the time of the function return. It is safe to release or reuse the memory + * used as the transmit buffer once this function returns. + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data + * regarding this instance of the CoreUARTapbUART. + * @param tx_buffer The tx_buffer parameter is a pointer to a buffer that + * contains the data to be transmitted. + * @param tx_size The tx_size parameter is the size in bytes of the + * transmitted data. + * + * @return This function does not return a value. + * + * @example + * @code + * uint8_t testmsg1[] = {"\n\r\n\r\n\rUART_send() test message 1"}; + * UART_send(&g_uart,(const uint8_t *)&testmsg1,sizeof(testmsg1)); + * @endcode + */ +void +UART_send +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +); + +/***************************************************************************//** + * The UART_fill_tx_fifo() function fills the UART's transmitter hardware FIFO + * with the data found in the transmitter buffer that is passed in as a + * function parameter. The function returns either when the FIFO is full or + * when the complete contents of the transmitter buffer have been copied into + * the FIFO. It returns the number of bytes copied into the UART's transmitter + * hardware FIFO. This function is intended to be used as part of + * interrupt-driven transmission. + * + * Note: You should not assume that the data you transmit using this function + * has been received at the other end by the time this function returns. The + * actual transmission over the serial connection is still be taking place at + * the time of the function return. + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data + * regarding this instance of the UART. + * @param tx_buffer The tx_buffer parameter is a pointer to a buffer that + * contains the data to be transmitted. + * @param tx_size The tx_size parameter is the size in bytes of the + * transmitted data. + * @return This function returns the number of bytes copied into + * the UART's transmitter hardware FIFO. + * + * @example + * @code + * void send_using_interrupt + * ( + * uint8_t * pbuff, + * size_t tx_size + * ) + * { + * size_t size_in_fifo; + * size_in_fifo = UART_fill_tx_fifo( &g_uart, pbuff, tx_size ); + * } + * @endcode + */ +size_t +UART_fill_tx_fifo +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +); + +/***************************************************************************//** + * The UART_get_rx() function reads the content of the UART's receiver hardware + * FIFO and stores it in the receiver buffer that is passed in as a function + * parameter. It copies either the full contents of the FIFO into the receiver + * buffer, or just enough data from the FIFO to fill the receiver buffer, + * depending on the size of the receiver buffer. The size of the receiver + * buffer is passed in as a function parameter. UART_get_rx() returns the number + * of bytes copied into the receiver buffer. If no data was received at the time + * the function is called, the function returns 0. + * + * Note: This function reads and accumulates the receiver status of the + * CoreUARTapb instance before reading each byte from the receiver's + * data register/FIFO. This allows the driver to maintain a sticky + * record of any receiver errors that occur as the UART receives each + * data byte; receiver errors would otherwise be lost after each read + * from the receiver's data register. A call to the UART_get_rx_status() + * function returns any receiver errors accumulated during the execution + * of the UART_get_rx() function. + * + * Note: When FIFO mode is disabled in the CoreUARTapb hardware configuration, + * the driver accumulates a sticky record of any parity errors, framing + * errors, or overflow errors. When FIFO mode is enabled, the driver + * accumulates a sticky record of overflow errors only; in this case, + * interrupts must be used to handle parity errors or framing errors. + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data + * regarding this instance of the UART. + * @param rx_buffer The rx_buffer parameter is a pointer to a buffer where + * the received data is copied. + * @param buff_size The buff_size parameter is the size of the receive + * buffer in bytes. + * @return This function returns the number of bytes copied into + * the receive buffer. + * + * @example + * @code + * #define MAX_RX_DATA_SIZE 256 + * + * uint8_t rx_data[MAX_RX_DATA_SIZE]; + * uint8_t rx_size = 0; + * + * rx_size = UART_get_rx( &g_uart, rx_data, sizeof(rx_data) ); + * @endcode + */ +size_t +UART_get_rx +( + UART_instance_t * this_uart, + uint8_t * rx_buffer, + size_t buff_size +); + +/***************************************************************************//** + * The UART_polled_tx_string() function is used to transmit a NULL ('\0') + * terminated string. Internally, it polls for the transmit ready status and + * transfers the text starting at the address pointed by p_sz_string into + * the UART's hardware transmitter FIFO. It is a blocking function and returns + * only when the complete string has been transferred to the UART's transmit + * FIFO. + * + * Note: You should not assume that the data you transmit using this function + * has been received at the other end by the time this function returns. The + * actual transmission over the serial connection is still be taking place at + * the time of the function return. + * + * @param this_uart The this_uart parameter is the pointer to a + * UART_instance_t structure, which holds all data + * regarding this instance of the UART. + * @param p_sz_string The p_sz_string parameter is a pointer to a buffer + * containing the NULL ('\0') terminated string to be + * transmitted. + * @return This function does not return a value. + * + * @example + * @code + * uint8_t testmsg1[] = {"\r\n\r\nUART_polled_tx_string() test message 1\0"}; + * UART_polled_tx_string(&g_uart,(const uint8_t *)&testmsg1); + * @endcode + */ +void +UART_polled_tx_string +( + UART_instance_t * this_uart, + const uint8_t * p_sz_string +); + +/***************************************************************************//** + * The UART_get_rx_status() function returns the receiver error status of the + * CoreUARTapb instance. It reads both the current error status of the receiver + * and the accumulated error status from preceding calls to the UART_get_rx() + * function and combines them using a bitwise OR. It returns the cumulative + * parity, framing, and overflow error status of the receiver, since the + * previous call to UART_get_rx_status() as an 8-bit encoded value. + * + * Note: The UART_get_rx() function reads and accumulates the receiver status + * of the CoreUARTapb instance before reading each byte from the receiver's data + * register/FIFO. The driver maintains a sticky record of the cumulative error + * status, which persists after the UART_get_rx() function returns. The + * UART_get_rx_status() function clears this accumulated record of receiver + * errors before returning. + * + * @param this_uart The this_uart parameter is a pointer to a + * UART_instance_t structure which holds all data regarding + * this instance of the UART. + * @return This function returns the UART receiver error status as + * an 8-bit encoded value. The return value is 0, if there + * are no receiver errors occurred. The driver provides a + * set of bit mask constants, which should be compared with + * and/or used to mask the returned value to determine the + * receiver error status. + * When the return value is compared to the following bit + * masks, a non-zero result indicates that the + * corresponding error occurred: + * UART_APB_PARITY_ERROR (bit mask = 0x01) + * UART_APB_OVERFLOW_ERROR (bit mask = 0x02) + * UART_APB_FRAMING_ERROR (bit mask = 0x04) + * When the return value is compared to the following bit + * mask, a non-zero result indicates that no error + * occurred: + * UART_APB_NO_ERROR (0x00) + * + * @example + * @code + * UART_instance_t g_uart; + * uint8_t rx_data[MAX_RX_DATA_SIZE]; + * uint8_t err_status; + * err_status = UART_get_err_status(&g_uart); + * + * if(UART_APB_NO_ERROR == err_status ) + * { + * rx_size = UART_get_rx( &g_uart, rx_data, MAX_RX_DATA_SIZE ); + * } + * @endcode + */ +uint8_t +UART_get_rx_status +( + UART_instance_t * this_uart +); + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_UART_APB_H */ diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h new file mode 100644 index 0000000..c123cc3 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h @@ -0,0 +1,133 @@ +/******************************************************************************* + * (c) Copyright 2007-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file coreuartapb_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreUARTapb register definitions + */ + +#ifndef __CORE_UART_APB_REGISTERS +#define __CORE_UART_APB_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * TxData register details + */ +#define TXDATA_REG_OFFSET 0x0u + +/* + * TxData bits. + */ +#define TXDATA_OFFSET 0x0u +#define TXDATA_MASK 0xFFu +#define TXDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * RxData register details + */ +#define RXDATA_REG_OFFSET 0x4u + +/* + * RxData bits. + */ +#define RXDATA_OFFSET 0x4u +#define RXDATA_MASK 0xFFu +#define RXDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * ControReg1 register details + */ +#define CTRL1_REG_OFFSET 0x8u + +/* + * Baud value (Lower 8-bits) + */ +#define CTRL1_BAUDVALUE_OFFSET 0x8u +#define CTRL1_BAUDVALUE_MASK 0xFFu +#define CTRL1_BAUDVALUE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * ControReg2 register details + */ +#define CTRL2_REG_OFFSET 0xCu + +/* + * Bit length + */ +#define CTRL2_BIT_LENGTH_OFFSET 0xCu +#define CTRL2_BIT_LENGTH_MASK 0x01u +#define CTRL2_BIT_LENGTH_SHIFT 0u + +/* + * Parity enable. + */ +#define CTRL2_PARITY_EN_OFFSET 0xCu +#define CTRL2_PARITY_EN_MASK 0x02u +#define CTRL2_PARITY_EN_SHIFT 1u + +/* + * Odd/even parity selection. + */ +#define CTRL2_ODD_EVEN_OFFSET 0xCu +#define CTRL2_ODD_EVEN_MASK 0x04u +#define CTRL2_ODD_EVEN_SHIFT 2u + +/* + * Baud value (Higher 5-bits) + */ +#define CTRL2_BAUDVALUE_OFFSET 0xCu +#define CTRL2_BAUDVALUE_MASK 0xF8u +#define CTRL2_BAUDVALUE_SHIFT 3u + +/*------------------------------------------------------------------------------ + * StatusReg register details + */ +#define StatusReg_REG_OFFSET 0x10u + +#define STATUS_REG_OFFSET 0x10u + +/* + * Transmit ready. + */ +#define STATUS_TXRDY_OFFSET 0x10u +#define STATUS_TXRDY_MASK 0x01u +#define STATUS_TXRDY_SHIFT 0u + +/* + * Receive full. + */ +#define STATUS_RXFULL_OFFSET 0x10u +#define STATUS_RXFULL_MASK 0x02u +#define STATUS_RXFULL_SHIFT 1u + +/* + * Parity error. + */ +#define STATUS_PARITYERR_OFFSET 0x10u +#define STATUS_PARITYERR_MASK 0x04u +#define STATUS_PARITYERR_SHIFT 2u + +/* + * Overflow. + */ +#define STATUS_OVERFLOW_OFFSET 0x10u +#define STATUS_OVERFLOW_MASK 0x08u +#define STATUS_OVERFLOW_SHIFT 3u + +/* + * Frame Error. + */ +#define STATUS_FRAMERR_OFFSET 0x10u +#define STATUS_FRAMERR_MASK 0x10u +#define STATUS_FRAMERR_SHIFT 4u + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_UART_APB_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.c b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.c new file mode 100644 index 0000000..a2f4911 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.c @@ -0,0 +1,765 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Mi-V I2C Soft IP bare-metal driver. This module is delivered as part of + * Extended Sub System(ESS) MIV_ESS. + * Please refer to miv_i2c.h file for more information. + */ + +#include "miv_i2c.h" + +#define MIV_I2C_ERROR 0xFFu + +/*------------------------------------------------------------------------------ + * MIV I2C transaction direction. + */ +#define MIV_I2C_WRITE_DIR 0u +#define MIV_I2C_READ_DIR 1u + +/* -- TRANSACTIONS TYPES -- */ +#define MIV_I2C_NO_TRANSACTION 0u +#define MIV_I2C_MASTER_WRITE_TRANSACTION 1u +#define MIV_I2C_MASTER_READ_TRANSACTION 2u +#define MIV_I2C_MASTER_SEQUENTIAL_READ_TRANSACTION 3u + +/*------------------------------------------------------------------------------ + * MIV I2C HW states + */ +#define MIV_I2C_IDLE 0x00u +#define MIV_I2C_TX_STA_CB 0x01u +#define MIV_I2C_TX_DATA 0x02u +#define MIV_I2C_RX_DATA 0x03u + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_disable_irq() disables the Mi-V I2C interrupt. + */ +void +MIV_I2C_disable_irq +( + void +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_enable_irq() enables the Mi-V I2C interrupt. + */ +void +MIV_I2C_enable_irq +( + void +); + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_init +( + miv_i2c_instance_t *this_i2c, + addr_t base_addr +) +{ + /* Assign the base address + * Clock Prescale value set + * MIV_I2C interrupt enabled + * I2C core enable + */ + psr_t processor_state; + + /* Disabling the interrupts */ + processor_state = HAL_disable_interrupts(); + + /* + * Initialize all items of the this_miv_i2c data structure to zero. This + * initializes all state variables to their init value. It relies on + * the fact that NO_TRANSACTION, MIV_I2C_SUCCESS and I2C_RELEASE_BUS all + * have an actual value of zero. + */ + memset(this_i2c, 0, sizeof(miv_i2c_instance_t)); + + this_i2c->base_addr = base_addr; + + HAL_restore_interrupts(processor_state); +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_config +( + miv_i2c_instance_t *this_i2c, + uint16_t clk_prescale +) +{ + /* Assign the base address + * Clock Prescale value set + * MIV_I2C interrupt enabled + * I2C core enable + */ + psr_t processor_state; + + /* Disabling the interrupts */ + processor_state = HAL_disable_interrupts(); + + /* Before writing to prescale reg, the core enable must be zero */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CTRL_CORE_EN, 0x00u); + + /* Set the prescale value */ + HAL_set_16bit_reg(this_i2c->base_addr, PRESCALE, clk_prescale); + + /* Enable the MIV I2C interrupts */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CTRL_IRQ_EN, 0x01u); + + /* Enable the MIV I2C core */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CTRL_CORE_EN, 0x01u); + + this_i2c->master_state = MIV_I2C_IDLE; + + HAL_restore_interrupts(processor_state); +} + +/* + * Please refer to miv_i2c.h for more info + */ +uint8_t +MIV_I2C_start +( + miv_i2c_instance_t *this_i2c +) +{ + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + /* Generate I2C start condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + HAL_restore_interrupts(processor_state); + + return 0u; +} + +/* + * Please refer to miv_i2c.h for more info + */ +uint8_t +MIV_I2C_stop +( + miv_i2c_instance_t *this_i2c +) +{ + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + /* Generate I2C stop condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + HAL_restore_interrupts(processor_state); + + return 0u; +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_write +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t bus_options, + uint8_t ack_polling_options +) +{ + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + /* I2C write flow + * + * Check I2C status for ongoing transaction + * Populate the structure with input data + * Generate start condition + * Set the write_direction and target address. + */ + + /* Update the transaction only when there is no ongoing I2C transaction */ + if (this_i2c->transaction == MIV_I2C_NO_TRANSACTION) + { + this_i2c->transaction = MIV_I2C_MASTER_WRITE_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MIV_I2C_MASTER_WRITE_TRANSACTION ; + + /* Populate the i2c instance structure */ + + /* Set the target addr */ + this_i2c->target_addr = i2c_target_addr; + this_i2c->dir = MIV_I2C_WRITE_DIR; + + /* Set up the tx buffer */ + this_i2c->master_tx_buffer = write_buffer; + this_i2c->master_tx_size = write_size; + this_i2c->master_tx_idx = 0u; + + /* Set the I2C status in progress and setup the options */ + this_i2c->bus_options = bus_options; + this_i2c->ack_polling_options = ack_polling_options; + this_i2c->master_status = MIV_I2C_IN_PROGRESS; + + + /* Generate I2C start condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* write target address and write bit */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, MIV_I2C_WRITE_DIR); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, i2c_target_addr); + + /* Set WR bit to transmit start condition and control byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + /* Set current master hw state -> transmitted start condition and + * control byte + */ + this_i2c->master_state = MIV_I2C_TX_STA_CB; + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( MIV_I2C_HOLD_BUS == this_i2c->bus_status ) + { + /* Must toggle IACK bit to clear the MIV_I2C IRQ*/ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00); + } + + MIV_I2C_enable_irq(); + + HAL_restore_interrupts(processor_state); + +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_read +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +) +{ + psr_t processor_state; + uint8_t status = MIV_I2C_SUCCESS; + + processor_state = HAL_disable_interrupts(); + + /* MIV I2C Read operation flow + * + * Check for ongoing transaction + * Populate the i2c instance structure + * Generate the start condition + * Set the READ_direction bit and target addr + */ + + uint8_t read_stat = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_TIP); + + /* Update the transaction only when there is no ongoing I2C transaction */ + if (this_i2c->transaction == MIV_I2C_NO_TRANSACTION) + { + this_i2c->transaction = MIV_I2C_MASTER_READ_TRANSACTION; + } + + this_i2c->pending_transaction = MIV_I2C_MASTER_READ_TRANSACTION; + + /* Populate the MIV I2C instance structure */ + + this_i2c->target_addr = i2c_target_addr; + this_i2c->dir = MIV_I2C_READ_DIR; + + /* Populate read buffer */ + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set the BUS and ACK polling options */ + this_i2c->bus_options = bus_options; + this_i2c->ack_polling_options = ack_polling_options; + + /* Generate the start condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* Set the DIR bit and target addr */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, MIV_I2C_READ_DIR); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, i2c_target_addr); + + /* Set the WR bit to transmit the start condition and command byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + /* Set the i2c master state and status transmitting STA and Command Byte */ + this_i2c->master_state = MIV_I2C_TX_STA_CB; + this_i2c->master_status = MIV_I2C_IN_PROGRESS; + + /* Toggle the IACK bit if required */ + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( MIV_I2C_HOLD_BUS == this_i2c->bus_status ) + { + /* Must toggle IACK bit to clear the MIV_I2C IRQ*/ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00); + } + /* Enable the I2C interrupt */ + MIV_I2C_enable_irq(); + + HAL_restore_interrupts(processor_state); +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_write_read +( + miv_i2c_instance_t *this_i2c, + uint8_t target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +) +{ + uint8_t status = MIV_I2C_SUCCESS; + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + uint8_t read_stat = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_TIP); + + /* I2C write read operation flow + * + * Used to read the data from set address offset + * + * Configure the i2c instance structure + * generate the start and configure the dir and target addr + * set wr bit to transmit the start and command byte + * + */ + + /* Update the transaction only when there is no ongoing I2C transaction */ + if (this_i2c->transaction == MIV_I2C_NO_TRANSACTION) + { + this_i2c->transaction = MIV_I2C_MASTER_READ_TRANSACTION; + } + + this_i2c->pending_transaction = MIV_I2C_MASTER_READ_TRANSACTION; + + /* Populate the I2C instance */ + + this_i2c->target_addr = target_addr; + + /* setup the i2c direction */ + this_i2c->dir = MIV_I2C_WRITE_DIR; + + /* set up transmit buffer */ + this_i2c->master_tx_buffer = write_buffer; + this_i2c->master_tx_size = write_size; + this_i2c->master_tx_idx = 0u; + + /* set up receive buffer */ + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set the bus and ack polling options */ + this_i2c->bus_options = bus_options; + this_i2c->ack_polling_options = ack_polling_options; + + /* Generate the start command */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* Set the DIR and target addr */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + /* Set the WR bit to transmit the start command and command byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + /* Set the i2c master state and status transmitting STA and Command Byte */ + this_i2c->master_state = MIV_I2C_TX_STA_CB; + this_i2c->master_status = MIV_I2C_IN_PROGRESS; + + /* + * Clear interrupt if required + */ + if ( MIV_I2C_HOLD_BUS == this_i2c->bus_status ) + { + /* Must toggle IACK bit to clear the MIV_I2C IRQ*/ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00u); + } + + /* Enable the I2C interrupt */ + MIV_I2C_enable_irq(); + + HAL_restore_interrupts(processor_state); +} + +/* MIV_I2C_isr() + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_isr +( + miv_i2c_instance_t *this_i2c +) +{ + uint8_t i2c_state; + uint8_t i2c_ack_status; + uint8_t i2c_al_status; + uint8_t hold_bus; + + /* Read the I2C master state */ + i2c_state = this_i2c->master_state; + + /* Read the ack and al status */ + i2c_ack_status = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_RXACK); + i2c_al_status = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_AL); + + switch (i2c_state) + { + /* I2C ISR State Machine + * + * Cases: + * - Transmit start condition and control byte + * - Received ACK and bus arbitration was not lost (Read or Write) + * - Received NACK + * - Bus arbitration lost + * + * - Transmit data + * - Received ACK and bus arbitration was not lost (Read or Write) + * - Received NACK + * - Bus arbitration lost + * + * - Receive data + * - Received ACK and bus arbitration was not lost (Read or Write) + * - Bus arbitration lost + */ + + case MIV_I2C_TX_STA_CB: + + /* Received ACK from target and I2C bus arbitration is not lost */ + if (i2c_ack_status == 0u && i2c_al_status == 0u) + { + /* If I2C master write operation */ + if (this_i2c->dir == MIV_I2C_WRITE_DIR) + { + /* write first byte of data and set the WR bit to transfer the data */ + HAL_set_8bit_reg(this_i2c->base_addr, TRANSMIT, + this_i2c->master_tx_buffer[this_i2c->master_tx_idx]); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + /* Increment the index */ + this_i2c->master_tx_idx++; + + /* Set the master state to TX data */ + this_i2c->master_state = MIV_I2C_TX_DATA; + } + /* Master read operation */ + else + { + if (this_i2c->master_rx_size == 1u) + { + /* Send the ACK if the rx size is 1, transmit NACK to slave + * after receiving 1 byte to indicate slave to stop sending + * the data + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_ACK, 0x01u); + } + + /* Send the RD command to slave */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_RD, 0x01u); + + /* Increment the index */ + this_i2c->master_rx_idx++; + + /* Change state to receive data */ + this_i2c->master_state = MIV_I2C_RX_DATA; + } + } + else if (i2c_ack_status == 1u) + { + if (this_i2c->ack_polling_options == MIV_I2C_ACK_POLLING_ENABLE) + { + /* Target responded with NACK and ACK polling option is enabled + * + * Re-send the start condition and control byte + * + * TO-DO: This might become infinite loop check for timeout + * options. + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + this_i2c->master_tx_idx = 0u; + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + else + { + /* Target responded with NACK and ACK polling is disabled + * Abort the transaction and move to IDLE state + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + + this_i2c->master_status = MIV_I2C_FAILED; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + + this_i2c->master_state = MIV_I2C_IDLE; + } + } + + else if (i2c_al_status == 1u) + { + /* Arbitration was lost on the BUS during the transmission of + * previous start condition and control byte. + * Re-send the STA and CB + */ + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + break; + + /* Transmit master data */ + case MIV_I2C_TX_DATA: + + /* ACK received and arbitration was not lost */ + if (i2c_ack_status == 0u && i2c_al_status == 0u) + { + uint8_t tx_buff[this_i2c->master_tx_size]; + if (this_i2c->master_tx_idx < this_i2c->master_tx_size) + { + HAL_set_8bit_reg(this_i2c->base_addr, TRANSMIT, + this_i2c->master_tx_buffer[this_i2c->master_tx_idx]); + + tx_buff[this_i2c->master_tx_idx] = this_i2c->master_tx_buffer[this_i2c->master_tx_idx]; + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + /* Increment the index */ + this_i2c->master_tx_idx++; + + /* Set the master state to TX data */ + this_i2c->master_state = MIV_I2C_TX_DATA; + } + + /* All the bytes are transmitted */ + else if (this_i2c->master_tx_idx == this_i2c->master_tx_size) + { + /* If this is a MASTER_READ_TRANSACTION, hold bus and start a + new transfer in read mode now that the read address has been + written to the slave */ + if(this_i2c->transaction == MIV_I2C_MASTER_READ_TRANSACTION) + + { + //Switch direction to READ + this_i2c->dir = MIV_I2C_READ_DIR; + + // Set the STA bit + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* Set the DIR bit and target addr */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, MIV_I2C_READ_DIR); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, this_i2c->target_addr); + + /* Set the WR bit to transmit the start condition and command byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + // Reset the buffer index + this_i2c->master_tx_idx = 0u; + this_i2c->master_rx_idx = 0u; + + /* Set the master state to RX data */ + this_i2c->master_state = MIV_I2C_RX_DATA; + } + + else + { + /* If releasing the bus, transmit the stop condition at the end + * of the transfer. + */ + hold_bus = this_i2c->bus_status & MIV_I2C_HOLD_BUS; + + if (hold_bus == 0) + { + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + } + else + { + MIV_I2C_disable_irq(); + } + this_i2c->master_status = MIV_I2C_SUCCESS; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + this_i2c->master_state = MIV_I2C_IDLE; + } + } + } + + else if (i2c_ack_status == 1u) + { + /* Received NACK from target device + * + * Release the bus and end the transfer + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + + this_i2c->master_status = MIV_I2C_FAILED; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + + this_i2c->master_state = MIV_I2C_IDLE; + } + + else if (i2c_al_status == 1u) + { + /* Arbitration was lost on the BUS during the transmission of + * previous start condition and control byte. + * Re-send the STA and CB + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, + this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + break; + + /* Receive target device data */ + case MIV_I2C_RX_DATA: + + if (i2c_al_status == 0u) + { + if (this_i2c->master_rx_idx < this_i2c->master_rx_size) + { + this_i2c->master_rx_buffer[this_i2c->master_rx_idx - 1u] = + HAL_get_8bit_reg(this_i2c->base_addr, RECEIVE); + + /* If next byte is last one + * Send NACK to target device to stop sending data + */ + if (this_i2c->master_rx_idx == (this_i2c->master_rx_size - 1u)) + { + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_ACK, 0x01u); + } + + else + { + /* Send ACK to receive next bytes */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_ACK, 0x00u); + } + + /* Set RD bit to receive next byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_RD, 0x01u); + + this_i2c->master_rx_idx++; + } + + /* Received all bytes */ + else //if (this_i2c->master_rx_idx == this_i2c->master_rx_size) + { + this_i2c->master_rx_buffer[this_i2c->master_rx_idx - 1] = + HAL_get_8bit_reg(this_i2c->base_addr, RECEIVE); + + hold_bus = this_i2c->bus_status & MIV_I2C_HOLD_BUS; + + if (hold_bus == 0) + { + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + } + else + { + MIV_I2C_disable_irq(); + } + this_i2c->master_status = MIV_I2C_SUCCESS; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + + this_i2c->master_state = MIV_I2C_IDLE; + } + } + + else if (i2c_al_status == 1u) + { + /* Arbitration was lost on the BUS during the transmission of + * previous start condition and control byte. + * Re-send the STA and CB + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, + this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + break; + } + + /* Toggle the IACK bit to clear interrupt */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00u); +} + +/* + * Please refer to miv_i2c.h for more info + */ +uint8_t +MIV_I2C_get_status +( + miv_i2c_instance_t *this_i2c +) +{ + uint8_t i2c_status; + + i2c_status = HAL_get_8bit_reg(this_i2c->base_addr, STATUS); + + return i2c_status; +} diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.h new file mode 100644 index 0000000..c5e704d --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.h @@ -0,0 +1,854 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * I2C module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(MIV_ESS). + */ + +/*=========================================================================*//** + @mainpage Mi-V I2C Bare Metal Driver + + ============================================================================== + Introduction + ============================================================================== + The Mi-V I2C driver provides a set of functions for controlling the Mi-V I2C + Soft-IP module. This module is delivered as a part of the Mi-V Extended + Sub System(MIV_ESS). The driver provides a minimal APB-driven I2C interface, + supporting initiator read and write access to peripheral I2C devices. + + The major features provided by the Mi-V I2C driver are: + - Support for configuring the I2C instance. + - I2C master operations. + - I2C ISR. + + This driver can be used as part of a bare metal system where no operating + system is available. The driver can be adapted for use as part of an + operating system, but the implementation of the adaptation layer between the + driver and the operating system's driver model is outside the scope of this + driver. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + The application software should initialize and configure the Mi-V I2C through + the call to the MIV_I2C_init() and MIV_I2C_config() function for Mi-V I2C + instance in the design. The configuration parameter include base address and + Prescaler value. + + ------------------------------ + Interrupt Control + ------------------------------ + The Mi-V I2C driver has to enable and disable the generation of interrupts by + Mi-V I2C at various times while operating. This enabling and disabling of the + interrupts must be done through the Mi-V RV32 HAL provided interrupt handlers. + For that reason, the method controlling the Mi-V I2C interrupts is system + specific and it is necessary to customize the MIV_I2C_enable_irq() and + MIV_I2C_disable_irq() functions as per requirement. + + The implementation of MIV_I2C_enable_irq() should permit the interrupts + generated by the Mi-V I2C to the processor through a call to respective miv-hal + interrupt handler. The implementation of MIV_I2C_disable_irq() should prevent + the interrupts generated by a Mi-V I2C from interrupting the processor. + Please refer to the miv_i2c_interrupt.c for more information about the + implementation. + + No MIV_I2C hardware configuration parameters are used by the driver, apart + from the MIV_I2C base address. Hence, no additional configuration files + are required to use the driver. + + ============================================================================== + Theory of Operation + ============================================================================== + The Mi-V I2C software driver is designed to allow the control of multiple + instances of Mi-V I2C. Each instance of Mi-V I2C in the hardware design is + associated with a single instance of the miv_i2c_instance_t structure in the + software. User must allocate memory for one unique miv_i2c_instance_t + structure for each instance of Mi-V I2C in the hardware. + A pointer to the structure is passed to the subsequent driver functions in + order to identify the MIV_I2C hardware instance and to perform requested + operation. + + Note: Do not attempt to directly manipulate the contents of the + miv_i2c_instance_t structure. These structures are only intended to be modified + by the driver functions. + + The Mi-V I2C driver functions are grouped into following categories: + - Initialization and configuration + - I2C master operation functions to handle write, read and write_read + operations. + - Interrupt control + + -------------------------------- + Initialization and configuration + -------------------------------- + The Mi-V I2C device is first initialized by the call to MIV_I2C_init(). This + function initializes the instance of Mi-V I2C with the base address. + MIV_I2C_init() function must be called before any other Mi-V I2C driver API. + + The configuration of the Mi-V I2C instance is done via call to the + MIV_I2C_config() function. This function will set the prescale value which is + used to set the frequency of the I2C clock(SCLK) generated by I2C module. + + --------------------------------- + Transaction types + --------------------------------- + The driver is designed to handle three types of transactions: + - Write transactions + - Read transactions + - Write-Read transaction + + ### Write Transaction + The write transaction begins with master sending a start condition, followed + by device address byte with the R/W bit set to logic '0', and then by the + word address bytes. The slave acknowledges the receipt of its address with + acknowledge bit. The master sends one byte at a time to the slave, which must + acknowledge the receipt of each byte for the next byte to be sent. The master + sends STOP condition to complete the transaction. The slave can abort the + transaction by replying with negative acknowledge. + + The application programmer can choose not to send the STOP bit at the end of + the transaction causing repetitive start conditions. + + ### Read Transaction + The master I2C device initiates a read transaction by sending a START bit + as soon as the bus becomes free. The start condition is followed by the + control byte which contains 7-bit slave address followed by R/W bit set to + logic '1'. The slave sends data one byte at a time to the master, which must + acknowledge receipt of each byte for the next byte to be sent. The master + sends a non-acknowledge bit following the last byte it wishes to read + followed by a STOP bit. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ### Write-Read Transaction + The write read transaction is a combination of a write transaction + immediately followed by a read transaction. There is no STOP condition sent + between the write and read phase of write-read transaction. A repeated START + condition is sent between the write and read phases. + + Whilst the write handler is being executed, the slave holds the clock line + low to stretch the clock until the response is ready. + + The write-read transaction is typically used to send an memory/register + address in the write transaction specifying the start address of the data to + be transferred during the read phase. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ------------------------------------- + Interrupt Control + ------------------------------------- + The Mi-V I2C driver is interrupt driven and it uses the MIV_I2C_irq() function + to drive the ISR state machine which is at the heart of the driver. The + application is responsible for providing the link between the interrupt + generating hardware and the Mi-V I2C interrupt handler and must ensure that + the MIV_I2C_isr() function is called with the correct miv_i2c_instance_t + structure pointer for the Mi-V I2C instance initiating the interrupt. + +*//*=========================================================================*/ +#ifndef MIV_I2C_H_ +#define MIV_I2C_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "miv_i2c_regs.h" +#include + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#else +#include "hal.h" +#endif + +/*-------------------------------------------------------------------------*//** + The miv_i2c_status_t type is used to report the status of I2C transactions. + */ +typedef enum miv_i2c_status +{ + MIV_I2C_SUCCESS = 0u, + MIV_I2C_IN_PROGRESS, + MIV_I2C_FAILED, + MIV_I2C_TIMED_OUT +}miv_i2c_status_t; + +/*-------------------------------------------------------------------------*//** + This structure is used to identify the MIV_I2C hardware instances in a system. + Your application software should declare one instance of this structure for + each instance of the MIV_I2C in your system. The function MIV_I2C_init() + Initializes this structure. A pointer to an initialised instance of the structure + should be passed as the first parameter to the MIV_I2C driver functions, to + identify which MIV_I2C hardware instance should perform the requested operation. + + The contents of this data structure should not be modified or used outside of + the MIV_I2C driver. Software using the MIV_I2C driver should only need to + create one single instance of this data structure for each MIV_I2C hardware + instance in the system, then pass a pointer to these data structures with each + call to the MIV_I2C driver in order to identify the MIV_I2C hardware instance + it wishes to use. +*/ + +typedef struct miv_i2c_instance +{ + addr_t base_addr; + + /* Transmit related info:*/ + uint_fast8_t target_addr; + + /* Current transaction type */ + uint8_t transaction; + + uint8_t bus_options; + + uint8_t ack_polling_options; + + /* Current State of the I2C master */ + uint8_t master_state; + + /* Master TX INFO: */ + const uint8_t * master_tx_buffer; + uint_fast16_t master_tx_size; + uint_fast16_t master_tx_idx; + uint_fast8_t dir; + + /* Master RX INFO: */ + uint8_t * master_rx_buffer; + uint_fast16_t master_rx_size; + uint_fast16_t master_rx_idx; + + /* Master Status */ + volatile miv_i2c_status_t master_status; + uint32_t master_timeout_ms; + + /* user specific data */ + void *p_user_data ; + + /* I2C bus status */ + uint8_t bus_status; + + /* Is transaction pending flag */ + uint8_t is_transaction_pending; + + /* I2C Pending transaction */ + uint8_t pending_transaction; + +}miv_i2c_instance_t; + + +/*-------------------------------------------------------------------------*//** + MIV_I2C_RELEASE_BUS + ===================== + The MIV_I2C_RELEASE_BUS constant is used to specify the bus_options parameter + for MIV_I2C_read(), MIV_I2C_write() and MIV_I2C_write_read() to indicate + that a STOP bit must be generated at the end of the I2C transaction to release + the bus. + */ +#define MIV_I2C_RELEASE_BUS 0x00u + + +/*-------------------------------------------------------------------------*//** + MIV_I2C_HOLD_BUS + ===================== + The MIV_I2C_HOLD_BUS constant is used to specify the bus_optionsparameter + for MIV_I2C_read(), MIV_I2C_write() and MIV_I2C_write_read() to indicate + that a STOP bit must not be generated at the end of the I2C transaction in + order to retain the bus ownership. This causes the next transaction to + begin with a repeated START bit and no STOP bit between the transactions. + */ +#define MIV_I2C_HOLD_BUS 0x01u + +/*-------------------------------------------------------------------------*//** + MIV_I2C_ACK_POLLING_DISABLE + ===================== + The MIV_I2C_ACK_POLLING_DISABLE constant is used to specify the + ack_polling_options parameter to functions MIV_I2C_write(), + MIV_I2C_write_read() and MIV_I2C_read(). Acknowledgment polling is used when + working with I2C memory devices such as EEPROM, which feature an internal + write cycle. + + With acknowledgment polling disabled, if the target slave device responds to the + control byte with a NACK, the MIV_I2C will abort the transfer. + */ +#define MIV_I2C_ACK_POLLING_DISABLE 0x00u + +/*-------------------------------------------------------------------------*//** + MIV_I2C_ACK_POLLING_ENABLE + ===================== + The MIV_I2C_ACK_POLLING_ENABLE constant is used to specify the + ack_polling_options parameter to functions MIV_I2C_write(), + MIV_I2C_write_read() and MIV_I2C_read(). acknowledgment polling is used when + working with I2C memory devices such as EEPROM, which feature an internal + write cycle. + + With acknowledgment polling enabled, if the slave device responds to the + control byte with a NACK, the MIV_I2C will repeatedly transmit another control + byte until the slave device accepts the connection with an ACK, or the timeout + specified in the MIV_I2C_wait_complete() function is reached. Acknowledgment + polling allows for the next read/write operation to be started as soon as the + EEPROM has completed its internal write cycle. + */ +#define MIV_I2C_ACK_POLLING_ENABLE 0x01u + +/*--------------------------------Public APIs---------------------------------*/ + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_init() function is used to initialize the Mi-V I2C module instance + with the base address. + + Note: This function should be called before calling any other Mi-V I2C + functions. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + @param base_addr + Base address of the Mi-V I2C module instance in the MIV_ESS + soft IP. + + @return + This function does not return any value. + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + } + @endcode + */ +void +MIV_I2C_init +( + miv_i2c_instance_t *this_i2c, + addr_t base_addr +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_config() function is used to configure the Mi-V I2C module. This + function will set the prescale value which is used to set the frequency of + the I2C clock(SCLK) generated by I2C module and also enables the I2C core and + interrupts. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param clk_prescale + The value used to set the frequency of Mi-V I2C serial clock + (SCLK) generated by the Mi-V I2C module instance. The + prescaler value required to set particular frequency of + Mi-V I2C can be calculated using following formula: + + prescaler = (System Clock Frequency) / (5 * (Desired I2C Clock Frequency)) - 1 + + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + } + @endcode + */ +void +MIV_I2C_config +( + miv_i2c_instance_t *this_i2c, + uint16_t clk_prescale +); + + +uint8_t +MIV_I2C_start +( + miv_i2c_instance_t *this_i2c +); + + +uint8_t +MIV_I2C_stop +( + miv_i2c_instance_t *this_i2c +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_write() is used to set up and start the Mi-V I2C master write + transaction. This function is used for all Mi-V master write operation. + + For more information about the operation, please refer to the 'theory of + operations' section at the start of this document. + + This function returns immediately after initiating the transaction. The content + of the write buffer passed as parameter should not be modified until the write + transaction completes. It also means that the memory allocated for the write + buffer should not be freed or should not go out of scope before the write + completes. + You can check for the write transaction completion by polling the master_status + from miv_i2c_instance_t structure as shown in the sample code. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param i2c_target_addr + This parameter specifies the serial address for the slave + device. + + @param write_buffer + This parameter is a pointer to the buffer holding data to be + written to target I2C device. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param write_size + Number of bytes held in the write_buffer to be written to the + I2C device. + @param bus_options: + The bus_options parameter is used to indicate if the I2C bus + should be released on completion of the write transaction. + Using the MIV_I2C_RELEASE_BUS constant for the bus_options + parameter causes a STOP bit to be generated at the end of the + write transaction causing the bus to be released for other I2C + devices to use. Using the MIV_I2C_HOLD_BUS constant as + bus_options parameter prevents a STOP bit from being generated + at the end of the write transaction, preventing other I2C + devices from initiating a bus transaction. + + @param ack_polling_options: + The ack_polling_options parameter is used to indicate how the + MIV_I2C will respond if the slave device transmits a NACK to + the I2C control byte. Using the MIV_I2C_ACK_POLLING_DISABLE + constant for the ack_polling_options parameter causes the + MIV_I2C to abort the transfer if the slave device responds to + the I2C control byte with a NACK. Using the + MIV_I2C_ACK_POLLING_ENABLE constant for the ack_polling_options + parameter causes the MIV_I2C to repeatedly transmit a control + byte to the slave device until the slave device responds with + an ACK. + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + + MIV_I2C_write (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_tx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + } + @endcode + */ +void +MIV_I2C_write +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t bus_options, + uint8_t ack_polling_options +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_read() is used to set up and start the Mi-V I2C master read + transaction. This function is used for all MIV_I2C master read operation. + + For more information about the operation, please refer to the 'theory of + operations' section at the start of this document. + + This function returns immediately after initiating the transaction. The content + of the read buffer passed as parameter should not be modified until the write + transaction completes. It also means that the memory allocated for the read + buffer should not be freed or should not go out of scope before the read + completes. + You can check for the write transaction completion by polling the master_status + from miv_i2c_instance_t structure as shown in the sample code. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param i2c_target_addr + This parameter specifies the serial address for the slave + device. + + @param read_buffer + This parameter is a pointer to the buffer where the data + received from the I2C slave device is stored. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param read_size + Number of bytes held in the write_buffer to be read from the + I2C device. + + @param bus_options: + The bus_options parameter is used to indicate if the I2C bus + should be released on completion of the write transaction. + Using the MIV_I2C_RELEASE_BUS constant for the bus_options + parameter causes a STOP bit to be generated at the end of the + write transaction causing the bus to be released for other I2C + devices to use. Using the MIV_I2C_HOLD_BUS constant as + bus_options parameter prevents a STOP bit from being generated + at the end of the write transaction, preventing other I2C + devices from initiating a bus transaction. + + @param ack_polling_options: + The ack_polling_options parameter is used to indicate how the + MIV_I2C will respond if the slave device transmits a NACK to + the I2C control byte. Using the MIV_I2C_ACK_POLLING_DISABLE + constant for the ack_polling_options parameter causes the + MIV_I2C to abort the transfer if the slave device responds to + the I2C control byte with a NACK. Using the + MIV_I2C_ACK_POLLING_ENABLE constant for the ack_polling_options + parameter causes the MIV_I2C to repeatedly transmit a control + byte to the slave device until the slave device responds with + an ACK. + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + + MIV_I2C_write (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_tx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + + // reset miv_i2c_status variable + miv_i2c_status = 0u; + + MIV_I2C_read (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_rx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + } + @endcode + */ +void +MIV_I2C_read +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_write_read() is used to set up and start the Mi-V I2C master + write_read transaction. This function is used for all MIV_I2C master write_read + operation. + + This function is used in cases where data is being requested from a specific + address offset inside the target I2C slave device. + In this type of I2C operation, the I2C master starts by initiating a write + operation. During this write operation, the specific address offset is written + to the I2C slave. Once the address offset has been written to the I2C slave, + the I2C master transmits a repeated start, and initiates a read operation to + read data from the set address. + + For more information about the operation, please refer to the 'theory of + operations' section at the start of this document. + + This function returns immediately after initiating the transaction. The content + of the write and read buffer passed as parameter should not be modified until + the write transaction completes. It also means that the memory allocated for + the write and read buffer should not be freed or should not go out of scope + before the operation completes. + You can check for the write_read transaction completion by polling the + master_status from miv_i2c_instance_t structure. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param i2c_target_addr + This parameter specifies the serial address for the slave + device. + + @param write_buffer + This parameter is a pointer to the buffer holding data to be + written to target I2C device. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param write_size + Number of bytes held in the write_buffer to be written to the + I2C device. + + @param read_buffer + This parameter is a pointer to the buffer where the data + received from the I2C slave device is stored. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param read_size + Number of bytes held in the write_buffer to be read from the + I2C device. + + @param bus_options: + The bus_options parameter is used to indicate if the I2C bus + should be released on completion of the write transaction. + Using the MIV_I2C_RELEASE_BUS constant for the bus_options + parameter causes a STOP bit to be generated at the end of the + write transaction causing the bus to be released for other I2C + devices to use. Using the MIV_I2C_HOLD_BUS constant as + bus_options parameter prevents a STOP bit from being generated + at the end of the write transaction, preventing other I2C + devices from initiating a bus transaction. + + @param ack_polling_options: + The ack_polling_options parameter is used to indicate how the + MIV_I2C will respond if the slave device transmits a NACK to + the I2C control byte. Using the MIV_I2C_ACK_POLLING_DISABLE + constant for the ack_polling_options parameter causes the + MIV_I2C to abort the transfer if the slave device responds to + the I2C control byte with a NACK. Using the + MIV_I2C_ACK_POLLING_ENABLE constant for the ack_polling_options + parameter causes the MIV_I2C to repeatedly transmit a control + byte to the slave device until the slave device responds with + an ACK or the timeout specified in the MIV_I2C_wait_complete() + function is reached. + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + + MIV_I2C_write (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_tx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + + // reset miv_i2c_status variable + miv_i2c_status = 0u; + + uint8_t addr_offset[2] = {0x00, 0x00}; + MIV_I2C_write_read(&miv_i2c, + DUALEE_SLAVEADDRESS_1, + addr_offset, + sizeof(addr_offset), + i2c_rx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + } + @endcode + */ +void +MIV_I2C_write_read +( + miv_i2c_instance_t *this_i2c, + uint8_t target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_isr() function contains the MIV_I2C's interrupt service routine. + This ISR is at the heart of the MIV_I2C driver, and is used to control the + interrupt-driven, byte-by-byte I2C read and write operations. + + The ISR operates as a Finite State Machine (FSM), which uses the previously + completed I2C operation and its result to determine which I2C operation will + be performed next. + + The ISR operation is divided into following categories: + - MIV_I2C_IDLE + - MIV_I2C_TX_STA_CB + - MIV_I2C_TX_DATA + - MIV_I2C_RX_DATA + + ##### MIV_I2C_IDLE + The MIV_I2C_IDLE is entered on reset, or when an I2C master operation has been + completed or aborted. + Upon entering, the FSM will remain in this state until a write, read, or + write-read operation is requested + + ##### MIV_I2C_STA_CB + The MIV_I2C_TX_STA_CB operation is performed when the start condition and + control byte(i2c target address(7-bit) and direction of transaction(1-bit)) is + transmitted by the Mi-V I2C master device to the slave. + If the target I2C slave device responded to the previous START Condition + + Control Byte with an ACK, the MIV_I2C will start the requested I2C + read/write operation. + If the target slave I2C slave device responds with NACK, the MIV_I2C will + remain in this state or return to the idle state based on ack_polling + configuration. + + ##### MIV_I2C_TX_DATA + The MIV_I2C_TX_DATA state is entered after the target slave device accepts a + write request with an ACK. + This state is used to handle the byte-by-byte MIV_I2C write operations. + The FSM will remain in this state until either all data bytes have been + written to the target slave device, or an error occurs during the write + operation. + + ##### MIV_I2C_RX_DATA + The MIV_I2C_RX_DATA state is entered after the target slave device accepts a + read request with an ACK. + This state is used to handle the byte-by-byte MIV_I2C read operations. + The FSM will remain in this state until either all data bytes have been + received from the target slave device, or an error occurs. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + */ +void +MIV_I2C_isr +( + miv_i2c_instance_t *this_i2c +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_get_status() returns the 8-bit Mi-V I2C status register value. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + @return + This function returns 8-bit Mi-V I2C status register value. + */ +uint8_t +MIV_I2C_get_status +( + miv_i2c_instance_t *this_i2c +); + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_I2C_H_ */ diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_interrupt.c b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_interrupt.c new file mode 100644 index 0000000..871eafe --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_interrupt.c @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains functions used for MIV_I2C driver interrupt control. + * User should enable and disable the interrupts according to their design. + * Please refer to miv_i2c.h file for more information. + */ + +#include "miv_rv32_hal/miv_rv32_hal.h" + +void MIV_I2C_disable_irq(void) +{ +/* Disable I2C interrupt */ + MRV_disable_local_irq(MRV32_MSYS_EIE2_IRQn); +} + +void MIV_I2C_enable_irq(void) +{ +/* Enable I2C interrupt */ + MRV_enable_local_irq(MRV32_MSYS_EIE2_IRQn); +} + + diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_regs.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_regs.h new file mode 100644 index 0000000..9a4bfbf --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_regs.h @@ -0,0 +1,158 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP I2C module driver. This module is delivered as a part of Mi-V extended + * Sub-System(MIV_ESS). + */ + +#ifndef MIV_I2C_APB_REGISTERS +#define MIV_I2C_APB_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * Prescale register details + */ +#define PRESCALE_REG_OFFSET 0x00u + +/* Prescale register bits */ +#define PRESCALE_OFFSET 0x00u +#define PRESCALE_MASK 0xFFFFu +#define PRESCALE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Control register details + */ +#define CONTROL_REG_OFFSET 0x04u + +/* Control register bits */ +#define CONTROL_OFFSET 0x04u +#define CONTROL_MASK 0xC0u +#define CONTROL_SHIFT 0u + +/* Control register Core Enable Bit */ +#define CTRL_CORE_EN_OFFSET 0x04u +#define CTRL_CORE_EN_MASK 0x80u +#define CTRL_CORE_EN_SHIFT 7u + +/* Control register IRQ Enable bit */ +#define CTRL_IRQ_EN_OFFSET 0x04u +#define CTRL_IRQ_EN_MASK 0x40u +#define CTRL_IRQ_EN_SHIFT 6u + +/*------------------------------------------------------------------------------ + * Transmit register details + */ +#define TRANSMIT_REG_OFFSET 0x08u + +/* Transmit register bits */ +#define TRANSMIT_OFFSET 0x08u +#define TRANSMIT_MASK 0xFFu +#define TRANSMIT_SHIFT 0u + +/* Transmit register DIR bit */ +#define TX_DIR_OFFSET 0x08u +#define TX_DIR_MASK 0x01u +#define TX_DIR_SHIFT 0u + +/* Transmit register TARGET_ADDR bit */ +#define TX_TARGET_ADDR_OFFSET 0x08u +#define TX_TARGET_ADDR_MASK 0xFEu +#define TX_TARGET_ADDR_SHIFT 1u + +/*------------------------------------------------------------------------------ + * Receive register details + */ +#define RECEIVE_REG_OFFSET 0x0Cu + +/* Receive register bits */ +#define RECEIVE_OFFSET 0x0Cu +#define RECEIVE_MASK 0xFFu +#define RECEIVE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Command register details + */ +#define COMMAND_REG_OFFSET 0x10u + +/* Command register bits */ +#define COMMAND_OFFSET 0x10u +#define COMMAND_MASK 0xF9u +#define COMMAND_SHIFT 0u + +/* Command register IACK bit */ +#define CMD_IACK_OFFSET 0x10u +#define CMD_IACK_MASK 0x01u +#define CMD_IACK_SHIFT 0u + +/* Command register ACK bit */ +#define CMD_ACK_OFFSET 0x10u +#define CMD_ACK_MASK 0x08u +#define CMD_ACK_SHIFT 3u + +/* Command register WR bit */ +#define CMD_WR_OFFSET 0x10u +#define CMD_WR_MASK 0x10u +#define CMD_WR_SHIFT 4u + +/* Command register RD bit */ +#define CMD_RD_OFFSET 0x10u +#define CMD_RD_MASK 0x20u +#define CMD_RD_SHIFT 5u + +/* Command register STO bit */ +#define CMD_STO_OFFSET 0x10u +#define CMD_STO_MASK 0x40u +#define CMD_STO_SHIFT 6u + +/* Command register STA bit */ +#define CMD_STA_OFFSET 0x10u +#define CMD_STA_MASK 0x80u +#define CMD_STA_SHIFT 7u + +/*------------------------------------------------------------------------------ + * Status register details + */ +#define STATUS_REG_OFFSET 0x14u + +/* Command register bits */ +#define STATUS_OFFSET 0x14u +#define STATUS_MASK 0xFFu +#define STATUS_SHIFT 0u + +/* Status register Interrupt Flag(IF) bit */ +#define STAT_IF_OFFSET 0x14u +#define STAT_IF_MASK 0x01u +#define STAT_IF_SHIFT 0u + +/* Status register Transfer in Progress(TIP) bit */ +#define STAT_TIP_OFFSET 0x14u +#define STAT_TIP_MASK 0x02u +#define STAT_TIP_SHIFT 1u + +/* Status register Arbitration Lost(AL) bit */ +#define STAT_AL_OFFSET 0x14u +#define STAT_AL_MASK 0x20u +#define STAT_AL_SHIFT 5u + +/* Status register Busy(BUSY) bit */ +#define STAT_BUSY_OFFSET 0x14u +#define STAT_BUSY_MASK 0x40u +#define STAT_BUSY_SHIFT 6u + +/* Status register Ack received(RXACK) bit */ +#define STAT_RXACK_OFFSET 0x14u +#define STAT_RXACK_MASK 0x80u +#define STAT_RXACK_SHIFT 7u + + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_I2C_APB_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.c b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.c new file mode 100644 index 0000000..903f029 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.c @@ -0,0 +1,283 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * MI-V Soft IP fabric bare-metal driver for Mi-V PLIC module. This module is + * delivered as a part of Mi-V Extended Sub System(MIV_ESS). + * Please refer to miv_plic.h file for more information. + */ + +#include "miv_plic.h" + +/***************************************************************************//** + * Mi-V PLIC interrupt handler function declaration. + * These functions are called by the external interrupt handler of the MIV_RV32 + * core base on the PLIC source causing the interrupt. + */ +uint8_t Invalid_IRQHandler(void); +uint8_t MIV_PLIC_EXT0_IRQHandler(void); +uint8_t MIV_PLIC_EXT1_IRQHandler(void); +uint8_t MIV_PLIC_EXT2_IRQHandler(void); +uint8_t MIV_PLIC_EXT3_IRQHandler(void); +uint8_t MIV_PLIC_EXT4_IRQHandler(void); +uint8_t MIV_PLIC_EXT5_IRQHandler(void); +uint8_t MIV_PLIC_EXT6_IRQHandler(void); +uint8_t MIV_PLIC_EXT7_IRQHandler(void); +uint8_t MIV_PLIC_EXT8_IRQHandler(void); +uint8_t MIV_PLIC_EXT9_IRQHandler(void); +uint8_t MIV_PLIC_EXT10_IRQHandler(void); +uint8_t MIV_PLIC_EXT11_IRQHandler(void); +uint8_t MIV_PLIC_EXT12_IRQHandler(void); +uint8_t MIV_PLIC_EXT13_IRQHandler(void); +uint8_t MIV_PLIC_EXT14_IRQHandler(void); +uint8_t MIV_PLIC_EXT15_IRQHandler(void); +uint8_t MIV_PLIC_EXT16_IRQHandler(void); +uint8_t MIV_PLIC_EXT17_IRQHandler(void); +uint8_t MIV_PLIC_EXT18_IRQHandler(void); +uint8_t MIV_PLIC_EXT19_IRQHandler(void); +uint8_t MIV_PLIC_EXT20_IRQHandler(void); +uint8_t MIV_PLIC_EXT21_IRQHandler(void); +uint8_t MIV_PLIC_EXT22_IRQHandler(void); +uint8_t MIV_PLIC_EXT23_IRQHandler(void); +uint8_t MIV_PLIC_EXT24_IRQHandler(void); +uint8_t MIV_PLIC_EXT25_IRQHandler(void); +uint8_t MIV_PLIC_EXT26_IRQHandler(void); +uint8_t MIV_PLIC_EXT27_IRQHandler(void); +uint8_t MIV_PLIC_EXT28_IRQHandler(void); +uint8_t MIV_PLIC_EXT29_IRQHandler(void); +uint8_t MIV_PLIC_EXT30_IRQHandler(void); + +/***************************************************************************//** + * MIV_PLIC interrupt handler for external interrupts. + * The array of the function pointers pointing to the weak handler of the Mi-V + * PLIC interrupt handlers. + * These functions are called by the external interrupt handler of the MIV_RV32 + * core base on the PLIC source causing the interrupt. + */ +uint8_t (* const ext_irq_handler_table[32]) (void) = +{ + Invalid_IRQHandler, + MIV_PLIC_EXT0_IRQHandler, + MIV_PLIC_EXT1_IRQHandler, + MIV_PLIC_EXT2_IRQHandler, + MIV_PLIC_EXT3_IRQHandler, + MIV_PLIC_EXT4_IRQHandler, + MIV_PLIC_EXT5_IRQHandler, + MIV_PLIC_EXT6_IRQHandler, + MIV_PLIC_EXT7_IRQHandler, + MIV_PLIC_EXT8_IRQHandler, + MIV_PLIC_EXT9_IRQHandler, + MIV_PLIC_EXT10_IRQHandler, + MIV_PLIC_EXT11_IRQHandler, + MIV_PLIC_EXT12_IRQHandler, + MIV_PLIC_EXT13_IRQHandler, + MIV_PLIC_EXT14_IRQHandler, + MIV_PLIC_EXT15_IRQHandler, + MIV_PLIC_EXT16_IRQHandler, + MIV_PLIC_EXT17_IRQHandler, + MIV_PLIC_EXT18_IRQHandler, + MIV_PLIC_EXT19_IRQHandler, + MIV_PLIC_EXT20_IRQHandler, + MIV_PLIC_EXT21_IRQHandler, + MIV_PLIC_EXT22_IRQHandler, + MIV_PLIC_EXT23_IRQHandler, + MIV_PLIC_EXT24_IRQHandler, + MIV_PLIC_EXT25_IRQHandler, + MIV_PLIC_EXT26_IRQHandler, + MIV_PLIC_EXT27_IRQHandler, + MIV_PLIC_EXT28_IRQHandler, + MIV_PLIC_EXT29_IRQHandler, + MIV_PLIC_EXT30_IRQHandler +}; + +/* Mi-V PLIC interrupt weak handlers */ +__attribute__((weak)) uint8_t Invalid_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT0_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT1_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT2_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT3_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT4_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT5_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT6_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT7_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT8_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT9_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT10_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT11_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT12_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT13_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT14_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT15_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT16_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT17_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT18_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT19_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT20_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT21_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT22_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT23_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT24_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT25_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT26_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT27_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT28_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT29_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT30_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +/*-------------------------------------------------------------------------*//** + * Please refer to miv_plic.h for more information about this function. +*/ +void +MIV_PLIC_isr +( + miv_plic_instance_t *this_plic +) +{ + unsigned long hart_id = read_csr(mhartid); + + /* claim the interrupt from PLIC controller */ + + uint32_t int_num = HAL_get_32bit_reg(this_plic->base_addr + + (0x1000 * hart_id), INT_CLAIM_COMPLETE); + + uint8_t disable = EXT_IRQ_KEEP_ENABLED; + disable = ext_irq_handler_table[int_num](); + + /* Indicate the PLIC controller that the interrupt is processed and claim is + * complete. */ + HAL_set_32bit_reg(this_plic->base_addr + + (0x1000 * hart_id), INT_CLAIM_COMPLETE, int_num); + + if (EXT_IRQ_DISABLE == disable) + { + MIV_PLIC_disable_irq(this_plic, (miv_plic_irq_num_t)int_num); + } +} diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.h new file mode 100644 index 0000000..f5d64cd --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.h @@ -0,0 +1,425 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * PLIC module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(ESS). + */ + /*=========================================================================*//** + @mainpage Mi-V PLIC Bare Metal Driver + + ============================================================================== + Introduction + ============================================================================== + The Mi-V driver provides a set of functions for controlling the Mi-V PLIC + (platform level interrupt controller) soft-IP module. This module is delivered + as a part of the MIV_ESS. The PLIC multiplexes external interrupt signals into + a single interrupt signal that is connected to an external interrupt of the + processor. + + The major features provided by the driver are: + - Support for configuring the PLIC instances. + - Enabling and Disabling interrupts + - Interrupt Handling + + This driver can be used as part of a bare metal system where no operating + system is available. The driver can be adapted for use as part of an + operating system, but the implementation of the adaptation layer between the + driver and the operating system's driver model is outside the scope of this + driver. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + The application software should initialize the Mi-V PLIC through the call to + the MIV_PLIC_init() function for Mi-V PLIC instance in the design. + + No Mi-V PLIC hardware configuration parameters are used by the driver, apart + from the Mi-V PLIC base address. Hence, no additional configuration files + are required to use the driver. + + ============================================================================== + Theory of Operation + ============================================================================== + The operation of Mi-V PLIC driver is divided into following steps: + - Initialization + - Enabling and Disabling interrupts + - Interrupt control + + -------------------------------------------- + Initialization + -------------------------------------------- + The Mi-V PLIC module is first initialized by the call to MIV_PLIC_init(). This + function takes a pointer to the Mi-V PLIC instance data structure and the base + address of the Mi-V PLIC instance is defined by the hardware design. The + instance data structure is used to store the base address of the Mi-V PLIC + module and a pointer to the Mi-V PLIC register data structure. The Mi-V PLIC + register data structure maps the address of the Mi-V PLIC registers. + + --------------------------------------------- + Enabling and Disabling interrupts + --------------------------------------------- + The MIV_PLIC_enable_irq() function enables the specific interrupt provided by + user. A call to this function will allow the enabling of each of the global + interrupts corresponding to the bit in the interrupt enable register of Mi-V + PLIC. + The MIV_PLIC_disable_irq() function disables the specific interrupt provided + by the user. This function can be used to disable the interrupts from outside + of the external interrupt handler. + + ---------------------------------------- + Interrupt Control + ---------------------------------------- + When an interrupt occurs on an enabled interrupt, the PLIC gateway captures + the interrupt and asserts the corresponding interrupt pending bit. Once + the enable bit and pending bit are asserted, then the PLIC_IRQ signal asserts + until the interrupt is claimed by the driver interrupt handler MIV_PLIC_irq() + function. + When multiple interrupts assert then the lowest interrupt number will be + serviced first, for example, if interrupt 1 and 6 assert at the same time, + interrupt 1 will be serviced first, followed by interrupt 6. + +*/ + +#ifndef MIV_PLIC_H_ +#define MIV_PLIC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "miv_plic_regs.h" + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#include "miv_rv32_hal/miv_rv32_hal.h" +#else +#include "hal.h" +#include "miv_rv32_hal.h" +#endif + +/*-------------------------------------------------------------------------*//** + This enumeration is used to select a specific Mi-V PLIC interrupt. It is + used as a parameter to enable or disable the interrupt. +*/ +typedef enum miv_plic_irq_num +{ + NoInterrupt_IRQn = 0, + MIV_PLIC_EXT0_IRQn = 1, + MIV_PLIC_EXT1_IRQn = 2, + MIV_PLIC_EXT2_IRQn = 3, + MIV_PLIC_EXT3_IRQn = 4, + MIV_PLIC_EXT4_IRQn = 5, + MIV_PLIC_EXT5_IRQn = 6, + MIV_PLIC_EXT6_IRQn = 7, + MIV_PLIC_EXT7_IRQn = 8, + MIV_PLIC_EXT8_IRQn = 9, + MIV_PLIC_EXT9_IRQn = 10, + MIV_PLIC_EXT10_IRQn = 11, + MIV_PLIC_EXT11_IRQn = 12, + MIV_PLIC_EXT12_IRQn = 13, + MIV_PLIC_EXT13_IRQn = 14, + MIV_PLIC_EXT14_IRQn = 15, + MIV_PLIC_EXT15_IRQn = 16, + MIV_PLIC_EXT16_IRQn = 17, + MIV_PLIC_EXT17_IRQn = 18, + MIV_PLIC_EXT18_IRQn = 19, + MIV_PLIC_EXT19_IRQn = 20, + MIV_PLIC_EXT20_IRQn = 21, + MIV_PLIC_EXT21_IRQn = 22, + MIV_PLIC_EXT22_IRQn = 23, + MIV_PLIC_EXT23_IRQn = 24, + MIV_PLIC_EXT24_IRQn = 25, + MIV_PLIC_EXT25_IRQn = 26, + MIV_PLIC_EXT26_IRQn = 27, + MIV_PLIC_EXT27_IRQn = 28, + MIV_PLIC_EXT28_IRQn = 29, + MIV_PLIC_EXT29_IRQn = 30, + MIV_PLIC_EXT30_IRQn = 31 +} miv_plic_irq_num_t; + +/*--------------------------------------------------------------------------*//* + * This structure maps the priority threshold and claim complete register in + * the memory. + */ +typedef struct +{ + volatile uint32_t PRIORITY_THRESHOLD; + volatile uint32_t CLAIM_COMPLETE; + volatile uint32_t reserved[1022]; +} IRQ_Target_Type; + +/*--------------------------------------------------------------------------*//* + * This structure maps the Interrupt enable sources from 0 - 1023 for one + * context. + */ +typedef struct +{ + volatile uint32_t ENABLES[32]; +} Target_Enables_Type; + +/*-------------------------------------------------------------------------*//** + This structure holds the base address of the Mi-V PLIC module. This structure + is used by all the functions to access the Mi-V PLIC registers. +*/ +typedef struct miv_plic_instance +{ + addr_t base_addr; +} miv_plic_instance_t; + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_isr is the top level interrupt handler function for the Mi-V PLIC + * driver. You must call the MIV_PLIC_isr() from the system level interrupt + * handler(External_IRQHandler). + * This function must be called from the external interrupt handler function + * provided by the processor hardware abstraction layer. In case of MIV_RV32 + * soft processor, it must be called from External_IRQHandler() function + * provided by MIV_RV32 HAL. + * + * The MIV_PLIC_isr() function claims the interrupt number + * that triggered the interrupt and then invokes the appropriate PLIC interrupt + * handler. + * After handling the PLIC interrupt, this function will complete the interrupt + * by clearing the claim complete bit for the particular interrupt source. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * + * @return + * This function does not return any value. + * + * Example: + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * uint8_t MIV_PLIC_EXT0_IRQHandler(void) + * { + * *** ISR operation *** + * + * return(EXT_IRQ_KEEP_ENABLED); + * } + * + * void External_IRQHandler(void) + * { + * uint32_t reg_val = read_csr(mip); + * MIV_PLIC_isr(&g_plic); + * } + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * } + * @endcode + */ +void MIV_PLIC_isr(miv_plic_instance_t *this_plic); + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_init() function initializes the Mi-V PLIC instance with base + * address. This function resets the PLIC controller by disabling all the PLIC + * interrupts. + * + * Note: This function must be called before calling any other Mi-V PLIC driver + * function. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * + * @param base_addr + * Base address of the Mi-V PLIC instance in the MIV_ESS soft-IP. + * + * @param ext_intr_sources + * Number of interrupts initialized in the design. + * + * @return + * This function does not return any value. + * + * Example + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * } + * @endcode + */ +static inline void +MIV_PLIC_init +( + miv_plic_instance_t *this_plic, + addr_t base_addr, + uint8_t ext_intr_sources +) +{ + uint32_t inc; + unsigned long hart_id = read_csr(mhartid); + + this_plic->base_addr = base_addr; + + /* Disable all interrupts for the current hart. + * The PLIC_EXT_INTR_SOURCES should be defined in the hw_platform.h. This + * macro holds the number of PLIC interrupts enabled in the design. + */ + for(inc = 0; inc < ((ext_intr_sources + 32u) / 32u); ++inc) + { + HAL_set_32bit_reg( + (this_plic->base_addr + inc + (hart_id * 128)), INT_ENABLE , 0x0u); + } +} + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_enable_irq() function enables the PLIC interrupt provided with + * IRQn parameter. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * @param IRQn + * Number of PLIC interrupt to enable. + * + * @return + * This function does not return any value. + * + * Example + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * } + * @endcode + */ +static inline void +MIV_PLIC_enable_irq +( + miv_plic_instance_t *this_plic, + miv_plic_irq_num_t IRQn +) +{ + unsigned long hart_id = read_csr(mhartid); + + uint32_t current = HAL_get_32bit_reg( + (this_plic->base_addr + (IRQn/32) + (hart_id * 128)) , INT_ENABLE); + + current |= (uint32_t)1 << (IRQn % 32); + + HAL_set_32bit_reg( + (this_plic->base_addr + (IRQn/32) + (hart_id * 128)), INT_ENABLE, current); + +} + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_disable_irq() function disables the PLIC interrupt provided with + * IRQn parameter. + * + * NOTE: + * This function can be used to disable the PLIC interrupt from outside the + * external interrupt handler functions. + * If you wish to disable the PLIC interrupt from the external interrupt handler, + * you should use the return value of EXT_IRQ_DISABLE. This will disable the + * selected PLIC interrupt from the Mi-V PLIC driver interrupt handler. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * @param IRQn + * Number of PLIC interrupt to disable. + * + * @return + * This function does not return any value. + * + * Example + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * } + * @endcode + */ +static inline void +MIV_PLIC_disable_irq +( + miv_plic_instance_t *this_plic, + miv_plic_irq_num_t IRQn +) +{ + unsigned long hart_id = read_csr(mhartid); + + uint32_t current = HAL_get_32bit_reg((this_plic->base_addr + (IRQn/32) + (hart_id * 128)) , INT_ENABLE); + + current &= ~((uint32_t)1 << (IRQn % 32)); + + HAL_set_32bit_reg((this_plic->base_addr + (IRQn/32) + (hart_id * 128)), INT_ENABLE, current); + +} + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_PLIC_H_ */ diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic_regs.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic_regs.h new file mode 100644 index 0000000..76cbc0b --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic_regs.h @@ -0,0 +1,31 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP PLIC module driver. This module is delivered as a part of Mi-V extended + * Sub-System(MIV_ESS). + */ + +#ifndef MIV_PLIC_REGISTERS +#define MIV_PLIC_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Interrupt pending register offset */ +#define INT_PENDING_REG_OFFSET 0x1000u + +/* Interrupt enable register */ +#define INT_ENABLE_REG_OFFSET 0x2000u + +/* Interrupt claim complete register */ +#define INT_CLAIM_COMPLETE_REG_OFFSET 0x200004u + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_PLIC_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_timer/miv_timer.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_timer/miv_timer.h new file mode 100644 index 0000000..5f00889 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_timer/miv_timer.h @@ -0,0 +1,329 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Mi-V Timer Soft IP bare-metal driver. This module is delivered as part of + * the Mi-V Extended Sub System(ESS) MIV_ESS. + */ + +/*=========================================================================*//** + @mainpage Mi-V Timer Bare Metal Driver. + The Mi-V Timer bare metal software driver supports the timer module which + serves as a system timer for the Mi-V Extended Sub System(ESS). + + @section intro_sec Introduction + The MI-V Timer driver supports set of functions for controlling the Mi-V + Timer module. + The Mi-V Timer can generate a timer interrupt signal for the system based on + special system clock intervals specified by the parameters that can be passed + in by the user. + + The major features provided by Mi-V Timer driver are: + - Support for Mi-V Timer instance for each Mi-V Timer peripheral. + - Read current time + - Write to the machine time compare register + + @section hw_dependencies Hardware Flow dependency + The application should configure the Mi-V Timer driver through calls to + MIV_TIMER_init() functions for each MIV_TIMER instance in the hardware + design. The configuration parameter include the MIV_TIMER hardware instance, + base address and number of ticks to generate timer interrupt. + + MIV_RV32 core offers flexibility in terms of generating the MTIME and MTIMECMP + registers internal to the core or using external time reference. + When MIV_ESS is interfaced with MIV_RV32 core, the timer module in the MIV_ESS + can be configured as follows: + - Internal MTIME External MTIME IRQ + Generate the MTIME internally(MIV_RV32) and have a timer interrupt input + to the core as external pin(from MIV_ESS). + + - External MTIME Internal MTIME IRQ + Generate the time value externally(from MIV_ESS), in this case a 64-bit + port will open in the MIV_RV32 core as input and MIV_ESS will output the + 64-bit TIME_COUNT value. The generation of mtimecmp and interrupt is + done internally(MIV_RV32). + + - External MTIME External MTIME IRQ + Generate both the time and timer interrupt externally. + In this case 64-bit port will be available on the Mi-V RV32 core as input + and a 1 pin port will be available for timer interrupt. + + The design must be configured accordingly to use these combinations in the + firmware. + + No MIV_TIMER hardware configuration parameters are used by the driver, apart + from MIV_TIMER base address. Hence, no additional configuration files are + required to use the driver. + + @section theory_op Theory of Operation + + The MIV_TIMER module is a simple systick timer which can generate a timer + interrupt signal for the system at specific intervals specified by the + parameters that can be passed by the user. + These interrupt signal are then fed to the MIV_RV32 core via timer interrupt. + + The operation of MIV_TIMER is divided into following steps: + - Initialization + - Configuration + - Read/Write TIME + + ## Initialization + The MIV_TIMER is first initialized by a call to MIV_TIMER_init(). This + function initializes the instance of Mi-V TIMER with the base address. + The MIV_TIMER_init() function must be called before any other Mi-V Timer driver + function. + + ## Configuration + The Mi-V TIMER configuration includes writing the mtimecmp register with the + initial time value at which timer interrupt should be generated. + When the mtime register value becomes greater than or equal to mtimecmp value, + a timer interrupt signal(TIMER_IRQ) is generated. + + ## Read/Write TIME + The time value can be read by reading the mtime register via call to the + MIV_TIMER_read_mtime(). This function reads the MTIME register which contains + the 64-bit value of the timer count. The count increments by 1 every time the + prescale ticks. This function returns 64-bit MTIME_COUNT value which is the + current value of timer count. + + The time value read in the MIV_TIMER_read_mtime() function can be written to + the mtimecmp register by calling MIV_TIMER_write_mtimecmp() to generate + periodic interrupts. + The writing of the mtimecmp register should be done in the systick_handler() + function. + */ + +#ifndef MIV_TIMER_H_ +#define MIV_TIMER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#endif +/*-------------------------------------------------------------------------*//** +MIV_TIMER_SUCCESS +===================== + +The MIV_TIMER_SUCCESS constant indicates successful configuration of +Mi-V Timer module. +*/ +#define MIV_TIMER_SUCCESS 0u + +/*-------------------------------------------------------------------------*//** +MIV_TIMER_ERROR +===================== + +The MIV_TIMER_ERROR constant indicates that there is an error with +configuring the Mi-V Timer module. +*/ +#define MIV_TIMER_ERROR 1u + +/*-------------------------------------------------------------------------*//* +MIV_TIMER_MASK_32BIT +===================== + +32-bit mask constant used in calculation of 64-bit register value. +*/ +#define MIV_TIMER_MASK_32BIT 0xFFFFFFFFu + +/*-------------------------------------------------------------------------*//* +Mi-V Timer register offsets +===================== +The MTIMECMP is the 64-bit timer compare register, it pre-sets the threshold +which needs to be reached by the timer count register. +This 64-bit register is accessed with 2 32-bit address offset, lower 32-bits +and higher 32-bits. + - MIV_TIMER_MTIMECMP_L_REG_OFFSET + - MIV_TIMER_MTIMECMP_H_REG_OFFSET + +The MTIME is the 64-bit register that contains the 64-bit timer count. The +count increments by 1 every time the prescaler ticks. +This 64-bit register is accessed with 2 32-bit address offset, lower 32-bits +and higher 32-bits. + - MIV_TIMER_MTIME_L_REG_OFFSET + - MIV_TIMER_MTIME_H_REG_OFFSET + +The PRESCALE register is used to determine the amount of clock cycles the +selected clock needs to go through, for MTIME register to increment count. + - MIV_TIMER_PRESCALAR_REG_OFFSET +*/ + +/// @cond private +#define MIV_TIMER_MTIMECMP_L_REG_OFFSET 0x4000u +#define MIV_TIMER_MTIMECMP_H_REG_OFFSET 0x4004u + +#define MIV_TIMER_MTIME_L_REG_OFFSET 0xBFF8u +#define MIV_TIMER_MTIME_H_REG_OFFSET 0xBFFCu + +#define MIV_TIMER_PRESCALAR_REG_OFFSET 0x5000u +/// @endcond + +/*-------------------------------------------------------------------------*//** + This structure holds the base address of the Mi-V Timer module and instance + of the Mi-V Timer register structure. +*/ +typedef struct miv_timer_instance +{ + addr_t base_addr; +} miv_timer_instance_t; + +/** The MIV_TIMER_init() is used to initialize the Mi-V Timer module. This + function will assign the base addresses of the Mi-V Timer module. + User should call this function before calling any of the Mi-V Timer driver + APIs. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @param base_address + Base address of the Mi-V Timer module. + + @return + This function does not return any value. + */ +static inline void +MIV_TIMER_init +( + miv_timer_instance_t* this_timer, + addr_t base_addr +) +{ + this_timer->base_addr = base_addr; +} + +/** MIV_TIMER_read_current_time() is used to read the mtimecmp register values. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @return + This function returns 64-bit mtimecmp register value. + */ +static inline uint64_t +MIV_TIMER_read_current_time +( + miv_timer_instance_t* this_timer +) +{ + volatile uint64_t read_data = 0u; + volatile uint32_t mtime_hi = 0u; + volatile uint32_t mtime_lo = 0u; + + /* when mtime lower word is 0xFFFFFFFF, there will be rollover and + * returned value could be wrong. */ + do { + mtime_hi = HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIME_H); + mtime_lo = HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIME_L); + + } while(mtime_hi != HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIME_H)); + + read_data = mtime_hi; + + return(((read_data) << 32u) | mtime_lo); +} + +/** MIV_TIMER_write_compare_time() is used to write to the MTIMECMP register in + the event of interrupt. User must use this function in the interrupt handler + to de-assert the MIV_TIMER interrupt. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @param write_value + Value to write into the mtimecmp register. + + @return + This function does not return any value. + */ +static inline void +MIV_TIMER_write_compare_time +( + miv_timer_instance_t* this_timer, + uint64_t compare_reg_value +) +{ + HAL_set_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIMECMP_H, MIV_TIMER_MASK_32BIT); + + HAL_set_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIMECMP_L, + (compare_reg_value & MIV_TIMER_MASK_32BIT)); + + HAL_set_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIMECMP_H, + ((compare_reg_value >> 32u) & MIV_TIMER_MASK_32BIT)); +} + +/** The MIV_TIMER_config() is used to configure the MIV_ESS Timer module. The + prescale value serves to divide the count of clock cycles for the timer and + provides control over what point in time, the timer interrupt gets + asserted. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @param ticks + Number of ticks after which interrupt will be generated. + + @return + This function returns Mi-V Timer configuration status. + */ +static inline uint32_t +MIV_TIMER_config +( + miv_timer_instance_t* this_timer, + uint64_t ticks +) +{ + uint32_t ret_val = MIV_TIMER_ERROR; + uint64_t mtime_val = 0u; + uint32_t prescalar = 0u; + uint64_t miv_timer_increment = 0U; + + prescalar = HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_PRESCALAR); + + miv_timer_increment = (uint64_t)(ticks) / prescalar; + + if (miv_timer_increment > 0U) + { + mtime_val = MIV_TIMER_read_current_time(this_timer); + + MIV_TIMER_write_compare_time(this_timer ,(mtime_val + miv_timer_increment)); + + ret_val = MIV_TIMER_SUCCESS; + } + + return ret_val; +} + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_TIMER_H */ diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c new file mode 100644 index 0000000..cbd9652 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c @@ -0,0 +1,109 @@ +/******************************************************************************* + * (c) Copyright 2022-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Mi-V uDMA Soft IP bare-metal driver. This module is delivered as part of + * Mi-V Extended Sub System(MIV_ESS) + */ + +#include "miv_udma_regs.h" +#include "miv_udma.h" + +/***************************************************************************//** + * MIV_uDMA_init() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_init +( + miv_udma_instance_t* this_udma, + addr_t base_addr +) +{ + /* Assign the Mi-V uDMA base address to the uDMA instance structure */ + this_udma->base_address = base_addr; +} + +/***************************************************************************//** + * MIV_uDMA_config() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_config +( + miv_udma_instance_t* this_udma, + addr_t src_addr, + addr_t dest_addr, + uint32_t transfer_size, + uint32_t irq_config +) +{ + /* Source memory start address */ + HAL_set_32bit_reg(this_udma->base_address, SRC_START_ADDR, src_addr); + + /* Destination memory start address */ + HAL_set_32bit_reg(this_udma->base_address, DEST_START_ADDR, dest_addr); + + /* Data transfer size */ + HAL_set_32bit_reg(this_udma->base_address, BLK_SIZE, transfer_size); + + /* Configure the uDMA IRQ */ + HAL_set_32bit_reg(this_udma->base_address, IRQ_CFG, irq_config); +} + +/***************************************************************************//** + * MIV_uDMA_start() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_start +( + miv_udma_instance_t* this_udma +) +{ + /* Start the uDMA transfer */ + HAL_set_32bit_reg(this_udma->base_address, CONTROL_SR, CTRL_START_TX_MASK); +} + +/***************************************************************************//** + * MIV_uDMA_reset() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_reset +( + miv_udma_instance_t* this_udma +) +{ + /* Toggle the uDMA_reset bit to reset the uDMA. + * Resetting the uDMA will clear all the configuration made by + * MIV_uDMA_config(). + * + * This function should be called from the interrupt handler to clear the + * IRQ. + */ + HAL_set_32bit_reg_field(this_udma->base_address, CTRL_RESET_TX, 0x1u); + HAL_set_32bit_reg_field(this_udma->base_address, CTRL_RESET_TX, 0x0u); +} + +/***************************************************************************//** + * MIV_uDMA_read_status() + * See "miv_udma.h" for details of how to use this function. + */ +uint32_t +MIV_uDMA_read_status +( + miv_udma_instance_t* this_udma +) +{ + uint32_t status = 0u; + + /* Read the status of the uDMA transfer. + * The transfer status register can be Error or Busy depending on the + * current uDMA transfer. + */ + status = HAL_get_32bit_reg(this_udma->base_address, TX_STATUS); + + return status; +} diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h new file mode 100644 index 0000000..efa8731 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h @@ -0,0 +1,290 @@ +/******************************************************************************* + * Copyright 2022-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * uDMA module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(MIV_ESS). + */ + +/*=========================================================================*//** + @mainpage Mi-V uDMA Bare Metal Driver. + The Mi-V uDMA bare metal software driver. + + @section intro_sec Introduction + The Mi-V uDMA driver provides a set of functions to control the Mi-V uDMA + module in the Mi-V Extended Subsystem (MIV_ESS) soft-IP. The Mi-V uDMA module + allows peripherals with AHB interfaces to transfer data independently of the + MIV_RV32 RISC-V processor. + + Following are the major features provided by the Mi-V uDMA driver: + - Initialization and configuration + - Start and reset the transaction + + This driver can be used as part of a bare metal system where no operating + system is available. The driver can be adapted for use as part of an + operating system, but the implementation of the adaptation layer between the + driver and the operating system's driver model is outside the scope of this + driver. + + @section hw_dependencies Hardware Flow Dependency + The application software should initialize and configure the Mi-V uDMA through + calling the MIV_uDMA_init() and MIV_uDMA_config() functions for each Mi-V + uDMA instance in the design. + + The uDMA can operate in two possible transfer configurations: + + - AHBL Read -> AHBL Write: + In this configuration, the uDMA reads data from the source memory over an + AHBL (mirrored main/initiator) read interface and writes data to the + destination memory over an AHBL (mirrored main/initiator) write interface. + + - AHBL Read -> TAS Write: + In this configuration, the uDMA reads data from the source memory over an + AHBL (mirrored main/initiator) read interface and writes data to the + destination memory over the TAS (mirrored main/initiator) write interface. + + Note: The AHBL Read -> TAS Write configuration is out of scope for this + driver. + + @section theory_op Theory of Operation + The uDMA module in the Mi-V Extended Sub System (MIV_ESS) is a single-channel + uDMA module that allows peripherals to perform read-write operations between + source and destination memory. The Mi-V uDMA driver is used in + interrupt-driven mode and uses the Mi-V uDMA IRQ signal to drive the + interrupt service routine (ISR), which signifies a transfer has completed. + The status is checked in the ISR to ensure the transfer is completed + successfully. + The reset operation in the ISR resets the Mi-V uDMA controller. Once the Mi-V + uDMA transfer is complete, Mi-V uDMA retires. To initiate another + transaction, Mi-V uDMA needs to be configured again. + + The operation of the Mi-V uDMA driver is divided into the following + categories: + - Initialization + - Configuration + - Start and reset the transfer + + Initialization and configuration: + Mi-V uDMA is first initialized by calling MIV_uDMA_init() function. This + function initializes the instance of Mi-V uDMA with the base address. The + MIV_uDMA_init() function must be called before calling any other Mi-V uDMA + driver functions. + + The Mi-V uDMA is configured by calling MIV_uDMA_config() function. This + function configures the source_addr and dest_addr registers of the Mi-V + uDMA with source and destination addresses for Mi-V uDMA transfers. + This function also configures the transfer size and interrupt preference for + successful transfers using Mi-V uDMA. + + Start and reset the transfer: + Once the Mi-V uDMA is configured, initiate the transfers by calling the + MIV_uDMA_start() function. Once the Mi-V uDMA transfer is started, it cannot + be aborted, and the status of the transfer should be read from the ISR by + calling the MIV_uDMA_read_status() function. + + Reset the Mi-V uDMA to the default state by calling the MIV_uDMA_reset() + function. After performing the reset operation, reconfigure the Mi-V uDMA to + perform transfers as MIV_uDMA_reset() resets the Mi-V uDMA controller. + */ + +#ifndef MIV_uDMA_H_ +#define MIV_uDMA_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#include "hal/cpu_types.h" + +#else +#include "hal.h" +#include "cpu_types.h" +#endif + +/*-------------------------------------------------------------------------*//** + MIV_uDMA_CTRL_IRQ_CONFIG + ===================== + + The MIV_uDMA_CTRL_IRQ_CONFIG macro is used to assert the uDMA IRQ when an error + occurs during a uDMA transfer or on the completion of a uDMA transfer. + */ +#define MIV_uDMA_CTRL_IRQ_CONFIG 1u + +/*-------------------------------------------------------------------------*//** + MIV_uDMA_STATUS_BUSY + ===================== + + The MIV_uDMA_STATUS_BUSY macro is used to indicate that the uDMA transfer is + in progress. + */ +#define MIV_uDMA_STATUS_BUSY 1u + +/*-------------------------------------------------------------------------*//** + MIV_uDMA_STATUS_ERROR + ===================== + + The MIV_uDMA_STATUS_ERROR macro is used to indicate that the last uDMA + transfer has caused an error. + */ +#define MIV_uDMA_STATUS_ERROR 2u + +/***************************************************************************//** + * This structure holds the base of the Mi-V uDMA module, which is used in the + * other functions of the driver to access the uDMA registers. + */ +typedef struct miv_udma_instance +{ + addr_t base_address; +} miv_udma_instance_t; + +/***************************************************************************//** + * The MIV_uDMA_init() function assigns the base address of the Mi-V uDMA module + * to the uDMA instance structure. + * This address is used in a later part of the driver to access the uDMA + * registers. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure. + * + * @param base_addr + * Base address of the Mi-V uDMA module. + * + * @return + * This function does not return a value. + */ +void +MIV_uDMA_init +( + miv_udma_instance_t* this_udma, + addr_t base_addr +); + +/***************************************************************************//** + * The MIV_uDMA_config() function is used to configure the Mi-V uDMA controller. + * This function will set the source address, destination address, block size, + * and IRQ configuration register. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @param base_addr + * Base address of the Mi-V uDMA. + * + * @param src_addr + * Source address of memory from where the uDMA reads the data. + * + * @param dest_addr + * Destination address where the data is written from src_addr. + * + * @param transfer_size + * Number of 32-bit words to transfer. + * + * @param irq_config + * uDMA IRQ configuration + * - When set, the IRQ is asserted when an error occurs during a uDMA + * transfer or on the completion of the uDMA transfer. + * - When clear, the IRQ is only asserted when an error occurs during a + * uDMA transfer. + * + * @return + * This function does not return any value. + */ +void +MIV_uDMA_config +( + miv_udma_instance_t* this_udma, + addr_t src_addr, + addr_t dest_addr, + uint32_t transfer_size, + uint32_t irq_config +); + +/***************************************************************************//** + * The MIV_uDMA_start() function is used to start the uDMA transfer. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @return + * This function does not return any value. + */ +void +MIV_uDMA_start +( + miv_udma_instance_t* this_udma +); + +/***************************************************************************//** + * The MIV_uDMA_reset() function is used to clear the uDMA interrupt and reset + * the uDMA transfer. + * + * This function should be called from the interrupt handler to reset the values + * set during MIV_uDMA_config(). + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @return + * This function does not return any value. + */ +void +MIV_uDMA_reset +( + miv_udma_instance_t* this_udma +); + +/***************************************************************************//** + * The MIV_uDMA_read_status() function is used to read the status of the uDMA + * transfer. When interrupt is enabled, this function can be called from the + * interrupt handler to know the reason for a uDMA interrupt. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @return + * The return value indicates an error due to the busy status of the uDMA + * channel. + * + * |Bit Number| Name | Description | + * |----------|---------|------------------------------------------------------| + * | 0 | Busy | When set indicates that uDMA transfer is in progress| + * | 1 | Error | When set indicates that last uDMA transfer caused an| + * | | | error. | + */ +uint32_t +MIV_uDMA_read_status +( + miv_udma_instance_t* this_pdma +); + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_uDMA_H_ */ diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h new file mode 100644 index 0000000..14d0759 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h @@ -0,0 +1,94 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP uDMA module driver. This module is delivered as a part of Mi-V + * extended Sub-System(ESS) MIV_ESS. + */ + +#ifndef MIV_UDMA_APB_REGISTERS +#define MIV_UDMA_APB_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/**************************************************************************//** + * Control start/Reset register details + */ + +#define CONTROL_SR_REG_OFFSET 0x0u + +/* Control start/Reset register bits */ +#define CONTROL_SR_OFFSET 0x00u +#define CONTROL_SR_MASK 0x03u +#define CONTROL_SR_SHIFT 0u + +/* uDMA Control Start Transfer */ + +#define CTRL_START_TX_OFFSET 0x00u +#define CTRL_START_TX_MASK 0x01u +#define CTRL_START_TX_SHIFT 0u + +/* uDMA Control Reset Transfer */ +#define CTRL_RESET_TX_OFFSET 0x00u +#define CTRL_RESET_TX_MASK 0x02u +#define CTRL_RESET_TX_SHIFT 1u + +/**************************************************************************//** + * IRQ Configuration register details + */ +#define IRQ_CFG_REG_OFFSET 0x4u + +/* Control start/Reset register bits */ +#define IRQ_CFG_OFFSET 0x04u +#define IRQ_CFG_MASK 0x01u +#define IRQ_CFG_SHIFT 0u + +/***************************************************************************//** + * Transfer Status register details + */ +#define TX_STATUS_REG_OFFSET 0x08u + +/* Transfer status register bits */ +#define TX_STATUS_OFFSET 0x08u +#define TX_STATUS_MASK 0x03u +#define TX_STATUS_SHIFT 0u + +/***************************************************************************//** + * Source Memory Start Address Register + */ +#define SRC_START_ADDR_REG_OFFSET 0x0cu + +/* Source Memory Start Address Register bits */ +#define SRC_START_ADDR_OFFSET 0x0cu +#define SRC_START_ADDR_MASK 0xFFFFFFFFu +#define SRC_START_ADDR_SHIFT 0u + +/***************************************************************************//** + * Destination Memory Start Address register details + */ +#define DEST_START_ADDR_REG_OFFSET 0x10u + +/* Destination Memory Start Address register bits */ +#define DEST_START_ADDR_OFFSET 0x10u +#define DEST_START_ADDR_MASK 0xFFFFFFFFu +#define DEST_START_ADDR_SHIFT 0x0u + +/***************************************************************************//** + * Block Size register details + */ +#define BLK_SIZE_REG_OFFSET 0x14u + +/* Destination Memory Start Address register bits */ +#define BLK_SIZE_OFFSET 0x14u +#define BLK_SIZE_MASK 0xFFFFFFFFu +#define BLK_SIZE_SHIFT 0x0u + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_UDMA_APB_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c new file mode 100644 index 0000000..525928a --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Mi-V Watchdog Soft IP bare-metal driver. This module is delivered as part of + * Extended Sub System(ESS) MIV_ESS. + * Please refer to miv_watchdog.h file for more information. + */ + +#include "miv_watchdog.h" + +addr_t g_this_wdog; + +/***************************************************************************//* + * Please refer to miv_watchdog.h for more info about this function + */ +void +MIV_WDOG_init +( + addr_t base_addr +) +{ + /* Register the Mi-V Watchdog base address to the driver */ + g_this_wdog = base_addr; +} + +/***************************************************************************//* + * Please refer to miv_watchdog.h for more info about this function + */ +uint8_t MIV_WDOG_configure +( + const miv_wdog_config_t *config +) +{ + uint8_t error = 0u; + + /* check load value and trigger max value */ + if (config->timeout_val <= MIV_WDOG_TRIGGER_MAX) + { + HAL_set_32bit_reg(g_this_wdog, WDOGTRIG,(config->timeout_val)); + } + else + { + error = 1u; + } + + if (config->time_val <= MIV_WDOG_TIMER_MAX) + { + HAL_set_32bit_reg(g_this_wdog, WDOGMSVP,(config->mvrp_val)); + } + else + { + error = 1u; + } + + HAL_set_32bit_reg_field(g_this_wdog, WDOGCNTL_NEXT_ENFORBIDDEN, + config->forbidden_en); + + /* Reload watchdog with new load if it is not in forbidden window */ + if (!(WDOGSTAT_FORBIDDEN_MASK & (HAL_get_32bit_reg(g_this_wdog, WDOGSTAT)))) + { + HAL_set_32bit_reg(g_this_wdog, WDOGRFSH, MIV_WDOG_REFRESH_KEY); + } + else + { + error = 1u; + } + + return (error); +} + +/***************************************************************************//* + * Please refer to miv_watchdog.h for more info about this function + */ +void MIV_WDOG_get_config +( + miv_wdog_config_t *config +) +{ + if (0 != g_this_wdog) + { + + config->time_val = HAL_get_32bit_reg(g_this_wdog, WDOGTIME); + + config->timeout_val = HAL_get_32bit_reg(g_this_wdog, WDOGTRIG); + + config->mvrp_val = HAL_get_32bit_reg(g_this_wdog, WDOGMSVP); + + config->forbidden_en = HAL_get_32bit_reg_field(g_this_wdog, + WDOGCNTL_NEXT_ENFORBIDDEN); + } +} + diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h new file mode 100644 index 0000000..8877e55 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h @@ -0,0 +1,553 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * Watchdog module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(MIV_ESS). + */ +/*=========================================================================*//** + @mainpage MiV Watchdog Bare Metal Driver + + ============================================================================== + Introduction + ============================================================================== + The Mi-V Watchdog module in the MIV_ESS is used to generate a reset for the + system automatically if the software doesn't periodically update or refresh + the timer countdown register. This software driver provides set of functions + for controlling Mi-V Watchdog module as a part of bare metal system where no + operating system is available. The driver can be adapted for use as a part of + an operating system, but the implementation of the adaptation layer between + the driver and the operating system's driver model is outside the scope of the + driver. + + Mi-V Watchdog provides following features: + - Initializing the Mi-V Watchdog + - Reading current value and status of watchdog timer + - Refreshing the watchdog timer value + - Enabling, disabling and clearing timeout and Maximum Value up to which + Refresh is Permitted (MVRP) interrupts. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + The application software should initialize and configure the Mi-V Watchdog + module the the call to the MIV_WDOG_init() and MIV_WDOG_configure() functions. + + No MIV_WDOG hardware configuration parameter are used by the driver, apart + from the MIV_WDOG base address. Hence, no additional configuration files are + required to use the driver. + + ============================================================================== + Theory of Operation + ============================================================================== + The Mi-V Watchdog driver functions are grouped into the following categories: + - Initialization and configuration + - Reading the current value and status of the watchdog timer + - Refreshing the watchdog timer value + - Support for enabling, disabling and clearing time-out and MVRP interrupts. + + -------------------------------- + Initialization and Configuration + -------------------------------- + The MIV_WDOG_init() function stores the base of MIV_WDT module in the MIV_ESS. + This base address is used by rest of the functions to access the Mi-V Watchdog + registers. Please make call this function before calling any other function + from this driver. + Note: The Mi-V Watchdog driver supports only one instance of MIV_WDT in the + hardware. + The Mi-V Watchdog driver provides the MIV_WDOG_configure() function to + configure the MIV_WDOG module with desired configuration values. It also + provides the MIV_WDOG_get_config() to read back the current configuration of + the MIV_WDOG. You can use this function to retrieve the current configurations + and then overwrite them with the application specific values, such as initial + watchdog timer value, Maximum Value (up to which) Refresh (is) Permitted, + watchdog time-out value, enable/disable forbidden region, enable/disable + MVRP interrupt and interrupt type. + + -------------------------------------------- + Reading the Watchdog Timer Value and Status + -------------------------------------------- + Mi-V Watchdog is a down counter. A refresh forbidden window can be created by + configuring the watchdog Maximum Value up to which Refresh is Permitted (MVRP). + When the current value of the watchdog timer is greater than the MVRP value, + refreshing the watchdog is forbidden. Attempting to refresh the watchdog timer + in the forbidden window will assert a timeout interrupt. The + MIV_WDOG_forbidden_status() function can be used to know whether the watchdog + timer is in forbidden window or has crossed it. By default, the forbidden + window is disabled. It can be enabled by providing an appropriate value as + parameter to the MIV_WDOG_configure() function. When the forbidden window is + disabled, any attempt to refresh the watchdog timer is ignored and the counter + keeps on down counting. + + The current value of the watchdog timer can be read using the + MIV_WDOG_current_value() function. This function can be called at any time. + + -------------------------------------------- + Refreshing the Watchdog Timer Value + -------------------------------------------- + The watchdog timer value is refreshed using the MIV_WDOG_reload() function. + The value reloaded into the watchdog timer down-counter is specified at the + configuration time with an appropriate value as parameter to the + MIV_WDOG_get_config() function. + + -------------------------------------------- + Interrupt Control + -------------------------------------------- + The Mi-V Watchdog generates two interrupts, The MVRP interrupt and + the timeout interrupt. + The MVRP interrupt is generated when the watchdog down-counter crosses the + Maximum Value up to which Refresh is Permitted (MVRP). Following functions to + control MVRP interrupt: + - MIV_WDOG_enable_mvrp_irq + - MIV_WDOG_disable_mvrp_irq + - MIV_WDOG_clear_mvrp_irq + + The timeout interrupt is generated when the watchdog down-counter crosses the + watchdog timeout value. The timeout value is a non-zero value and it can be + set to a maximum of MIV_WDOG_TRIGGER_MAX. The non-maskable interrupt is + generated when the watchdog crosses this timeout value, the down counter + keeps on down counting and a reset signal is generated when reaches zero. + Following functions to control timeout interrupt: + - MIV_WDOG_enable_timeout_irq + - MIV_WDOG_disable_timeout_irq + - MIV_WDOG_clear_timeout_irq + +*//*=========================================================================*/ + +#ifndef MIV_WATCHDOG_H_ +#define MIV_WATCHDOG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "miv_watchdog_regs.h" + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#else +#include "hal.h" +#endif + +/****************************************************************************//* + * The following constants can be used to configure the Mi-V Watchdog where a + * zero or non-zero value such as enable or disable is to be provided as a input + * parameter as shown below: + */ +#define MIV_WDOG_ENABLE 1u +#define MIV_WDOG_DISABLE 0u + +/***************************************************************************//** + The miv_wdog_config_t type for the watchdog Configuration structure. This + type is used as a parameter for the MIV_WDOG_configure() and the + MIV_WDOG_get_config() functions. + + Following are the values as part of this structure +| Parameter | Description | +|------------------|-----------------------------------------------------------| +| time_val | The value from which the watchdog timer counts down | +| mvrp_val | The Watchdog MVRP value | +| timeout_val | The watchdog timeout value | +| forbidden_en | Enable/disable the forbidden window | +| | When set, if a refresh occurs in the forbidden window, | +| | the watchdog timeout interrupt will be generated. | + +Time calculation example: + + time_val = 0xFFFFF0u + mvrp_val = 0x989680u + timeout_val = 0x3e8u + + A prescaler = 256 is used. + Considering clock = 50Mhz + + The MVRP interrupt will happen after + (0xFFFFF0 - 0x989680) * ( 1/(50MHz/256)) + mvrp interrupt will happen after 34 sec. after system reset + + (0xFFFFF0 - 0x3e8) * ( 1/(50MHz/256)) + timeout interrupt will happen after 85 sec. after system reset + */ +typedef struct miv_wdog_config +{ + uint32_t time_val; + uint32_t mvrp_val; + uint32_t timeout_val; + uint32_t forbidden_en; + uint32_t intr_type; +}miv_wdog_config_t; + +extern addr_t g_this_wdog; + +/***************************************************************************//* + Internal constants and types +*******************************************************************************/ + +/// @cond private +#define MIV_WDOG_TRIGGER_MAX 4095u +#define MIV_WDOG_TIMER_MAX 16777200u +/// @endcond + +/*-------------------------------------------------------------------------*//* +MIV_WDOG_REFRESH_KEY +===================== + +The MIV_WDOG_REFRESH_KEY macro holds the magic value which will cause a +reload of the watchdog's down counter when written to the watchdog's +WDOGREFRESH register. +*/ +#define MIV_WDOG_REFRESH_KEY (uint32_t)0xDEADC0DEU + +/*-------------------------------------------------------------------------*//* +MIV_WDOG_FORCE_RESET_KEY +===================== +The MIV_WDOG_FORCE_RESET_KEY macro holds the magic value which will force a +reset if the watchdog is already timeout. Writing any other value or writing +TRIGGER register at other times will trigger the watchdog NMI sequence +(i.e raise a timeout interrupt) + */ +#define MIV_WDOG_FORCE_RESET_KEY (uint32_t)0xDEADU + +/***************************************************************************//** + * The MIV_WDOG_init() is used to register the Mi-V Watchdog module base + * address to the driver. + * + * Note: User should call this function before calling any other Mi-V watchdog + * driver function. + * + * @param base_addr + * The base address of the Mi-V watchdog module. This address is used by + * rest of the watchdog driver functions to access the registers. + * + * @return + * This function does not return any value. + */ +void +MIV_WDOG_init +( + addr_t base_addr +); + +/***************************************************************************//** + * The MIV_WDOG_get_config() function returns the current configurations of the + * Mi-V Watchdog. The Mi-V Watchdog is pre-initialized by the flash + * bits at the design time. When used for the first time before calling the + * MIV_WDOG_configure() function, this function will return the default + * configurations as configured at the design time. + * + * @param config + * The config parameter is used to store the current configuration of the Mi-V + * Watchdog. + * + * Please see the description of miv_wdog_config_t for details. + * + * @return + * This function does not return any value. + * + * Example: + */ +void +MIV_WDOG_get_config +( + miv_wdog_config_t* config +); + +/***************************************************************************//** + * The MIV_WDOG_configure() function configures the watchdog module. The + * Watchdog module is pre-initialized by the flash bits at the design time to the + * default values. You can reconfigure the Watchdog module using + * MIV_WDOG_configure() function. + * + * Note that the MIV_WDOG_configure() function can be used only once, as it + * writes into the TIME register. After a write into the TIME register, the TIME, + * TRIGGER and MSVP register values are frozen and can't be altered again unless + * a system reset happens. + * + * Note also that the Mi-V Watchdog is not enabled at reset, calling this function + * will start the watchdog, it cannot then be disabled and must be refreshed + * periodically. + * + * @param config + * The config parameter is the input parameter in which the configurations to + * be applied to the watchdog module are provided by the application. + * Please see the description of miv_wdog_config_t for details. + * + * @return + * This function returns a zero value when executed successfully. A non-zero + * value is returned when the configuration values are out of bound. + * + * Example: + */ +uint8_t +MIV_WDOG_configure +( + const miv_wdog_config_t * config +); + +/***************************************************************************//** + * The MIV_WDOG_reload() function causes the watchdog to reload its down-counter + * timer with the load value configured through interrupt handler. This function + * must be called regularly to avoid a system reset or a watchdog interrupt. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_reload +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg(g_this_wdog, WDOGRFSH, MIV_WDOG_REFRESH_KEY); + } +} + +/***************************************************************************//** + * The MIV_WDOG_current_value() function returns the current value of the + * watchdog's down-counter. + * + * @param + * Void + * + * @return + * This function returns the current value of the watchdog’s down-counter as + * a 32-bit unsigned integer. + */ +static inline uint32_t +MIV_WDOG_current_value +( + void +) +{ + return (HAL_get_32bit_reg(g_this_wdog, WDOGRFSH)); +} + +/***************************************************************************//** + * The MIV_WDOG_forbidden_status() function returns the refresh status of the + * Mi-V Watchdog. + * + * @param + * Void + * + * @return + * This function returns the refresh status of the watchdog. A value of 1 + * indicates that watchdog's down-counter is within the forbidden window and + * that a reload should not be done. A value of 0 indicates that the watchdog's + * down counter is within the permitted window and that a reload is allowed. + */ +static inline uint32_t +MIV_WDOG_forbidden_status +( + void +) +{ + return (HAL_get_32bit_reg_field(g_this_wdog, WDOGSTAT_FORBIDDEN)); +} + +/***************************************************************************//** + * The MIV_WDOG_enable_mvrp_irq() function enables the MVRP interrupt. + * This interrupt is asserted when the timer countdown register leaves the + * maximum value up to which refresh is permitted (MVRP) window. + * + * @param + * Void + * + * @return + * This function does not return a value. + * + * Example: + */ +static inline void +MIV_WDOG_enable_mvrp_irq +( + void +) +{ + + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGCNTL_NEXT_INTENT_MSVP, 0x01u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_disable_mvrp_irq() function disables the generation of the + * MVRP interrupt. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_disable_mvrp_irq +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGCNTL_NEXT_INTENT_MSVP, 0x0u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_clear_timeout_irq() function clears the watchdog’s timeout + * interrupt which is connected to the MIV-RV32 interrupt. Calling + * MIV_WDOG_clear_timeout_irq() results in clearing the MIV-RV32 interrupt. + * Note: You must call the MIV_WDOG_clear_timeout_irq() function as part of your + * implementation of the interrupt handler in order to prevent the same + * interrupt event re-triggering a call to the timeout ISR. + * + * @param + * Void + * + * @return + * This function does not return any value. + * + */ +static inline void +MIV_WDOG_clear_timeout_irq +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_WDOG_TRIPPED, 0x01u); + /* + * Perform a second write to ensure that the first write completed before + * returning from this function. This is to account for posted writes across + * the AHB matrix. The second write ensures that the first write has + * completed and that the interrupt line has been de-asserted by the time + * the function returns. Omitting the second write may result in a delay + * in the de-assertion of the interrupt line going to the RISC-V and a + * retriggering of the interrupt. + */ + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_WDOG_TRIPPED, 0x01u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_clear_mvrp_irq() function clears the mvrp interrupt. + * + * Note: You must call the MIV_WDOG_clear_mvrp_irq() function as part of your + * implementation of the interrupt service routine (ISR) in order to + * prevent the same interrupt event re-triggering a call to the mvrp ISR. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_clear_mvrp_irq +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_MSVP_TRIPPED, 0x01u); + /* + * Perform a second write to ensure that the first write completed before + * returning from this function. This is to account for posted writes across + * the AHB matrix. The second write ensures that the first write has + * completed and that the interrupt line has been de-asserted by the time + * the function returns. Omitting the second write may result in a delay + * in the de-assertion of the interrupt line going to the RISC-V and a + * re-triggering of the interrupt. + */ + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_MSVP_TRIPPED, 0x01u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_timeout_occured() function reports the occurrence of a timeout + * event. + * + * @param + * Void + * + * @return + * A zero value indicates no watchdog timeout event occurred. A value of 1 + * indicates that a timeout event occurred. + */ +static inline uint32_t +MIV_WDOG_timeout_occured +( + void +) +{ + return (HAL_get_32bit_reg_field(g_this_wdog, WDOGSTAT_TRIGGERED)); +} + +/***************************************************************************//** + * The MIV_WDOG_force_reset() function is used to force an immediate reset + * if the watchdog has already triggered. Writing any value in this condition + * will result in watchdog timeout. + * The time out interrupt WDOG_IRQ will be set to high and watchdog timer + * countdown register updated with watchdog trigger timeout register value. + * If the Watchdog has timed out, a special 16-bit value needs to be written + * to the register to force a reset on CPU_RESETN, 0xDEAD + * Then the Watchdog countdown is reset/updated with the top Watchdog Runtime + * register value. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_force_reset +( + void +) +{ + if (WDOGSTAT_TRIGGERED_MASK == + HAL_get_32bit_reg_field(g_this_wdog, WDOGSTAT_TRIGGERED)) + + { + HAL_set_32bit_reg(g_this_wdog, WDOGFORCE, MIV_WDOG_FORCE_RESET_KEY); + } + + else + { + HAL_set_32bit_reg(g_this_wdog, WDOGFORCE, 0x0u); + } +} + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_WATCHDOG_H_ */ diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h new file mode 100644 index 0000000..2fca983 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h @@ -0,0 +1,122 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP watchdog module driver. This module is delivered as a part of Mi-V + * extended Sub-System(ESS) MIV_ESS. + */ + +#ifndef MIV_WDOG_REGISTERS +#define MIV_WDOG_REGISTERS 1u + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * Refresh register details + */ +#define WDOGRFSH_REG_OFFSET 0x00u + +/* Refresh register bits */ +#define WDOGRFSH_OFFSET 0x00u +#define WDOGRFSH_MASK 0xFFFFFFFFu +#define WDOGRFSH_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Control register details + */ +#define WDOGCNTL_REG_OFFSET 0x04u + +/* Control register next intent msvp bit */ +#define WDOGCNTL_NEXT_INTENT_MSVP_OFFSET 0x04u +#define WDOGCNTL_NEXT_INTENT_MSVP_MASK 0x01u +#define WDOGCNTL_NEXT_INTENT_MSVP_SHIFT 0u + +/* Control register next intent wdog bit */ +#define WDOGCNTL_NEXT_INTENT_WDOG_OFFSET 0x04u +#define WDOGCNTL_NEXT_INTENT_WDOG_MASK 0x02u +#define WDOGCNTL_NEXT_INTENT_WDOG_SHIFT 1u + +/* Control register next enforbidden bit */ +#define WDOGCNTL_NEXT_ENFORBIDDEN_OFFSET 0x04u +#define WDOGCNTL_NEXT_ENFORBIDDEN_MASK 0x10u +#define WDOGCNTL_NEXT_ENFORBIDDEN_SHIFT 4u + +/*------------------------------------------------------------------------------ + * Watchdog status register + */ +#define WDOGSTAT_REG_OFFSET 0x08u + +/* msvp_tripped bit */ +#define WDOGSTAT_MSVP_TRIPPED_OFFSET 0x08u +#define WDOGSTAT_MSVP_TRIPPED_MASK 0x01u +#define WDOGSTAT_MSVP_TRIPPED_SHIFT 0u + +/* WDOG Tripped bit */ +#define WDOGSTAT_WDOG_TRIPPED_OFFSET 0x08u +#define WDOGSTAT_WDOG_TRIPPED_MASK 0x02u +#define WDOGSTAT_WDOG_TRIPPED_SHIFT 1u + +/* Forbidden bit */ +#define WDOGSTAT_FORBIDDEN_OFFSET 0x08u +#define WDOGSTAT_FORBIDDEN_MASK 0x04u +#define WDOGSTAT_FORBIDDEN_SHIFT 2u + +/* Triggered bit */ +#define WDOGSTAT_TRIGGERED_OFFSET 0x08u +#define WDOGSTAT_TRIGGERED_MASK 0x08u +#define WDOGSTAT_TRIGGERED_SHIFT 3u + +/* wdoglocked bit */ +#define WDOGSTAT_WDOGLOCKED_OFFSET 0x08u +#define WDOGSTAT_WDOGLOCKED_MASK 0x10u +#define WDOGSTAT_WDOGLOCKED_SHIFT 4u + +/*------------------------------------------------------------------------------ + * Watchdog runtime register + */ +#define WDOGTIME_REG_OFFSET 0x0Cu + +/* wdogmsvp bit */ +#define WDOGTIME_WDOGVALUE_OFFSET 0x0Cu +#define WDOGTIME_WDOGVALUE_MASK 0xFFFFFFu +#define WDOGTIME_WDOGVALUE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Watchdog MVRP register + */ +#define WDOGMSVP_REG_OFFSET 0x10u + +/* wdogmsvp bit */ +#define WDOGMSVP_OFFSET 0x10u +#define WDOGMSVP_MASK 0xFFFFFFu +#define WDOGMSVP_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Watchdog Trigger Timeout register + */ +#define WDOGTRIG_REG_OFFSET 0x14u + +/* wdogmsvp bit */ +#define WDOGTRIG_WDOGRST_OFFSET 0x14u +#define WDOGTRIG_WDOGRST_MASK 0xFFFFFFu +#define WDOGTRIG_WDOGRST_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Watchdog Force Reset register details + */ +#define WDOGFORCE_REG_OFFSET 0x18u + +/* Refresh register bits */ +#define WDOGFORCE_OFFSET 0x18u +#define WDOGFORCE_MASK 0xFFFFFFFFu +#define WDOGFORCE_SHIFT 0u + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_WATCHDOG_REGS_H_ */ diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/hal/cpu_types.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/hal/cpu_types.h new file mode 100644 index 0000000..ef8ab20 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/hal/cpu_types.h @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file cpu_types.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Type definitions which can be commonly used by the fabric-ip drivers. + * + */ +#ifndef __CPU_TYPES_H +#define __CPU_TYPES_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned int size_t; + +/*------------------------------------------------------------------------------ + * addr_t: address type. + * Used to specify the address of peripherals present in the processor's memory + * map. + */ +typedef unsigned int addr_t; + +/*------------------------------------------------------------------------------ + * psr_t: processor state register. + * Used by HAL_disable_interrupts() and HAL_restore_interrupts() to store the + * processor's state between disabling and restoring interrupts. + */ +typedef unsigned int psr_t; + +#ifdef __cplusplus +} +#endif + +#endif /* CPU_TYPES_H */ + diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/hal/hal.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/hal/hal.h new file mode 100644 index 0000000..7eec17a --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/hal/hal.h @@ -0,0 +1,235 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file hal.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware abstraction layer functions for peripheral register accesses. + * + */ +#ifndef __HAL_H +#define __HAL_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include "cpu_types.h" +#include "hw_reg_access.h" +#include "hal_assert.h" +/***************************************************************************//** + * Enable all interrupts at the processor level. + */ +void HAL_enable_interrupts( void ); + +/***************************************************************************//** + * Disable all interrupts at the processor core level. + * Return the interrupts enable state before disabling occurred so that it can + * later be restored. + */ +psr_t HAL_disable_interrupts( void ); + +/***************************************************************************//** + * Restore the interrupts enable state at the processor core level. + * This function is normally passed the value returned from a previous call to + * HAL_disable_interrupts(). + */ +void HAL_restore_interrupts( psr_t saved_psr ); + +/***************************************************************************//** + */ +#define FIELD_OFFSET(FIELD_NAME) (FIELD_NAME##_OFFSET) +#define FIELD_SHIFT(FIELD_NAME) (FIELD_NAME##_SHIFT) +#define FIELD_MASK(FIELD_NAME) (FIELD_NAME##_MASK) + +/***************************************************************************//** + * The macro HAL_set_32bit_reg() allows writing a 32 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint32_t containing the value to write. + */ +#define HAL_set_32bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_32bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_32bit_reg() is used to read the value of a 32 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint32_t value. + */ +#define HAL_get_32bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_32bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)) )) + +/***************************************************************************//** + * The macro HAL_set_32bit_reg_field() is used to write a field within a + * 32 bits wide register. The field written can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * VALUE: A variable of type uint32_t containing the field value to write. + */ +#define HAL_set_32bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_32bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_32bit_reg_field() is used to read a register field from + * within a 32 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint32_t value. + */ +#define HAL_get_32bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_32bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +/***************************************************************************//** + * The macro HAL_set_16bit_reg() allows writing a 16 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint_fast16_t containing the value to write. + */ +#define HAL_set_16bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_16bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_16bit_reg() is used to read the value of a 16 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint16_t value. + */ +#define HAL_get_16bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_16bit_reg( (BASE_ADDR) + (REG_NAME##_REG_OFFSET) )) + +/***************************************************************************//** + * The macro HAL_set_16bit_reg_field() is used to write a field within a + * 16 bits wide register. The field written can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * VALUE: A variable of type uint16_t containing the field value to write. + */ +#define HAL_set_16bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_16bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_16bit_reg_field() is used to read a register field from + * within a 8 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint16_t value. + */ +#define HAL_get_16bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_16bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +/***************************************************************************//** + * The macro HAL_set_8bit_reg() allows writing a 8 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint_fast8_t containing the value to write. + */ +#define HAL_set_8bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_8bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_8bit_reg() is used to read the value of a 8 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint8_t value. + */ +#define HAL_get_8bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_8bit_reg( (BASE_ADDR) + (REG_NAME##_REG_OFFSET) )) + +/***************************************************************************//** + */ +#define HAL_set_8bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_8bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_8bit_reg_field() is used to read a register field from + * within a 8 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint8_t value. + */ +#define HAL_get_8bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_8bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +#ifdef __cplusplus +} +#endif + +#endif /*HAL_H*/ + diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/hal/hal_assert.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/hal/hal_assert.h new file mode 100644 index 0000000..1e18b54 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/hal/hal_assert.h @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hal_assert.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief HAL assert functions + */ +#ifndef __HAL_ASSERT_HEADER +#define __HAL_ASSERT_HEADER 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Disable assertions if we do not recognize the compiler. */ +#if defined ( __GNUC__ ) +#if defined(NDEBUG) +/***************************************************************************//** + * HAL_ASSERT() is defined out when the NDEBUG symbol is used. + ******************************************************************************/ +#define HAL_ASSERT(CHECK) + +#else + +/***************************************************************************//** + * Default behavior for HAL_ASSERT() macro: + *------------------------------------------------------------------------------ + The behavior is toolchain specific and project setting specific. + ******************************************************************************/ +#define HAL_ASSERT(CHECK)\ + do { \ + if (!(CHECK)) \ + { \ + __asm__ volatile ("ebreak"); \ + }\ + } while(0); + +#endif /* NDEBUG */ +#endif /*__GNUC__*/ + +#ifdef __cplusplus +} +#endif +#endif /* __HAL_ASSERT_HEADER */ + diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/hal/hal_irq.c b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/hal/hal_irq.c new file mode 100644 index 0000000..95a0775 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/hal/hal_irq.c @@ -0,0 +1,45 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hal_irq.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Legacy interrupt control functions for the Microchip driver library + * hardware abstraction layer. + * + */ +#include "hal.h" +#include "miv_rv32_hal/miv_rv32_hal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * + */ +void HAL_enable_interrupts(void) { + MRV_enable_interrupts(); +} + +/*------------------------------------------------------------------------------ + * + */ +psr_t HAL_disable_interrupts(void) { + psr_t psr; + psr = read_csr(mstatus); + MRV_disable_interrupts(); + return(psr); +} + +/*------------------------------------------------------------------------------ + * + */ +void HAL_restore_interrupts(psr_t saved_psr) { + write_csr(mstatus, saved_psr); +} + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/hal/hw_macros.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/hal/hw_macros.h new file mode 100644 index 0000000..189609c --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/hal/hw_macros.h @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hw_macros.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware registers access macros. + * + * THE MACROS DEFINED IN THIS FILE ARE DEPRECATED. DO NOT USE FOR NEW + * DEVELOPMENT. + * + * These macros are used to access peripheral registers. They allow access to + * 8, 16 and 32 bit wide registers. All accesses to peripheral registers should + * be done through these macros in order to ease porting across different + * processors/bus architectures. + * + * Some of these macros also allow access to a specific register field. + * + */ +#ifndef __HW_REGISTER_MACROS_H +#define __HW_REGISTER_MACROS_H 1 +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * 32 bits registers access: + */ +#define HW_get_uint32_reg(BASE_ADDR, REG_OFFSET) (*((uint32_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint32_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint32_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint32_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint32_t) \ + ( \ + (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint32_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint32_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 32 bits memory access: + */ +#define HW_get_uint32(BASE_ADDR) (*((uint32_t volatile *)(BASE_ADDR))) + +#define HW_set_uint32(BASE_ADDR, VALUE) (*((uint32_t volatile *)(BASE_ADDR)) = (VALUE)) + +/*------------------------------------------------------------------------------ + * 16 bits registers access: + */ +#define HW_get_uint16_reg(BASE_ADDR, REG_OFFSET) (*((uint16_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint16_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint16_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint16_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint16_t) \ + ( \ + (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint16_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint16_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 8 bits registers access: + */ +#define HW_get_uint8_reg(BASE_ADDR, REG_OFFSET) (*((uint8_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint8_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint8_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint8_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint8_t) \ + ( \ + (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint8_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint8_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 8 bits memory access: + */ +#define HW_get_uint8(BASE_ADDR) (*((uint8_t volatile *)(BASE_ADDR))) + +#define HW_set_uint8(BASE_ADDR, VALUE) (*((uint8_t volatile *)(BASE_ADDR)) = (VALUE)) + +#ifdef __cplusplus +extern "C" { +#endif + +#endif /* __HW_REGISTER_MACROS_H */ + diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/hal/hw_reg_access.S b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/hal/hw_reg_access.S new file mode 100644 index 0000000..dd29223 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/hal/hw_reg_access.S @@ -0,0 +1,215 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hw_reg_access.S + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware registers access functions. + * The implementation of these function is platform and toolchain specific. + * The functions declared here are implemented using assembler as part of the + * processor/toolchain specific HAL. This implementation is for the combination + * of the 32 bit RISC-V processors and GNU tool chain. + * + */ + +.section .text + .globl HW_set_32bit_reg + .globl HW_get_32bit_reg + .globl HW_set_32bit_reg_field + .globl HW_get_32bit_reg_field + .globl HW_set_16bit_reg + .globl HW_get_16bit_reg + .globl HW_set_16bit_reg_field + .globl HW_get_16bit_reg_field + .globl HW_set_8bit_reg + .globl HW_get_8bit_reg + .globl HW_set_8bit_reg_field + .globl HW_get_8bit_reg_field + + +/***************************************************************************//** + * HW_set_32bit_reg is used to write the content of a 32 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint32_t value + */ +HW_set_32bit_reg: + sw a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_32bit_reg is used to read the content of a 32 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + + * @return 32 bits value read from the peripheral register. + */ +HW_get_32bit_reg: + lw a0, 0(a0) + ret + +/***************************************************************************//** + * HW_set_32bit_reg_field is used to set the content of a field in a 32 bits + * wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint32_t mask + * a3: uint32_t value + */ +HW_set_32bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lw t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sw t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_32bit_reg_field is used to read the content of a field out of a + * 32 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint32_t mask + * + * @return 32 bits value containing the register field value specified + * as parameter. + */ +HW_get_32bit_reg_field: + lw a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +/***************************************************************************//** + * HW_set_16bit_reg is used to write the content of a 16 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint_fast16_t value + */ +HW_set_16bit_reg: + sh a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_16bit_reg is used to read the content of a 16 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + + * @return 16 bits value read from the peripheral register. + */ +HW_get_16bit_reg: + lh a0, (a0) + ret + +/***************************************************************************//** + * HW_set_16bit_reg_field is used to set the content of a field in a 16 bits + * wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast16_t mask + * a3: uint_fast16_t value + * @param value Value to be written in the specified field. + */ +HW_set_16bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lh t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sh t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_16bit_reg_field is used to read the content of a field from a + * 16 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast16_t mask + * + * @return 16 bits value containing the register field value specified + * as parameter. + */ +HW_get_16bit_reg_field: + lh a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +/***************************************************************************//** + * HW_set_8bit_reg is used to write the content of a 8 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint_fast8_t value + */ +HW_set_8bit_reg: + sb a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_8bit_reg is used to read the content of a 8 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + + * @return 8 bits value read from the peripheral register. + */ +HW_get_8bit_reg: + lb a0, 0(a0) + ret + +/***************************************************************************//** + * HW_set_8bit_reg_field is used to set the content of a field in a 8 bits + * wide peripheral register. + * + * a0: addr_t reg_addr, + * a1: int_fast8_t shift + * a2: uint_fast8_t mask + * a3: uint_fast8_t value + */ +HW_set_8bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lb t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sb t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_8bit_reg_field is used to read the content of a field from a + * 8 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast8_t mask + * + * @return 8 bits value containing the register field value specified + * as parameter. + */ +HW_get_8bit_reg_field: + lb a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +.end diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/hal/hw_reg_access.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/hal/hw_reg_access.h new file mode 100644 index 0000000..1a24309 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/hal/hw_reg_access.h @@ -0,0 +1,239 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hw_reg_access.S + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware registers access functions. + * The implementation of these function is platform and tool-chain specific. + * The functions declared here are implemented using assembler as part of the + * processor/tool-chain specific HAL. This implementation is for the combination + * of the 32 bit RISC-V processors and GNU tool chain. + * + */ +#ifndef __HW_REG_ACCESS +#define __HW_REG_ACCESS +#ifdef __cplusplus +extern "C" { +#endif + +#include "cpu_types.h" +/***************************************************************************//** + * HW_set_32bit_reg is used to write the content of a 32 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_32bit_reg +( + addr_t reg_addr, + uint32_t value +); + +/***************************************************************************//** + * HW_get_32bit_reg is used to read the content of a 32 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 32 bits value read from the peripheral register. + */ +uint32_t +HW_get_32bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_32bit_reg_field is used to set the content of a field in a 32 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void +HW_set_32bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint32_t mask, + uint32_t value +); + +/***************************************************************************//** + * HW_get_32bit_reg_field is used to read the content of a field out of a + * 32 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 32 bits value containing the register field value specified + * as parameter. + */ +uint32_t +HW_get_32bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint32_t mask +); + +/***************************************************************************//** + * HW_set_16bit_reg is used to write the content of a 16 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_16bit_reg +( + addr_t reg_addr, + uint_fast16_t value +); + +/***************************************************************************//** + * HW_get_16bit_reg is used to read the content of a 16 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 16 bits value read from the peripheral register. + */ +uint16_t +HW_get_16bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_16bit_reg_field is used to set the content of a field in a 16 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void HW_set_16bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast16_t mask, + uint_fast16_t value +); + +/***************************************************************************//** + * HW_get_16bit_reg_field is used to read the content of a field from a + * 16 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 16 bits value containing the register field value specified + * as parameter. + */ +uint16_t HW_get_16bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast16_t mask +); + +/***************************************************************************//** + * HW_set_8bit_reg is used to write the content of a 8 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_8bit_reg +( + addr_t reg_addr, + uint_fast8_t value +); + +/***************************************************************************//** + * HW_get_8bit_reg is used to read the content of a 8 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 8 bits value read from the peripheral register. + */ +uint8_t +HW_get_8bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_8bit_reg_field is used to set the content of a field in a 8 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void HW_set_8bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast8_t mask, + uint_fast8_t value +); + +/***************************************************************************//** + * HW_get_8bit_reg_field is used to read the content of a field from a + * 8 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 8 bits value containing the register field value specified + * as parameter. + */ +uint8_t HW_get_8bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast8_t mask +); + +#ifdef __cplusplus +} +#endif + +#endif /* __HW_REG_ACCESS */ + diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld new file mode 100644 index 0000000..474eb43 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld @@ -0,0 +1,154 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-execute-in-place.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * image executing from a one address space whereas the data, sdata and stack + * sections are placed in another address space. This could be used in cases such + * as: + * 1) When using MIV_RV32, the reset vector points to the LSRAM at address + * 0x80000000 and the data, sdata, bss and stack sections are placed in the + * TCM region. + * + * 2) Executing from a Non Volatile memory. The actual memory will depend on + * the FPGA platform. For exameple, it could be the eNVM on SmartFusion2, + * Igloo2 or on-board non-volatile memory which supports code execution. + * + * NOTE: Modify the memory section addresses and the sizes according to your + * Libero design. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + + +MEMORY +{ + rom (rx) : ORIGIN = 0x80000000, LENGTH = 16k + ram (rwx) : ORIGIN = 0x80004000, LENGTH = 16k +} + +STACK_SIZE = 1k; /* needs to be calculated for your application */ +HEAP_SIZE = 1k; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > rom + + .text : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.text.entry))) + . = ALIGN(0x10); + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } >rom + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } >ram AT>rom + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } >ram AT>rom + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram +} + diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv-rv32-ram.ld b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv-rv32-ram.ld new file mode 100644 index 0000000..53076a0 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv-rv32-ram.ld @@ -0,0 +1,150 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-ram.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * debug image executing in SRAM. + * + * This linker script assumes that a RAM is connected at on Mi-V soft processor + * memory space pointed by the reset vector address. + * + * NOTE : Modify the memory section address and the size according to your + * Libero design. + * For example: + * 1) If you want to download and step debug at a different RAM memory address in + * your design (For example TCM base address) than the one provided in this file. + * 2) The MIV_RV32, when used with MIV_ESS IP, provides ways to copy the executable + * HEX file from external Non-Volatile memory into the TCM at reset. In this + * case your executable must be linked to the TCM address. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +MEMORY +{ + ram (rwx) : ORIGIN = 0x80000000, LENGTH = 32k +} + +STACK_SIZE = 2k; /* needs to be calculated for your application */ +HEAP_SIZE = 1k; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > ram + + .text : ALIGN(0x10) + { + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } > ram + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } > ram + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } > ram + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram +} + diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv_rv32_assert.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv_rv32_assert.h new file mode 100644 index 0000000..b3912ed --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv_rv32_assert.h @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * MIV_RV32 HAL Embedded Software + * + */ +#ifndef MIV_RV32_ASSERT_HEADER +#define MIV_RV32_ASSERT_HEADER + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + * ASSERT() implementation. + ******************************************************************************/ +/* Disable assertions if we do not recognize the compiler. */ +#if defined ( __GNUC__ ) +#if defined(NDEBUG) +#define ASSERT(CHECK) +#else +#define ASSERT(CHECK)\ + do { \ + if (!(CHECK)) \ + { \ + __asm__ volatile ("ebreak"); \ + }\ + } while(0); + +#endif /* NDEBUG check */ +#endif /* compiler check */ + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_RV32_ASSERT_HEADER */ + diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv_rv32_entry.S b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv_rv32_entry.S new file mode 100644 index 0000000..0ea3172 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv_rv32_entry.S @@ -0,0 +1,590 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_entry.S + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor vectors, trap handling and startup code. + * + */ +#ifndef ENTRY_S +#define ENTRY_S + +#define A_EXTENSION_MASK 0x00000001u +#define MTVEC_MODE_BIT_MASK 0x00000003u +#define MTVEC_VECTORED_MODE_VAL 0x00000001u + +#define MTIMEH_ADDR 0x200BFFCu + + +#if __riscv_xlen == 64 +# define LREG ld +# define SREG sd +# define REGBYTES 8 +#else +# define LREG lw +# define SREG sw +# define REGBYTES 4 +#endif + +#if defined(MIV_FP_CONTEXT_SAVE) && defined(__riscv_flen) +#define SP_SHIFT_OFFSET 64 +#else +#define SP_SHIFT_OFFSET 32 +#endif + +.macro STORE_CONTEXT + addi sp, sp, -SP_SHIFT_OFFSET*REGBYTES + SREG x1, 0 * REGBYTES(sp) + SREG x1, 0 * REGBYTES(sp) + SREG x2, 1 * REGBYTES(sp) + SREG x3, 2 * REGBYTES(sp) + SREG x4, 3 * REGBYTES(sp) + SREG x5, 4 * REGBYTES(sp) + SREG x6, 5 * REGBYTES(sp) + SREG x7, 6 * REGBYTES(sp) + SREG x8, 7 * REGBYTES(sp) + SREG x9, 8 * REGBYTES(sp) + SREG x10, 9 * REGBYTES(sp) + SREG x11, 10 * REGBYTES(sp) + SREG x12, 11 * REGBYTES(sp) + SREG x13, 12 * REGBYTES(sp) + SREG x14, 13 * REGBYTES(sp) + SREG x15, 14 * REGBYTES(sp) + SREG x16, 15 * REGBYTES(sp) + SREG x17, 16 * REGBYTES(sp) + SREG x18, 17 * REGBYTES(sp) + SREG x19, 18 * REGBYTES(sp) + SREG x20, 19 * REGBYTES(sp) + SREG x21, 20 * REGBYTES(sp) + SREG x22, 21 * REGBYTES(sp) + SREG x23, 22 * REGBYTES(sp) + SREG x24, 23 * REGBYTES(sp) + SREG x25, 24 * REGBYTES(sp) + SREG x26, 25 * REGBYTES(sp) + SREG x27, 26 * REGBYTES(sp) + SREG x28, 27 * REGBYTES(sp) + SREG x29, 28 * REGBYTES(sp) + SREG x30, 29 * REGBYTES(sp) + SREG x31, 30 * REGBYTES(sp) + + #ifdef __riscv_flen + #ifdef MIV_FP_CONTEXT_SAVE + fsw f0, 31*REGBYTES(sp) + fsw f1, 32*REGBYTES(sp) + fsw f2, 33*REGBYTES(sp) + fsw f3, 34*REGBYTES(sp) + fsw f4, 35*REGBYTES(sp) + fsw f5, 36*REGBYTES(sp) + fsw f6, 37*REGBYTES(sp) + fsw f7, 38*REGBYTES(sp) + fsw f8, 39*REGBYTES(sp) + fsw f9, 40*REGBYTES(sp) + fsw f10, 41*REGBYTES(sp) + fsw f11, 42*REGBYTES(sp) + fsw f12, 43*REGBYTES(sp) + fsw f13, 44*REGBYTES(sp) + fsw f14, 45*REGBYTES(sp) + fsw f15, 46*REGBYTES(sp) + fsw f16, 47*REGBYTES(sp) + fsw f17, 48*REGBYTES(sp) + fsw f18, 49*REGBYTES(sp) + fsw f19, 50*REGBYTES(sp) + fsw f20, 51*REGBYTES(sp) + fsw f21, 52*REGBYTES(sp) + fsw f22, 53*REGBYTES(sp) + fsw f23, 54*REGBYTES(sp) + fsw f24, 55*REGBYTES(sp) + fsw f25, 56*REGBYTES(sp) + fsw f26, 57*REGBYTES(sp) + fsw f27, 58*REGBYTES(sp) + fsw f28, 59*REGBYTES(sp) + fsw f29, 60*REGBYTES(sp) + fsw f30, 61*REGBYTES(sp) + fsw f31, 62*REGBYTES(sp) + #endif /* __riscv_flen */ + #endif /* MIV_FP_CONTEXT_SAVE */ +.endm + + .section .entry, "ax" + .globl _start + +_start: + j handle_reset + +/* Some of the Mi-V soft IP cores support compressed 'C' extension. If the Mi-V + core in your design doesn't support 'C' extension and you enable 'C' extension + in firmware project compiler options, then it would result in a trap. For this + case, we are avoiding compressed instruction here so you can put a breakpoint + at the jump and you can at least look at mcause, mepc and get some hints + about the crash. */ +trap_entry: +.option push +.option norvc +j generic_trap_handler +.option pop + .word 0 + .word 0 + +sw_trap_entry: + j vector_sw_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + +tmr_trap_entry: + j vector_tmr_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + +ext_trap_entry: + j vector_ext_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + .word 0 + +#ifndef MIV_LEGACY_RV32 +MGEUI_trap_entry: + j vector_MGEUI_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MGECI_trap_entry: + j vector_MGECI_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + .word 0 + +#ifndef MIV_RV32_V3_0 +MSYS_MIE22_trap_entry: +#ifndef MIV_RV32_V3_0 + j vector_SUBSYSR_IRQHandler +#endif /*MIV_RV32_V3_0*/ +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE23_trap_entry: + j vector_SUBSYS_IRQHandler +#ifdef __riscv_compressed + .2byte 0 +#endif +#endif /*MIV_RV32_V3_0*/ + +MSYS_MIE24_trap_entry: + j vector_MSYS_EI0_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE25_trap_entry: + j vector_MSYS_EI1_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE26_trap_entry: + j vector_MSYS_EI2_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE27_trap_entry: + j vector_MSYS_EI3_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE28_trap_entry: + j vector_MSYS_EI4_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE29_trap_entry: + j vector_MSYS_EI5_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE30_trap_entry: +#ifndef MIV_RV32_V3_0 + j vector_MSYS_EI6_trap_handler +#else + j vector_SUBSYS_IRQHandler +#endif +#ifdef __riscv_compressed + .2byte 0 +#endif + +#ifndef MIV_RV32_V3_0 +MSYS_MIE31_trap_entry: + j vector_MSYS_EI7_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif +#endif /* MIV_RV32_V3_0 */ +#endif /* MIV_LEGACY_RV32 */ + +.align 4 +generic_trap_handler: + STORE_CONTEXT + csrr a0, mcause + csrr a1, mepc + jal handle_trap + j generic_restore + +vector_sw_trap_handler: + STORE_CONTEXT + jal handle_m_soft_interrupt + j generic_restore + +vector_tmr_trap_handler: + STORE_CONTEXT + jal handle_m_timer_interrupt + j generic_restore + +vector_ext_trap_handler: + STORE_CONTEXT +#ifdef MIV_LEGACY_RV32 + jal handle_m_ext_interrupt +#else + jal External_IRQHandler +#endif /* MIV_LEGACY_RV32 */ + j generic_restore + +#ifndef MIV_LEGACY_RV32 +vector_MGEUI_trap_handler: + STORE_CONTEXT + jal MGEUI_IRQHandler + j generic_restore + +vector_MGECI_trap_handler: + STORE_CONTEXT + jal MGECI_IRQHandler + j generic_restore + +vector_MSYS_EI0_trap_handler: + STORE_CONTEXT + jal MSYS_EI0_IRQHandler + j generic_restore + +vector_MSYS_EI1_trap_handler: + STORE_CONTEXT + jal MSYS_EI1_IRQHandler + j generic_restore + +vector_MSYS_EI2_trap_handler: + STORE_CONTEXT + jal MSYS_EI2_IRQHandler + j generic_restore + +vector_MSYS_EI3_trap_handler: + STORE_CONTEXT + jal MSYS_EI3_IRQHandler + j generic_restore + +vector_MSYS_EI4_trap_handler: + STORE_CONTEXT + jal MSYS_EI4_IRQHandler + j generic_restore + +vector_MSYS_EI5_trap_handler: + STORE_CONTEXT + jal MSYS_EI5_IRQHandler + j generic_restore + +vector_SUBSYS_IRQHandler: + STORE_CONTEXT + jal SUBSYS_IRQHandler + j generic_restore + +#ifndef MIV_RV32_V3_0 +vector_MSYS_EI6_trap_handler: + STORE_CONTEXT + jal MSYS_EI6_IRQHandler + j generic_restore + +vector_MSYS_EI7_trap_handler: + STORE_CONTEXT + jal MSYS_EI7_IRQHandler + j generic_restore + + +vector_SUBSYSR_IRQHandler: + STORE_CONTEXT + jal SUBSYSR_IRQHandler + j generic_restore + +#endif /*MIV_RV32_V3_0*/ +#endif /* MIV_LEGACY_RV32 */ + +generic_restore: + LREG x1, 0 * REGBYTES(sp) + LREG x2, 1 * REGBYTES(sp) + LREG x3, 2 * REGBYTES(sp) + LREG x4, 3 * REGBYTES(sp) + LREG x5, 4 * REGBYTES(sp) + LREG x6, 5 * REGBYTES(sp) + LREG x7, 6 * REGBYTES(sp) + LREG x8, 7 * REGBYTES(sp) + LREG x9, 8 * REGBYTES(sp) + LREG x10, 9 * REGBYTES(sp) + LREG x11, 10 * REGBYTES(sp) + LREG x12, 11 * REGBYTES(sp) + LREG x13, 12 * REGBYTES(sp) + LREG x14, 13 * REGBYTES(sp) + LREG x15, 14 * REGBYTES(sp) + LREG x16, 15 * REGBYTES(sp) + LREG x17, 16 * REGBYTES(sp) + LREG x18, 17 * REGBYTES(sp) + LREG x19, 18 * REGBYTES(sp) + LREG x20, 19 * REGBYTES(sp) + LREG x21, 20 * REGBYTES(sp) + LREG x22, 21 * REGBYTES(sp) + LREG x23, 22 * REGBYTES(sp) + LREG x24, 23 * REGBYTES(sp) + LREG x25, 24 * REGBYTES(sp) + LREG x26, 25 * REGBYTES(sp) + LREG x27, 26 * REGBYTES(sp) + LREG x28, 27 * REGBYTES(sp) + LREG x29, 28 * REGBYTES(sp) + LREG x30, 29 * REGBYTES(sp) + LREG x31, 30 * REGBYTES(sp) + + #ifdef __riscv_flen + #ifdef MIV_FP_CONTEXT_SAVE + flw f0, 0 * REGBYTES(sp) + flw f1, 1 * REGBYTES(sp) + flw f2, 2 * REGBYTES(sp) + flw f3, 3 * REGBYTES(sp) + flw f4, 4 * REGBYTES(sp) + flw f5, 5 * REGBYTES(sp) + flw f6, 6 * REGBYTES(sp) + flw f7, 7 * REGBYTES(sp) + flw f8, 8 * REGBYTES(sp) + flw f9, 9 * REGBYTES(sp) + flw f10, 10 * REGBYTES(sp) + flw f11, 11 * REGBYTES(sp) + flw f12, 12 * REGBYTES(sp) + flw f13, 13 * REGBYTES(sp) + flw f14, 14 * REGBYTES(sp) + flw f15, 15 * REGBYTES(sp) + flw f16, 16 * REGBYTES(sp) + flw f17, 17 * REGBYTES(sp) + flw f18, 18 * REGBYTES(sp) + flw f19, 19 * REGBYTES(sp) + flw f20, 20 * REGBYTES(sp) + flw f21, 21 * REGBYTES(sp) + flw f22, 22 * REGBYTES(sp) + flw f23, 23 * REGBYTES(sp) + flw f24, 24 * REGBYTES(sp) + flw f25, 25 * REGBYTES(sp) + flw f26, 26 * REGBYTES(sp) + flw f27, 27 * REGBYTES(sp) + flw f28, 28 * REGBYTES(sp) + flw f29, 29 * REGBYTES(sp) + flw f30, 30 * REGBYTES(sp) + flw f31, 31 * REGBYTES(sp) + #endif /* __riscv_flen */ + #endif /* MIV_FP_CONTEXT_SAVE */ + + addi sp, sp, SP_SHIFT_OFFSET*REGBYTES + mret + + .section .text, "ax" +handle_reset: +/* Ensure instructions are not relaxed, since gp is not yet set */ +.option push +.option norelax + +#ifndef MIV_RV32_V3_0 + csrwi mstatus, 0 + csrwi mie, 0 + la ra, _start + +/* Clearnig this to be on safer side as RTL doesnt seem to clear it on reset. */ +#ifndef MIV_LEGACY_RV32 + li t0, MTIMEH_ADDR + sw x0, 0(t0) +#endif + + csrr t0, misa + andi t0, t0, A_EXTENSION_MASK + bnez t0, ima_cores_setup /* Jump to IMA core handling */ + + +/* For MIV_RV32 cores the mtvec exception base address is fixed at Reset vector + address + 0x4. Check the mode bits. */ +/* In the MIV_RV32 v3.1, the MTVEC exception base address is WARL, and can be + configured by the user at runtime */ + + csrr t0, mtvec + andi t0, t0, MTVEC_MODE_BIT_MASK + li t1, MTVEC_VECTORED_MODE_VAL + bne t0, t1, ima_cores_setup /* Jump to IMA core handling */ + + /* When mode = 1 => this is vectored mode on MIV_RV32 core. + Verify that the trap_handler address matches the configuration in MTVEC */ + csrr t0, mtvec + andi t0, t0, 0xFFFFFFFC + la t1, trap_entry + bne t0, t1, vector_address_not_matching + j generic_reset_handling + +#else /* MIV_RV32_V3_0 */ + +/* Clearnig this to be on safer side as RTL doesnt seem to clear it on reset. */ +#ifndef MIV_LEGACY_RV32 + li t0, MTIMEH_ADDR + sw x0, 0(t0) +#endif + +/* In the MIV_RV32 v3.1, the MTVEC exception base address is WARL, and can be + configured by the user at runtime */ + csrr t0, mtvec + andi t0, t0, MTVEC_MODE_BIT_MASK + li t1, MTVEC_VECTORED_MODE_VAL + bne t0, t1, ima_cores_setup /* Jump to IMA core handling */ + +/* When mode = 1 => this is vectored mode on MIV_RV32 core. + Verify that the trap_handler address matches the configuration in MTVEC */ + csrr t0, mtvec + andi t0, t0, 0xFFFFFFFC + la t1, trap_entry + bne t0, t1, vector_address_not_matching + j generic_reset_handling +#endif /*MIV_RV32_V3_0*/ + +ima_cores_setup: + la t0, trap_entry + +#ifdef MIV_LEGACY_RV32_VECTORED_INTERRUPTS + addi t0, t0, 0x01 /* Set the mode bit for IMA cores. + For both MIV_RV32 v3.1 and v3.0 cores this is done by configurator. */ +#endif + csrw mtvec, t0 + +generic_reset_handling: +/* Copy sdata section first so that the gp is set and linker relaxation can be + used */ + la a4, __sdata_load + la a5, __sdata_start + la a6, __sdata_end + beq a4, a5, 1f /* Exit if source and dest are same */ + beq a5, a6, 1f /* Exit if section start and end addresses are same */ + call block_copy + +1: + /* initialize global pointer */ + la gp, __global_pointer$ + +.option pop + +/* Floating point support configuration */ +#ifdef __riscv_flen + csrr t0, mstatus + lui t1, 0xffffa + addi t1, t1, -1 + and t0, t0, t1 + lui t1, 0x4 + or t1, t0, t1 + csrw mstatus, t1 + + lui t0, 0x0 + fscsr t0 +#endif + call initializations + /* Initialize stack pointer */ + la sp, __stack_top + + /* Jump into C code */ + j _init + +/* Error: trap_entry is not at the expected address of reset_vector+mtvec offset + as configured in the MIV_RV32 core vectored mode */ +vector_address_not_matching: + ebreak + +initializations: +/* Initialize the .bss section */ + mv t0, ra /* Store ra for future use */ + la a5, __bss_start + la a6, __bss_end + beq a5, a6, 1f /* Section start and end address are the same */ + call zeroize_block + +1: +/* Initialize the .sbss section */ + la a5, __sbss_start + la a6, __sbss_end + beq a5, a6, 1f /* Section start and end address are the same */ + call zeroize_block + +/* Clear heap */ + la a5, __heap_start + la a6, __heap_end + beq a5, a6, 1f /* Section start and end address are the same */ + call zeroize_block + +1: +/* Copy data section */ + la a4, __data_load + la a5, __data_start + la a6, __data_end + beq a4, a5, 1f /* Exit early if source and dest are same */ + beq a5, a6, 1f /* Section start and end addresses are the same */ + call block_copy + +1: + mv ra, t0 /* Retrieve ra */ + ret + +zeroize_block: + bltu a6, a5, block_copy_error /* Error. End address is less than start */ + or a7, a6, a5 /* Check if start or end is unalined */ + andi a7, a7, 0x03u + bgtz a7, block_copy_error /* Unaligned addresses error*/ +zeroize_loop: + sw x0, 0(a5) + add a5, a5, __SIZEOF_POINTER__ + blt a5, a6, zeroize_loop + ret + +block_copy: + bltu a6, a5, block_copy_error /* Error. End address is less than start */ + or a7, a6, a5 /* Check if start or end is unalined */ + andi a7, a7, 0x03u + bgtz a7, block_copy_error /* Unaligned addresses error*/ +block_copy_loop: + lw a7, 0(a4) + sw a7, 0(a5) + addi a5, a5, 0x04 + addi a4, a4, 0x04 + blt a5, a6, block_copy_loop + j block_copy_exit + +block_copy_error: + j block_copy_error + +block_copy_exit: + ret + +#endif /*ENTRY_S*/ diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv_rv32_hal.c b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv_rv32_hal.c new file mode 100644 index 0000000..a112821 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv_rv32_hal.c @@ -0,0 +1,410 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_hal.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Implementation of Hardware Abstraction Layer for Mi-V soft processors + * + */ +#include +#include "miv_rv32_hal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SUCCESS 0U +#define ERROR 1U +#define MASK_32BIT 0xFFFFFFFFu + +/*------------------------------------------------------------------------------ + * Write in a sequence recommended by privileged spec to avoid spurious + * interrupts + + # New comparand is in a1:a0. + li t0, -1 + sw t0, mtimecmp # No smaller than old value. + sw a1, mtimecmp+4 # No smaller than new value. + sw a0, mtimecmp # New value. + */ +#ifndef MIV_RV32_EXT_TIMECMP +#define WRITE_MTIMECMP(value) MTIMECMPH = MASK_32BIT; \ + MTIMECMP = value & MASK_32BIT;\ + MTIMECMPH = (value >> 32u) & MASK_32BIT; +#else +#define WRITE_MTIMECMP(value) +#endif + +#ifndef MIV_RV32_EXT_TIMER +#define WRITE_MTIME(value) MTIME = value & MASK_32BIT;\ + MTIMEH = (value >> 32u) & MASK_32BIT; +#else +#define WRITE_MTIME(value) +#endif + +extern void Software_IRQHandler(void); + +#ifdef MIV_LEGACY_RV32 +#define MTIME_PRESCALER 100UL +/*------------------------------------------------------------------------------ + * + */ +uint8_t Invalid_IRQHandler(void); +uint8_t External_1_IRQHandler(void); +uint8_t External_2_IRQHandler(void); +uint8_t External_3_IRQHandler(void); +uint8_t External_4_IRQHandler(void); +uint8_t External_5_IRQHandler(void); +uint8_t External_6_IRQHandler(void); +uint8_t External_7_IRQHandler(void); +uint8_t External_8_IRQHandler(void); +uint8_t External_9_IRQHandler(void); +uint8_t External_10_IRQHandler(void); +uint8_t External_11_IRQHandler(void); +uint8_t External_12_IRQHandler(void); +uint8_t External_13_IRQHandler(void); +uint8_t External_14_IRQHandler(void); +uint8_t External_15_IRQHandler(void); +uint8_t External_16_IRQHandler(void); +uint8_t External_17_IRQHandler(void); +uint8_t External_18_IRQHandler(void); +uint8_t External_19_IRQHandler(void); +uint8_t External_20_IRQHandler(void); +uint8_t External_21_IRQHandler(void); +uint8_t External_22_IRQHandler(void); +uint8_t External_23_IRQHandler(void); +uint8_t External_24_IRQHandler(void); +uint8_t External_25_IRQHandler(void); +uint8_t External_26_IRQHandler(void); +uint8_t External_27_IRQHandler(void); +uint8_t External_28_IRQHandler(void); +uint8_t External_29_IRQHandler(void); +uint8_t External_30_IRQHandler(void); +uint8_t External_31_IRQHandler(void); + + +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for external interrupts. + */ +uint8_t (* const mrv_ext_irq_handler_table[32])(void) = +{ + + Invalid_IRQHandler, + External_1_IRQHandler, + External_2_IRQHandler, + External_3_IRQHandler, + External_4_IRQHandler, + External_5_IRQHandler, + External_6_IRQHandler, + External_7_IRQHandler, + External_8_IRQHandler, + External_9_IRQHandler, + External_10_IRQHandler, + External_11_IRQHandler, + External_12_IRQHandler, + External_13_IRQHandler, + External_14_IRQHandler, + External_15_IRQHandler, + External_16_IRQHandler, + External_17_IRQHandler, + External_18_IRQHandler, + External_19_IRQHandler, + External_20_IRQHandler, + External_21_IRQHandler, + External_22_IRQHandler, + External_23_IRQHandler, + External_24_IRQHandler, + External_25_IRQHandler, + External_26_IRQHandler, + External_27_IRQHandler, + External_28_IRQHandler, + External_29_IRQHandler, + External_30_IRQHandler, + External_31_IRQHandler +}; + +#else +/*------------------------------------------------------------------------------ + * Interrupt handlers as mapped into the MIE register of the MIV_RV32 + */ +extern void Reserved_IRQHandler(void); +extern void External_IRQHandler(void); +extern void MGEUI_IRQHandler(void); +extern void MGECI_IRQHandler(void); +extern void MSYS_EI0_IRQHandler(void); +extern void MSYS_EI1_IRQHandler(void); +extern void MSYS_EI2_IRQHandler(void); +extern void MSYS_EI3_IRQHandler(void); +extern void MSYS_EI4_IRQHandler(void); +extern void MSYS_EI5_IRQHandler(void); +extern void SUBSYS_IRQHandler(void); + +#ifndef MIV_RV32_V3_0 /*For MIV_RV32 v3.1*/ +extern void MSYS_EI6_IRQHandler(void); +extern void MSYS_EI7_IRQHandler(void); +extern void SUBSYSR_IRQHandler(void); // @suppress("Unused function declaration") +#endif /*MIV_RV32_V3_0*/ + +#endif /* MIV_LEGACY_RV32 */ + +/*------------------------------------------------------------------------------ + * Increment value for the mtimecmp register in order to achieve a system tick + * interrupt as specified through the MRV_systick_config() function. + */ +static uint64_t g_systick_increment = 0U; +static uint64_t g_systick_cmp_value = 0U; + +/*------------------------------------------------------------------------------ + * Configure the machine timer to generate an interrupt. + */ +uint32_t MRV_systick_config(uint64_t ticks) +{ + uint32_t ret_val = ERROR; + uint64_t remainder = ticks; + g_systick_increment = 0U; + g_systick_cmp_value = 0U; + + while (remainder >= MTIME_PRESCALER) + { + remainder -= MTIME_PRESCALER; + g_systick_increment++; + } + + g_systick_cmp_value = g_systick_increment + MRV_read_mtime(); + + if (g_systick_increment > 0U) + { + WRITE_MTIMECMP(g_systick_cmp_value); + set_csr(mie, MIP_MTIP); + MRV_enable_interrupts(); + ret_val = SUCCESS; + } + + return ret_val; +} + +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for machine timer interrupts. + */ +void handle_m_timer_interrupt(void) +{ + clear_csr(mie, MIP_MTIP); + + uint64_t mtime_at_irq = MRV_read_mtime(); + +#ifndef NDEBUG + static volatile uint32_t d_tick = 0u; +#endif + + while(g_systick_cmp_value < (mtime_at_irq + MTIME_DELTA)) { + g_systick_cmp_value = g_systick_cmp_value + g_systick_increment; + +#ifndef NDEBUG + d_tick += 1; +#endif + } +/***************************************************************************//** + /* + * Note: If d_tick > 1 it means, that a system timer interrupt has been + * missed. + * Please ensure that interrupt handlers are as short as possible to prevent + * them stopping other interrupts from being handled. For example, if a + * system timer interrupt occurs during a software interrupt, the system + * timer interrupt will not be handled until the software interrupt handling + * is complete. If the software interrupt handling time is more than one + * systick interval, it will result in d_tick > 1. + * If you are running the program using the debugger and halt the CPU at a + * breakpoint, MTIME will continue to increment and interrupts will be + * missed; resulting in d_tick > 1. + */ + + WRITE_MTIMECMP(g_systick_cmp_value); + + SysTick_Handler(); + + set_csr(mie, MIP_MTIP); +} + +void handle_m_soft_interrupt(void) +{ + Software_IRQHandler(); + MRV_clear_soft_irq(); +} +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for software interrupts. + */ +#ifdef MIV_LEGACY_RV32 +void handle_m_ext_interrupt(void) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; + uint8_t disable = EXT_IRQ_KEEP_ENABLED; + + if (0u !=int_num) + { + disable = mrv_ext_irq_handler_table[int_num](); + + PLIC->TARGET[hart_id].CLAIM_COMPLETE = int_num; + + if(EXT_IRQ_DISABLE == disable) + { + MRV_PLIC_disable_irq((IRQn_Type)int_num); + } + } +} +#else + +/*------------------------------------------------------------------------------ + * MSYS local interrupts table + */ +void (* const local_irq_handler_table[16])(void) = +{ +#ifndef MIV_RV32_V3_0 + MGEUI_IRQHandler, + MGECI_IRQHandler, + SUBSYS_IRQHandler, + SUBSYSR_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + MSYS_EI0_IRQHandler, + MSYS_EI1_IRQHandler, + MSYS_EI2_IRQHandler, + MSYS_EI3_IRQHandler, + MSYS_EI4_IRQHandler, + MSYS_EI5_IRQHandler, + MSYS_EI6_IRQHandler, + MSYS_EI7_IRQHandler +#else + MGEUI_IRQHandler, + MGECI_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + MSYS_EI0_IRQHandler, + MSYS_EI1_IRQHandler, + MSYS_EI2_IRQHandler, + MSYS_EI3_IRQHandler, + MSYS_EI4_IRQHandler, + MSYS_EI5_IRQHandler, + SUBSYS_IRQHandler, + Reserved_IRQHandler, +#endif +}; + +/*------------------------------------------------------------------------------ + * Jump to interrupt table containing local interrupts + */ +void handle_local_ei_interrupts(uint8_t irq_no) +{ + uint64_t mhart_id = read_csr(mhartid); + ASSERT(irq_no <= MIV_LOCAL_IRQ_MAX) + ASSERT(irq_no >= MIV_LOCAL_IRQ_MIN) + + uint8_t ei_no = (uint8_t)(irq_no - MIV_LOCAL_IRQ_MIN); + (*local_irq_handler_table[ei_no])(); +} +#endif /* MIV_LEGACY_RV32 */ + + +/*------------------------------------------------------------------------------ + * Trap handler. This function is invoked in the non-vectored mode. + */ +void handle_trap(uintptr_t mcause, uintptr_t mepc) +{ + uint64_t is_interrupt = mcause & MCAUSE_INT; + + if (is_interrupt) + { +#ifndef MIV_LEGACY_RV32 + if (((mcause & MCAUSE_CAUSE) >= MIV_LOCAL_IRQ_MIN) && ((mcause & MCAUSE_CAUSE) <= MIV_LOCAL_IRQ_MAX)) + { + handle_local_ei_interrupts((uint8_t)(mcause & MCAUSE_CAUSE)); + } + else if ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT) +#else + if ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT) +#endif + { +#ifndef MIV_LEGACY_RV32 + External_IRQHandler(); +#else + handle_m_ext_interrupt(); +#endif + } + else if ((mcause & MCAUSE_CAUSE) == IRQ_M_SOFT) + { + handle_m_soft_interrupt(); + } + else if ((mcause & MCAUSE_CAUSE) == IRQ_M_TIMER) + { + handle_m_timer_interrupt(); + } + } + else + { +#ifndef NDEBUG + /* + Arguments supplied to this function are mcause, mepc (exception PC) and + stack pointer. + Based on privileged-isa specification mcause values and meanings are: + + 0 Instruction address misaligned (mtval/mtval is the address) + 1 Instruction access fault (mtval/mtval is the address) + 2 Illegal instruction (mtval/mtval contains the + offending instruction opcode) + 3 Breakpoint + 4 Load address misaligned (mtval/mtval is the address) + 5 Load address fault (mtval/mtval is the address) + 6 Store/AMO address fault (mtval/mtval is the address) + 7 Store/AMO access fault (mtval/mtval is the address) + 8 Environment call from U-mode + 9 Environment call from S-mode + A Environment call from M-mode + B Instruction page fault + C Load page fault (mtval/mtval is the address) + E Store page fault (mtval/mtval is the address) + + # Please note: mtval is the newer name for register mbadaddr + # If you get a compile failure here, use the older name. + # At this point, both are supported in latest compiler, older compiler + # versions only support mbadaddr. + # See: https://github.com/riscv/riscv-gcc/issues/133 + */ + + /* interrupt pending */ + uintptr_t mip = read_csr(mip); + + /* additional info and meaning depends on mcause */ + uintptr_t mtval = read_csr(mtval); + + /* trap vector */ + uintptr_t mtvec = read_csr(mtvec); + + /* temporary, sometimes might hold temporary value of a0 */ + uintptr_t mscratch = read_csr(mscratch); + + /* status contains many smaller fields: */ + uintptr_t mstatus = read_csr(mstatus); + + /* PC value when the exception was taken*/ + uintptr_t mmepc = read_csr(mepc); + + /* breakpoint */ + __asm__("ebreak"); +#else + _exit(1 + mcause); +#endif /* NDEBUG */ + } +} + +#ifdef __cplusplus +} +#endif + diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv_rv32_hal.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv_rv32_hal.h new file mode 100644 index 0000000..9ce9ef6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv_rv32_hal.h @@ -0,0 +1,773 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_hal.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware Abstraction Layer functions for Mi-V soft processors + * + */ + +/*=========================================================================*//** + @mainpage MIV_RV32 Hardware Abstraction Layer + + ============================================================================== + Introduction + ============================================================================== + This document describes the Hardware Abstraction Layer (HAL) for the MIV_RV32 + Soft IP Core. This release of the HAL corresponds to the Soft IP core MIV_RV32 + v3.1 release. It also supports earlier versions of the MIV_RV32 as well as the + legacy RV32 IP cores. + The preprocessor macros provided with the MIV_RV32 HAL are used to customize + it to target the Soft Processor IP version being used in your project. + + The term "MIV_RV32" represents following two cores: + - MIV_RV32 v3.0 and later (the latest and greatest Mi-V soft processor) + - MIV_RV32IMC v2.1 (MIV_RV32 v3.0 is a drop in replacement for this core) + It is highly recommended to migrate your design to MIV_RV32 v3.1 + + The term, Legacy RV32 IP cores, represents following IP cores: + - MIV_RV32IMA_L1_AHB + - MIV_RV32IMA_L1_AXI + - MIV_RV32IMAF_L1_AHB + + These legacy RV32 IP cores are deprecated. It is highly recommended to migrate + your designs to MIV_RV32 v3.1 (and subsequent IP releases) for the latest + enhancements, bug fixes, and support. + + -------------------------------- + MIV_RV32 V3.1 + -------------------------------- + This is the latest release of the MIV_RV32 Soft IP core. For more details, + refer to the MIV_RV32 User [Guide](https://www.microchip.com/en-us/products/fpgas-and-plds/ip-core-tools/miv-rv32) + + The MIV_RV32 Core as well as this document use the terms defined below: + + -------------------------------- + - SUBSYS - Processor Subsystem for RISC-V + - OPSRV - Offload Processor Subsystem for RISC-V + - GPR - General Purpose Registers + - MGECIE - Machine GPR ECC Correctable Interrupt Enable + - MGEUIE - Machine GPR ECC Uncorrectable Interrupt Enable + - MTIE - Machine Timer Interrupt Enable + - MEIE - Machine External Interrupt Enable + - MSIE - Machine Software Interrupt Enable + - ISR - Interrupt Service Routine + + ============================================================================== + Customizing MIV_RV32 HAL + ============================================================================== + To use the HAL with older releases of MIV_RV32, preprocessor macros have been + provided. Using these macros, any of the IP version is targeted. + The HAL is used to target any of the mentioned platforms by adding the + following macros in the way : + Project Properties > C/C++ Build > Settings > Preprocessor in Assembler and + Compiler settings. + The table below shows the macros corresponding to the MIV Core being used in + your libero project. By default, the HAL targets v3.1 of the IP core and no + macros need to be set for this configutation. + + | Libero MI-V Soft IP Version | SoftConsole Macro | + |-----------------------------|-------------------| + | MIV_RV32 v3.1 | no macro required | + | MIV_RV32 v3.0 | MIV_CORE_V3_0 | + | Legacy RV32 Cores | MIV_LEGACY_RV32 | + + -------------------------------- + Interrupt Handling + -------------------------------- + The MIE Register is defined as a enum in the HAL, and the table below is used + as a reference when the vectored interrupts are enabled in the GUI core + configurator. + + The MIE register is a RISC-V Control and Status Register (CSR), which stands + for the Machine Interrupt Enable. This is used to enable the machine mode + interrupts in the MIV_RV32 hart. Refer to the RISC-V Priv spec for more details. + + The following table shows the trap entry addresses when an interrupt occurs and + the vectored interrupts are enabled in the GUI configurator. + + | MIE Register Bit | Interrupt Enable | Vector Address | + |-------------------|------------------|----------------| + | 31 | MSYS_IE7 | mtvec.BASE + 0x7C | + | 30 | MSYS_IE6 | mtvec.BASE + 0x78 | + | 29 | MSYS_IE5 | mtvec.BASE + 0x74 | + | 28 | MSYS_IE4 | mtvec.BASE + 0x70 | + | 27 | MSYS_IE3 | mtvec.BASE + 0x6C | + | 26 | MSYS_IE2 | mtvec.BASE + 0x68 | + | 25 | MSYS_IE1 | mtvec.BASE + 0x64 | + | 24 | MSYS_IE0 | mtvec.BASE + 0x60 | + | 23 | SUBSYS_EI | mtvec.BASE + 0x5C | + | 22 | SUBSYSR | mtvec.BASE + 0x58 | + | 17 | MGECIE | mtvec.BASE + 0x44 | + | 16 | MGEUIE | mtvec.BASE + 0x40 | + | 11 | MEIE | mtvec.BASE + 0x2C | + | 7 | MTIE | mtvec.BASE + 0x1C | + | 3 | MSIE | mtvec.BASE + 0x0C | + + + For changes in MIE register map, see the [MIE Register Map for MIV_RV32 v3.0] + (#mie-register-map-for-miv_rv32-v3.0) section. + + SUBSYSR is currently not being used by the core and is Reserved for future use. + + The mtvec.BASE field corresponds to the bits [31:2], where mtvec stands for + Machine Trap Vector, and all traps set the PC to the the value stored in the + mtvec.BASE field when in Non-Vectored mode. In this case, a generic trap + handler is as an interrupt service routine. + + When Vectored interrupts are enabled, use this formula to calculate the trap + address: (mtvec.BASE + 4*cause), where cause comes from the mcause CSR. The + mcause register is written with a code indicating the event that caused the trap. + For more details, see the RISC-V priv specification. + + The MIV_RV32 Soft IP core does not contain a Platfrom Level Interrup Controller + (PLIC). It is advised to use the PLIC contained within the MIV_ESS sub-system. + Connect the PLIC interrupt output of the MIV_ESS to the EXT_IRQ pin on the + MIV_RV32. + + The following table is the MIE register map for the MIV_RV32 Core V3.0. It only + highlights the differences between the V3.0 and V3.1 of the core. + + -------------------------------- + MIE Register Map for MIV_RV32 V3.0 + -------------------------------- + + | MIE Register Bit | Target Interrupt | Vector Address | + |-------------------|------------------|----------------| + | 31 | Not in use | top table | + | 30 | SUBSYS_EI | addr + 0x78 | + | 23 | Not in use | Not in use | + | 22 | Not in use | Not in use | + + Other interrupt bit postions like the MGEUIE and MSYS_IE5 to MSYS_IE0 remain + unchanged. + + -------------------------------- + Floating Point Interrupt Support + -------------------------------- + When an interrupt is taken and Floating Point instructions are used in the + ISR, the floating point register context must be saved to resume the application + correctly. To use this feature, enable the provided macro in the + Softconsole build settings. + This feature is turned off by default as it adds overhead which is not required + when the ISR does not used FP insturctions and saving the general purpose + register context is sufficient. + + | Macro Name | Definition | + |--------------------------|-------------------------------------------------| + | MIV_FP_CONTEXT_SAVE | Define to save the FP register file | + + + -------------------------------- + SUBSYS - SubSystem for RISC-V + -------------------------------- + SUBSYS stands for SubSystem for RISC-V. This was previously (MIV_RV32 v3.0) + known as OPSRV, which stands for "Offload Processor Subsystem + for RISC-V". See the earlier versions of the handbook for more details. + In the latest release of the MIV_RV32 IP core v3.1, OPSRV has been renamed to + SUBSYS. The MIV_RV32 HAL now uses SUBSYS instead of OPSRV. + + *//*=========================================================================*/ +#ifndef RISCV_HAL_H +#define RISCV_HAL_H + +#include "miv_rv32_regs.h" +#include "miv_rv32_plic.h" +#include "miv_rv32_assert.h" +#include "miv_rv32_subsys.h" + +#ifndef LEGACY_DIR_STRUCTURE +#include "fpga_design_config/fpga_design_config.h" +#else +#include "hw_platform.h" +#endif /*LEGACY_DIR_STRUCTURE*/ + +#ifdef __cplusplus +extern "C" { +#endif +/*-------------------------------------------------------------------------*//** + SUBSYS Backwards Compatibility + ======================================= + For application code using the older macro names and API functions, these macros + act as a compatibility layer and applications which use OPSRV API features work + due to these macro definitions. However, it is adviced to update your + application code to use the SUBSYS macros and API functions. + + | Macro Name | Now Called | + |-------------------------|--------------------------| + | OPSRV_TCM_ECC_CE_IRQ | SUBSYS_TCM_ECC_CE_IRQ | + | OPSRV_TCM_ECC_UCE_IRQ | SUBSYS_TCM_ECC_UCE_IRQ | + | OPSRV_AXI_WR_RESP_IRQ | SUBSYS_AXI_WR_RESP_IRQ | + | MRV32_MSYS_OPSRV_IRQn | MRV32_SUBSYS_IRQn | + | MRV32_opsrv_enable_irq | MRV32_subsys_enable_irq | + | MRV32_opsrv_disable_irq | MRV32_subsys_disable_irq | + | MRV32_opsrv_clear_irq | MRV32_subsys_clear_irq | + | OPSRV_IRQHandler | SUBSYS_IRQHandler | + */ + +/*-------------------------------------------------------------------------*//** + MTIME Timer Interrupt Constants + ======================================= + These values contain the register addresses for the registers used by the + machine timer interrupt + + MTIME_PRESCALER is not defined on the MIV_RV32IMC v2.0 and v2.1. By using this + definition the system crashes. For those core, use the following definition: + + #define MTIME_PRESCALER 100u + + MTIME and MTIMECMP + -------------------------------- + MIV_RV32 core offers flexibility in terms of generating MTIME and MTIMECMP + registers internal to the core or using external time reference. There four + possible combinations: + + - Internal MTIME and Internal MTIME IRQ enabled Generate the MTIME and MTIMECMP + registers internally. (The only combination available on legacy RV32 cores) + + - Internal MTIME enabled and Internal MTIME IRQ disabled Generate the MTIME + internally and have a timer interrupt input to the core as external pin. In + this case, 1 pin port will be available on MIV_RV32 for timer interrupt. + + - When the internal MTIME is disabled, and the Internal MTIME IRQ is enabled, the + system generates the time value externally and generates the mtimecmp and + interrupt internally (for example, a multiprocessor system with a shared time + between all cores). In this case, a 64-bit port is available on the MIV_RV32 + core as input. + + - Internal MTIME and Internal MTIME IRQ disabled Generate both the time and + timer interrupts externally. In this case a 64 bit port will be available on + the MIV_RV32 core as input, and a 1 pin port will be available for timer + interrupt. + + To handle all these combinations in the firmware, the following constants must + be defined in accordance with the configuration that you have made on your + MIV_RV32 core design. + + MIV_RV32_EXT_TIMER + -------------------------------- + When defined, it means that the MTIME register is not available internal to + the core. In this case, a 64 bit port will be available on the MIV_RV32 core as + input. When this macro is not defined, it means that the MTIME register is + available internally to the core. + + MIV_RV32_EXT_TIMECMP + -------------------------------- + When defined, it means the MTIMECMP register is not available internally to + the core and the Timer interrupt input to the core comes as an external pin. + When this macro is not defined it means the that MTIMECMP register exists + internal to the core and that the timer interrupt is generated internally. + +NOTE: All these macros must not be defined if you are using a MIV_RV32 core. + */ + +#define OPSRV_TCM_ECC_CE_IRQ SUBSYS_TCM_ECC_CE_IRQ +#define OPSRV_TCM_ECC_UCE_IRQ SUBSYS_TCM_ECC_UCE_IRQ +#define OPSRV_AXI_WR_RESP_IRQ SUBSYS_AXI_WR_RESP_IRQ +#define MRV32_MSYS_OPSRV_IRQn MRV32_SUBSYS_IRQn +#define MRV32_opsrv_enable_irq MRV32_subsys_enable_irq +#define MRV32_opsrv_disable_irq MRV32_subsys_disable_irq +#define MRV32_opsrv_clear_irq MRV32_subsys_clear_irq +#define OPSRV_IRQHandler SUBSYS_IRQHandler + +/*-------------------------------------------------------------------------*//** + External IRQ + ======================================= + Return value from External IRQ handler. This is used to disable the + External Interrupt. + + | Macro Name | Value | Description| + |-------------------|--------|----------------| + | EXT_IRQ_KEEP_ENABLED | 0 | Keep external interrupts enabled | + | EXT_IRQ_DISABLE | 1 | Disable external interrupts | + */ +#define EXT_IRQ_KEEP_ENABLED 0U +#define EXT_IRQ_DISABLE 1U + +#define MTIME_DELTA 5 +#ifdef MIV_LEGACY_RV32 +#define MSIP (*(uint32_t*)0x44000000UL) +#define MTIMECMP (*(uint32_t*)0x44004000UL) +#define MTIMECMPH (*(uint32_t*)0x44004004UL) +#define MTIME (*(uint32_t*)0x4400BFF8UL) +#define MTIMEH (*(uint32_t*)0x4400BFFCUL) + +/* To maintain backward compatibility with FreeRTOS config code */ +#define PRCI_BASE 0x44000000UL +#else /* MIV_LEGACY_RV32 */ + +/* To maintain backward compatibility with FreeRTOS config code */ +#define PRCI_BASE 0x02000000UL + +#ifndef MIV_RV32_EXT_TIMECMP +#define MTIMECMP (*(volatile uint32_t*)0x02004000UL) +#define MTIMECMPH (*(volatile uint32_t*)0x02004004UL) +#else +#define MTIMECMP (0u) +#define MTIMECMPH (0u) +#endif + +#define MTIME_PRESCALER (*(volatile uint32_t*)0x02005000UL) + +#ifndef MIV_RV32_EXT_TIMER +#define MTIME (*(volatile uint32_t*)0x0200BFF8UL) +#define MTIMEH (*(volatile uint32_t*)0x0200BFFCUL) + +/***************************************************************************//** + MIMPID Register + The MIMPID register is a RISC-V Control and Status Register In the v3.0 of + MIV_RV32, the value of `MIMPID = 0x000540AD`. In the v3.1 of MIV_RV32, the + value if `MIMPID = 0xE5010301` corresponding to (E)mbedded (5)ystem(01) core + version (03).(01) this terminology will be followed in the subsequent releases + of the core read the csr value and store it in a varible which may be used to + check the MIV_RV32 core version during runtime. + + Future releases of the core will increment the 03 and 01 as major and minor + releases respectively and the register can be read at runtime to find the + Soft IP core version. + + | Core Version | Register | Value | Notes | + |----------------|------------|---------|---------| + | MIV_RV32 V3.1 | mimpid | 0xE5010301 | implimentation ID | + | MIV_RV32 V3.0 | mimpid | 0x000540AD | implimentation ID | + */ +#define MIMPID read_csr(mimpid) + +/*Used as a mask to read and write to mte mtvec.BASE address*/ +#define MTVEC_BASE_ADDR_MASK 0xFFFFFFFC + +#else +#define MTIME (0u) +#define MTIMEH (0u) +#endif /*MIV_RV32_EXT_TIMER*/ + +/*-------------------------------------------------------------------------*//** + RISC-V Specification Interrupts + ======================================= + These definitions are provided for easy identification of the interrupt + in the MIE/MIP registers. + Apart from the standard software, timer, and external interrupts, the names + of the additional interrupts correspond to the names as used in the MIV_RV32 + handbook. Please refer the MIV_RV32 handbook for more details. + + All the interrups, provided by the MIV_RV32 core, follow the interrupt priority + order and register description as mentioned in the RISC-V spec. + + | Macro Name | Value | Description| + |-------------------|--------|----------------| + | MRV32_SOFT_IRQn | MIE_3_IRQn | Software interrupt enable | + | MRV32_TIMER_IRQn | MIE_7_IRQn | Timer interrupt enable | + | MRV32_EXT_IRQn | MIE_11_IRQn | External interrupt enable | + + */ +#define MRV32_SOFT_IRQn MIE_3_IRQn +#define MRV32_TIMER_IRQn MIE_7_IRQn +#define MRV32_EXT_IRQn MIE_11_IRQn + +/***************************************************************************//** + Interrupt numbers: + This enum represents the interrupt enable bits in the MIE register. + */ +enum +{ + MIE_0_IRQn = (0x01u), + MIE_1_IRQn = (0x01u<<1u), + MIE_2_IRQn = (0x01u<<2u), + MIE_3_IRQn = (0x01u<<3u), /*MSIE 0xC*/ + MIE_4_IRQn = (0x01u<<4u), + MIE_5_IRQn = (0x01u<<5u), + MIE_6_IRQn = (0x01u<<6u), + MIE_7_IRQn = (0x01u<<7u), /*MTIE 0x1C*/ + MIE_8_IRQn = (0x01u<<8u), + MIE_9_IRQn = (0x01u<<9u), + MIE_10_IRQn = (0x01u<<10u), + MIE_11_IRQn = (0x01u<<11u), /*MEIE 0x2C*/ + MIE_12_IRQn = (0x01u<<12u), + MIE_13_IRQn = (0x01u<<13u), + MIE_14_IRQn = (0x01u<<14u), + MIE_15_IRQn = (0x01u<<15u), + MIE_16_IRQn = (0x01u<<16u), /*MGEUIE ECC Uncorrectable 0x40*/ + MIE_17_IRQn = (0x01u<<17u), /*MGECIE ECC Correctable 0x44*/ + MIE_18_IRQn = (0x01u<<18u), + MIE_19_IRQn = (0x01u<<19u), + MIE_20_IRQn = (0x01u<<20u), + MIE_21_IRQn = (0x01u<<21u), + MIE_22_IRQn = (0x01u<<22u), /*SUBSYSR 0x58 (R)eserved*/ + MIE_23_IRQn = (0x01u<<23u), /*SUBSYS_IE 0x5C for MIV_RV32 v3.1*/ + MIE_24_IRQn = (0x01u<<24u), /*MSYS_IE0 0x60*/ + MIE_25_IRQn = (0x01u<<25u), /*MSYS_IE1 0x64*/ + MIE_26_IRQn = (0x01u<<26u), /*MSYS_IE2 0x68*/ + MIE_27_IRQn = (0x01u<<27u), /*MSYS_IE3 0x6C*/ + MIE_28_IRQn = (0x01u<<28u), /*MSYS_IE4 0x70*/ + MIE_29_IRQn = (0x01u<<29u), /*MSYS_IE5 0x74*/ + MIE_30_IRQn = (0x01u<<30u), /*MSYS_IE6 0x78, read comment below*/ + MIE_31_IRQn = (0x01u<<31u) /*MSYS_IE7 0x7C*/ +} MRV_LOCAL_IRQn_Type; + +#define MRV32_MGEUIE_IRQn MIE_16_IRQn +#define MRV32_MGECIE_IRQn MIE_17_IRQn +#define MRV32_MSYS_EIE0_IRQn MIE_24_IRQn +#define MRV32_MSYS_EIE1_IRQn MIE_25_IRQn +#define MRV32_MSYS_EIE2_IRQn MIE_26_IRQn +#define MRV32_MSYS_EIE3_IRQn MIE_27_IRQn +#define MRV32_MSYS_EIE4_IRQn MIE_28_IRQn +#define MRV32_MSYS_EIE5_IRQn MIE_29_IRQn +#ifndef MIV_RV32_V3_0 /*For MIV_RV32 v3.1*/ +#define MRV32_SUBSYSR_IRQn MIE_22_IRQn +#define MRV32_SUBSYS_IRQn MIE_23_IRQn +#define MRV32_MSYS_EIE6_IRQn MIE_30_IRQn +#define MRV32_MSYS_EIE7_IRQn MIE_31_IRQn +#else +#define MRV32_SUBSYS_IRQn MIE_30_IRQn +#endif /*MIV_RV32_V3_0*/ + +/*--------------------------------Public APIs---------------------------------*/ + +/***************************************************************************//** + The MRV32_clear_gpr_ecc_errors() function clears single bit ECC errors on the + GPRs. The ECC block does not write back corrected data to memory. Hence, when + ECC is enabled for the GPRs and if that data has a single bit error then the + data coming out of the ECC block is corrected and will not have the error, but + the data source will still have the error. Therefore, if data has a single bit + error, then the corrected data must be written back to prevent the single bit + error from becoming a double bit error. Clear the pending interrupt bit after + this using MRV32_mgeci_clear_irq() function to complete the ECC error handling. + + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline void MRV32_clear_gpr_ecc_errors(void) +{ + uint32_t temp; + + __asm__ __volatile__ ( + "sw x31, %0" + :"=m" (temp)); + + __asm__ volatile ( + "mv x31, x1;" + "mv x1, x31;" + + "mv x31, x2;" + "mv x2, x31;" + + "mv x31, x3;" + "mv x3, x31;" + + "mv x31, x4;" + "mv x4, x31;" + + "mv x31, x5;" + "mv x5, x31;" + + "mv x31, x6;" + "mv x6, x31;" + + "mv x31, x7;" + "mv x7, x31;" + + "mv x31, x8;" + "mv x8, x31;" + + "mv x31, x9;" + "mv x9, x31;" + + "mv x31, x10;" + "mv x10, x31;" + + "mv x31, x11;" + "mv x11, x31;" + + "mv x31, x12;" + "mv x12, x31;" + + "mv x31, x13;" + "mv x13, x31;" + + "mv x31, x14;" + "mv x14, x31;" + + "mv x31, x15;" + "mv x15, x31;" + + "mv x31, x16;" + "mv x16, x31;" + + "mv x31, x17;" + "mv x17, x31;" + + "mv x31, x18;" + "mv x18, x31;" + + "mv x31, x19;" + "mv x19, x31;" + + "mv x31, x20;" + "mv x20, x31;" + + "mv x31, x21;" + "mv x21, x31;" + + "mv x31, x22;" + "mv x22, x31;" + + "mv x31, x23;" + "mv x23, x31;" + + "mv x31, x24;" + "mv x24, x31;" + + "mv x31, x25;" + "mv x25, x31;" + + "mv x31, x26;" + "mv x26, x31;" + + "mv x31, x27;" + "mv x27, x31;" + + "mv x31, x28;" + "mv x28, x31;" + + "mv x31, x29;" + "mv x29, x31;" + + "mv x31, x30;" + "mv x30, x31;"); + + __asm__ __volatile__ ( + "lw x31, %0;" + : + :"m" (temp)); +} + + +/***************************************************************************//** + The MRV32_mgeui_clear_irq() function clears the GPR ECC Uncorrectable + Interrupt. MGEUI interrupt is available only when ECC is enabled in the MIV_RV32 + IP configurator. + + @return + This function does not return any value. + */ +static inline void MRV32_mgeui_clear_irq(void) +{ + clear_csr(mip, MRV32_MGEUIE_IRQn); +} + +/***************************************************************************//** + The MRV32_mgeci_clear_irq() function clears the GPR ECC Correctable Interrupt + MGECI interrupt is available only when ECC is enabled in the MIV_RV32 IP + configurator. + + @return + This function does not return any value. + */ +static inline void MRV32_mgeci_clear_irq(void) +{ + clear_csr(mip, MRV32_MGECIE_IRQn); +} + +/***************************************************************************//** + The MRV_enable_local_irq() function enables the local interrupts. It takes a + mask value as input. For each set bit in the mask value, the corresponding + interrupt bit in the MIE register is enabled. + + MRV_enable_local_irq( MRV32_SOFT_IRQn | MRV32_TIMER_IRQn | MRV32_EXT_IRQn | + MRV32_MSYS_EIE0_IRQn | + MRV32_MSYS_SUBSYS_IRQn); + */ +static inline void MRV_enable_local_irq(uint32_t mask) +{ + set_csr(mie, mask); +} + +/***************************************************************************//** + The MRV_disable_local_irq() function disables the local interrupts. It takes a + mask value as input. For each set bit in the mask value, the corresponding + interrupt bit in the MIE register is disabled. + + MRV_disable_local_irq( MRV32_SOFT_IRQn | MRV32_TIMER_IRQn | MRV32_EXT_IRQn | + MRV32_MSYS_EIE0_IRQn | + MRV32_MSYS_SUBSYS_IRQn); + */ +static inline void MRV_disable_local_irq(uint32_t mask) +{ + clear_csr(mie, mask); +} +#endif /* MIV_LEGACY_RV32 */ + +/***************************************************************************//** + The MRV_enable_interrupts() function enables all interrupts by setting the + machine mode interrupt enable bit in MSTATUS register. + + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline void MRV_enable_interrupts(void) +{ + set_csr(mstatus, MSTATUS_MIE); +} + +/***************************************************************************//** + The MRV_disable_interrupts() function disables all interrupts by clearing the + machine mode interrupt enable bit in MSTATUS register. + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline void MRV_disable_interrupts(void) +{ + clear_csr(mstatus, MSTATUS_MPIE); + clear_csr(mstatus, MSTATUS_MIE); +} + +/***************************************************************************//** + The MRV_read_mtvec_base() function reads the mtvec base value, which is the + addr used when an interrupt/trap occurs. In the mtvec register, [31:2] is the + BASE address. NOTE: The BASE address must be aligned on a 4B boundary. + + @param + The function does not take any parameters. + + @return + The function returns the value of the BASE field [31:2] as an unsigned 32-bit + value. + */ + +#ifndef MIV_LEGACY_RV32 +#ifndef MIV_RV32_v3_0 +static inline uint32_t MRV_read_mtvec_base (void) +{ + uint32_t mtvec_addr_base = read_csr(mtvec); + return mtvec_addr_base & MTVEC_BASE_ADDR_MASK; +} + +/***************************************************************************//** + The MRV_set_mtvec_base() function takes the mtvec_base address as a unsigned int + and writes the value into the BASE field [31:2] in the mtvec CSR, MODE[1:0] + is Read-only. BASE is 4B aligned, so the lowest 2 bits of mtvec_base are + ignored. + + @param mtvec_base + Any legal value is passed into the function, and it is used as the trap_entry + for interrupts. The PC jumps to this address provided when an interrupt occurs. + In case of vectored interrupts, the address value mentioned in the vector + table under the MIE Register Map is updated to the value passed to this + function parameter. + + @return + This function does not return any value. + */ +static inline void MRV_set_mtvec_base (uint32_t mtvec_base) +{ + mtvec_base = mtvec_base & MTVEC_BASE_ADDR_MASK; + write_csr(mtvec, mtvec_base); +} +#endif /*MIV_RV32_v3_0*/ +#endif /*MIV_LEGACY_RV32*/ + +/***************************************************************************//** + The MRV_read_mtime() function returns the current MTIME register value. + */ +static inline uint64_t MRV_read_mtime(void) +{ + volatile uint32_t hi = 0u; + volatile uint32_t lo = 0u; + + /* when mtime lower word is 0xFFFFFFFF, there will be rollover and + * returned value could be wrong. */ + do { + hi = MTIMEH; + lo = MTIME; + } while(hi != MTIMEH); + + return((((uint64_t)MTIMEH) << 32u) | lo); +} + +/***************************************************************************//** + The MRV_raise_soft_irq() function raises a synchronous software interrupt + by writing into the MSIP register. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV_raise_soft_irq(void) +{ + set_csr(mie, MIP_MSIP); /* Enable software interrupt bit */ + +#ifdef MIV_LEGACY_RV32 + /* You need to make sure that the global interrupt is enabled */ + MSIP = 0x01; /* raise soft interrupt */ +#else + /* Raise soft IRQ on MIV_RV32 processor */ + SUBSYS->soft_reg |= SUBSYS_SOFT_IRQ; +#endif +} + +/***************************************************************************//** + The MRV_clear_soft_irq() function clears a synchronous software interrupt + by clearing the MSIP register. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV_clear_soft_irq(void) +{ +#ifdef MIV_LEGACY_RV32 + MSIP = 0x00u; /* clear soft interrupt */ +#else + /* Clear soft IRQ on MIV_RV32 processor */ + SUBSYS->soft_reg &= ~SUBSYS_SOFT_IRQ; +#endif +} + +/***************************************************************************//** + System tick handler. This handler function gets called when the Machine + timer interrupt asserts. An implementation of this function must be provided + by the application to implement the application specific machine timer + interrupt handling. If application does not provide such implementation, the + weakly linked handler stub function implemented in riscv_hal_stubs.c gets + linked. + */ +void SysTick_Handler(void); + +/***************************************************************************//** + System timer tick configuration. + Configures the machine timer to generate a system tick interrupt at regular + intervals. Takes the number of system clock ticks between interrupts. + + Though this function can take any valid ticks value as parameter, we expect + that, for all practical purposes, a small tick value (to generate periodic + interrupts every few miliseconds) is passed. If you need to generate periodic + events in the range of seconds or more, you may use the SysTick_Handler() to + further count the number of interrupts and hence the larger time intervals. + + @param ticks + This is the number of ticks or clock cycles which are counted down from the + interrupt to be triggered. + + @return + Returns 0 if successful. + Returns 1 if the interrupt interval is not achieved. + */ +uint32_t MRV_systick_config(uint64_t ticks); + +#ifdef __cplusplus +} +#endif +#endif /* RISCV_HAL_H */ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv_rv32_hal_version.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv_rv32_hal_version.h new file mode 100644 index 0000000..4922bf2 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv_rv32_hal_version.h @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_hal_version.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware Abstraction Layer functions for Mi-V soft processors + * + */ + +#ifndef MIV_RV32_HAL_VERSION_H +#define MIV_RV32_HAL_VERSION_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MIV_RV32_HAL_VERSION_MAJOR 4 +#define MIV_RV32_HAL_VERSION_MINOR 2 +#define MIV_RV32_HAL_VERSION_PATCH 100 + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv_rv32_init.c b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv_rv32_init.c new file mode 100644 index 0000000..85f8aca --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv_rv32_init.c @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_init.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor memory section initializations and start-up code. + * + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern void main(void); + +void _init(void) +{ + /* This function is a placeholder for the case where some more hardware + * specific initializations are required before jumping into the application + * code. You can implement it here. */ + + /* Jump to the application code after all initializations are completed */ + main(); +} + +/* Function called after main() finishes */ +void +_fini(void) +{ +} + +#ifdef __cplusplus +} +#endif + diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv_rv32_plic.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv_rv32_plic.h new file mode 100644 index 0000000..3fd4103 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv_rv32_plic.h @@ -0,0 +1,214 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_plic.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V legacy RV32 soft processor PLIC access data structures and + * functions. + * Legacy RV32 soft processors are DEPRICATED. + * Migrate to MIV_RV32 v3.0 or later. + * + */ +#ifndef RISCV_PLIC_H +#define RISCV_PLIC_H + +#include +#include "miv_rv32_regs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================== + * Interrupt numbers: + */ +#ifdef MIV_LEGACY_RV32 +typedef enum +{ + MRV_NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + External_3_IRQn = 3, + External_4_IRQn = 4, + External_5_IRQn = 5, + External_6_IRQn = 6, + External_7_IRQn = 7, + External_8_IRQn = 8, + External_9_IRQn = 9, + External_10_IRQn = 10, + External_11_IRQn = 11, + External_12_IRQn = 12, + External_13_IRQn = 13, + External_14_IRQn = 14, + External_15_IRQn = 15, + External_16_IRQn = 16, + External_17_IRQn = 17, + External_18_IRQn = 18, + External_19_IRQn = 19, + External_20_IRQn = 20, + External_21_IRQn = 21, + External_22_IRQn = 22, + External_23_IRQn = 23, + External_24_IRQn = 24, + External_25_IRQn = 25, + External_26_IRQn = 26, + External_27_IRQn = 27, + External_28_IRQn = 28, + External_29_IRQn = 29, + External_30_IRQn = 30, + External_31_IRQn = 31 +} IRQn_Type; + +#define EXT_INTR_SOURCES 31 + +/*============================================================================== + * PLIC: Platform Level Interrupt Controller + */ +#define PLIC_BASE_ADDR 0x40000000UL + +typedef struct +{ + volatile uint32_t PRIORITY_THRESHOLD; + volatile uint32_t CLAIM_COMPLETE; + volatile uint32_t reserved[1022]; +} MRV_IRQ_Target_Type; + +typedef struct +{ + volatile uint32_t ENABLES[32]; +} MRV_Target_Enables_Type; + +typedef struct +{ + /*-------------------- Source Priority --------------------*/ + volatile uint32_t SOURCE_PRIORITY[1024]; + + /*-------------------- Pending array --------------------*/ + volatile const uint32_t PENDING_ARRAY[32]; + volatile uint32_t RESERVED1[992]; + + /*-------------------- Target enables --------------------*/ + volatile MRV_Target_Enables_Type TARGET_ENABLES[15808]; + + volatile uint32_t RESERVED2[16384]; + + /*--- Target Priority threshold and claim/complete---------*/ + MRV_IRQ_Target_Type TARGET[15872]; + +} PLIC_Type; + +#define PLIC ((PLIC_Type *)PLIC_BASE_ADDR) + +/*============================================================================== + * The function MRV_PLIC_init() initializes the PLIC controller and enables + * the global external interrupt bit. + */ +static inline void MRV_PLIC_init(void) +{ + uint32_t inc; + unsigned long hart_id = read_csr(mhartid); + + /* Disable all interrupts for the current hart. */ + for(inc = 0; inc < ((EXT_INTR_SOURCES + 32u) / 32u); ++inc) + { + PLIC->TARGET_ENABLES[hart_id].ENABLES[inc] = 0; + } + + /* Set priorities to zero. */ + for(inc = 0; inc < EXT_INTR_SOURCES; ++inc) + { + PLIC->SOURCE_PRIORITY[inc] = 0; + } + + /* Set the threshold to zero. */ + PLIC->TARGET[hart_id].PRIORITY_THRESHOLD = 0; + + /* Enable machine external interrupts. */ + set_csr(mie, MIP_MEIP); +} + +/*============================================================================== + * The function MRV_PLIC_enable_irq() enables the external interrupt for the + * interrupt number indicated by the parameter IRQn. + */ +static inline void MRV_PLIC_enable_irq(IRQn_Type IRQn) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t current = PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32]; + current |= (uint32_t)1 << (IRQn % 32); + PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32] = current; +} + +/*============================================================================== + * The function MRV_PLIC_disable_irq() disables the external interrupt for + * the interrupt number indicated by the parameter IRQn. + + * NOTE: + * This function can be used to disable the external interrupt from outside + * external interrupt handler function. + * This function MUST NOT be used from within the External Interrupt handler. + * If you wish to disable the external interrupt while the interrupt handler + * for that external interrupt is executing then you must use the return value + * EXT_IRQ_DISABLE to return from the extern interrupt handler. + */ +static inline void MRV_PLIC_disable_irq(IRQn_Type IRQn) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t current = PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32]; + + current &= ~((uint32_t)1 << (IRQn % 32)); + + PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32] = current; +} + +/*============================================================================== + * The function MRV_PLIC_set_priority() sets the priority for the external + * interrupt for the interrupt number indicated by the parameter IRQn. + */ +static inline void MRV_PLIC_set_priority(IRQn_Type IRQn, uint32_t priority) +{ + PLIC->SOURCE_PRIORITY[IRQn] = priority; +} + +/*============================================================================== + * The function MRV_PLIC_get_priority() returns the priority for the external + * interrupt for the interrupt number indicated by the parameter IRQn. + */ +static inline uint32_t MRV_PLIC_get_priority(IRQn_Type IRQn) +{ + return PLIC->SOURCE_PRIORITY[IRQn]; +} + +/***************************************************************************//** + * MRV_PLIC_clear_pending_irq(void) + * This is only called by the startup hart and only once + * Clears any pending interrupts as PLIC can be in unknown state on startup + */ +static inline void MRV_PLIC_clear_pending_irq(void) +{ + unsigned long hart_id = read_csr(mhartid); + volatile uint32_t int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; + volatile int32_t wait_possible_int; + + while (MRV_NoInterrupt_IRQn != int_num) + { + PLIC->TARGET[hart_id].CLAIM_COMPLETE = int_num; + wait_possible_int = 0xFU; + while (wait_possible_int) + { + wait_possible_int--; + } + + int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; + } +} + +#endif /* MIV_LEGACY_RV32 */ + +#ifdef __cplusplus +} +#endif + +#endif /* RISCV_PLIC_H */ diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv_rv32_regs.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv_rv32_regs.h new file mode 100644 index 0000000..07d58e7 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv_rv32_regs.h @@ -0,0 +1,520 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor register bit mask and shift constants encodings. + * + */ +#ifndef MIV_RV32_REGS_H +#define MIV_RV32_REGS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MSTATUS_UIE 0x00000001UL +#define MSTATUS_SIE 0x00000002UL +#define MSTATUS_HIE 0x00000004UL +#define MSTATUS_MIE 0x00000008UL +#define MSTATUS_UPIE 0x00000010UL +#define MSTATUS_SPIE 0x00000020UL +#define MSTATUS_HPIE 0x00000040UL +#define MSTATUS_MPIE 0x00000080UL +#define MSTATUS_SPP 0x00000100UL +#define MSTATUS_HPP 0x00000600UL +#define MSTATUS_MPP 0x00001800UL +#define MSTATUS_FS 0x00006000UL +#define MSTATUS_XS 0x00018000UL +#define MSTATUS_MPRV 0x00020000UL +#define MSTATUS_SUM 0x00040000UL +#define MSTATUS_MXR 0x00080000UL +#define MSTATUS_TVM 0x00100000UL +#define MSTATUS_TW 0x00200000UL +#define MSTATUS_TSR 0x00400000UL +#define MSTATUS_RES 0x7F800000UL +#define MSTATUS32_SD 0x80000000UL +#define MSTATUS64_SD 0x8000000000000000UL + +#define MCAUSE32_CAUSE 0x7FFFFFFFUL +#define MCAUSE64_CAUSE 0x7FFFFFFFFFFFFFFFUL +#define MCAUSE32_INT 0x80000000UL +#define MCAUSE64_INT 0x8000000000000000UL + +#define MIP_SSIP (1u << IRQ_S_SOFT) +#define MIP_HSIP (1u << IRQ_H_SOFT) +#define MIP_MSIP (1u << IRQ_M_SOFT) +#define MIP_STIP (1u << IRQ_S_TIMER) +#define MIP_HTIP (1u << IRQ_H_TIMER) +#define MIP_MTIP (1u << IRQ_M_TIMER) +#define MIP_SEIP (1u << IRQ_S_EXT) +#define MIP_HEIP (1u << IRQ_H_EXT) +#define MIP_MEIP (1u << IRQ_M_EXT) + +#define PRV_M 3U + +#define VM_MBARE 0U +#define VM_MBB 1U +#define VM_MBBID 2U +#define VM_SV32 8U +#define VM_SV39 9U +#define VM_SV48 10U + +#define IRQ_S_SOFT 1U +#define IRQ_H_SOFT 2U +#define IRQ_M_SOFT 3U +#define IRQ_S_TIMER 5U +#define IRQ_H_TIMER 6U +#define IRQ_M_TIMER 7U +#define IRQ_S_EXT 9U +#define IRQ_H_EXT 10U +#define IRQ_M_EXT 11U + +#define DEFAULT_RSTVEC 0x00001000 +#define DEFAULT_NMIVEC 0x00001004 +#define DEFAULT_MTVEC 0x00001010 +#define CONFIG_STRING_ADDR 0x0000100C +#define EXT_IO_BASE 0x40000000 +#define DRAM_BASE 0x80000000 + +#ifdef __riscv + +#if __riscv_xlen == 64 +# define MSTATUS_SD MSTATUS64_SD +# define SSTATUS_SD SSTATUS64_SD +# define MCAUSE_INT MCAUSE64_INT +# define MCAUSE_CAUSE MCAUSE64_CAUSE +# define RISCV_PGLEVEL_BITS 9 +#else +# define MSTATUS_SD MSTATUS32_SD +# define SSTATUS_SD SSTATUS32_SD +# define RISCV_PGLEVEL_BITS 10 +# define MCAUSE_INT MCAUSE32_INT +# define MCAUSE_CAUSE MCAUSE32_CAUSE +#endif + +#define RISCV_PGSHIFT 12U +#define RISCV_PGSIZE (1U << RISCV_PGSHIFT) + +#ifndef __ASSEMBLER__ + +#ifdef __GNUC__ + +#define read_csr(reg) ({ unsigned long __tmp; \ + __asm__ volatile ("csrr %0, " #reg : "=r"(__tmp)); \ + __tmp; }) + +#define write_csr(reg, val) ({ \ + __asm__ volatile ("csrw " #reg ", %0" :: "rK"(val)); }) + +#define swap_csr(reg, val) ({ unsigned long __tmp; \ + __asm__ volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "rK"(val)); \ + __tmp; }) + +#define set_csr(reg, bit) ({ unsigned long __tmp; \ + __asm__ volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ + __tmp; }) + +#define clear_csr(reg, bit) ({ unsigned long __tmp; \ + __asm__ volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ + __tmp; }) + +#ifdef __riscv_atomic + +#define MASK(nr) (1UL << nr) +#define MASK_NOT(nr) (~(1UL << nr)) + +/** + * atomic_read - read atomic variable + * @v: pointer of type int + * + * Atomically reads the value of @v. + */ +static inline int atomic_read(const int *v) +{ + return *((volatile int *)(v)); +} + +/** + * atomic_set - set atomic variable + * @v: pointer of type int + * @i: required value + * + * Atomically sets the value of @v to @i. + */ +static inline void atomic_set(int *v, int i) +{ + *v = i; +} + +/** + * atomic_add - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v. + */ +static inline void atomic_add(int i, int *v) +{ + __asm__ __volatile__ ( + "amoadd.w zero, %1, %0" + : "+A" (*v) + : "r" (i)); +} + +static inline int atomic_fetch_add(unsigned int mask, int *v) +{ + int out; + + __asm__ __volatile__ ( + "amoadd.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_sub - subtract integer from atomic variable + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v. + */ +static inline void atomic_sub(int i, int *v) +{ + atomic_add(-i, v); +} + +static inline int atomic_fetch_sub(unsigned int mask, int *v) +{ + int out; + + __asm__ __volatile__ ( + "amosub.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_add_return - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v and returns the result + */ +static inline int atomic_add_return(int i, int *v) +{ + register int c; + __asm__ __volatile__ ( + "amoadd.w %0, %2, %1" + : "=r" (c), "+A" (*v) + : "r" (i)); + return (c + i); +} + +/** + * atomic_sub_return - subtract integer from atomic variable + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v and returns the result + */ +static inline int atomic_sub_return(int i, int *v) +{ + return atomic_add_return(-i, v); +} + +/** + * atomic_inc - increment atomic variable + * @v: pointer of type int + * + * Atomically increments @v by 1. + */ +static inline void atomic_inc(int *v) +{ + atomic_add(1, v); +} + +/** + * atomic_dec - decrement atomic variable + * @v: pointer of type int + * + * Atomically decrements @v by 1. + */ +static inline void atomic_dec(int *v) +{ + atomic_add(-1, v); +} + +static inline int atomic_inc_return(int *v) +{ + return atomic_add_return(1, v); +} + +static inline int atomic_dec_return(int *v) +{ + return atomic_sub_return(1, v); +} + +/** + * atomic_sub_and_test - subtract value from variable and test result + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v and returns + * true if the result is zero, or false for all + * other cases. + */ +static inline int atomic_sub_and_test(int i, int *v) +{ + return (atomic_sub_return(i, v) == 0); +} + +/** + * atomic_inc_and_test - increment and test + * @v: pointer of type int + * + * Atomically increments @v by 1 + * and returns true if the result is zero, or false for all + * other cases. + */ +static inline int atomic_inc_and_test(int *v) +{ + return (atomic_inc_return(v) == 0); +} + +/** + * atomic_dec_and_test - decrement and test + * @v: pointer of type int + * + * Atomically decrements @v by 1 and + * returns true if the result is 0, or false for all other + * cases. + */ +static inline int atomic_dec_and_test(int *v) +{ + return (atomic_dec_return(v) == 0); +} + +/** + * atomic_add_negative - add and test if negative + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v and returns true + * if the result is negative, or false when + * result is greater than or equal to zero. + */ +static inline int atomic_add_negative(int i, int *v) +{ + return (atomic_add_return(i, v) < 0); +} + +static inline int atomic_xchg(int *v, int n) +{ + register int c; + __asm__ __volatile__ ( + "amoswap.w %0, %2, %1" + : "=r" (c), "+A" (*v) + : "r" (n)); + return c; +} + +/** + * atomic_and - Atomically clear bits in atomic variable + * @mask: Mask of the bits to be retained + * @v: pointer of type int + * + * Atomically retains the bits set in @mask from @v + */ +static inline void atomic_and(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoand.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_and(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoand.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_or - Atomically set bits in atomic variable + * @mask: Mask of the bits to be set + * @v: pointer of type int + * + * Atomically sets the bits set in @mask in @v + */ +static inline void atomic_or(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoor.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_or(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoor.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_xor - Atomically flips bits in atomic variable + * @mask: Mask of the bits to be flipped + * @v: pointer of type int + * + * Atomically flips the bits set in @mask in @v + */ +static inline void atomic_xor(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoxor.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_xor(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoxor.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * test_and_set_bit - Set a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_set_bit(int nr, volatile unsigned long *addr) +{ + unsigned long __res, __mask; + __mask = MASK(nr); + __asm__ __volatile__ ( \ + "amoor.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to clear + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_clear_bit(int nr, volatile unsigned long *addr) +{ + unsigned long __res, __mask; + __mask = MASK_NOT(nr); + __asm__ __volatile__ ( \ + "amoand.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * test_and_change_bit - Change a bit and return its old value + * @nr: Bit to change + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_change_bit(int nr, volatile unsigned long *addr) +{ + + unsigned long __res, __mask; + __mask = MASK(nr); + __asm__ __volatile__ ( \ + "amoxor.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * set_bit - Atomically set a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * This function is atomic and may not be reordered. + */ + +static inline void set_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOOR.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK(nr))); +} + +/** + * clear_bit - Clears a bit in memory + * @nr: Bit to clear + * @addr: Address to start counting from + * + * clear_bit() is atomic and may not be reordered. + */ +static inline void clear_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOAND.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK_NOT(nr))); +} + +/** + * change_bit - Toggle a bit in memory + * @nr: Bit to change + * @addr: Address to start counting from + * + * change_bit() is atomic and may not be reordered. + */ +static inline void change_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOXOR.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK(nr))); +} + +#endif /* __riscv_atomic */ + +#endif /* __GNUC__ */ + +#endif /* __ASSEMBLER__ */ + +#endif /* __riscv */ + +#ifdef __cplusplus +} +#endif + +#endif /* RISCV_REGS_H */ diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv_rv32_stubs.c b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv_rv32_stubs.c new file mode 100644 index 0000000..e26ecfc --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv_rv32_stubs.c @@ -0,0 +1,243 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_stubs.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Stubs for the Mi-V soft processor Interrupt handler. + * + * The functions below will only be linked with the application code if the user + * does not provide an implementation for these functions. These functions are + * defined with weak linking so that they can be overridden by a function with + * same prototype in the user's application code. + * + */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +__attribute__((weak)) void Software_IRQHandler(void) +{ + _exit(10); +} + +__attribute__((weak)) void SysTick_Handler(void) +{ + /* Default handler */ +} + +#ifdef MIV_LEGACY_RV32 +__attribute__((weak)) uint8_t Invalid_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_1_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_2_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_3_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_4_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_5_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_6_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_7_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_8_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_9_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_10_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_11_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_12_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_13_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_14_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_15_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_16_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_17_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_18_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_19_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_20_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_21_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_22_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_23_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_24_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_25_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_26_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_27_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_28_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_29_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_30_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_31_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +#else +__attribute__((weak)) void External_IRQHandler(void) +{ +} +__attribute__((weak)) void MGECI_IRQHandler(void) +{ +} +__attribute__((weak)) void MGEUI_IRQHandler(void) +{ +} +__attribute__((weak)) void SUBSYS_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI0_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI1_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI2_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI3_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI4_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI5_IRQHandler(void) +{ +} +__attribute__((weak)) void Reserved_IRQHandler(void) +{ + _exit(10); +} +#ifndef MIV_RV32_V3_0 /* For MIV_RV32 v3.0 */ +__attribute__((weak)) void MSYS_EI6_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI7_IRQHandler(void) +{ +} +__attribute__((weak)) void SUBSYSR_IRQHandler(void) +{ +} +#endif /* MIV_RV32_V3_0 */ +#endif /* MIV_LEGACY_RV32 */ + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv_rv32_subsys.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv_rv32_subsys.h new file mode 100644 index 0000000..509f13b --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv_rv32_subsys.h @@ -0,0 +1,293 @@ +/******************************************************************************* + * Copyright 2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_subsys.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor SUBSYS regsiter description and API fuctions. + * + */ +#ifndef MIV_RV32_SUBSYS_H +#define MIV_RV32_SUBSYS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef MIV_LEGACY_RV32 +#define MGEUI 16U +#define MGECI 17U +#define MSYS_EI0 24U +#define MSYS_EI1 25U +#define MSYS_EI2 26U +#define MSYS_EI3 27U +#define MSYS_EI4 28U +#define MSYS_EI5 29U + +#define MGEUI_MEIP (1u << MGEUI) +#define MGECI_MEIP (1u << MGECI) +#define MSYS_EI0IP (1u << MSYS_EI0) +#define MSYS_EI1IP (1u << MSYS_EI1) +#define MSYS_EI2IP (1u << MSYS_EI2) +#define MSYS_EI3IP (1u << MSYS_EI3) +#define MSYS_EI4IP (1u << MSYS_EI4) +#define MSYS_EI5IP (1u << MSYS_EI5) + +#define MIV_LOCAL_IRQ_MIN 16 +#ifndef MIV_RV32_V3_0 /*For MIV_RV32 v3.1*/ +#define SUBSYSR 22U +#define SUBSYS_EI 23U +#define MSYS_EI6 30U +#define MSYS_EI7 31U +#define MIV_SUBSYSR (1u << SUBSYSR) +#define MIV_SUBSYS (1u << SUBSYS_EI) +#define MSYS_EI6IP (1u << MSYS_EI6) +#define MSYS_EI7IP (1u << MSYS_EI7) +#define MIV_LOCAL_IRQ_MAX 31 + +#else /* MIV_RV32_V3_0 */ +#define MIV_LOCAL_IRQ_MAX 29 +#define SUBSYS_EI 30U +#define MIP_SUBSYS_REG (1u << SUBSYS_EI) + +#endif /* MIV_RV32_V3_0 */ +#endif /* MIV_LEGACY_RV32 */ + +#ifdef MIV_LEGACY_RV32 +#define MIV_LOCAL_IRQ_MAX 0U +#define MIV_LOCAL_IRQ_MIN 0U +#endif /* MIV_LEGACY_RV32 */ + +#ifdef __cplusplus +} +#endif + +/*-------------------------------------------------------------------------*//** + SUBSYS Register Configuration + ======================================= + For the SUBSYS registers configutation, the following definitions are used in + the SUBSUS API functions. For example, to raise soft interrupts, enable parity + checks, soft reset, and so on. + + | Configuration | Value | Description | + |--------------------------|-------|------------------------------------------------| + | SUBSYS_SOFT_REG_GRP_DED | 0x04 | Mask for the Core GPR DED Reset Register | + | SUBSYS_CFG_PARITY_CHECK | 0x01 | Use to set or clear the parity check on the TCM | + | SUBSYS_SOFT_RESET | 0x01 | Use the SUBSYS soft reset the MIV_RV32 IP core | + | SUBSYS_SOFT_IRQ | 0x02 | Use to raise a software interrupt through SUBSYS| + */ +/*Mask for the Core GPR DED Reset Register*/ +#define SUBSYS_SOFT_REG_GRP_DED 0x04U + +/*Use to set or clear the parity check on the TCM*/ +#define SUBSYS_CFG_PARITY_CHECK 0x01U + +/*Use the SUBSYS soft reset the MIV_RV32 IP core*/ +#define SUBSYS_SOFT_RESET 0x01U + +/*Use to raise a software interrupt through SUBSYS*/ +#define SUBSYS_SOFT_IRQ 0x02U + +/*-------------------------------------------------------------------------*//** + SUBSYS Interrupt Request Masks + ======================================= + The following values correspond to the bit value of the SUBSYS interrupt + enable and interrupt pending register. + + | Interrupt Mask | Value | Description | + |----------------------------|---------|-------------------------------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | TCM ECC controllable error irq enable | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | TCM ECC uncontrollable error irq enable | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | AXI write response error irq enable | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | Icache ECC Correctable error irq | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | Icache ECC Uncorrectable error irq | + | SUBSYS_BASE_ADDR | 0x6000u | Base address of the SUBSYS | + */ +/* TCM ECC correctable error irq enable mask value */ +#define SUBSYS_TCM_ECC_CE_IRQ 0x01u + +/* TCMECC uncorrectable error irq enable */ +#define SUBSYS_TCM_ECC_UCE_IRQ 0x02u + +/* AXI write response error irq enable */ +#define SUBSYS_AXI_WR_RESP_IRQ 0x10u + +/*Icache ECC Correctable error irq*/ +#define SUBSYS_ICACHE_ECC_CE_IRQ 0x40u + +/*Icache ECC Uncorrectable error irq*/ +#define SUBSYS_ICACHE_ECC_UCE_IRQ 0x80u + +/*Base address of the SUBSYS*/ +#define SUBSYS_BASE_ADDR 0x00006000UL + +/***************************************************************************//** + Subsys contains interrupt enable, interrupt pending and Subsys registers + which can be used to enable SUBSYS specific features such as ECC for vaious + memories. For more available features refer to the MIV_RV32 User Guide +*/ +typedef struct +{ + volatile uint32_t cfg; /*Parity is not supported by MIV_RV32 v3.1 and MIV_RV32 v3.0.100*/ + volatile uint32_t reserved0[3]; + volatile uint32_t irq_en; /*offset 0x10*/ + volatile uint32_t irq_pend; + volatile uint32_t reserved1[2]; + volatile uint32_t soft_reg; /*offset 0x20*/ +} SUBSYS_Type; + +#define SUBSYS ((SUBSYS_Type *)SUBSYS_BASE_ADDR) + +/***************************************************************************//** + The MRV32_subsys_enable_irq() function initializes the SUBSYS interrupts. It + takes the logical OR of the following defined IRQ masks as a parameter. + + @param irq_mask + | irq_mask | Value | + |------------------------|------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | + Use logical OR values of one or more interrupts to enable them in the SUBSYS + @return + This function does not return any value. + */ +static inline void MRV32_subsys_enable_irq(uint32_t irq_mask) +{ + SUBSYS->irq_en |= irq_mask; +} + +/***************************************************************************//** + The MRV32_subsys_disable_irq() function disables the SUBSYS interrupts. It + takes the logical OR of the following defined IRQ masks as a parameter. + + @param irq_mask + | irq_mask | Value | + |------------------------|------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | + Use logical OR values of one or more interrupts to disable them in the SUBSYS + @return + This function does not return any value. + */ +static inline void MRV32_subsys_disable_irq(uint32_t irq_mask) +{ + SUBSYS->irq_en &= ~irq_mask; +} + +/***************************************************************************//** + The MRV32_subsys_clear_irq() function clears the SUBSYS interrupts, which was + triggered. It takes the logical OR of the following defined IRQ masks as a + parameter. + @param irq_mask + | irq_mask | Value | + |------------------------|------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | + Use logical OR values of one or more interrupts to disable them in the SUBSYS + @return + This function does not return any value. + */ +static inline void MRV32_subsys_clear_irq(uint32_t irq_mask) +{ + SUBSYS->irq_pend |= irq_mask; +} + +/***************************************************************************//** + The MRV32_subsys_irq_cause() function returns the irq_pend register value which + is present in the SUBSYS. This is be used to check which irq_mask value + caused the SUBSYS interrupt to occur. + @param + This function does not take any parameters + + @return + This function returns the irq_pend regsiter value. +*/ +static inline uint32_t MRV32_subsys_irq_cause() +{ + return SUBSYS->irq_pend; +} + +/***************************************************************************//** + The MRV32_is_gpr_ded() function returns the core_gpr_ded_reset_reg bit value. + When ECC is enabled, the core_gpr_ded_reset_reg is set when the core was + reset due to GPR DED error. + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline uint32_t MRV32_is_gpr_ded(void) +{ + return((SUBSYS->soft_reg & SUBSYS_SOFT_REG_GRP_DED) >> 0x02u); +} + +/***************************************************************************//** + The MRV32_clear_gpr_ded() function must be used to clear the + core_gpr_ded_reset_reg bit. When ECC is enabled, the core_gpr_ded_reset_reg is + set when the core was previously reset due to GPR DED error. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV32_clear_gpr_ded(void) +{ + SUBSYS->soft_reg &= ~SUBSYS_SOFT_REG_GRP_DED; +} + +/***************************************************************************//** + The MRV32_enable_parity_check() function is used to enable parity check on + the TCM and it's interface transactions. This feature is not available on + MIV_RV32 v3.1 and MIV_RV32 v3.0.100 + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV32_enable_parity_check(void) +{ + SUBSYS->cfg |= SUBSYS_CFG_PARITY_CHECK; +} + +/***************************************************************************//** + The MRV32_disable_parity_check() function is used to disable parity check on + the TCM and it's interface transactions. + @param + This function does not take any parameters + + @return + This function does not return any value. + + */ +static inline void MRV32_disable_parity_check(void) +{ + SUBSYS->cfg &= ~SUBSYS_CFG_PARITY_CHECK; +} + +/***************************************************************************//** + The MRV32_cpu_soft_reset() function is used to cause a soft cpu reset on + the MIV_RV32 soft processor core. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV32_cpu_soft_reset(void) +{ + SUBSYS->soft_reg |= SUBSYS_SOFT_RESET; +} +#endif /* MIV_RV32_SUBSYS_H */ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv_rv32_syscall.c b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv_rv32_syscall.c new file mode 100644 index 0000000..bd2f881 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/miv_rv32_syscall.c @@ -0,0 +1,364 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_syscall.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Stubs for system calls. + * + */ +#include +#include +#include +#include +#include "miv_rv32_hal.h" + +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +#include + +#ifndef LEGACY_DIR_STRUCTURE +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" +#else +#include "core_uart_apb.h" +#endif + +#endif /*MSCC_STDIO_THRU_CORE_UART_APB*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + +/*------------------------------------------------------------------------------ + * CoreUARTapb instance data for the CoreUARTapb instance used for standard + * output. + */ +static UART_instance_t g_stdio_uart; + +/*============================================================================== + * Flag used to indicate if the UART driver needs to be initialized. + */ +static int g_stdio_uart_init_done = 0; + +/* + * Disable semihosting apis + */ +#pragma import(__use_no_semihosting_swi) + +/*============================================================================== + * sendchar() + */ +int sendchar(int ch) +{ + /*-------------------------------------------------------------------------- + * Initialize the UART driver if it is the first time this function is + * called. + */ + if ( !g_stdio_uart_init_done ) + { + /****************************************************************************** + * Baud value: + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + UART_init( &g_stdio_uart, + MSCC_STDIO_UART_BASE_ADDR, + ((SYS_CLK_FREQ/(16 * MSCC_STDIO_BAUD_VALUE))-1), + (DATA_8_BITS | NO_PARITY)); + + g_stdio_uart_init_done = 1; + } + + /*-------------------------------------------------------------------------- + * Output text to the UART. + */ + UART_send( &g_stdio_uart, (uint8_t *)&ch, 1 ); + + return (ch); +} + +/*============================================================================== + * getachar() + */ +int getachar(void) +{ + uint8_t rx_size; + uint8_t rx_byte; + + if ( !g_stdio_uart_init_done ) + { + /****************************************************************************** + * Baud value: + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + UART_init( &g_stdio_uart, + MSCC_STDIO_UART_BASE_ADDR, + ((SYS_CLK_FREQ/(16 * MSCC_STDIO_BAUD_VALUE))-1), + (DATA_8_BITS | NO_PARITY)); + + g_stdio_uart_init_done = 1; + } + + do + { + rx_size = UART_get_rx(&g_stdio_uart, &rx_byte, 1); + } while(0u == rx_size); + + return rx_byte; +} + +#endif /*MSCC_STDIO_THRU_CORE_UART_APB*/ + +#undef errno +static int errno; + +static char *__env[1] = { 0 }; +char **environ = __env; + +void write_hex(int fd, uint32_t hex) +{ + char towrite; + + write( fd , "0x", 2U ); + + for (uint32_t ii = 8U ; ii > 0U; ii--) + { + uint32_t jj = ii-1U; + uint8_t digit = ((hex & (0xFU << (jj*4U))) >> (jj*4U)); + towrite = digit < 0xAU ? (0x48U + digit) : (0x65U + (digit - 0xAU)); + write( fd, &towrite, 1U); + } +} + + +#ifdef GDB_TESTING +void __attribute__((optimize("O0"))) _exit(int code) +#else +void _exit(int code) +#endif +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + const char * message = "\nProgam has exited with code:"; + + write(STDERR_FILENO, message, strlen(message)); + write_hex(STDERR_FILENO, code); +#endif + + while (1){}; +} + +void *_sbrk(ptrdiff_t incr) +{ + extern char _end; + extern char _heap_end; + extern char __heap_start; + extern char __heap_end; + static char *curbrk = &_end; + void * ret = NULL; + + /* + * Did we allocated memory for the heap in the linker script? + * You need to set HEAP_SIZE to a non-zero value in your linker script if + * the following assertion fires. + */ + ASSERT(&__heap_end > &__heap_start); + + if (((curbrk + incr) < &_end) || ((curbrk + incr) > &_heap_end)) + { + errno = ENOMEM; + ret = ((char *) - 1); + } + else + { + curbrk += incr; + ret = curbrk - incr; + } + + /* + * Did we run out of heap? + * You need to increase the heap size in the linker script if the following + * assertion fires. + * */ + ASSERT(curbrk <= &__heap_end); + + return(ret); +} + +int _isatty(int fd) +{ + int ret = 0; + + if (fd <= 2) /* one of stdin, stdout, stderr */ + { + ret = 1; + } + else + { + errno = EBADF; + ret = 0; + } + + return(ret); +} + +static int stub(int err) +{ + errno = err; + return -1; +} + +int _open(const char* name, int flags, int mode) +{ + return stub(ENOENT); +} + +int _openat(int dirfd, const char* name, int flags, int mode) +{ + return stub(ENOENT); +} + +int _close(int fd) +{ + return stub(EBADF); +} + +int _execve(const char* name, char* const argv[], char* const env[]) +{ + return stub(ENOMEM); +} + +int _fork(void) +{ + return stub(EAGAIN); +} + +int _fstat(int fd, struct stat *st) +{ + int ret = 0; + + if (isatty(fd)) + { + st->st_mode = S_IFCHR; + ret = 0; + } + else + { + ret = stub(EBADF); + } + + return ret; +} + +int _getpid(void) +{ + return 1; +} + +int _kill(int pid, int sig) +{ + return stub(EINVAL); +} + +int _link(const char *old_name, const char *new_name) +{ + return stub(EMLINK); +} + +off_t _lseek(int fd, off_t ptr, int dir) +{ + off_t ret = 0; + if (_isatty(fd)) + { + ret = 0; + } + else + { + ret = stub(EBADF); + } + + return ret; +} + +ssize_t _read(int fd, void* ptr, size_t len) +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + + char* ptr1 = (char*)ptr; + + if (_isatty(fd)) + { + int count; + + for (count = 0; count < len; count++) + { + ptr1[count] = getachar(); + sendchar(ptr1[count]); + + /* Return partial buffer if we get EOL */ + if (('\r' == ptr1[count])||('\n' == ptr1[count])) + { + ptr1[count] = '\n'; + return count; + } + } + + return count; /* Filled the buffer */ + } +#endif + + return stub(EBADF); +} + +int _stat(const char* file, struct stat* st) +{ + return stub(EACCES); +} + +clock_t _times(struct tms* buf) +{ + return stub(EACCES); +} + +int _unlink(const char* name) +{ + return stub(ENOENT); +} + +int _wait(int* status) +{ + return stub(ECHILD); +} + +ssize_t _write(int fd, const void* ptr, size_t len) +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + int count_out; + char* ptr1 = (char*)ptr; + + /*-------------------------------------------------------------------------- + * Output text to the UART. + */ + count_out = 0; + while(len--) + { + sendchar(ptr1[count_out]); + count_out++; + } + + errno = 0; + return count_out; + +#else /* MSCC_STDIO_THRU_CORE_UART_APB */ + + return stub(EBADF); + +#endif /* MSCC_STDIO_THRU_CORE_UART_APB */ + +} + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/sample_fpga_design_config.h b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/sample_fpga_design_config.h new file mode 100644 index 0000000..a380d96 --- /dev/null +++ b/applications/user-crypto/miv-rv32-ndrbg-services/src/platform/miv_rv32_hal/sample_fpga_design_config.h @@ -0,0 +1,167 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file sample_fpga_design_config.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Sample design configuration settings + * + */ + /*========================================================================*//** + @mainpage + Example file detailing how the fpga_design_config.h should be constructed + for the SoftConsole project targeted for Mi-V processors. + + @section intro_sec Introduction + The SoftConsole project targeted for Mi-V processors now have an improved + folder structure. Detailed description of the folder structure is available + at https://github.com/Mi-V-Soft-RISC-V/miv-rv32-documentation. + + The fpga_design_config.h must be stored as shown below + /boards//fpga_design_config.h + + Currently this file must be hand crafted when using the Mi-V Soft Processor. + In future, all the design and soft IP configurations will be automatically + generated from the Libero design description data. + + You can use this sample file as an example. + Rename this file from sample_fpga_design_config.h to fpga_design_config.h + and then customize it per your hardware design. + + @section Project configuration Instructions + 1. Change SYS_CLK_FREQ define to frequency of Mi-V Soft processor clock + 2 Add all the soft IP core BASE addresses + 3. Add the peripheral Core Interrupts to Mi-V Soft processor IRQ number + mappings + 4. Define MSCC_STDIO_UART_BASE_ADDR if you want a CoreUARTapb mapped to + STDIO + + **NOTE** + In the legacy folder structures, the file hw_config.h as was used at the + root of the project folder. This file is now depricated. + +*//*=========================================================================*/ + +#ifndef FPGA_DESIGN_CONFIG_H_ +#define FPGA_DESIGN_CONFIG_H_ + +/***************************************************************************//** + * Soft-processor clock definition + * This is the only clock brought over from the Mi-V Libero design. + */ +#ifndef SYS_CLK_FREQ +#define SYS_CLK_FREQ 50000000UL +#endif + +/***************************************************************************//** + * Peripheral base addresses. + * Format of define is: + * __BASE_ADDR + * The field is optional if there is only one instance of the core + * in the design + * MIV_ESS is an extended peripheral subsystem IP core with peripherals + * connections as defined below. + * The system can be further extended by attaching APB peripherals to the + * empty APB slots. + */ +#define MIV_ESS_PLIC_BASE_ADDR 0x70000000UL +#define COREUARTAPB0_BASE_ADDR 0x71000000UL +#define MIV_MTIMER_BASE_ADDR 0x72000000UL +#define MIV_ESS_APBSLOT3_BASE_ADDR 0x73000000UL +#define MIV_ESS_APBSLOT4_BASE_ADDR 0x74000000UL +#define COREGPIO_OUT_BASE_ADDR 0x75000000UL +#define CORESPI_BASE_ADDR 0x76000000UL +#define MIV_ESS_uDMA_BASE_ADDR 0x78000000UL +#define MIV_ESS_WDOG_BASE_ADDR 0x79000000UL +#define MIV_ESS_I2C_BASE_ADDR 0x7A000000UL +#define MIV_ESS_APBSLOTB_BASE_ADDR 0x7B000000UL +#define MIV_ESS_APBSLOTC_BASE_ADDR 0x7C000000UL +#define MIV_ESS_APBSLOTD_BASE_ADDR 0x7D000000UL +#define MIV_ESS_APBSLOTE_BASE_ADDR 0x7E000000UL +#define MIV_ESS_APBSLOTF_BASE_ADDR 0x7F000000UL + +/***************************************************************************//** + * Peripheral Interrupts are mapped to the corresponding Mi-V Soft processor + * interrupt in the Libero design. + * + * On the legacy RV32 cores, there can be up to 31 external interrupts (IRQ[30:0] + * pins). The legacy RV32 Soft processor external interrupts are defined in the + miv_rv32_plic.h + * + * These are of the form + * typedef enum +{ + NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + . + . + . + External_31_IRQn = 31 +} IRQn_Type; + + On the legacy RV32 processors, the PLIC identifies the interrupt and passes it + on to the processor core. The interrupt 0 is not used. The pin IRQ[0] should + map to External_1_IRQn likewise IRQ[30] should map to External_31_IRQn + +e.g + +#define TIMER0_IRQn External_30_IRQn +#define TIMER1_IRQn External_31_IRQn + + The MIV_RV32 soft processor has up to six optional system interrupts, MSYS_EI[n] + in addition to one EXT_IRQ. + The MIV_RV32 does not have an inbuilt PLIC and all the interrupts are directly + delivered to the processor core, hence unlike legacy RV32 cores, no interrupt + number mapping is necessary on MIV_RV32 core. + */ + +/**************************************************************************** + * Baud value to achieve a 115200 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ +#define BAUD_VALUE_115200 ((SYS_CLK_FREQ / (16 * 115200)) - 1) + +/****************************************************************************** + * Baud value to achieve a 57600 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + #define BAUD_VALUE_57600 ((SYS_CLK_FREQ / (16 * 57600)) - 1) + +/***************************************************************************//** + * Define MSCC_STDIO_THRU_CORE_UART_APB in the project settings if you want the + * standard IOs to be redirected to a terminal via UART. + */ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +/* + * A base address mapping for the STDIO printf/scanf mapping to CortUARTapb + * must be provided if it is being used + * + * e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR + */ +#define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB0_BASE_ADDR + +#ifndef MSCC_STDIO_UART_BASE_ADDR +#error MSCC_STDIO_UART_BASE_ADDR not defined- e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR +#endif + +#ifndef MSCC_STDIO_BAUD_VALUE +/* + * The MSCC_STDIO_BAUD_VALUE define should be set in your project's settings to + * specify the baud value used by the standard output CoreUARTapb instance for + * generating the UART's baud rate if you want a different baud rate from the + * default of 115200 baud + */ +#define MSCC_STDIO_BAUD_VALUE 115200 +#endif /*MSCC_STDIO_BAUD_VALUE*/ + +#endif /* end of MSCC_STDIO_THRU_CORE_UART_APB */ +/******************************************************************************* + * End of user edit section + */ +#endif /* FPGA_DESIGN_CONFIG_H_ */ diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/.cproject b/applications/user-crypto/miv-rv32-rsa-cryptography/.cproject new file mode 100644 index 0000000..507c5ba --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/.cproject @@ -0,0 +1,333 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/.gitignore b/applications/user-crypto/miv-rv32-rsa-cryptography/.gitignore new file mode 100644 index 0000000..f1b6b72 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/.gitignore @@ -0,0 +1,3 @@ +/.settings/ +/*miv-rv32-imc-debug*/ +/*miv-rv32-imc-release*/ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/.project b/applications/user-crypto/miv-rv32-rsa-cryptography/.project new file mode 100644 index 0000000..f949c55 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/.project @@ -0,0 +1,26 @@ + + + miv-rv32-rsa-cryptography + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/README.md b/applications/user-crypto/miv-rv32-rsa-cryptography/README.md new file mode 100644 index 0000000..11ac2e2 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/README.md @@ -0,0 +1,166 @@ + +PolarFire User Crypto RSA Encyption/Deryption Services example +================================================================================ +This example project demonstrates the use of the PolarFire RSA service to +encrypt and decrypt the message. The following User Athena service are used: + + - RSA Encryption + - RSA Decryption + +There are two different build configurations provided with this project which +configure this SoftConsole project for RISC-V IMC instruction extension. +The following configurations are provided with the example: + + - miv-rv32-imc-debug + - miv-rv32-imc-release + +Mi-V Soft Processor +-------------------------------------------------------------------------------- +This example uses Mi-V SoftProcessor MiV_RV32.The design is built for debugging +MiV_RV32 through the PolarFire FPGA programming JTAG port using a FlashPro5. +To achieve this the CoreJTAGDebug IP is used to connect to the JTAG port of the +MiV_RV32. + +All the platform/design specific definitions such as peripheral base addresses, +system clock frequency etc. are included in fpga_design_config.h. The +fpga_design_config.h is located at the root folder of this project. + +The Mi-V Soft Processor MiV_RV32 firmware projects needs the miv_rv32_hal and +the hal firmware(RISC-V HAL). + +The RISC-V HAL is available at GitHub [Mi-V-Soft-RISC-V](https://mi-v-ecosystem.github.io/redirects/platform). + +How to use this example +-------------------------------------------------------------------------------- +This example project is targeted at a MIV_RV32 design running on a PolarFire-Eval-Kit +connected via a USB-UART serial cable to a host PC running a terminal emulator +such as TeraTerm or Putty configured as follows: + + - 115200 baud + - 8 data bits + - 1 stop bit + - no parity + - no flow control. + +The example project will display instructions over the serial port. To execute +the particular service, user has to enter the required information as shown over +the serial port. This program also displays the return data from User Crypto +processor. + +RSA is an algorithm used by modern computers to encrypt and decrypt messages. +It is an asymmetric cryptographic algorithm. Asymmetric means that there are two +different keys. This is also called public key cryptography, because one of them +can be given to everyone. The other key must be kept private. It is based on the +fact that finding the factors of an integer is hard (the factoring problem). +RSA involves a public key and private key. The public key can be known to +everyone, it is used to encrypt messages. Messages encrypted using the public +key can only be decrypted with the private key. + +fpga_design_config (formerly known as hw_config.h) +-------------------------------------------------------------------------------- +The SoftConsole project targeted for Mi-V processors now use an improved +directory structure. The fpga_design_config.h must be stored as shown below + +` + /boards//fpga_design_config/fpga_design_config.h +` + +Currently, this file must be hand crafted when using the Mi-V Soft Processor. +In future, all the design and soft IP configurations will be automatically +generated from the Libero design description data. + +You can use the sample file provided with MIV_RV32 HAL as an example. Rename it +from sample_fpga_design_config.h to fpga_design_config.h and then customize it +per your hardware design such as SYS_CLK_FREQ, peripheral BASE addresses, +interrupt numbers, definition of MSCC_STDIO_UART_BASE_ADDR if you want a +CoreUARTapb mapped to STDIO, etc. + +### Data Encryption + +Option '1' to encrypt the message using RSA. +This service encrypt the message based on public key. This example project will +read the public key(n & e) and message from UART terminal and computes the +cipher text corresponding to c = m^e mod n. The cipher text is displayed on +UART terminal. + +### Data Decryption + +Option '2' to decrypt the message using RSA. +This service decrypt the message based on private key. This service performs +an RSA private key decryption operation with CRT and SCA countermeasures on the +data buffer. This example project will read the cipher text, private key (n & d), +public key(n & e), private prime modulus i.e. P modulus and q modulus from UART +terminal and computes the plain text corresponding to m = c^d mod n = m^(de) mod n +The computed plain text is displayed on UART terminal. + +### Configurations + +The CAL library needs a config_user.h containing the configuration data. +This application provides following settings as per CAL requirement + 1. A variable which provides the base address of the User Crypto hardware block + is defined in main.c + + `uint32_t g_user_crypto_base_addr = 0x62000000UL;` + + 2. A symbol INC_STDINT_H is defined in project preprocessor setting. + For more detail, please refer to caltypes.h file present in CAL folder. + +**NOTE**: + 1. If you try to enter data values other than 0 - 9, a - f, A - F, an error + message will be displayed on the serial terminal. + 2. You must enter all input data as whole bytes. If you enter the 128-bit key + {1230...0} as 0x12 0x3 and press return, this will be treated as + byte0 = 0x12, byte1 = 0x30, byte2-127 = 0x00. + +### Test script + +A test script is provided with this example which automatically enters the NIST +vectors and associated data to verify the functionality. You can use +RV32_RSA_cryptography.ttl Tera Term Macro script present in project directory for +testing rsa cryptography example project. + +**NOTE:** +1. Tera Term Macros don’t work with Windows 10 build 14393.0. You should update + to Windows 10 build 14393.0.105 or [later.](https://osdn.net/ticket/browse.php?group_id=1412&tid=36526) +2. Before running Tera Term Macro script, set language as English + (Setup->General->Language). Also setup transmit delay in (Setup->Serial port) + to 5msec/char and 5msec/line. +3. By default, Tera Term log will be stored in Tera Term installation Directory. + +## Target hardware + +This project was tested on PolarFire-Eval-Kit with CFG4 configuration of the +MIV_RV32 design available [here](https://github.com/Mi-V-Soft-RISC-V/PolarFire-Eval-Kit/tree/main/Libero_Projects) + +All the design specific definitions such as peripheral base addresses, system +clock frequency etc. are included in fpga_design_config.h. + +The firmware projects needs the HAL and the MIV_RV32 HAL firmware components. + +This example project can be used with another design using a different hardware +configurations. This can be achieved by overwriting the content of this example +project's "fpga_design_config.h" file with the correct data per your Libero design. + +### Booting the system + +Currently the example project is configured to use FlashPro debugger to execute +from LSRAM in both Debug and Release mode. + +In the release mode build configuration, following setting is used +`--change-section-lma *-0x80000000` under +Tool Settings > Cross RISCV GNU Create Flash Image > General > Other flags. + +This will allow you to attach the release mode executable as the memory +initialization client in Libero when you want to execute it from non-volatile memory. + +## Silicon revision dependencies + +This example is tested on PolarFire MPF300TS device. + +### CAL library src + +To obtain the CAL source code and a SoftConsole project to generate the CAL +library archive file (*.a) refer [SoftConsole Documentation](https://mi-v-ecosystem.github.io/SoftConsole-Documentation/SoftConsole-v2021.3/using_softconsole/other.html#crypto-application-library). +The CAL source code is bound by license agreement and it will be available as +part of the SoftConsole installation if the CAL specific license was agreed +while installing it. \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/RV32_RSA_cryptography.ttl b/applications/user-crypto/miv-rv32-rsa-cryptography/RV32_RSA_cryptography.ttl new file mode 100644 index 0000000..f6f702a --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/RV32_RSA_cryptography.ttl @@ -0,0 +1,324 @@ +; Tera Term Setting: +; 1. Before running Tera Term Macro script, you should set language as English +; and transmit delay in Serial port setup to 5msec/char and 5msec/line. +; 2. By default, Tera Term log will be stored in Tera Term installation Directory. + +changedir '.' +logopen "RSA_CRYPTO.log" 0 0 0 1 + +settitle 'PolarFire User Crypto RSA Crypto service' + +setsync 1 + +;Clear screen +clearscreen 0 + +; Set baud rate to 115200 +setbaud 115200 + +; local echo off +setecho 0 + +send 13 +pause 2 + +; ---------------------------------------------------------------------------------------------------------------------------------------------------------- +; RSA Encryption +; INPUT +; msg = +; 657874736f6e207479707469456e6372697468206e74207772696d656578706520746f20 +; 77616e7477686f206f7365206c2074687220616c6c20666f736566756c79207568696768 +; 2062652077696c6c696e6720207374725468697369742e20666f72206c7365206e672065 +; 797468696f20616e746f2064656564202774206e20646f6e642077656520616e2066696e +; 6f726b733732207741203330742052532074686176696e672070726f6c20696e73656675 +; 62652075696c6c20697420776c6c7920706566752e20486f7468697320646f206520746f +; 6f77206d20616c6c6f756c6461742077652074687373616767206d65206c6f6e74652061 +; 6372656120746f2079696e676d20747220492061656e6365732e2048737375656e792069 +; 757420616974686f6c7920777265637420636f7270746564656372796265206474657220 +; 6e206c6174206361617420696f20746865642073727970746520656e746f206265647320 +; 65206e65652074687373616761206d652069732054686973 +; n = +; 8e1a97593b3adf945529c78997ed0bca70b04f410bf64db50c2754a6ad2cb9b752d0d5e4 +; 2a496b00df4a0836b6ae5e80e4b4aecde54f556459bdc01c0dc72343d32ae8beaf490519 +; e7aa351fbb154b47f8e7fa9e29b97e6b0832c35085c20c00d4046ed687cd1701348a69de +; 858424aa3c98b1ca3cab4ae8341aa2f02f78603794c6c454ac9c6c751fda472250d7efda +; bb84522da75750c044e5105330fdaddc9ce9fa55e2ffe0f4ddaf8adc1786526e22a58242 +; f6668a0fcd98b9477e5fe304626bfb9ed86f5997393fe230f1bb404a6b5cc69718fa5552 +; c6ae147bf381750dc7fcd7e420d150455502408cd0e7636735ede40f55f946a5b6a643fb +; 9f90f54ce7276e2b04f08d1a1759534bbfbeada60932c2321b7bc5986c08b3a7ae8b61b4 +; 595ddd16558961a9dc82b0e9f70e0d4c9ada379f7e7b51a12af6fe2631ac2afb165ac45c +; db329c8c8df45d6b6c4123782a8f50f69d44bc9fc52a6b92e635bcda279f1c9e0f902964 +; 63762849dd2a069073cdba018497a60ea97bf561d8d379d1 +; e = 00010001 + +; OUTPUT +; Cipher text = +; fa0c027cfd836d2c9e90dd3b8d69596f49db7b63237a209b3a627601cbb8828c074edfff +; 1f40f770f9774a38b0e55fc801f643f393c3afc86c361fad1669ef599abfea16dd43e752 +; fb75675d3b2a1c4f9a521b475513970b9fa2494a42e038dac5c5d0989a65a9e211f65132 +; 4cf0dfb89e0bae3c7b0c6b884637b6d29e0e4b526bf248ea9f97c71eeafa9d5ef1de894f +; 978ed0571eb64d40ca3da83023128e82df0f6fa19d97c9640b862782e5768474093d9c8c +; f6ad159c77e6fd2b68de7fac12cea60eac0056aa38b3840b465cb4b961a6ff00b7c723c9 +; 1602a9bbc99b5f1594b4d2457fa0d4f644cf08f1b3d41f2b5cb7de02e3f2c0540c63ab78 +; fa716c34fbda85b8c9d540d8d45c636895400b8b746abe42db906e2e54addbcd0fb69056 +; d63c48b4e42ad0255aa67aefdea02c4bb8b69a068921aaf5f330e48b0c5df1e4c6da190f +; 5003ed0c6be09f787419cdea9b5f581eccf9f6b58741631998d776c3cc1a4d91f7ffe87c +; 6bb3bf8f1df4d03ae43477e7e90d2f4dd98e5ba248f284c7 +; ---------------------------------------------------------------------------------------------------------------------------------------------------------- + +pause 1 +send '1' + +;Message = 128 Bytes +pause 1 +send '657874736f6e207479707469456e6372' +send '697468206e74207772696d6565787065' +send '20746f2077616e7477686f206f736520' +send '6c2074687220616c6c20666f73656675' +send '6c792075686967682062652077696c6c' +send '696e6720207374725468697369742e20' +send '666f72206c7365206e67206579746869' +send '6f20616e746f2064656564202774206e' +send '20646f6e642077656520616e2066696e' +send '6f726b73373220774120333074205253' +send '2074686176696e672070726f6c20696e' +send '7365667562652075696c6c2069742077' +send '6c6c7920706566752e20486f74686973' +send '20646f206520746f6f77206d20616c6c' +send '6f756c64617420776520746873736167' +send '67206d65206c6f6e7465206163726561' +send '20746f2079696e676d20747220492061' +send '656e6365732e2048737375656e792069' +send '757420616974686f6c79207772656374' +send '20636f72707465646563727962652064' +send '746572206e206c617420636161742069' +send '6f20746865642073727970746520656e' +send '746f20626564732065206e6565207468' +send '7373616761206d652069732054686973' +pause 5 + +;n = 256 bytes +send '8e1a97593b3adf945529c78997ed0bca' +send '70b04f410bf64db50c2754a6ad2cb9b7' +send '52d0d5e42a496b00df4a0836b6ae5e80' +send 'e4b4aecde54f556459bdc01c0dc72343' +send 'd32ae8beaf490519e7aa351fbb154b47' +send 'f8e7fa9e29b97e6b0832c35085c20c00' +send 'd4046ed687cd1701348a69de858424aa' +send '3c98b1ca3cab4ae8341aa2f02f786037' +send '94c6c454ac9c6c751fda472250d7efda' +send 'bb84522da75750c044e5105330fdaddc' +send '9ce9fa55e2ffe0f4ddaf8adc1786526e' +send '22a58242f6668a0fcd98b9477e5fe304' +send '626bfb9ed86f5997393fe230f1bb404a' +send '6b5cc69718fa5552c6ae147bf381750d' +send 'c7fcd7e420d150455502408cd0e76367' +send '35ede40f55f946a5b6a643fb9f90f54c' +send 'e7276e2b04f08d1a1759534bbfbeada6' +send '0932c2321b7bc5986c08b3a7ae8b61b4' +send '595ddd16558961a9dc82b0e9f70e0d4c' +send '9ada379f7e7b51a12af6fe2631ac2afb' +send '165ac45cdb329c8c8df45d6b6c412378' +send '2a8f50f69d44bc9fc52a6b92e635bcda' +send '279f1c9e0f90296463762849dd2a0690' +send '73cdba018497a60ea97bf561d8d379d1' + +;e +pause 5 +send '00010001' +send 13 +pause 5 +send 13 +pause 5 +; ---------------------------------------------------------------------------------------------------------------------------------------------------------- +; RSA Decryption +; INPUT +; Cipher text = +; fa0c027cfd836d2c9e90dd3b8d69596f49db7b63237a209b3a627601cbb8828c074edfff1 +; f40f770f9774a38b0e55fc801f643f393c3afc86c361fad1669ef599abfea16dd43e752fb +; 75675d3b2a1c4f9a521b475513970b9fa2494a42e038dac5c5d0989a65a9e211f651324cf +; 0dfb89e0bae3c7b0c6b884637b6d29e0e4b526bf248ea9f97c71eeafa9d5ef1de894f978e +; d0571eb64d40ca3da83023128e82df0f6fa19d97c9640b862782e5768474093d9c8cf6ad1 +; 59c77e6fd2b68de7fac12cea60eac0056aa38b3840b465cb4b961a6ff00b7c723c91602a9 +; bbc99b5f1594b4d2457fa0d4f644cf08f1b3d41f2b5cb7de02e3f2c0540c63ab78fa716c3 +; 4fbda85b8c9d540d8d45c636895400b8b746abe42db906e2e54addbcd0fb69056d63c48b4 +; e42ad0255aa67aefdea02c4bb8b69a068921aaf5f330e48b0c5df1e4c6da190f5003ed0c6 +; be09f787419cdea9b5f581eccf9f6b58741631998d776c3cc1a4d91f7ffe87c6bb3bf8f1d +; f4d03ae43477e7e90d2f4dd98e5ba248f284c7 +; Private key = +; c8f79e0138e6d31ae9c5303de1d838a997f99441e1c210d01e42de9f4af06122a21e7c7e7 +; 9fbdc624f0b90751165e4d0f075842ee659875bb35569035508bc3938f31e69766b856ba4 +; 90ecd37e5665e47d522647fd7fe7350a58bd92431fb423c83561694d419eea51ac3159b7b +; c2274ba2624801c819e4649fc55a80b4f1c30ff080e778cff797e16e564158e80a0334d0f +; 321f5d1361bc636201f8fedd87a46a80e7f2eeb02a8a0717deaba8619b27c0b081e0e45a4 +; 314dd44df6d4139f06d4697e353b26cece2b011284111eef9ea2dfb7a693560e460012d87 +; f16c096775d12ec643183f32b163407c832e8b57c5dacbacfa2afbe277bbb259d03442538 +; 3efe2fe65427546757b462dd06864ba3a4c9d1e0a6afb45d64e20c9e06ad760c2dee92a7c +; 3027d17848f802e2fd5569a4ac39835c883e92299074f4845cb1547af3e4da54ef592fec7 +; 0ea4ba85336d5f4a95f8ca906e8b0f6441276eecae77039a3ca094bff42b6341fc6effe93 +; 07bee7fcafafcfd60eb77d65c717541377892c +; P = +; 2d05e449f1cdfba2602176a59719daeeb5ce0ec32d1c359ac5b13a811c116c2513caaa800 +; bbd34a8a881558f1e9590d0ae020bcc97ff94cae7f6c6d3a15b75507a6842eda2197c9947 +; 498612074d6e4ae882130977b73f810a25f8ff84ae213b50099c8368f54ad63fb72dd89c0 +; 7438e4cf3e0be2f214ba88a86c2c6a2ef215a77335f5e91f1853efd3ff6863980efc53e35 +; 4d45fce1a2fc1a72e49ac29cdfaa5a9866ee58455406cbd6e95310cb75a850fbf2fd84299 +; 554adfeea06f303642e +; Q = +; cc2dfa91c81e3a5e18bf7bc4a025660592c31718e3fcf6661d8560da9156a4ff1fd2e4012 +; 75d7805f8a90bb64c0c00c15e23bab155c6e3b15c68fb5108f5751b4c79ee31411759910d +; 40c68773a7a84dec371b8cfefa8ebb3139850f33da584ae9c7ef194a9259fc28246028e9c +; c7d8b00a939dc1c6e347de111050a7361c32629a00896638ac5de4e438484d749d495d50a +; d59ffa59e2afa82a95c6caf09ec6a3facd2eb2674f62fb1899046c9d1f92cdc7619fe0ea5 +; 0d5ee3b1b2fe469d2e6 +; e = +; 00010001 +; n = +; 8e1a97593b3adf945529c78997ed0bca70b04f410bf64db50c2754a6ad2cb9b752d0d5e42 +; a496b00df4a0836b6ae5e80e4b4aecde54f556459bdc01c0dc72343d32ae8beaf490519e7 +; aa351fbb154b47f8e7fa9e29b97e6b0832c35085c20c00d4046ed687cd1701348a69de858 +; 424aa3c98b1ca3cab4ae8341aa2f02f78603794c6c454ac9c6c751fda472250d7efdabb84 +; 522da75750c044e5105330fdaddc9ce9fa55e2ffe0f4ddaf8adc1786526e22a58242f6668 +; a0fcd98b9477e5fe304626bfb9ed86f5997393fe230f1bb404a6b5cc69718fa5552c6ae14 +; 7bf381750dc7fcd7e420d150455502408cd0e7636735ede40f55f946a5b6a643fb9f90f54 +; ce7276e2b04f08d1a1759534bbfbeada60932c2321b7bc5986c08b3a7ae8b61b4595ddd16 +; 558961a9dc82b0e9f70e0d4c9ada379f7e7b51a12af6fe2631ac2afb165ac45cdb329c8c8 +; df45d6b6c4123782a8f50f69d44bc9fc52a6b92e635bcda279f1c9e0f90296463762849dd +; 2a069073cdba018497a60ea97bf561d8d379d1 + +; OUTPUT +; Decrypted msg = +; 657874736f6e207479707469456e6372697468206e74207772696d656578706520746f20 +; 77616e7477686f206f7365206c2074687220616c6c20666f736566756c79207568696768 +; 2062652077696c6c696e6720207374725468697369742e20666f72206c7365206e672065 +; 797468696f20616e746f2064656564202774206e20646f6e642077656520616e2066696e +; 6f726b733732207741203330742052532074686176696e672070726f6c20696e73656675 +; 62652075696c6c20697420776c6c7920706566752e20486f7468697320646f206520746f +; 6f77206d20616c6c6f756c6461742077652074687373616767206d65206c6f6e74652061 +; 6372656120746f2079696e676d20747220492061656e6365732e2048737375656e792069 +; 757420616974686f6c7920777265637420636f7270746564656372796265206474657220 +; 6e206c6174206361617420696f20746865642073727970746520656e746f206265647320 +; 65206e65652074687373616761206d652069732054686973 + +; ---------------------------------------------------------------------------------------------------------------------------------------------------------- +pause 10 +send '2' +pause 5 +;decrypted message +send 'fa0c027cfd836d2c9e90dd3b8d69596f' +send '49db7b63237a209b3a627601cbb8828c' +send '074edfff1f40f770f9774a38b0e55fc8' +send '01f643f393c3afc86c361fad1669ef59' +send '9abfea16dd43e752fb75675d3b2a1c4f' +send '9a521b475513970b9fa2494a42e038da' +send 'c5c5d0989a65a9e211f651324cf0dfb8' +send '9e0bae3c7b0c6b884637b6d29e0e4b52' +send '6bf248ea9f97c71eeafa9d5ef1de894f' +send '978ed0571eb64d40ca3da83023128e82' +send 'df0f6fa19d97c9640b862782e5768474' +send '093d9c8cf6ad159c77e6fd2b68de7fac' +send '12cea60eac0056aa38b3840b465cb4b9' +send '61a6ff00b7c723c91602a9bbc99b5f15' +send '94b4d2457fa0d4f644cf08f1b3d41f2b' +send '5cb7de02e3f2c0540c63ab78fa716c34' +send 'fbda85b8c9d540d8d45c636895400b8b' +send '746abe42db906e2e54addbcd0fb69056' +send 'd63c48b4e42ad0255aa67aefdea02c4b' +send 'b8b69a068921aaf5f330e48b0c5df1e4' +send 'c6da190f5003ed0c6be09f787419cdea' +send '9b5f581eccf9f6b58741631998d776c3' +send 'cc1a4d91f7ffe87c6bb3bf8f1df4d03a' +send 'e43477e7e90d2f4dd98e5ba248f284c7' +pause 5 + +;private key D +send 'c8f79e0138e6d31ae9c5303de1d838a9' +send '97f99441e1c210d01e42de9f4af06122' +send 'a21e7c7e79fbdc624f0b90751165e4d0' +send 'f075842ee659875bb35569035508bc39' +send '38f31e69766b856ba490ecd37e5665e4' +send '7d522647fd7fe7350a58bd92431fb423' +send 'c83561694d419eea51ac3159b7bc2274' +send 'ba2624801c819e4649fc55a80b4f1c30' +send 'ff080e778cff797e16e564158e80a033' +send '4d0f321f5d1361bc636201f8fedd87a4' +send '6a80e7f2eeb02a8a0717deaba8619b27' +send 'c0b081e0e45a4314dd44df6d4139f06d' +send '4697e353b26cece2b011284111eef9ea' +send '2dfb7a693560e460012d87f16c096775' +send 'd12ec643183f32b163407c832e8b57c5' +send 'dacbacfa2afbe277bbb259d034425383' +send 'efe2fe65427546757b462dd06864ba3a' +send '4c9d1e0a6afb45d64e20c9e06ad760c2' +send 'dee92a7c3027d17848f802e2fd5569a4' +send 'ac39835c883e92299074f4845cb1547a' +send 'f3e4da54ef592fec70ea4ba85336d5f4' +send 'a95f8ca906e8b0f6441276eecae77039' +send 'a3ca094bff42b6341fc6effe9307bee7' +send 'fcafafcfd60eb77d65c717541377892c' +pause 5 + +;P +send '2d05e449f1cdfba2602176a59719daee' +send 'b5ce0ec32d1c359ac5b13a811c116c25' +send '13caaa800bbd34a8a881558f1e9590d0' +send 'ae020bcc97ff94cae7f6c6d3a15b7550' +send '7a6842eda2197c9947498612074d6e4a' +send 'e882130977b73f810a25f8ff84ae213b' +send '50099c8368f54ad63fb72dd89c07438e' +send '4cf3e0be2f214ba88a86c2c6a2ef215a' +send '77335f5e91f1853efd3ff6863980efc5' +send '3e354d45fce1a2fc1a72e49ac29cdfaa' +send '5a9866ee58455406cbd6e95310cb75a8' +send '50fbf2fd84299554adfeea06f303642e' + +;Q +send 'cc2dfa91c81e3a5e18bf7bc4a0256605' +send '92c31718e3fcf6661d8560da9156a4ff' +send '1fd2e401275d7805f8a90bb64c0c00c1' +send '5e23bab155c6e3b15c68fb5108f5751b' +send '4c79ee31411759910d40c68773a7a84d' +send 'ec371b8cfefa8ebb3139850f33da584a' +send 'e9c7ef194a9259fc28246028e9cc7d8b' +send '00a939dc1c6e347de111050a7361c326' +send '29a00896638ac5de4e438484d749d495' +send 'd50ad59ffa59e2afa82a95c6caf09ec6' +send 'a3facd2eb2674f62fb1899046c9d1f92' +send 'cdc7619fe0ea50d5ee3b1b2fe469d2e6' +pause 5 + +;e +pause 5 +send '00010001' +send 13 +pause 5 + +;n = 256 bytes +send '8e1a97593b3adf945529c78997ed0bca' +send '70b04f410bf64db50c2754a6ad2cb9b7' +send '52d0d5e42a496b00df4a0836b6ae5e80' +send 'e4b4aecde54f556459bdc01c0dc72343' +send 'd32ae8beaf490519e7aa351fbb154b47' +send 'f8e7fa9e29b97e6b0832c35085c20c00' +send 'd4046ed687cd1701348a69de858424aa' +send '3c98b1ca3cab4ae8341aa2f02f786037' +send '94c6c454ac9c6c751fda472250d7efda' +send 'bb84522da75750c044e5105330fdaddc' +send '9ce9fa55e2ffe0f4ddaf8adc1786526e' +send '22a58242f6668a0fcd98b9477e5fe304' +send '626bfb9ed86f5997393fe230f1bb404a' +send '6b5cc69718fa5552c6ae147bf381750d' +send 'c7fcd7e420d150455502408cd0e76367' +send '35ede40f55f946a5b6a643fb9f90f54c' +send 'e7276e2b04f08d1a1759534bbfbeada6' +send '0932c2321b7bc5986c08b3a7ae8b61b4' +send '595ddd16558961a9dc82b0e9f70e0d4c' +send '9ada379f7e7b51a12af6fe2631ac2afb' +send '165ac45cdb329c8c8df45d6b6c412378' +send '2a8f50f69d44bc9fc52a6b92e635bcda' +send '279f1c9e0f90296463762849dd2a0690' +send '73cdba018497a60ea97bf561d8d379d1' +pause 5 + +pause 10 +logclose \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/miv-rv32-rsa-cryptography hw Debug.launch b/applications/user-crypto/miv-rv32-rsa-cryptography/miv-rv32-rsa-cryptography hw Debug.launch new file mode 100644 index 0000000..db49533 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/miv-rv32-rsa-cryptography hw Debug.launch @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/miv-rv32-rsa-cryptography hw attach.launch b/applications/user-crypto/miv-rv32-rsa-cryptography/miv-rv32-rsa-cryptography hw attach.launch new file mode 100644 index 0000000..6d0db3c --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/miv-rv32-rsa-cryptography hw attach.launch @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/application/helper.c b/applications/user-crypto/miv-rv32-rsa-cryptography/src/application/helper.c new file mode 100644 index 0000000..4a78569 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/application/helper.c @@ -0,0 +1,312 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file helper.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Helper function for PolarFire User Crypto- Cryptography service example. + * + */ +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" +#include "helper.h" + +extern UART_instance_t g_uart; + +static const uint8_t g_separator[] = +"\r\n\ +------------------------------------------------------------------------------"; + + +/*============================================================================== + Function to clear local variable and array. + */ +static void clear_variable(uint8_t *p_var, uint16_t size) +{ + uint16_t inc; + + for(inc = 0; inc < size; inc++) + { + *p_var = 0x00; + p_var++; + } +} + +/*============================================================================== + Function to get the input data from user. + */ +uint16_t get_input_data +( + uint8_t* location, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +) +{ + uint16_t count = 0u; + + /* Clear the memory location. */ + clear_variable(location, size); + + /* Read data from UART terminal. */ + count = get_data_from_uart(location, size, msg, msg_size); + + return count; +} + +/*============================================================================== + Function to get the key from user. + */ +void get_key +( + uint8_t key_type, + uint8_t* location, + uint8_t size, + const uint8_t* msg, + uint8_t msg_size +) +{ + uint8_t status = 0u; + const uint8_t invalid_ms[] = "\r\n Invalid key type. "; + + if(status == VALID) + { + /* Read the 16 bytes of input data from UART terminal. */ + get_input_data(location, size, msg, msg_size); + } + else + { + UART_send(&g_uart, invalid_ms, sizeof( invalid_ms)); + } +} + +/*============================================================================== + Convert ASCII value to hex value. + */ +uint8_t convert_ascii_to_hex(uint8_t* dest, const uint8_t* src) +{ + uint8_t error_flag = 0u; + + if((*src >= '0') && (*src <= '9')) + { + *dest = (*src - '0'); + } + else if((*src >= 'a') && (*src <= 'f')) + { + *dest = (*src - 'a') + 10u; + } + else if((*src >= 'A') && (*src <= 'F')) + { + *dest = (*src - 'A') + 10u; + } + else if(*src != 0x00u) + { + UART_send(&g_uart, (const uint8_t *)"\r\n Invalid data.", sizeof("\r\n Invalid data.")); + error_flag = 1u; + } + return error_flag; +} + +/*============================================================================== + Validate the input hex value . + */ +uint8_t validate_input(uint8_t ascii_input) +{ + uint8_t valid_key = 0u; + + if(((ascii_input >= 'A') && (ascii_input <= 'F')) || \ + ((ascii_input >= 'a') && (ascii_input <= 'f')) || \ + ((ascii_input >= '0') && (ascii_input <= '9'))) + { + valid_key = 1u; + } + else + { + valid_key = 0u; + } + return valid_key; +} + +const uint8_t hex_chars[16] = { '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + +/*============================================================================== + Display content of buffer passed as parameter as hex values. + */ +void display_output +( + uint8_t* in_buffer, + uint32_t byte_length +) +{ + uint32_t inc; + uint8_t byte = 0; + + UART_send(&g_uart, (const uint8_t*)" ", sizeof(" ")); + for(inc = 0; inc < byte_length; ++inc) + { + if((inc > 1u) &&(0u == (inc % 16u))) + { + UART_send(&g_uart, (const uint8_t*)"\r\n ", sizeof("\r\n ")); + } + + byte = in_buffer[inc]; + UART_send(&g_uart, &hex_chars[((byte & 0xF0) >> 4) ], 1); + UART_send(&g_uart, &hex_chars[(byte & 0x0F)], 1); + } + +} + +/*============================================================================== + Function to read data from UART terminal and stored it. + */ +uint16_t get_data_from_uart +( + uint8_t* src_ptr, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +) +{ + uint8_t complete = 0u; + uint8_t rx_buff[1]; + uint8_t rx_size = 0u; + uint16_t count = 0u; + uint16_t ret_size = 0u; + uint8_t first = 0u; + uint16_t src_ind = 0u; + uint8_t prev = 0; + uint8_t curr = 0; + uint8_t temp = 0; + uint8_t next_byte = 0; + uint16_t read_data_size = 0; + + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, msg, msg_size); + + if(size != 1) + { + read_data_size = size * 2; + } + else + { + read_data_size = size; + } + + /* Read the key size sent by user and store it. */ + count = 0u; + while(!complete) + { + rx_size = UART_get_rx(&g_uart, rx_buff, sizeof(rx_buff)); + if(rx_size > 0u) + { + /* Is it to terminate from the loop */ + if(ENTER == rx_buff[0]) + { + complete = 1u; + } + /* Is entered key valid */ + else if(validate_input(rx_buff[0]) != 1u) + { + UART_send(&g_uart, rx_buff, sizeof(rx_buff)); + UART_send(&g_uart, (const uint8_t *)"\r\n Invalid input.", + sizeof("\r\n Invalid input.")); + UART_send(&g_uart, msg, msg_size); + complete = 0u; + count = 0u; + first = 0u; + clear_variable(src_ptr, 4); + } + else + { + if(next_byte == 0) + { + convert_ascii_to_hex(&src_ptr[src_ind], &rx_buff[0]); + prev = src_ptr[src_ind]; + next_byte = 1; + } + else + { + convert_ascii_to_hex(&curr, &rx_buff[0]); + temp = ((prev << 4) & 0xF0); + src_ptr[src_ind] = (temp | curr); + next_byte = 0; + src_ind++; + } + + + /* Switching to next line after every 8 bytes */ + if(((count % 32u) == 0x00u) && (count > 0x00u) && (complete != 0x01u)) + { + UART_send(&g_uart, (const uint8_t *)"\n\r", sizeof("\n\r")); + first = 0u; + } + + if(first == 0u) + { + UART_send(&g_uart, (const uint8_t *)" ", sizeof(" ")); + first++; + } + UART_send(&g_uart, rx_buff, sizeof(rx_buff)); + count++; + if(read_data_size == count) + { + complete = 1u; + } + } + } + } + + if((count%2) == 0) + { + ret_size = count/2; + } + else + { + if(size!=1) + { + temp = src_ptr[src_ind]; + src_ptr[src_ind] = ((temp << 4) & 0xF0); + + ret_size = (count/2)+1; + } + else + { + ret_size = 1; + } + } + + return ret_size; +} + +/*============================================================================== + Function to get the key from user. + */ +uint8_t enable_dma +( + const uint8_t* msg, + uint8_t msg_size +) +{ + volatile uint8_t invalid_ip = 1u; + uint8_t dma_enable = 0; + + const uint8_t invalid_ms[] = "\r\n Invalid input. "; + + while(invalid_ip != 0) + { + /* Read the 16 bytes of input data from UART terminal. */ + get_input_data(&dma_enable, 1, msg, msg_size); + + if(dma_enable >= 2) + { + UART_send(&g_uart, invalid_ms, sizeof( invalid_ms)); + } + else + { + invalid_ip = 0; + } + } + + return dma_enable; +} diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/application/helper.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/application/helper.h new file mode 100644 index 0000000..7f21b6e --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/application/helper.h @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file helper.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Helper function public API. + * + */ +#ifndef __HELPER_H_ +#define __HELPER_H_ 1 + +/****************************************************************************** + * Maximum buffer size. + *****************************************************************************/ +#define MAX_RX_DATA_SIZE 256 +#define MASTER_TX_BUFFER 10 + +/*============================================================================== + Macro + */ +#define VALID 0U +#define INVALID 1U +#define ENTER 13u + +/****************************************************************************** + * CoreUARTapb instance data. + *****************************************************************************/ + +uint16_t get_input_data +( + uint8_t* location, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +); +void get_key +( + uint8_t key_type, + uint8_t* location, + uint8_t size, + const uint8_t* msg, + uint8_t msg_size +); +uint16_t get_data_from_uart +( + uint8_t* src_ptr, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +); +uint8_t enable_dma +( + const uint8_t* msg, + uint8_t msg_size +); +void display_output +( + uint8_t* in_buffer, + uint32_t byte_length +); +#endif /* __HELPER_H_ */ diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/application/main.c b/applications/user-crypto/miv-rv32-rsa-cryptography/src/application/main.c new file mode 100644 index 0000000..360c9a9 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/application/main.c @@ -0,0 +1,422 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file main.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief This example project demonstrates the use of the PolarFire RSA service + * to encrypt and decrypt the message. + * + */ +#include +#include +#include +#include "stdint.h" +#include "helper.h" +#include "hal/hal.h" +#include "fpga_design_config/fpga_design_config.h" +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" + +#include "cal/calpolicy.h" +#include "cal/pk.h" +#include "cal/pkx.h" +#include "cal/pkxlib.h" +#include "cal/calini.h" +#include "cal/utils.h" +#include "cal/hash.h" +#include "cal/drbgf5200.h" +#include "cal/drbg.h" +#include "cal/nrbg.h" +#include "cal/sym.h" +#include "cal/shaf5200.h" +#include "cal/calenum.h" +#include "cal/utils.h" +#include + +/****************************************************************************** + * CoreUARTapb instance data. + *****************************************************************************/ +UART_instance_t g_uart; + +uint32_t g_user_crypto_base_addr = 0x62000000UL; + +static const uint8_t g_separator[] = +"\r\n\ +------------------------------------------------------------------------------"; + SATR CAL_EXECUTE(SATR result) { + + return (result == SATR_SUCCESS) ? CALPKTrfRes(SAT_TRUE) : result; +} + +/*============================================================================== + Messages displayed over the UART. + */ +const uint8_t g_greeting_msg[] = +"\r\n\r\n\ +******************************************************************************\r\n\ +** PolarFire User Crypto RSA Encryption Decryption Service Example Project **\r\n\ +******************************************************************************\r\n\ + This example project demonstrates the use of the PolarFire RSA service to \r\n\ + encrypt and decrypt the message. The following User Athena service are \r\n\ + demonstrated:\r\n\ + 1 - RSA encryption.\r\n\ + 2 - RSA decryption.\r\n"; +const uint8_t g_select_operation_msg[] = +"\r\n\ +------------------------------------------------------------------------------\r\n\ + Select the RSA operation to perform:\r\n\ + Press Key '1' to perform RSA encryption \r\n\ + Press Key '2' to perform RSA decryption \r\n\ +------------------------------------------------------------------------------\r\n"; + +/* RSA encryption message */ +const uint8_t encrpt_msg[] = +"\r\n Enter message (max size: 256 bytes): \r\n"; +const uint8_t ecrypt_modval_msg[] = +"\r\n Enter modulus n value (max size: 256 bytes): \r\n"; +const uint8_t encrypt_dval_msg[] = +"\r\n Enter parameter E value (max size: 256 bytes): \r\n"; +const uint8_t precomputes_fail_msg[] = +"\r\n Modulus pre-compute fails. \r\n"; +const uint8_t encrypt_success[] = +"\r\n RSA encryption successful. \r\n Generated Cipher Text: \r\n"; +const uint8_t encrypt_fail[] = +"\r\n RSA encryption fail. \r\n"; + +/* RSA decryption message */ +const uint8_t decrpt_msg[] = +"\r\n Enter cipher text (max size: 256 bytes): \r\n"; +const uint8_t read_prvtkey_msg[] = +"\r\n Enter parameter D value (max size: 256 bytes): \r\n"; +const uint8_t read_paramP_msg[] = +"\r\n Enter parameter P value (max size: 256 bytes): \r\n"; +const uint8_t read_paramQ_msg[] = +"\r\n Enter parameter Q value (max size: 256 bytes): \r\n"; +const uint8_t decrypt_modval_msg[] = +"\r\n Enter modulus n value (max size: 256 bytes): \r\n"; +const uint8_t decrypt_success[] = +"\r\n RSA decryption successful. \r\n Generated Plain Text: \r\n"; +const uint8_t decrypt_fail[] = +"\r\n RSA decryption fail.\r\n"; + +/*============================================================================== + Global Variables + */ +/* RSA encryption */ +const SATUINT32_t plaintext[96] = { 0x00 }; +const SATUINT32_t n_m3072_ecrypt[96]={ 0x00 }; +const SATUINT32_t e_m3072_ecrypt[96] = { 0x00 }; +const SATUINT32_t encrypt_NMu[97] = {0x00}; +const SATUINT32_t ciphertext[96] = {0x00}; + +/* RSA decryption */ +uint32_t decrypt_plaintext[96] = { 0x00 }; +uint32_t decrypt_cipher[96] = { 0x00 }; +uint32_t decrypt_D[96] = { 0x00 }; +uint32_t decrypt_QInv[48] = { 0x00 }; +uint32_t decrypt_DP[48] = { 0x00 }; +uint32_t decrypt_DQ[48] = { 0x00 }; +uint32_t decrypt_P[48] = { 0x00 }; +uint32_t decrypt_Pm1[48] = { 0x00 }; +uint32_t decrypt_Pm2[48] = { 0x00 }; +uint32_t decrypt_precomP[49] = { 0x00 }; +uint32_t decrypt_precomPm1[49] = { 0x00 }; +uint32_t decrypt_Q[48] = { 0x00 }; +uint32_t decrypt_Qm1[48] = { 0x00 }; +uint32_t decrypt_precomQ[49] = { 0x00 }; +uint32_t decrypt_precomQm1[49] = { 0x00 }; + +/*============================================================================== + Local function. + */ +static void display_greeting(void); +static void display_operation_choices(void); +static void display_option(void); + +/*============================================================================== + Message encryption using RSA. + */ +static void rsa_encrypt(void) +{ + SATR result; + + /* Read message value to be encrypted using RSA encryption. */ + get_input_data((uint8_t*)&plaintext, sizeof(plaintext), + encrpt_msg, sizeof(encrpt_msg)); + + /* Read module n value. */ + get_input_data((uint8_t*)&n_m3072_ecrypt, sizeof(n_m3072_ecrypt), + ecrypt_modval_msg, sizeof(ecrypt_modval_msg)); + + /* Read E parameter. - RSA public key */ + get_input_data((uint8_t*)&e_m3072_ecrypt, sizeof(e_m3072_ecrypt), + encrypt_dval_msg, sizeof(encrypt_dval_msg)); + + /* Change the endianness of data received from UART terminal. */ + CALByteReverseWord((uint32_t*)&plaintext, (sizeof(plaintext)/4)); + CALByteReverseWord((uint32_t*)&n_m3072_ecrypt, (sizeof(n_m3072_ecrypt)/4)); + CALByteReverseWord((uint32_t*)&e_m3072_ecrypt, (sizeof(e_m3072_ecrypt)/4)); + + result = CALPreCompute(n_m3072_ecrypt,(uint32_t*)&encrypt_NMu[0],96u); + if(result == SATR_SUCCESS) + { + CALPKTrfRes(SAT_TRUE); + } + else + { + UART_send(&g_uart, precomputes_fail_msg, sizeof(precomputes_fail_msg)); + } + + result = CALExpo(plaintext, e_m3072_ecrypt, n_m3072_ecrypt, + (uint32_t*)&encrypt_NMu[0], 96u, 96u, + (uint32_t*)&ciphertext[0]); + + /* Display encrypted message. */ + if(result == SATR_SUCCESS) + { + CALPKTrfRes(SAT_TRUE); + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, encrypt_success, sizeof(encrypt_success)); + CALByteReverseWord((uint32_t*)&ciphertext, (sizeof(ciphertext)/4)); + display_output((uint8_t*)&ciphertext[0], sizeof(ciphertext)); + } + else + { + UART_send(&g_uart, precomputes_fail_msg, sizeof(precomputes_fail_msg)); + } +} + +/*============================================================================== + Message decryption using RSA. + */ +static SATR rsa_decryption(void) +{ + SATR result; + uint16_t p_len = 0; + uint16_t q_len = 0; + uint16_t index = 0; + + /* Read cipher text to be decrypted using RSA decryption. */ + get_input_data((uint8_t*)&decrypt_cipher, sizeof(decrypt_cipher), + decrpt_msg, sizeof(decrpt_msg)); + + /* Read D parameter. i.e Private key */ + get_input_data((uint8_t*)&decrypt_D, sizeof(decrypt_D), + read_prvtkey_msg, sizeof(read_prvtkey_msg)); + + /* Read P parameter */ + p_len = get_input_data((uint8_t*)&decrypt_P, sizeof(decrypt_P), + read_paramP_msg, sizeof(read_paramP_msg)); + + /* Read Q parameter */ + q_len = get_input_data((uint8_t*)&decrypt_Q, sizeof(decrypt_Q), + read_paramQ_msg, sizeof(read_paramQ_msg)); + + /* Read E parameter. - RSA public key */ + get_input_data((uint8_t*)&e_m3072_ecrypt, sizeof(e_m3072_ecrypt), + encrypt_dval_msg, sizeof(encrypt_dval_msg)); + + /* Read module n value. */ + get_input_data((uint8_t*)&n_m3072_ecrypt, sizeof(n_m3072_ecrypt), + ecrypt_modval_msg, sizeof(ecrypt_modval_msg)); + + /* Change the endianness of data received from UART terminal. */ + CALByteReverseWord((uint32_t*)&decrypt_cipher, (sizeof(decrypt_cipher)/4)); + CALByteReverseWord((uint32_t*)&decrypt_D, (sizeof(decrypt_D)/4)); + CALByteReverseWord((uint32_t*)&decrypt_P, (sizeof(decrypt_P)/4)); + CALByteReverseWord((uint32_t*)&decrypt_Q, (sizeof(decrypt_Q)/4)); + CALByteReverseWord((uint32_t*)&n_m3072_ecrypt, (sizeof(n_m3072_ecrypt)/4)); + CALByteReverseWord((uint32_t*)&e_m3072_ecrypt, (sizeof(e_m3072_ecrypt)/4)); + + /* Initiate generation of pre-compute value for P. */ + result = CAL_EXECUTE(CALPreCompute(decrypt_P, decrypt_precomP, 48u)); + if(result != SATR_SUCCESS) + { + UART_send(&g_uart, precomputes_fail_msg, sizeof(precomputes_fail_msg)); + } + + /* Initiate generation of pre-compute value for Q. */ + result = CAL_EXECUTE(CALPreCompute(decrypt_Q, decrypt_precomQ, 48u)); + if(result!=SATR_SUCCESS) + { + UART_send(&g_uart, precomputes_fail_msg, sizeof(precomputes_fail_msg)); + } + + /* Calculate P - 1 and P - 2 */ + for(index = 0; index < (p_len/4); index++) + { + decrypt_Pm1[index] = decrypt_P[index]; + decrypt_Pm2[index] = decrypt_P[index]; + } + if(index == (p_len/4)) + { + decrypt_Pm1[0]--; + decrypt_Pm2[0] = decrypt_P[0] - 2; + } + + /* Calculate Q - 1 */ + for(index = 0; index < q_len/4; index++) + { + decrypt_Qm1[index] = decrypt_Q[index]; + } + if(index == (q_len/4)) + { + decrypt_Qm1[0]--; + } + + result = CALPreCompute(n_m3072_ecrypt,(uint32_t*)&encrypt_NMu[0],96u); + if(result == SATR_SUCCESS) + { + CALPKTrfRes(SAT_TRUE); + } + else + { + UART_send(&g_uart, precomputes_fail_msg, sizeof(precomputes_fail_msg)); + } + + /* Initiate generation of pre-compute value for P - 1. */ + result = CAL_EXECUTE( CALPreCompute(decrypt_Pm1, decrypt_precomPm1, 48u)); + if(result != SATR_SUCCESS) + { + UART_send(&g_uart, precomputes_fail_msg, sizeof(precomputes_fail_msg)); + } + + /* Initiate generation of pre-compute value for Q - 1. */ + result = CAL_EXECUTE(CALPreCompute(decrypt_Qm1, decrypt_precomQm1, 48u)); + if(result != SATR_SUCCESS) + { + UART_send(&g_uart, precomputes_fail_msg, sizeof(precomputes_fail_msg)); + } + + /* puiDP - Derive values d mod p-1 */ + result = CAL_EXECUTE(CALModRed(decrypt_D, decrypt_Pm1, decrypt_precomPm1, + 96u, 48u, decrypt_DP)); + if(result != SATR_SUCCESS) + { + UART_send(&g_uart, precomputes_fail_msg, sizeof(precomputes_fail_msg)); + } + + /* puiDQ - Derive values d mod q-1 (puiDQ) */ + result = CAL_EXECUTE(CALModRed(decrypt_D, decrypt_Qm1, decrypt_precomQm1, + 96u, 48u, decrypt_DQ)); + if(result != SATR_SUCCESS) + { + UART_send(&g_uart, precomputes_fail_msg, sizeof(precomputes_fail_msg)); + } + + /* ipQInv - Derive value q^(-1) mod p = q**(p-2) mod p */ + result = CAL_EXECUTE(CALExpo(decrypt_Q, decrypt_Pm2, decrypt_P, + decrypt_precomP, 48u, 48u, decrypt_QInv)); + if(result != SATR_SUCCESS) + { + UART_send(&g_uart, precomputes_fail_msg, sizeof(precomputes_fail_msg)); + } + + /* Decrypt cipher text. */ + result = CAL_EXECUTE( CALRSACRTCM(decrypt_cipher, decrypt_QInv, decrypt_DP, + decrypt_DQ, e_m3072_ecrypt, decrypt_P, + decrypt_Q, n_m3072_ecrypt, encrypt_NMu, + 48u, 1u, decrypt_plaintext)); + + /* Display the decryption output. i.e. plain text. */ + if(result == SATR_SUCCESS) + { + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, decrypt_success, sizeof(decrypt_success)); + CALByteReverseWord((uint32_t*)&decrypt_plaintext, (sizeof(decrypt_plaintext)/4)); + display_output((uint8_t*)&decrypt_plaintext[0], sizeof(decrypt_plaintext)); + } + else + { + UART_send(&g_uart, decrypt_fail, sizeof(decrypt_fail)); + } + + return 1; +} + +/****************************************************************************** + * main function. + *****************************************************************************/ +int main( void ) +{ + uint8_t rx_buff[1]; + size_t rx_size = 0; + + + /* Initialize CoreUARTapb with its base address, baud value, and line + configuration. */ + UART_init(&g_uart, COREUARTAPB0_BASE_ADDR, BAUD_VALUE_115200, + (DATA_8_BITS | NO_PARITY)); + + /* Initialize the User Athena core. */ + CALIni(); + + /* Display greeting message. */ + display_greeting(); + + /* Select cryptographic operation to perform */ + display_operation_choices(); + + for(;;) + { + /* Read input from UART terminal. */ + rx_size = UART_get_rx(&g_uart, rx_buff, sizeof(rx_buff)); + if(rx_size > 0) + { + switch(rx_buff[0]) + { + case '1': + /* Perform RSA encryption. - RSA-2048 */ + rsa_encrypt(); + display_option(); + display_operation_choices(); + break; + + case '2': + /* Perform RSA decryption - Decrypt, RSA-2048, CRT*/ + rsa_decryption(); + display_option(); + display_operation_choices(); + break; + + default: + break; + } + } + } +} + + +/*============================================================================== + Display greeting message when application is started. + */ +static void display_greeting(void) +{ + UART_send(&g_uart, g_greeting_msg,sizeof(g_greeting_msg)); +} + +/*============================================================================== + Display the choice of cryptographic operation to perform. + */ +static void display_operation_choices(void) +{ + UART_send(&g_uart, g_select_operation_msg, sizeof(g_select_operation_msg)); +} + +/*============================================================================== + Display the Option to continue or exit. + */ +static void display_option(void) +{ + uint8_t rx_size; + uint8_t rx_buff[1]; + + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, (const uint8_t*)"\r\n Press any key to continue.\r\n", + sizeof("\r\n Press any key to continue.\r\n")); + do + { + rx_size = UART_get_rx(&g_uart, rx_buff, sizeof(rx_buff)); + } while(0u == rx_size); +} diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h new file mode 100644 index 0000000..3fd1438 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h @@ -0,0 +1,156 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file fpga_design_config.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Sample design configuration settings. + * + */ + /*========================================================================*//** + @mainpage + Example file detailing how the fpga_design_config.h should be constructed + for the SoftConsole project targeted for Mi-V processors. + + @section intro_sec Introduction + The SoftConsole project targeted for Mi-V processors now have an improved + folder structure. Detailed description of the folder structure is available + at https://github.com/Mi-V-Soft-RISC-V/miv-rv32-documentation. + + The fpga_design_config.h must be stored as shown below + /boards//fpga_design_config.h + + Currently this file must be hand crafted when using the Mi-V Soft Processor. + In future, all the design and soft IP configurations will be automatically + generated from the Libero design description data. + + You can use this sample file as an example. + Rename this file from sample_fpga_design_config.h to fpga_design_config.h + and then customize it per your hardware design. + + @section Project configuration Instructions + 1. Change SYS_CLK_FREQ define to frequency of Mi-V Soft processor clock + 2 Add all the soft IP core BASE addresses + 3. Add the peripheral Core Interrupts to Mi-V Soft processor IRQ number + mappings + 4. Define MSCC_STDIO_UART_BASE_ADDR if you want a CoreUARTapb mapped to + STDIO + + **NOTE** + In the legacy folder structures, the file hw_config.h as was used at the + root of the project folder. This file is now depricated. + +*//*=========================================================================*/ + +#ifndef FPGA_DESIGN_CONFIG_H_ +#define FPGA_DESIGN_CONFIG_H_ + +/***************************************************************************//** + * Soft-processor clock definition + * This is the only clock brought over from the Mi-V Libero design. + */ +#ifndef SYS_CLK_FREQ +#define SYS_CLK_FREQ 83000000UL +#endif + +/***************************************************************************//** + * Peripheral base addresses. + * Format of define is: + * __BASE_ADDR + * The field is optional if there is only one instance of the core + * in the design + * MIV_ESS is an extended peripheral subsystem IP core with peripherals + * connections as defined below. + * The system can be further extended by attaching APB peripherals to the + * empty APB slots. + */ +#define COREUARTAPB0_BASE_ADDR 0x70000000UL +#define COREGPIO_OUT_BASE_ADDR 0x70001000UL +#define CORESPI_BASE_ADDR 0x70002000UL +#define CORESYS_SERV_BASE_ADDR 0x70003000UL + +/***************************************************************************//** + * Peripheral Interrupts are mapped to the corresponding Mi-V Soft processor + * interrupt in the Libero design. + * + * On the legacy RV32 cores, there can be up to 31 external interrupts (IRQ[30:0] + * pins). The legacy RV32 Soft processor external interrupts are defined in the + miv_rv32_plic.h + * + * These are of the form + * typedef enum +{ + NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + . + . + . + External_31_IRQn = 31 +} IRQn_Type; + + On the legacy RV32 processors, the PLIC identifies the interrupt and passes it + on to the processor core. The interrupt 0 is not used. The pin IRQ[0] should + map to External_1_IRQn likewise IRQ[30] should map to External_31_IRQn + +e.g + +#define TIMER0_IRQn External_30_IRQn +#define TIMER1_IRQn External_31_IRQn + + The MIV_RV32 soft processor has up to six optional system interrupts, MSYS_EI[n] + in addition to one EXT_IRQ. + The MIV_RV32 does not have an inbuilt PLIC and all the interrupts are directly + delivered to the processor core, hence unlike legacy RV32 cores, no interrupt + number mapping is necessary on MIV_RV32 core. + */ + +/**************************************************************************** + * Baud value to achieve a 115200 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ +#define BAUD_VALUE_115200 ((SYS_CLK_FREQ / (16 * 115200)) - 1) + +/****************************************************************************** + * Baud value to achieve a 57600 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + #define BAUD_VALUE_57600 ((SYS_CLK_FREQ / (16 * 57600)) - 1) + +/***************************************************************************//** + * Define MSCC_STDIO_THRU_CORE_UART_APB in the project settings if you want the + * standard IOs to be redirected to a terminal via UART. + */ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +/* + * A base address mapping for the STDIO printf/scanf mapping to CortUARTapb + * must be provided if it is being used + * + * e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR + */ +#define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB0_BASE_ADDR + +#ifndef MSCC_STDIO_UART_BASE_ADDR +#error MSCC_STDIO_UART_BASE_ADDR not defined- e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR +#endif + +#ifndef MSCC_STDIO_BAUD_VALUE +/* + * The MSCC_STDIO_BAUD_VALUE define should be set in your project's settings to + * specify the baud value used by the standard output CoreUARTapb instance for + * generating the UART's baud rate if you want a different baud rate from the + * default of 115200 baud + */ +#define MSCC_STDIO_BAUD_VALUE 115200 +#endif /*MSCC_STDIO_BAUD_VALUE*/ + +#endif /* end of MSCC_STDIO_THRU_CORE_UART_APB */ +/******************************************************************************* + * End of user edit section + */ +#endif /* FPGA_DESIGN_CONFIG_H_ */ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld b/applications/user-crypto/miv-rv32-rsa-cryptography/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld new file mode 100644 index 0000000..8541db6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld @@ -0,0 +1,160 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-ram.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * debug image executing in SRAM. + * + * This linker script assumes that a RAM is connected at on Mi-V soft processor + * memory space pointed by the reset vector address. + * + * NOTE : Modify the memory section address and the size according to your + * Libero design. + * For example: + * 1) If you want to download and step debug at a different RAM memory address in + * your design (For example TCM base address) than the one provided in this file. + * 2) The MIV_RV32, when used with MIV_ESS IP, provides ways to copy the executable + * HEX file from external Non-Volatile memory into the TCM at reset. In this + * case your executable must be linked to the TCM address. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +MEMORY +{ + ram (rwx) : ORIGIN = 0x80000000, LENGTH = 64k + crypto_ram (rw) : ORIGIN = 0x61000000, LENGTH = 32k +} + +RAM_START_ADDRESS = 0x80000000; /* Must be the same value MEMORY region ram ORIGIN above. */ +RAM_SIZE = 64k; /* Must be the same value MEMORY region ram LENGTH above. */ +STACK_SIZE = 2k; /* needs to be calculated for your application */ +HEAP_SIZE = 0k; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > ram + + .text : ALIGN(0x10) + { + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } > ram + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } > ram + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } > ram + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram + + . = 0x61000000; + .crypto_data : ALIGN(0x10) + { + . = ALIGN(0x10); + *(.crypto_data) + } > crypto_ram +} + diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/aesf5200.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/aesf5200.h new file mode 100644 index 0000000..889dddd --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/aesf5200.h @@ -0,0 +1,104 @@ +/* ------------------------------------------------------------------- + $Rev: 1293 $ $Date: 2017-07-27 14:09:14 -0400 (Thu, 27 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for F5200 AES function hardware implementation for + CAL. + ------------------------------------------------------------------- */ + +#ifndef AESF5200_H +#define AESF5200_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef AESF5200_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATR aesf5200aes (SATSYMTYPE eSymType, SATSYMMODE eMode, + void *pIV, SATBOOL bLoadIV, const void *pSrc, void *pDest, SATUINT32_t uiLen, + SATBOOL bDecrypt); + +extern SATR aesf5200aesk (SATSYMTYPE eSymType, const SATUINT32_t *puiKey); + +extern SATR aesf5200gcm (SATSYMTYPE eSymType, SATSYMMODE eMode, void *pIV, + const void *pSrc, void *pDest, SATUINT32_t uiEncLen, + const void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, SATUINT32_t uiMACLen, + SATBOOL bDecrypt); + +extern SATR aesf5200gcmdma(SATSYMTYPE eSymType, SATSYMMODE eMode, void *pIV, + const void *pSrc, void *pDest, SATUINT32_t uiEncLen, const void *pAuth, + SATUINT32_t uiAuthLen, void *pMAC, SATUINT32_t uiMACLen, SATBOOL bDecrypt, + SATUINT32_t uiDMAChConfig); + +extern SATR aesf5200kw(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR aesf5200kwp(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR aesf5200kr(SATSYMTYPE eSymType, SATSYMMODE eMode, + const SATUINT32_t *puiKey, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKrf, SATBOOL bDecrypt); + +extern SATR aesf5200dma(SATSYMTYPE eSymType, SATSYMMODE eMode, void *pIV, + SATBOOL bLoadIV, const void *pExtSrc, void *pExtDest, SATUINT32_t uiLen, + SATUINT32_t uiDMAChConfig, SATBOOL bDecrypt); + +extern SATR aesf5200krdma(SATSYMTYPE eSymType, SATSYMMODE eMode, + const SATUINT32_t *puiKey, void *pIV, SATBOOL bLoadIV, const void *pExtSrc, + void *pExtDest, SATUINT32_t uiLen, SATUINT32_t uiKrf, + SATUINT32_t uiDMAChConfig, SATBOOL bDecrypt); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/calcontext.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/calcontext.h new file mode 100644 index 0000000..fc408c2 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/calcontext.h @@ -0,0 +1,88 @@ +/* ------------------------------------------------------------------- + $Rev: 1298 $ $Date: 2017-08-04 13:04:19 -0400 (Fri, 04 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL context management functions. + ------------------------------------------------------------------- */ + +#ifndef CALCONTEXT_H +#define CALCONTEXT_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* Function resource handle. */ +/* ----- ------ ------- ---- */ +#define SATRES_DEFAULT (SATRESHANDLE)0U +#define SATRES_CALSW (SATRESHANDLE)1U + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ +typedef struct{ + SATUINT32_t uiBase; + SATRESCONTEXTPTR pContext; + }SATRESHANDLESTRUCT; + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALCONTEXT_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATRESCONTEXTPTR CALContextCurrent(const SATRESHANDLE hResource); + +extern SATR CALContextLoad(const SATRESHANDLE hResource, + const SATRESCONTEXTPTR pContext); + +extern SATR CALContextRemove(const SATRESHANDLE hResource); + +extern SATR CALContextUnload(const SATRESHANDLE hResource); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern void init_reshandles(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/calenum.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/calenum.h new file mode 100644 index 0000000..6281f3f --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/calenum.h @@ -0,0 +1,289 @@ +/* ------------------------------------------------------------------- + $Rev: 1566 $ $Date: 2018-09-14 11:04:30 -0400 (Fri, 14 Sep 2018) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + This file defines common types in the CAL. + + Most CAL types and constants are defined with the "SAT" prefix to + reduce the chance of name space collisions with other users. + ------------------------------------------------------------------- */ + +#ifndef CALENUM_H +#define CALENUM_H + +/* -------- */ +/* Includes */ +/* -------- */ + +/* CAL base types. */ +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ +/* NULL definitions. */ +#define SAT_NULL 0 + +/* Boolean definitions. */ +#define SAT_TRUE ((SATBOOL)1) +#define SAT_FALSE ((SATBOOL)0) + + +/* Major cipher key/SSP type. */ +/* ----- ------ ------- ----- */ +#define SATSSPTYPE_NULL (SATSSPTYPE)0 +#define SATSSPTYPE_SYMKEY (SATSSPTYPE)1 +#define SATSSPTYPE_ASYMKEY (SATSSPTYPE)2 +/* Special marker for end of list. */ +#define SATSSPTYPE_LAST (SATSSPTYPE)3 + + +/* Asymmetric Ciphers */ +/* ---------- ------- */ +#define SATASYMTYPE_NULL (SATASYMTYPE)0U +#define SATASYMTYPE_DSA_SIGN (SATASYMTYPE)1U +#define SATASYMTYPE_DSA_VERIFY (SATASYMTYPE)2U +#define SATASYMTYPE_RSA_ENCRYPT (SATASYMTYPE)3U +#define SATASYMTYPE_RSA_DECRYPT (SATASYMTYPE)4U +#define SATASYMTYPE_DH (SATASYMTYPE)5U +#define SATASYMTYPE_ECDSA_SIGN (SATASYMTYPE)6U +#define SATASYMTYPE_ECDSA_VERIFY (SATASYMTYPE)7U +#define SATASYMTYPE_ECDH (SATASYMTYPE)8U +#define SATASYMTYPE_RSA_SIGN (SATASYMTYPE)9U +#define SATASYMTYPE_RSA_VERIFY (SATASYMTYPE)10U +/* Special marker for end of list. */ +#define SATASYMTYPE_LAST (SATASYMTYPE)11U + + +/* Encoding Types */ +/* -------- ----- */ +#define SATRSAENCTYPE_NULL (SATRSAENCTYPE)0U +#define SATRSAENCTYPE_PKCS (SATRSAENCTYPE)1U +#define SATRSAENCTYPE_ANSI (SATRSAENCTYPE)2U +#define SATRSAENCTYPE_PSS (SATRSAENCTYPE)3U +/* Special marker for end of list. */ +#define SATRSAENCTYPE_LAST (SATRSAENCTYPE)4U + + +/* Symmetric Ciphers */ +/* --------- ------- */ + +/* Cipher Type. */ +#define SATSYMTYPE_NULL (SATSYMTYPE)0U +#define SATSYMTYPE_AES128 (SATSYMTYPE)1U +#define SATSYMTYPE_AES192 (SATSYMTYPE)2U +#define SATSYMTYPE_AES256 (SATSYMTYPE)3U +#define SATSYMTYPE_AESKS128 (SATSYMTYPE)4U +#define SATSYMTYPE_AESKS192 (SATSYMTYPE)5U +#define SATSYMTYPE_AESKS256 (SATSYMTYPE)6U +/* Special marker for end of list. */ +#define SATSYMTYPE_LAST (SATSYMTYPE)7U + +/* Names for common cipher key lengths, in bits. */ +#define SATSYMKEYSIZE_AES128 (SATSYMKEYSIZE)128U +#define SATSYMKEYSIZE_AES192 (SATSYMKEYSIZE)192U +#define SATSYMKEYSIZE_AES256 (SATSYMKEYSIZE)256U +#define SATSYMKEYSIZE_AESKS128 (SATSYMKEYSIZE)256U +#define SATSYMKEYSIZE_AESKS192 (SATSYMKEYSIZE)384U +#define SATSYMKEYSIZE_AESKS256 (SATSYMKEYSIZE)512U + +/* Cipher Mode. */ +#define SATSYMMODE_NULL (SATSYMMODE)0U +#define SATSYMMODE_ECB (SATSYMMODE)1U +#define SATSYMMODE_CBC (SATSYMMODE)2U +#define SATSYMMODE_CFB (SATSYMMODE)3U +#define SATSYMMODE_OFB (SATSYMMODE)4U +#define SATSYMMODE_CTR (SATSYMMODE)5U +#define SATSYMMODE_GCM (SATSYMMODE)6U +#define SATSYMMODE_GHASH (SATSYMMODE)8U +/* Special marker for end of list. */ +#define SATSYMMODE_LAST (SATSYMMODE)9U + + +/* Hashes */ +/* ------ */ +#define SATHASHTYPE_NULL (SATHASHTYPE)0U +#define SATHASHTYPE_SHA1 (SATHASHTYPE)1U +#define SATHASHTYPE_SHA224 (SATHASHTYPE)2U +#define SATHASHTYPE_SHA256 (SATHASHTYPE)3U +#define SATHASHTYPE_SHA384 (SATHASHTYPE)4U +#define SATHASHTYPE_SHA512 (SATHASHTYPE)5U +#define SATHASHTYPE_SHA512_224 (SATHASHTYPE)6U +#define SATHASHTYPE_SHA512_256 (SATHASHTYPE)7U +/* Special marker for end of list. */ +#define SATHASHTYPE_LAST (SATHASHTYPE)8U + +/* Hash sizes defined in bits */ +#define SATHASHSIZE_NULL (SATHASHSIZE)0U +#define SATHASHSIZE_SHA1 (SATHASHSIZE)160U +#define SATHASHSIZE_SHA224 (SATHASHSIZE)224U +#define SATHASHSIZE_SHA256 (SATHASHSIZE)256U +#define SATHASHSIZE_SHA384 (SATHASHSIZE)384U +#define SATHASHSIZE_SHA512 (SATHASHSIZE)512U +#define SATHASHSIZE_SHA512_224 (SATHASHSIZE)224U +#define SATHASHSIZE_SHA512_256 (SATHASHSIZE)256U + +#define SATHASHSIZE_HASH160 (SATHASHSIZE)160U +#define SATHASHSIZE_HASH192 (SATHASHSIZE)192U +#define SATHASHSIZE_HASH224 (SATHASHSIZE)224U +#define SATHASHSIZE_HASH256 (SATHASHSIZE)256U +#define SATHASHSIZE_HASH320 (SATHASHSIZE)320U +#define SATHASHSIZE_HASH384 (SATHASHSIZE)384U +#define SATHASHSIZE_HASH512 (SATHASHSIZE)512U +#define SATHASHSIZE_HASH521 (SATHASHSIZE)521U + + +/* Message Authentication Codes */ +/* ------- -------------- ----- */ + +/* Message Authentication Types */ +#define SATMACTYPE_NULL (SATMACTYPE)0U +#define SATMACTYPE_SHA1 (SATMACTYPE)1U +#define SATMACTYPE_SHA224 (SATMACTYPE)2U +#define SATMACTYPE_SHA256 (SATMACTYPE)3U +#define SATMACTYPE_SHA384 (SATMACTYPE)4U +#define SATMACTYPE_SHA512 (SATMACTYPE)5U +#define SATMACTYPE_SHA512_224 (SATMACTYPE)6U +#define SATMACTYPE_SHA512_256 (SATMACTYPE)7U +#define SATMACTYPE_AESCMAC128 (SATMACTYPE)10U +#define SATMACTYPE_AESCMAC192 (SATMACTYPE)11U +#define SATMACTYPE_AESCMAC256 (SATMACTYPE)12U +#define SATMACTYPE_AESGMAC (SATMACTYPE)13U +/* Special marker for end of list. */ +#define SATMACTYPE_LAST (SATMACTYPE)14U + + +/* Message Authentication Flags */ +#define SATMACFLAG_OP (SATMACTYPEFLAG)0U +#define SATMACFLAG_FIRSTPASS (SATMACTYPEFLAG)1U +#define SATMACFLAG_FINALPASS (SATMACTYPEFLAG)2U +#define SATMACFLAG_IKEYFINAL (SATMACTYPEFLAG)4U +#define SATMACFLAG_OKEYFINAL (SATMACTYPEFLAG)8U + + +/* Non-deterministic Random Bit Generator */ +/* ------- -------------- ----- */ + +/* NRBG register write enables */ +#define SATNRBGCONFIG_NONE 0x0 +#define SATNRBGCONFIG_RNG_CSR 0x1 +#define SATNRBGCONFIG_RNG_CNTLIM 0x2 +#define SATNRBGCONFIG_RNG_VOTIMER 0X4 +#define SATNRBGCONFIG_RNG_FMSK 0X8 + +/* RNG_CSR access defines */ +#define SATNRBGCONFIG_CSR_RODIS 0x0 +#define SATNRBGCONFIG_CSR_ROEN 0x1 +#define SATNRBGCONFIG_CSR_ROFATAL 0x2 +#define SATNRBGCONFIG_CSR_ROFATALCLR 0X4 + +/* RNG_FMSK mask values */ +#define SATNRBGCONFIG_FMSK_ROOSCF 0xFF +#define SATNRBGCONFIG_FMSK_MONOBITF 0x10000 +#define SATNRBGCONFIG_FMSK_POKERF 0x20000 +#define SATNRBGCONFIG_FMSK_RUNSF 0x40000 +#define SATNRBGCONFIG_FMSK_LRUNSF 0x80000 +#define SATNRBGCONFIG_FMSK_F1401 0xF0000 +#define SATNRBGCONFIG_FMSK_REPCNTF 0x100000 +#define SATNRBGCONFIG_FMSK_APROPF 0x200000 +#define SATNRBGCONFIG_FMSK_SP800 0x300000 + +/* RNG_ROHEALTH mask values */ +#define SATNRBGCONFIG_HLTH_ROOSCF 0x3FC0 +#define SATNRBGCONFIG_HLTH_APROPF 0x20 +#define SATNRBGCONFIG_HLTH_REPCNTF 0x10 +#define SATNRBGCONFIG_HLTH_LRUNSF 0x8 +#define SATNRBGCONFIG_HLTH_RUNSF 0x4 +#define SATNRBGCONFIG_HLTH_POKERF 0x2 +#define SATNRBGCONFIG_HLTH_MONOBITF 0x1 + + +/* Return Codes */ +/* ------ ----- */ +#define SATR_SUCCESS (SATR)0U +#define SATR_FAIL (SATR)1U +#define SATR_BADPARAM (SATR)2U +#define SATR_VERIFYFAIL (SATR)3U +#define SATR_KEYSFULL (SATR)4U +#define SATR_BUSY (SATR)5U +#define SATR_ROFATAL (SATR)6U +#define SATR_PARITYFLUSH (SATR)7U +#define SATR_SIGNFAIL (SATR)8U +#define SATR_VALIDATEFAIL (SATR)9U +#define SATR_PAF (SATR)10U +#define SATR_VALPARMX (SATR)11U +#define SATR_VALPARMY (SATR)12U +#define SATR_VALPARMB (SATR)13U +#define SATR_DCMPPARMX (SATR)14U +#define SATR_DCMPPARMB (SATR)15U +#define SATR_DCMPPARMP (SATR)16U +#define SATR_SIGNPARMD (SATR)17U +#define SATR_SIGNPARMK (SATR)18U +#define SATR_VERPARMR (SATR)19U +#define SATR_VERPARMS (SATR)20U +#define SATR_MSBICV1 (SATR)21U +#define SATR_MSBICV2 (SATR)22U +#define SATR_PADLEN (SATR)23U +#define SATR_LSB0PAD (SATR)24U +#define SATR_BADLEN (SATR)25U +#define SATR_BADHASHTYPE (SATR)26U +#define SATR_BADTYPE (SATR)27U +#define SATR_BADMODE (SATR)28U +#define SATR_BADCONTEXT (SATR)29U +#define SATR_BADHASHLEN (SATR)30U +#define SATR_BADMACTYPE (SATR)31U +#define SATR_BADMACLEN (SATR)32U +#define SATR_BADHANDLE (SATR)33U +#define SATR_FNP (SATR)34U +#define SATR_HFAULT (SATR)35U +#define SATR_NOPEND (SATR)36U +#define SATR_BADRSAENC (SATR)37U +#define SATR_BADMOD (SATR)38U +/* Special marker for end of list. */ +#define SATR_LAST (SATR)39U + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* See caltypes.h for type definitions associated with defines above. */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALENUM_C +#ifdef __cplusplus +extern "C" { +#endif + +/* NOTE: this header file does not have an associated C file. */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/calini.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/calini.h new file mode 100644 index 0000000..62461d1 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/calini.h @@ -0,0 +1,69 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL initialization + ------------------------------------------------------------------- */ + +#ifndef CALINI_H +#define CALINI_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALINI_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALIni(void); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/calpolicy.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/calpolicy.h new file mode 100644 index 0000000..2a43445 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/calpolicy.h @@ -0,0 +1,183 @@ +/* ------------------------------------------------------------------- + $Rev: 1293 $ $Date: 2017-07-27 14:09:14 -0400 (Thu, 27 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file defining CAL policy for endianess, HW/SW, etc. + ------------------------------------------------------------------- */ + +#ifndef CALPOLICY_H +#define CALPOLICY_H + +/* -------- */ +/* Includes */ +/* -------- */ + +/* The following include provides a custom configuration header file when + CALCONFIGH is defined +*/ +#ifdef CALCONFIGH +# include CALCONFIGH +#else +# error "CALCONFIGH not defined. CAL requires a custom configuration header \ +defined by CALCONFIGH. Review CAL README." +#endif + +/* ------- */ +/* Defines */ +/* ------- */ + +/* Context switching */ +#ifndef MAXRESHANDLES +# define MAXRESHANDLES 1 +#endif + +/* Little Endian (default) / Big Endian */ +#ifndef SAT_LITTLE_ENDIAN +# define SAT_LITTLE_ENDIAN 1 +#endif + +/* PK SW Point Validate Checking */ +#ifndef PKSWCHKVALPT +# define PKSWCHKVALPT 1 +#endif + +/* DMA */ +#ifndef USE_X52EXEC_DMA +# define USE_X52EXEC_DMA 0 +#endif + +/* SHA */ +#define MAXHASHLEN 512 +#define MAXHMACKEYLEN 512 + +/* RNG */ +#define NRBGSIMNUMRO 16 +#define ENTROPYMEMBLOCKS 7 +#define BUFMEMBLOCKS 3 +#ifndef RNXBLKLEN +#define RNXBLKLEN 32 +#endif +#ifndef RNXBLKOUTLEN +#define RNXBLKOUTLEN 4 +#endif + +#ifndef USENRBGSW +# define USENRBGSW 0 +#endif + +/* PK */ +#ifndef PKX0_BASE +# define PKX0_BASE 0xE0000000u +#endif + +#if USEPKSW +# ifndef MAXMODSIZE +# define MAXMODSIZE 8192 +# endif +# ifndef PKSWBUFSIZE +# define PKSWBUFSIZE 15*(MAXMODSIZE/32) +# endif +#else +# define USEPKSW 0 +#endif + +/* Set default values for X52 configuration defines. */ +#ifndef X52_CFG_OPT +# define X52_CFG_OPT 0 +#endif +#ifndef X52_LIR_LEN +# define X52_LIR_LEN 0x800 +#endif +#ifndef X52_BER_LEN +# define X52_BER_LEN 0x400 +#endif +#ifndef X52_MMR_LEN +# define X52_MMR_LEN 0x400 +#endif +#ifndef X52_TSR_LEN +# define X52_TSR_LEN 0x400 +#endif +#ifndef X52_FPR_LEN +# define X52_FPR_LEN 0x400 +#endif +#if X52_LIR_ROM_LEN>0 && X52_LIR_LEN>X52_LIR_ROM_LEN +# define PKX_OFFSET 2048 +#else +# define PKX_OFFSET 0 +#endif + +/* X52 Configuration Options */ +#define AESPKX (X52_CFG_OPT&0x00000001u) +#define AESPKXGCM (X52_CFG_OPT&0x00000008u) +#define AESPKXFASTKEY (X52_CFG_OPT&0x01000000u) +#define SHAPKXOPT1 (X52_CFG_OPT&0x00000020u) +#define SHAPKXOPT224 (X52_CFG_OPT&0x00000040u) +#define SHAPKXOPT256 (X52_CFG_OPT&0x00000080u) +#define SHAPKXOPT384 (X52_CFG_OPT&0x00000100u) +#define SHAPKXOPT512 (X52_CFG_OPT&0x00000200u) +#define SHAPKXOPT5124 (X52_CFG_OPT&0x00400000u) +#define SHAPKXOPT5126 (X52_CFG_OPT&0x00800000u) + +/* Define the maximum number of return values that may be handled using + CAL*TrfRes() function(s). +*/ +#define CAL_MAXTRFS 4 + +/* Volatile pointer operations */ +/* These access macros are designed so that they may be redefined by a + user compiling CAL. +*/ +#ifndef CALREAD32 +# define CALREAD32(ptr) ( *(ptr) ) +#endif +#ifndef CALWRITE32 +# define CALWRITE32(ptr, val) ( *(ptr)=val ) +#endif +#ifndef CALPOLL32 +# define CALPOLL32(ptr, val, mask) while ((*(ptr) & (mask)) != (val)); +#endif + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +#ifndef CALPOLICY_C +#ifdef __cplusplus +extern "C" { +#endif + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +/* NOTE: this header file does not have an associated C file. */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/caltypes.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/caltypes.h new file mode 100644 index 0000000..3b2fe0b --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/caltypes.h @@ -0,0 +1,328 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + This file defines common types in the CAL. + + Since support for the C99 stdint.h integer types is not universal, + these are defined herein and may require customization from compiler + to compiler, or use of the stdint.h header, if present (recommended). + + C99 supports 64-bit types; however, support in older compilers is + spotty. For those that do not support it, the macro NO64BITINT may be + defined by the user to prevent defintion of 64-bit types. This is + generally safe with CAL-PK and CAL-SYM; however, this is incompatible + with CAL-SW. + + Most CAL types and constants are defined with the "SAT" prefix to + reduce the chance of name space collisions with other users. + ------------------------------------------------------------------- */ + +#ifndef CALTYPES_H +#define CALTYPES_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* Base Types */ +/* ---- ----- */ + +/* The user may compile using stdint.h instead of the definitions below + by defining the macro INC_STDINT_H. */ +#ifdef INC_STDINT_H +#include +#endif + +/* Integer type abstraction layer. */ +#ifndef INC_STDINT_H + +typedef unsigned char uint8_t; +typedef signed char int8_t; + +typedef unsigned short uint16_t; +typedef signed short int16_t; + +typedef unsigned int uint32_t; +typedef int int32_t; + +/* stdint.h is a C99 feature, and C99 supports 64-bit ints, so this is + immune to the macro used to disable 64-bit int support. +*/ +typedef unsigned long long uint64_t; +typedef long long int64_t; + +typedef long uintptr_t; + +#endif + +/* Boolean type. */ +typedef uint8_t SATBOOL; + +/* Unsigned integer type */ +typedef uint8_t SATUINT8_t; +typedef uint16_t SATUINT16_t; +typedef uint32_t SATUINT32_t; +#ifdef INC_STDINT_H +typedef uint64_t SATUINT64_t; +#else +#ifndef NO64BITINT +typedef uint64_t SATUINT64_t; +#endif +#endif + +/* Integer type */ +typedef int8_t SATINT8_t; +typedef int16_t SATINT16_t; +typedef int32_t SATINT32_t; +#ifdef INC_STDINT_H +typedef int64_t SATINT64_t; +#else +#ifndef NO64BITINT +typedef int64_t SATINT64_t; +#endif +#endif + +typedef uintptr_t SATUINTPTR_t; + +/* Major cipher key/SSP type. */ +/* ----- ------ ------- ----- */ +typedef uint8_t SATSSPTYPE; +typedef SATSSPTYPE * SATSSPTYPEPTR; + + +/* Asymmetric Ciphers */ +/* ---------- ------- */ + +/* Cipher type. */ +typedef uint8_t SATASYMTYPE; +typedef SATASYMTYPE * SATASYMTYPEPTR; + +/* Cipher size type. */ +typedef uint16_t SATASYMSIZE; +typedef SATASYMSIZE * SATASYMSIZEPTR; + +/* Cipher encoding */ +typedef uint8_t SATRSAENCTYPE; +typedef SATRSAENCTYPE * SATRSAENCTYPEPTR; + +/* DSA public/private key. */ +typedef struct { + uint16_t ui16PLen; /* Length of modulus p. */ + uint16_t ui16QLen; /* Length of prime divisor q. */ + uint32_t *pui32P; /* Prime modulus p. */ + uint32_t *pui32Q; /* Prime divisor q. */ + uint32_t *pui32G; /* Generator g, length==p. */ + uint32_t *pui32X; /* Private key x, length==p. */ + uint32_t *pui32Y; /* Private key y, length==q. */ +} SATASYMDSADOMAIN; +typedef SATASYMDSADOMAIN * SATASYMDSADOMAINPTR; + + +/* Symmetric Ciphers */ +/* --------- ------- */ + +/* Cipher type. */ +typedef uint8_t SATSYMTYPE; +typedef SATSYMTYPE * SATSYMTYPEPTR; + +/* Cipher key size type (in bits). */ +typedef uint16_t SATSYMKEYSIZE; +typedef SATSYMKEYSIZE * SATSYMKEYSIZEPTR; + +/* Cipher mode type. */ +typedef uint8_t SATSYMMODE; +typedef SATSYMMODE * SATSYMMODEPTR; + +/* Cipher key object. */ +/* Other fields are only valid when sstCipher!=SATSYMTYPE_NULL. */ +typedef struct { + SATSYMTYPE sstCipher; + SATSYMKEYSIZE ssksKeyLen; + uint32_t *pui32Key; +} SATSYMKEY; +typedef SATSYMKEY * SATSYMKEYPTR; + + +/* Hashes */ +/* ------ */ + +/* Hash type. */ +typedef uint8_t SATHASHTYPE; +typedef SATHASHTYPE * SATHASHTYPEPTR; + +/* Hash size type (in bits). */ +typedef uint16_t SATHASHSIZE; +typedef SATHASHSIZE * SATHASHSIZEPTR; + + +/* Context switching. */ +/* ----- ------ ------- ----- */ + +typedef uint32_t SATRESHANDLE; +typedef SATRESHANDLE * SATRESHANDLEPTR; + +typedef struct { + SATHASHTYPE sshashtype; + uint32_t uiRunLen; + uint32_t uiHash[MAXHASHLEN/32]; /* holds intermed hash */ +} SHACTX; + +typedef struct { + SATHASHTYPE sshashtype; + uint32_t uiRunLen; + uint32_t uiKeyLen; + uint32_t uiHash[MAXHASHLEN/32]; /* holds intermed hash */ + uint32_t uiKey[MAXHMACKEYLEN/32]; /* holds intermed key */ +} SHAHMACCTX; + +typedef struct { + uint8_t uiContextType; + union{ + SHACTX ctxSHA; + SHAHMACCTX ctxMAC; + }CTXUNION; +} SATRESCONTEXT; +typedef SATRESCONTEXT * SATRESCONTEXTPTR; + + +/* Message Authentication Codes */ +/* ------- -------------- ----- */ + +/* MAC type. */ +typedef uint8_t SATMACTYPE; +typedef SATMACTYPE * SATMACTYPEPTR; +typedef uint8_t SATMACTYPEFLAG; + + +/* Random Number Generator */ +/* ------ ------ --------- */ +typedef union { + uint32_t u32[4]; + uint8_t u8[16]; +} uint128_t; + +typedef struct { + uint128_t ui128V; + uint128_t ui128K[2]; + uint32_t uiReseedCnt; + uint32_t uiReseedLim; + uint32_t uiEntropyFactor; + SATSYMKEYSIZE eStrength; + SATBOOL bTesting; + +} DRBGCTX; + +typedef DRBGCTX * DRBGCTXPTR; + + +/* Function Return Code */ +/* -------- ------ ---- */ +typedef uint16_t SATR ; +typedef SATR * SATRPTR ; + + +/* Transfer Results */ +/* -------- ------- */ +typedef struct { + SATUINT32_t uiLen; + volatile SATUINT32_t* vpuiSrc; + void* pDest; +} SATDATATRF; + +typedef struct { + SATUINT32_t uiResType; + SATUINT32_t uiNumDataTrf; + SATDATATRF dtrfArray[CAL_MAXTRFS]; +} SATRESULT; + + +/* EC Ultra Structs */ +/* -- ----- ------- */ +typedef uint32_t SATECTYPE; + +typedef struct { + SATUINT32_t uiLen; + SATUINT32_t* puiX; + SATUINT32_t* puiY; +} SATECPOINT; + +typedef struct { + SATUINT32_t uiLen; + SATUINT32_t* puiMod; + SATUINT32_t* puiMontPrecompute; + SATUINT32_t* puiRSqd; +} SATECMONTMOD; + +typedef struct { + SATUINT32_t uiCurveSize; + SATECTYPE eCurveType; + SATECPOINT* pBasePoint; + SATECMONTMOD* pModP; + SATECMONTMOD* pModN; + SATUINT32_t* puiA; + SATUINT32_t* puiB; +} SATECCURVE; + +typedef struct { + SATUINT32_t uiLen; + SATUINT32_t* puiSigR; + SATUINT32_t* puiSigS; + SATUINT32_t* puiSigX; + SATUINT32_t* puiSigY; +} SATECDSASIG; + +typedef struct { + SATHASHSIZE sHashLen; + SATUINT32_t* puiHash; +} SATHASH; + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALTYPES_C +#ifdef __cplusplus +extern "C" { +#endif + +/* NOTE: this header file does not have an associated C file. */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/config_user.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/config_user.h new file mode 100644 index 0000000..3728565 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/config_user.h @@ -0,0 +1,44 @@ +/* ------------------------------------------------------------------- + $Rev: 727 $ $Date: 2017-10-20 16:50:53 -0400 (Fri, 20 Oct 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + + User configuration file to include/exclude CAL components. + ------------------------------------------------------------------- */ + +#ifndef CALCONFIG_F5200_H +#define CALCONFIG_F5200_H + +#include "x52cfg_user.h" +#include + +extern uint32_t g_user_crypto_base_addr; + +#define SAT_LITTLE_ENDIAN 1 +#define PKX0_BASE (g_user_crypto_base_addr) +#define USEPKX 1 +#define USEAESPKX 1 +#define USESHAPKX 1 +#define USEDRBGPKX 1 +#define USENRBGPKX 1 +#define USECALCTX 1 + +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/drbg.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/drbg.h new file mode 100644 index 0000000..dba16f7 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/drbg.h @@ -0,0 +1,91 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for DRBG functions for CAL + ------------------------------------------------------------------- */ + +#ifndef DRBG_H +#define DRBG_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ +#define CALDRBGENTROPYFACTOR 2 + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef DRBG_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALDRBGInstantiate(const SATUINT32_t *puiNonce, + SATUINT32_t uiNonceLen, const SATUINT32_t *puiPzStr, + SATUINT32_t uiPzStrLen, SATSYMKEYSIZE eStrength, + SATUINT32_t uiEntropyFactor, SATUINT32_t uiReseedLim, SATBOOL bTesting); + +extern SATR CALDRBGReseed(const SATUINT32_t *puiAddIn, SATUINT32_t uiAddInLen); + +extern SATR CALDRBGGenerate(const SATUINT32_t *puiAddIn, SATUINT32_t uiAddInLen, + SATBOOL bPredResist, SATUINT32_t *puiOut, SATUINT32_t uiOutBlocks); + +extern SATR CALDRBGUninstantiate(void); + +extern SATR CALDRBGGetCtx(DRBGCTXPTR drbgCtxExt); + +extern SATR CALDRBGLoadCtx(DRBGCTXPTR drbgCtxExt); + +extern SATR CALDRBGGetbInst(void); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +extern SATR CALDrbgTrfRes(SATBOOL bBlock); + +extern void CALDrbgIni(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/drbgf5200.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/drbgf5200.h new file mode 100644 index 0000000..d7f6c4c --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/drbgf5200.h @@ -0,0 +1,120 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for F5200 DRBG function hardware implementations + in CAL. + ------------------------------------------------------------------- */ + +#ifndef DRBGF5200_H +#define DRBGF5200_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ +#define RNXEFACTOR (X52BER+2) +#define RNXIRLEN (X52BER+2) +#define RNXKEYORD (X52BER+3) +#define RNXRESPRED (X52BER+4) +#define RNXTESTSEL (X52BER+5) +#define RNXBADDIN (X52BER+6) +#define RNXPPSTR (X52BER+7) +#define RNXPCTX (X52BER+8) +#define RNXPRENT (X52BER+13) +#define RNXITMP3 (X52BER+20) +#define RNXPCTX2 (X52BER+22) +/* These use same locs as tb generator, but can change */ +#define RNXRDATA (X52BER_ENDIAN+0x24) +#define RNXAIDATAOFF 0x0062 +#define RNXAIDATA (X52BER_ENDIAN+RNXAIDATAOFF) +#define RNXCTXOFF 0x0094 +#define RNXCTX (X52FPR+RNXCTXOFF) +#define RNXCTXV (X52FPR_ENDIAN+RNXCTXOFF+6) +#define RNXCTXVMMR (X52MMR_ENDIAN+RNXCTXOFF+6) +#define RNXTESTENT (X52TSR_ENDIAN+8) + +#define RNXCTXWORDS 18 +#define RNXBLENLOC (RNXCTX+RNXCTXWORDS) +#define RNXBOUTLENLOC (RNXCTX+RNXCTXWORDS+1) + +#define RNXMAXTESTENT32 512 +#define CALDRBGMAXADDINLEN X52_BER_LEN-RNXAIDATAOFF-4 +#define CALDRBGMAXPSNONCELEN X52_BER_LEN-RNXAIDATAOFF-4 + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef DRBGF5200_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATR drbgf5200Ini(void); + +extern SATR drbgf5200TrfRes(SATBOOL bBlock); + +extern SATR drbgf5200instantiate(const SATUINT32_t *puiNonce, + SATUINT32_t uiNonceLen, const SATUINT32_t *puiPzStr, SATUINT32_t uiPzStrLen, + SATSYMKEYSIZE eStrength, SATUINT32_t uiEntropyFactor, + SATUINT32_t uiReseedLim, SATBOOL bTesting); + +extern SATR drbgf5200reseed(const SATUINT32_t *puiAddIn, + SATUINT32_t uiAddInLen); + +extern SATR drbgf5200generate(const SATUINT32_t *puiAddIn, + SATUINT32_t uiAddInLen, SATBOOL bPredResist, SATUINT32_t uiReqLen, + SATUINT32_t *puiOut); + +extern SATR drbgf5200uninstantiate(void); + +extern SATR drbgf5200getctx(DRBGCTXPTR drbgCtxExt); + +extern SATR drbgf5200loadctx(DRBGCTXPTR drbgCtxExt); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/hash.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/hash.h new file mode 100644 index 0000000..f3fd6d4 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/hash.h @@ -0,0 +1,102 @@ +/* ------------------------------------------------------------------- + $Rev: 1293 $ $Date: 2017-07-27 14:09:14 -0400 (Thu, 27 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL hash functions. + ------------------------------------------------------------------- */ + +#ifndef HASH_H +#define HASH_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ +extern const SATHASHSIZE uiHashWordLen[SATHASHTYPE_LAST]; + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef HASH_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALHash(SATHASHTYPE eHashType, const void *pMsg, + SATUINT32_t uiMsgLen, void *pHash); + +extern SATR CALHashDMA(SATHASHTYPE eHashType, const void *pMsg, + SATUINT32_t uiMsgLen, void *pHash, SATUINT32_t uiDMAChConfig); + +extern SATR CALHashCtx(const SATRESHANDLE hResource, + const SATRESCONTEXTPTR pContext, const void *pMsg, SATUINT32_t uiMsgLen, + void *pHash, const SATBOOL bFinal); + +extern SATR CALHashCtxIni(const SATRESCONTEXTPTR pContext, + const SATHASHTYPE eHashType); + +extern SATR CALHashIni(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen); + +extern SATR CALHashWrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR CALHashRead(void *pHash); + +extern SATR CALKeyTree(SATBOOL bPathSizeSel, const SATUINT32_t* puiKey, + SATUINT8_t uiOpType, const SATUINT32_t* puiPath, SATUINT32_t* puiKeyOut); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATUINT32_t iGetHashLen(SATHASHTYPE eHashType); + +extern SATUINT32_t iGetBlockLen(SATHASHTYPE eHashType); + +extern SATR CALHashCtxLoad(const SATRESHANDLE hResource, + SATRESCONTEXTPTR const pContext, SATUINT32_t uiRunLen); + +extern SATUINT32_t iGetRunLen(SATRESCONTEXTPTR const pContext); + +extern SATR CALHashTypeIni(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/mac.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/mac.h new file mode 100644 index 0000000..acdc767 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/mac.h @@ -0,0 +1,95 @@ +/* ------------------------------------------------------------------- + $Rev: 1296 $ $Date: 2017-08-01 13:54:48 -0400 (Tue, 01 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL MAC functions. + ------------------------------------------------------------------- */ + +#ifndef MAC_H +#define MAC_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef MAC_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALMAC(SATMACTYPE eMACType, const SATUINT32_t *pKey, SATUINT32_t uiKeyLen, + const void *pMsg, SATUINT32_t uiMsgLen, void *pMAC); + +extern SATR CALMACDMA(SATMACTYPE eMACType, const SATUINT32_t *pKey, + SATUINT32_t uiKeyLen, const void *pMsg, SATUINT32_t uiMsgLen, + const void *pMAC, SATUINT32_t uiDMAChConfig); + +extern SATR CALMACIni(SATMACTYPE eMACType, const SATUINT32_t *pKey, + SATUINT32_t uiKeyLen, SATUINT32_t uiMsgLen); + +extern SATR CALMACCtx(const SATRESHANDLE hResource, + const SATRESCONTEXTPTR pContext, const void *pMsg, SATUINT32_t uiMsgLen, + void *pHash, const SATUINT8_t uiFlag); + +extern SATR CALMACCtxIni(const SATRESCONTEXTPTR pContext, const SATHASHTYPE eHashType, + const SATUINT32_t *pKey, SATUINT32_t uiKeyLen); + +extern SATR CALMACWrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR CALMACRead(void *pMAC); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATUINT32_t iGetMACKeyLen(SATMACTYPE eMACType); + +extern SATR CALMACCtxLoad(const SATRESHANDLE hResource, + SATRESCONTEXTPTR const pContext, SATUINT32_t uiRunLen); + +extern SATUINT32_t iGetMACRunLen(SATRESCONTEXTPTR const pContext); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/miv-rv32i-user-crypto-lib.a b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/miv-rv32i-user-crypto-lib.a new file mode 100644 index 0000000..5fda638 Binary files /dev/null and b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/miv-rv32i-user-crypto-lib.a differ diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/miv-rv32imc-user-crypto-lib.a b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/miv-rv32imc-user-crypto-lib.a new file mode 100644 index 0000000..ee7bcf4 Binary files /dev/null and b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/miv-rv32imc-user-crypto-lib.a differ diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/nrbg.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/nrbg.h new file mode 100644 index 0000000..d517065 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/nrbg.h @@ -0,0 +1,83 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for NRBG functions for CAL. + ------------------------------------------------------------------- */ + +#ifndef NRBG_H +#define NRBG_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef NRBG_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALNRBGSetTestEntropy(SATUINT32_t * puiEntropy, + SATUINT32_t uiEntLen32); + +extern SATR CALNRBGGetEntropy(SATUINT32_t * puiEntropy, SATUINT32_t uiEntLen32, + SATBOOL bTesting); + +extern SATR CALNRBGConfig(SATUINT32_t uiWriteEn, SATUINT32_t uiCSR, + SATUINT32_t uiCntLim, SATUINT32_t uiVoTimer, SATUINT32_t uiFMsk, + SATUINT32_t* puiStatus); + +extern SATUINT32_t CALNRBGHealthStatus(void); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATUINT32_t CALNRBGGetTestEntLen(void); + +extern SATR nrbgpkxgetentropy(SATUINT32_t * puiEntropy, + SATUINT32_t uiEntLen32); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/pk.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/pk.h new file mode 100644 index 0000000..5983d9a --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/pk.h @@ -0,0 +1,302 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for for CAL PK. + ------------------------------------------------------------------- */ + +#ifndef PK_H +#define PK_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef PK_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALPKTrfRes(SATBOOL bBlock); + +extern SATR CALDSASign(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALDSASignCM(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALDSASignHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, const SATUINT32_t* puiK, + const SATUINT32_t* puiX, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, SATUINT32_t uiN, + SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALDSASignHashCM(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, const SATUINT32_t* puiK, + const SATUINT32_t* puiX, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, SATUINT32_t uiN, + SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALDSAVerify(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiY, const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, + const SATUINT32_t* puiQMu, SATUINT32_t uiN, SATUINT32_t uiL); + +extern SATR CALDSAVerifyHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, const SATUINT32_t* puiY, + const SATUINT32_t* puiR, const SATUINT32_t* puiS, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALECDHC(const SATUINT32_t* puiS, const SATUINT32_t* puiWx, + const SATUINT32_t* puiWy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t* puiK, const SATUINT32_t* puiR, + const SATUINT32_t* puiRMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiZ); + +extern SATR CALECDSASign(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALECDSASignTwist(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALECDSASignCM(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALECDSASignTwistCM(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALECDSASignHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiK, const SATUINT32_t* puiD, const SATUINT32_t* puiB, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSASignHashCM(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiK, const SATUINT32_t* puiD, const SATUINT32_t* puiB, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSASignTwistHash(const SATUINT32_t* puiMsg, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSAVerify(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS,const + SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress); + +extern SATR CALECDSAVerifyTwist(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALECDSAVerifyHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSAVerifyTwistHash(const SATUINT32_t* puiMsg, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALECMult(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECMultCM(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t* puiN, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress, SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECMultTwist(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiLen, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECMultTwistCM(const SATUINT32_t* puiMul, + const SATUINT32_t* puiPx, const SATUINT32_t* puiPy, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiMod,const SATUINT32_t* puiMu, + const SATUINT32_t* puiN, SATUINT32_t uiLen, SATUINT32_t* puiRx, + SATUINT32_t* puiRy); + +extern SATR CALECMultAdd(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiB, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen, SATUINT32_t uiPtPCompress, SATUINT32_t uiPtQCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECPtValidate(const SATUINT32_t* puiPx, const SATUINT32_t* puiPy, + const SATUINT32_t* puiB, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen); + +extern SATR CALECKeyPairGen(const SATUINT32_t* puiC, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + const SATUINT32_t* puiNM1, const SATUINT32_t* puiNM1Mu, const SATUINT32_t* puiB, + SATUINT32_t* puiD, SATUINT32_t* puiQx, SATUINT32_t* puiQy, SATUINT32_t uiLen); + +extern SATR CALExpo(const SATUINT32_t* puiBase, const SATUINT32_t* puiExpo, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALExpoCM(const SATUINT32_t* puiBase, const SATUINT32_t* puiExpo, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALMMult(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALMMultAdd(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiC, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALModRed(const SATUINT32_t* puiA, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiALen, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPreCompute(const SATUINT32_t* puiMod, SATUINT32_t* puiMu, + SATUINT32_t uiModLen); + +extern SATR CALRSACRT(const SATUINT32_t* puiCipher, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ,const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiLen, SATUINT32_t* puiPlain); + +extern SATR CALRSACRTCM(const SATUINT32_t* puiCipher, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t * puiE, const SATUINT32_t* puiP, + const SATUINT32_t* puiQ, const SATUINT32_t * puiN, + const SATUINT32_t * puiNMu, SATUINT32_t uiLen, SATUINT32_t uiELen, + SATUINT32_t* puiPlain); + +extern SATR CALRSACRTSign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + const SATUINT32_t* puiN, SATUINT32_t uiLen, SATUINT32_t* puiSig); + +extern SATR CALRSACRTSignCM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, const SATUINT32_t* puiQ, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSig); + +extern SATR CALRSACRTSignHash(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ,const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + const SATUINT32_t* puiN, SATUINT32_t uiMsgLen, SATUINT32_t uiModLen, + SATUINT32_t* puiSig, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALRSACRTSignHashCM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, const SATUINT32_t* puiQ, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, SATUINT32_t* puiSig, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALRSASign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiD, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, SATUINT32_t* puiSig); + +extern SATR CALRSASignHash(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiD, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, SATUINT32_t uiModLen, + SATUINT32_t* puiSig, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALRSAVerify(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, + const SATUINT32_t* puiSig); + +extern SATR CALRSAVerifyHash(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiE, SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, const SATUINT32_t* puiSig, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPurge52(SATBOOL bVerify); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/pkx.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/pkx.h new file mode 100644 index 0000000..c23dda4 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/pkx.h @@ -0,0 +1,409 @@ +/* ------------------------------------------------------------------- + $Rev: 1298 $ $Date: 2017-08-04 13:04:19 -0400 (Fri, 04 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for for CAL PK. + ------------------------------------------------------------------- */ + +#ifndef PKX_H +#define PKX_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* X5200 Addressing */ +#define X52BER ((volatile SATUINT32_t *) (PKX0_BASE + 0x00000000u)) +#define X52MMR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00001000u)) +#define X52TSR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00002000u)) +#define X52FPR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00003000u)) +#define X52LIR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00004000u)) +#define X52CSR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00007F80u)) +#define X52CSRMERRS ((volatile SATUINT32_t *) (PKX0_BASE + 0x00007F8Cu)) +#define X52CSRMERRT0 ((volatile SATUINT32_t *) (PKX0_BASE + 0x00007F94u)) + +#if SAT_LITTLE_ENDIAN +#define X52BER_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00008000u)) +#define X52MMR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00009000u)) +#define X52TSR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x0000A000u)) +#define X52FPR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x0000B000u)) +#define X52DMACONFIG_ENDIAN 0x8 +#else +#define X52BER_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00000000u)) +#define X52MMR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00001000u)) +#define X52TSR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00002000u)) +#define X52FPR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00003000u)) +#define X52DMACONFIG_ENDIAN 0x0 +#endif + +/* X5200 Macros */ +#define X52GO(x) (0x10 | ((x)<<8)) + +/* Counter Measures */ +#define RANDLEN 4 + +/* X5200 CSRMAIN bit field masks. */ +#define X52CSRMAINRST 1 +#define X52CSRMAINCCMPLT 2 +#define X52CSRMAINCMPLT 4 +#define X52CSRMAINBUSY 8 +#define X52CSRMAINGO 0x10 +#define X52CSRMAINPURGE 0x20 +#define X52CSRMAINECDIS 0x40 +#define X52CSRMAINALARM 0x80 +#define X52CSRMAINLIRA ((0xFFF) << 8) +#define X52CSRMERRSSEC ((0x2) << 24) +#define X52CSRMERRSA 0x1FFF + +/* Address pointers for ROM'd P-curve moduli */ +#define P192_MOD (&uiROMMods[0]) +#define P224_MOD (&uiROMMods[1]) +#define P256_MOD (&uiROMMods[2]) +#define P384_MOD (&uiROMMods[3]) +#define P521_MOD (&uiROMMods[4]) + +/* X5200 Addressing Flags */ +#define X52BYTEREVERSE_FLAG 1 +#define X52WORDREVERSE_FLAG 2 +#define X52BYTEREVERSE 0x00002000 +#define X52WORDREVERSE 0x00004000 +#define X52ADDRESSRANGE 0x2000 + +/* X5200 DMA channel configuration constants. */ +#define X52CCR_DEFAULT 0 /* BSIZE=auto, ESWP=none, PROT=user, INC=inc */ +#define X52CCR_BSIZEAUTO 0 /* BSIZE=auto */ +#define X52CCR_BSIZEBYTE 0x10 /* BSIZE=byte */ +#define X52CCR_BSIZEHWORD 0x20 /* BSIZE=half word */ +#define X52CCR_BSIZEWORD 0x30 /* BSIZE=word */ +#define X52CCR_ESWPNONE 0 /* ESWP=none */ +#define X52CCR_ESWPWORD 0x8 /* ESWP=swap bytes in word [0123]->[3210] */ +#define X52CCR_PROTUSER 0 /* PROT=user */ +#define X52CCR_PROTPRIV 0x2 /* PROT=priv */ +#define X52CCR_INCADDR 0 /* INC=inc */ +#define X52CCR_NOINCADDR 0x1 /* INC=non-inc */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef PKX_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern void CALPKXIni(void); + +extern void CALPKMem32Load(volatile SATUINT32_t * puiDst, + const SATUINT32_t * puiSrc, SATUINT32_t uiNum ); + +extern SATR CALPKXTrfRes(SATBOOL bBlock); + +extern SATR CALPKXPreCompute(const SATUINT32_t* puiMod, SATUINT32_t* puiMu, + SATUINT32_t uiModLen); + +extern SATR CALPKXExpo(const SATUINT32_t* puiBase, const SATUINT32_t* puiExpo, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALPKXExpoCM(const SATUINT32_t* puiBase, + const SATUINT32_t* puiExpo, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPKXDSASign(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXDSASignCM(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXDSASHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATUINT32_t uiDMAChConfig, const SATBOOL bCM); + +extern SATR CALPKXDSAVerify(const SATUINT32_t *puiHash, + const SATUINT32_t *puiG, const SATUINT32_t *puiY, + const SATUINT32_t *puiSigR, const SATUINT32_t *puiSigS, + const SATUINT32_t *puiP, const SATUINT32_t *puiPMu, + const SATUINT32_t *puiQ, const SATUINT32_t *puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL); + +extern SATR CALPKXDSAVHDMA(const SATUINT32_t *puiExtInput, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t *puiG, const SATUINT32_t *puiY, + const SATUINT32_t *puiSigR, const SATUINT32_t *puiSigS, + const SATUINT32_t *puiP, const SATUINT32_t *puiPMu, const SATUINT32_t *puiQ, + const SATUINT32_t *puiQMu, SATUINT32_t uiN, SATUINT32_t uiL, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXModRed(const SATUINT32_t* puiA, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiALen, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPKXMMult(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPKXMMultAdd(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiC, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALPKXECMult(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECMultTwist(const SATUINT32_t* puiMul, + const SATUINT32_t* puiPx,const SATUINT32_t* puiPy, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen, SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECMultCM(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t * puiN, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress, SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECMultTwistCM(const SATUINT32_t* puiMul, + const SATUINT32_t* puiPx, const SATUINT32_t* puiPy, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + const SATUINT32_t * puiN, SATUINT32_t uiLen, SATUINT32_t* puiRx, + SATUINT32_t* puiRy); + +extern SATR CALPKXECMultAdd(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiB, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen, SATUINT32_t uiPtPCompress, SATUINT32_t uiPtQCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECDSASign(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASignTwist(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx,const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASignCM(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASignTwistCM(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASH(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + const SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASHCM(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + const SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, SATUINT32_t uiDMAChConfig, + const SATBOOL bCM); + +extern SATR CALPKXECDSASTwistH(const SATUINT32_t* puiHash, + const SATHASHTYPE eHashType, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiK, const SATUINT32_t* puiD, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, const SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASTwistHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECDSAVerify(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVerifyTwist(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVH(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB,const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + const SATUINT32_t uiLen, const SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB,const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECDSAVTwistH(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, const SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVTwistHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECDHC(const SATUINT32_t* puiS, const SATUINT32_t* puiWx, + const SATUINT32_t* puiWy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t* puiK, const SATUINT32_t* puiR, + const SATUINT32_t* puiRMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiZ); + +extern SATR CALPKXRSACRT(const SATUINT32_t* puiCipher, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, SATUINT32_t uiLen, + SATUINT32_t* puiPlain); + +extern SATR CALPKXRSACRTCM(const SATUINT32_t* puiCipher, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiE, + const SATUINT32_t* puiP, const SATUINT32_t* puiQ, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, const SATUINT32_t uiLen, const SATUINT32_t uiELen, + SATUINT32_t* puiPlain); + +extern SATR CALPKXRSACRTSign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiCipher, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, + const SATUINT32_t* puiQMu, const SATUINT32_t* puiN, SATUINT32_t uiLen, + SATUINT32_t* puiS); + +extern SATR CALPKXRSACRTSignCM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, + const SATUINT32_t* puiP, const SATUINT32_t* puiQ, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSig); + +extern SATR CALPKXRSACRTSHDMA(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + const SATUINT32_t* puiN, SATUINT32_t uiMsgLen, SATUINT32_t uiModLen, + SATUINT32_t* puiSig, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXRSACRTSHDMACM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, + const SATUINT32_t* puiP, const SATUINT32_t* puiQ, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, SATUINT32_t uiLen, + SATUINT32_t* puiSig, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXRSASign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiD, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, SATUINT32_t* puiSig); + +extern SATR CALPKXRSASHDMA(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiD, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, SATUINT32_t* puiSig, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXRSAVerify(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, + const SATUINT32_t* puiS); + +extern SATR CALPKXRSAVHDMA(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiE,SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, const SATUINT32_t* puiS, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECPtValidate(const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiLen); + +extern SATR CALPKXECKeyPairGen(const SATUINT32_t* puiC, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + const SATUINT32_t* puiNM1, const SATUINT32_t* puiNM1Mu, const SATUINT32_t* puiB, + SATUINT32_t* puiD, SATUINT32_t* puiQx, SATUINT32_t* puiQy, SATUINT32_t uiLen); + +extern SATR CALPKXPurge52(SATBOOL bVerify); + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ +extern SATRESULT SATResults; + +/* -------- ------ --------- */ +/* External Global Constants */ +/* -------- ------ --------- */ +extern const SATUINT32_t uiROMMods[]; + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/pkxlib.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/pkxlib.h new file mode 100644 index 0000000..fb4c0fc --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/pkxlib.h @@ -0,0 +1,95 @@ +/* ------------------------------------------------------------------- + $Rev: 1434 $ $Date: 2017-10-20 16:46:16 -0400 (Fri, 20 Oct 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for PKX-5200 Library. + ------------------------------------------------------------------- */ + +#ifndef PKXLIB_H +#define PKXLIB_H + +#include "caltypes.h" +#include "calpolicy.h" + +#define PKX_JMP_NONE (0xFFFFu + PKX_OFFSET) + +/* jump table entry points: starting PC value */ +#define PKX_JMP_RECIP_PRECOMPUTE (0x0000 + PKX_OFFSET) +#define PKX_JMP_MOD_EXP (0x0002 + PKX_OFFSET) +#define PKX_JMP_RSA_CRT (0x0004 + PKX_OFFSET) +#define PKX_JMP_EC_PTMUL (0x0006 + PKX_OFFSET) +#define PKX_JMP_EC_DSA_SIGN (0x0008 + PKX_OFFSET) +#define PKX_JMP_EC_DSA_VERIFY (0x000A + PKX_OFFSET) +#define PKX_JMP_DSA_SIGN (0x000C + PKX_OFFSET) +#define PKX_JMP_DSA_VERIFY (0x000E + PKX_OFFSET) +#define PKX_JMP_MOD_MULT (0x0010 + PKX_OFFSET) +#define PKX_JMP_MOD_RED (0x0012 + PKX_OFFSET) +#define PKX_JMP_EC_PTDECOMP (0x0014 + PKX_OFFSET) +#define PKX_JMP_EC_DHC (0x0016 + PKX_OFFSET) +#define PKX_JMP_MOD_MULT_ADD (0x0018 + PKX_OFFSET) +#define PKX_JMP_EC_PTMUL_ADD (0x001A + PKX_OFFSET) +#define PKX_JMP_EC_PTVALIDATE (0x001C + PKX_OFFSET) +#define PKX_JMP_F5200_SHA (0x001E + PKX_OFFSET) +#define PKX_JMP_F5200_AES (0x0020 + PKX_OFFSET) +#define PKX_JMP_F5200_AESK (0x0022 + PKX_OFFSET) +#define PKX_JMP_F5200_GCM (0x0024 + PKX_OFFSET) +#define PKX_JMP_F5200_GHA (0x0026 + PKX_OFFSET) +#define PKX_JMP_F5200_AESKW (0x0028 + PKX_OFFSET) +#define PKX_JMP_F5200_AESKWP (0x002A + PKX_OFFSET) +#define PKX_JMP_RNG_INSTANTIATE (0x002C + PKX_OFFSET) +#define PKX_JMP_RNG_RESEED (0x002E + PKX_OFFSET) +#define PKX_JMP_RNG_GENERATE (0x0030 + PKX_OFFSET) +#define PKX_JMP_RNG_UNINSTANTIATE (0x0032 + PKX_OFFSET) +#define PKX_JMP_RNG_GETENTROPY (0x0034 + PKX_OFFSET) +#define PKX_JMP_F5200_SHA_HMAC (0x0036 + PKX_OFFSET) +#define PKX_JMP_F5200_AES_DMA (0x0038 + PKX_OFFSET) +#define PKX_JMP_RNG_CTRLSTATUS (0x003A + PKX_OFFSET) +#define PKX_JMP_F5200_SHA_DMA (0x003C + PKX_OFFSET) +#define PKX_JMP_SHX_KEYTREE (0x003E + PKX_OFFSET) +#define PKX_JMP_PKX_DSA_DMA (0x0040 + PKX_OFFSET) +#define PKX_JMP_PKX_RSACRT_SIGN (0x0042 + PKX_OFFSET) +#define PKX_JMP_PKX_RSA_SIGN (0x0044 + PKX_OFFSET) +#define PKX_JMP_PKX_RSA_VERIFY (0x0046 + PKX_OFFSET) +#define PKX_JMP_PKX_EC_DSA_DMA (0x0048 + PKX_OFFSET) +#define PKX_JMP_F5200_AES_KEYROLL (0x004A + PKX_OFFSET) +#define PKX_JMP_EXPM (0x004C + PKX_OFFSET) +#define PKX_JMP_RSACRTM (0x004E + PKX_OFFSET) +#define PKX_JMP_EC_PTMULM (0x0050 + PKX_OFFSET) +#define PKX_JMP_DSA_SIGN_M (0x0052 + PKX_OFFSET) +#define PKX_JMP_EC_DSA_SIGN_M (0x0054 + PKX_OFFSET) +#define PKX_JMP_EC_KEYPAIRGEN (0x0056 + PKX_OFFSET) +#define PKX_JMP_RSACRTCM_SIGN (0x0058 + PKX_OFFSET) +#define PKX_JMP_F5200_GCM_NEW (0x005A + PKX_OFFSET) +/* PKX PKRev 2180 */ +/* PKX SHARev 2160 */ +/* PKX AESRev 2135 */ +/* Hex Checksum: 0xd0d79866 */ + +extern const SATUINT32_t uiPKX_Flags; +extern const SATUINT32_t uiPKX_BERWords; +extern const SATUINT32_t uiPKX_LIRWords; +extern const SATUINT32_t uiPKX_Rev; +extern const SATUINT32_t uiPKX_LibSize; +extern const SATUINT32_t uiPKX_LibChksum; +extern const SATUINT32_t uiPKX_Lib[]; +extern SATBOOL bMPF300TS_ES; + +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/shaf5200.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/shaf5200.h new file mode 100644 index 0000000..da598d1 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/shaf5200.h @@ -0,0 +1,101 @@ +/* ------------------------------------------------------------------- + $Rev: 1296 $ $Date: 2017-08-01 13:54:48 -0400 (Tue, 01 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for SHA function hardware implementation for CAL. + ------------------------------------------------------------------- */ + +#ifndef SHAF5200_H +#define SHAF5200_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef SHAF5200_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATR shapkxctx(SATRESCONTEXTPTR const pContext, const void *pBuffer, + SATUINT32_t uiBufLen,void *pHash, const SATBOOL bFinal); + +extern SATR shapkxhmacctx(SATRESCONTEXTPTR const pContext, const void *pBuffer, + SATUINT32_t uiBufLen, void *pHash, const SATUINT8_t uiFlag); + +extern SATR shapkxctxload(SATRESCONTEXTPTR const pContext); + +extern void shapkxctxunload(SATRESCONTEXTPTR const pContext); + +extern SATR shapkxini(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen); + +extern SATR shapkxhmacini(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, + const void *pKey, SATUINT32_t uiKeyLen); + +extern SATR shapkxwrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR shapkxhmacwrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR shapkxread(void *pHash, SATUINT32_t uiRevFlag); + +extern SATR shapkxkeytree(SATBOOL bPathSizeSel, const SATUINT32_t* puiKey, + SATUINT8_t uiOpType, const SATUINT32_t* puiPath, SATUINT32_t* puiKeyOut); + +extern SATR shapkxdma(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, + const void *pExtSrc, const void *pExtDest, SATUINT32_t uiDMAChConfig); + +extern SATR shapkxhmacdma(SATMACTYPE eMACType, const SATUINT32_t *pKey, + SATUINT32_t uiKeyLen, const void *pMsg, SATUINT32_t uiMsgLen, + const void *pMAC, SATUINT32_t uiDMAChConfig); + +extern SATR shapkxhashtypeini(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/sym.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/sym.h new file mode 100644 index 0000000..2e07faa --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/sym.h @@ -0,0 +1,129 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for Symmetric Key Cryptography in CAL. + ------------------------------------------------------------------- */ + +#ifndef SYM_H +#define SYM_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef SYM_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALSymTrfRes(SATBOOL bBlock); + +extern SATR CALSymEncrypt(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen); + +extern SATR CALSymDecrypt(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen); + +extern SATR CALSymEncryptDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymDecryptDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymEncryptKR(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF); + +extern SATR CALSymDecryptKR(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF); + +extern SATR CALSymEncryptKRDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymDecryptKRDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymEncAuth(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen); + +extern SATR CALSymDecVerify(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen); + +extern SATR CALSymKw(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR CALSymKwp(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR CALSymEncAuthDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymDecVerifyDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen, SATUINT32_t uiDMAChConfig); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/utils.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/utils.h new file mode 100644 index 0000000..91474f0 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/utils.h @@ -0,0 +1,93 @@ +/* ------------------------------------------------------------------- + $Rev: 1300 $ $Date: 2017-08-07 11:36:02 -0400 (Mon, 07 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL utility functions. + ------------------------------------------------------------------- */ + +#ifndef UTILS_H +#define UTILS_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef UTILS_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern void CALMemCopy(void *pDst, const void *pSrc, SATUINT32_t uiNum8); + +extern void CALMemClear( void * pLoc, SATUINT32_t uiNum ); + +extern void CALMemClear32( SATUINT32_t* puiLoc, SATUINT32_t uiLen32 ); + +extern SATBOOL CALMemCmp(const void *pA, const void *pB, SATUINT32_t uiNum); + +extern void CALVol32MemLoad(volatile SATUINT32_t * puiDst, const void * pSrc, + SATUINT32_t uiNum32); + +extern void CALVol32MemRead(void * pDst, volatile SATUINT32_t * puiSrc, + SATUINT32_t uiNum32); + +extern void CALByteReverse(SATUINT32_t* puiArray, SATINT32_t iNumberBytes); + +extern void CALByteReverseWord(SATUINT32_t* puiArray, SATINT32_t iNumberWords); + +extern void CALWordReverse(SATUINT32_t *puiArray, SATINT32_t iNumberWords); + +extern void vAppendNonzero(void *puiArray, SATUINT32_t uiLen, + SATUINT32_t uiBlockSize); + +extern void vAppendZero(void *puiArray, SATUINT32_t uiLen, + SATUINT32_t uiBlockSize); + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/x52cfg_user.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/x52cfg_user.h new file mode 100644 index 0000000..c8d8648 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/middleware/cal/x52cfg_user.h @@ -0,0 +1,72 @@ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ +/* X5200 configuration */ +/* $Date: 2015-07-23 14:30:19 -0400 (Thu, 23 Jul 2015) $ $Rev: 2093 $ */ +/* ------------------------------------------------------------------- + Options: + * LIR ROM size : 4096 + * LIR RAM size : 2048 + * BER size : 1024 + * MMR size : 1024 + * TSR size : 1024 + * FPR size : 1024 + * Single error correct, dual error detect (SECDED) memory parity + * DMA enabled + * FPGA multipliers disabled + * AES enabled + - Fast key schedule generation + - GCM/GHASH enabled + - AES countermeasures enabled + * RNG enabled + * External PRNG disabled + * SHA enabled + - Fast SHA enabled + - SHA-1 enabled + - SHA-224 enabled + - SHA-256 enabled + - SHA-384 enabled + - SHA-512 enabled + - SHA-512/224 enabled + - SHA-512/256 enabled + - SHA countermeasures enabled + * P-curves populated in FCR: + - P-192 populated + - P-224 populated + - P-256 populated + - P-384 populated + - P-521 populated + * Data memory scrambling enabled + + ------------------------------------------------------------------- */ + +#ifndef X52CFG_H +#define X52CFG_H + +#define X52_CFG_MODEL 0xf5200 +#define X52_CFG_DATE 0x15072720 +#define X52_CFG_REV 0x0000082e +#define X52_CFG_OPT 0x0fd87ff9 +#define X52_CFG_OPT2 0xc0000000 +#define X52_LIR_LEN 0x1800 +#define X52_LIR_ROM_LEN 0x1000 +#define X52_LIR_RAM_LEN 0x0800 +#define X52_BER_LEN 0x400 +#define X52_MMR_LEN 0x400 +#define X52_TSR_LEN 0x400 +#define X52_FPR_LEN 0x400 + +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/README.md b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/README.md new file mode 100644 index 0000000..f7f6030 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/README.md @@ -0,0 +1,27 @@ +# Mi-V soft processor platform source code + +## Repo organization + +``` + + | + |-- drivers + | |- fpga_ip + | | | CoreGPIO + | | | CoreSysServices_PF + | | | CoreUARTapb + | | + | |- off_chip + | | | . + | | | . + | | + |-- hal + | | + |-- miv_rv32_hal + + +``` + +The drivers published here are compatible with the improved SoftConsole project folder structure being used in the latest [example projects](https://github.com/Mi-V-Soft-RISC-V/miv-rv32-bare-metal-examples). +These drivers can also be used with the legacy folder structure (projects released via Firmware Catalog) by defining the **LEGACY_DIR_STRUCTURE** macro in the SoftConsole project settings. + diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c new file mode 100644 index 0000000..1a0073f --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c @@ -0,0 +1,533 @@ +/******************************************************************************* + * (c) Copyright 2008-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file core_gpio.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreGPIO bare metal driver implementation. + * + */ +#include "coregpio_regs.h" +#include "core_gpio.h" + +/*-------------------------------------------------------------------------*//** + * + */ +#define GPIO_INT_ENABLE_MASK (uint32_t)0x00000008UL +#define OUTPUT_BUFFER_ENABLE_MASK 0x00000004UL + + +#define NB_OF_GPIO 32 + +#define CLEAR_ALL_IRQ32 (uint32_t)0xFFFFFFFF +#define CLEAR_ALL_IRQ16 (uint16_t)0xFFFF +#define CLEAR_ALL_IRQ8 (uint8_t)0xFF + +/*-------------------------------------------------------------------------*//** + * GPIO_init() + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_init +( + gpio_instance_t * this_gpio, + addr_t base_addr, + gpio_apb_width_t bus_width +) +{ + uint8_t i = 0; + addr_t cfg_reg_addr = base_addr; + + this_gpio->base_addr = base_addr; + this_gpio->apb_bus_width = bus_width; + + /* Clear configuration. */ + for( i = 0, cfg_reg_addr = base_addr; i < NB_OF_GPIO; ++i ) + { + HW_set_8bit_reg( cfg_reg_addr, 0 ); + cfg_reg_addr += 4; + } + /* Clear any pending interrupts */ + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, CLEAR_ALL_IRQ32 ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, (uint16_t)CLEAR_ALL_IRQ16 ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, (uint16_t)CLEAR_ALL_IRQ16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, (uint8_t)CLEAR_ALL_IRQ8 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_config + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_config +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint32_t config +) +{ + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + uint32_t cfg_reg_addr = this_gpio->base_addr; + cfg_reg_addr += (port_id * 4); + HW_set_32bit_reg( cfg_reg_addr, config ); + + /* + * Verify that the configuration was correctly written. Failure to read + * back the expected value may indicate that the GPIO port was configured + * as part of the hardware flow and cannot be modified through software. + * It may also indicate that the base address passed as parameter to + * GPIO_init() was incorrect. + */ + HAL_ASSERT( HW_get_32bit_reg( cfg_reg_addr ) == config ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_set_outputs + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_set_outputs +( + gpio_instance_t * this_gpio, + uint32_t value +) +{ + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, GPIO_OUT, value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, GPIO_OUT0, (uint16_t)value ); + HAL_set_16bit_reg( this_gpio->base_addr, GPIO_OUT1, (uint16_t)(value >> 16) ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT0, (uint8_t)value ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT1, (uint8_t)(value >> 8) ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT2, (uint8_t)(value >> 16) ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT3, (uint8_t)(value >> 24) ); + break; + + default: + HAL_ASSERT(0); + break; + } + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( GPIO_get_outputs( this_gpio ) == value ); +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_inputs + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_inputs +( + gpio_instance_t * this_gpio +) +{ + uint32_t gpio_in = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + gpio_in = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_IN ); + break; + + case GPIO_APB_16_BITS_BUS: + gpio_in |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_IN0 ); + gpio_in |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_IN1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + gpio_in |= HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN0 ); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN1 ) << 8); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN2 ) << 16); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return gpio_in; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_outputs + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_outputs +( + gpio_instance_t * this_gpio +) +{ + uint32_t gpio_out = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + gpio_out = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ); + break; + + case GPIO_APB_16_BITS_BUS: + gpio_out |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT0 ); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + gpio_out |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT0 ); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT1 ) << 8); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT2 ) << 16); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return gpio_out; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_set_output + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_set_output +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint8_t value +) +{ + HAL_ASSERT( port_id < NB_OF_GPIO ); + + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + { + uint32_t outputs_state; + + outputs_state = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ); + if ( 0 == value ) + { + outputs_state &= ~(1 << port_id); + } + else + { + outputs_state |= 1 << port_id; + } + HAL_set_32bit_reg( this_gpio->base_addr, GPIO_OUT, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ) == outputs_state ); + } + break; + + case GPIO_APB_16_BITS_BUS: + { + uint16_t outputs_state; + uint32_t gpio_out_reg_addr = this_gpio->base_addr + GPIO_OUT_REG_OFFSET + ((port_id >> 4) * 4); + + outputs_state = HW_get_16bit_reg( gpio_out_reg_addr ); + if ( 0 == value ) + { + outputs_state &= ~(1 << (port_id & 0x0F)); + } + else + { + outputs_state |= 1 << (port_id & 0x0F); + } + HW_set_16bit_reg( gpio_out_reg_addr, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HW_get_16bit_reg( gpio_out_reg_addr ) == outputs_state ); + } + break; + + case GPIO_APB_8_BITS_BUS: + { + uint8_t outputs_state; + uint32_t gpio_out_reg_addr = this_gpio->base_addr + GPIO_OUT_REG_OFFSET + ((port_id >> 3) * 4); + + outputs_state = HW_get_8bit_reg( gpio_out_reg_addr ); + if ( 0 == value ) + { + outputs_state &= ~(1 << (port_id & 0x07)); + } + else + { + outputs_state |= 1 << (port_id & 0x07); + } + HW_set_8bit_reg( gpio_out_reg_addr, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HW_get_8bit_reg( gpio_out_reg_addr ) == outputs_state ); + } + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_drive_inout + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_drive_inout +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + gpio_inout_state_t inout_state +) +{ + uint32_t config; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + switch( inout_state ) + { + case GPIO_DRIVE_HIGH: + /* Set output high */ + GPIO_set_output( this_gpio, port_id, 1 ); + + /* Enable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config |= OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + case GPIO_DRIVE_LOW: + /* Set output low */ + GPIO_set_output( this_gpio, port_id, 0 ); + + /* Enable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config |= OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + case GPIO_HIGH_Z: + /* Disable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config &= ~OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_enable_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_enable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t cfg_value; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + cfg_reg_addr += (port_id * 4); + cfg_value = HW_get_8bit_reg( cfg_reg_addr ); + cfg_value |= GPIO_INT_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, cfg_value ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_disable_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_disable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t cfg_value; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + cfg_reg_addr += (port_id * 4); + cfg_value = HW_get_8bit_reg( cfg_reg_addr ); + cfg_value &= ~GPIO_INT_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, cfg_value ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_clear_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_clear_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t irq_clr_value = ((uint32_t)1) << ((uint32_t)port_id); + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, irq_clr_value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, irq_clr_value >> 16 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, irq_clr_value >> 24 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_irq_sources + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_irq_sources +( + gpio_instance_t * this_gpio +) +{ + uint32_t intr_src = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + intr_src = HAL_get_32bit_reg( this_gpio->base_addr, IRQ ); + break; + + case GPIO_APB_16_BITS_BUS: + intr_src |= HAL_get_16bit_reg( this_gpio->base_addr, IRQ0 ); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + intr_src |= HAL_get_16bit_reg( this_gpio->base_addr, IRQ0 ); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ1 ) << 8); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ2 ) << 16); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return intr_src; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_clear_all_irq_sources + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_clear_all_irq_sources +( + gpio_instance_t * this_gpio, + uint32_t bitmask +) +{ + uint32_t irq_clr_value = bitmask; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, irq_clr_value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, irq_clr_value >> 16 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, irq_clr_value >> 24 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h new file mode 100644 index 0000000..88ba178 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h @@ -0,0 +1,722 @@ +/******************************************************************************* + * (c) Copyright 2008-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file core_gpio.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreGPIO bare metal driver public API. + * + */ + +/*=========================================================================*//** + @mainpage CoreGPIO Bare Metal Driver. + + @section intro_sec Introduction + The CoreGPIO hardware IP includes up to 32 general-purpose input/output GPIOs. + This driver provides a set of functions for controlling the GPIOs as part of a + bare-metal system where no operating system is available. These drivers + can be adapted for use as part of an operating system, but the implementation + of the adaptation layer between this driver and the operating system's driver + model is outside the scope of this driver. + + @section driver_configuration Driver Configuration + The individual IOs of CoreGPIO can be configured either in the hardware flow + or as part of the software application through calls to the GPIO_config() + function. GPIOs configured as part of the hardware are fixed and cannot be + modified using a call to the GPI_config() function. + + @section theory_op Theory of Operation + The CoreGPIO driver uses the Actel Hardware Abstraction Layer (HAL) to access + hardware registers. You must ensure that the Actel HAL is included as part of + your software project. The Actel HAL is available through the Actel Firmware + Catalog. + + The CoreGPIO driver functions are logically grouped into the following groups: + - Initialization + - Configuration + - Reading and writing GPIO state + - Interrupt control + + The CoreGPIO driver is initialized through a call to the GPIO_init() function. + The GPIO_init() function must be called before any other GPIO driver functions + can be called. + + Each GPIO port is individually configured through a call to the + GPIO_config() function. Configuration includes deciding if a GPIO port is + going to be used as input, output, or both. GPIO ports configured as inputs + are further configured to generate interrupts based on the state of input. + Interrupts is either level- or edge-sensitive. + Note that a CoreGPIO hardware instance is generated as part of the hardware + flow with a fixed configuration for some or all of its IOs. + Attempting to modify the configuration of such a hardware-configured IO using + the GPIO_config() function has no effect. + + The state of the GPIO ports can be read and written using the following + functions: + - GPIO_get_inputs() + - GPIO_get_outputs() + - GPIO_set_outputs() + - GPIO_drive_inout() + + Interrupts generated by GPIO ports configured as inputs are controlled using + the following functions: + - GPIO_enable_irq() + - GPIO_disable_irq() + - GPIO_clear_irq() + - GPIO_get_irq_sources() + - GPIO_clear_all_irq_sources() + + *//*=========================================================================*/ +#ifndef CORE_GPIO_H_ +#define CORE_GPIO_H_ + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + The gpio_id_t enumeration is used to identify GPIOs as part of the + parameter to functions: + - GPIO_config(), + - GPIO_drive_inout(), + - GPIO_enable_int(), + - GPIO_disable_int(), + - GPIO_clear_int() + */ +typedef enum __gpio_id_t +{ + GPIO_0 = 0, + GPIO_1 = 1, + GPIO_2 = 2, + GPIO_3 = 3, + GPIO_4 = 4, + GPIO_5 = 5, + GPIO_6 = 6, + GPIO_7 = 7, + GPIO_8 = 8, + GPIO_9 = 9, + GPIO_10 = 10, + GPIO_11 = 11, + GPIO_12 = 12, + GPIO_13 = 13, + GPIO_14 = 14, + GPIO_15 = 15, + GPIO_16 = 16, + GPIO_17 = 17, + GPIO_18 = 18, + GPIO_19 = 19, + GPIO_20 = 20, + GPIO_21 = 21, + GPIO_22 = 22, + GPIO_23 = 23, + GPIO_24 = 24, + GPIO_25 = 25, + GPIO_26 = 26, + GPIO_27 = 27, + GPIO_28 = 28, + GPIO_29 = 29, + GPIO_30 = 30, + GPIO_31 = 31 +} gpio_id_t; + +/*-------------------------------------------------------------------------*//** + Possible width of the APB bus + */ +typedef enum __gpio_apb_width_t +{ + GPIO_APB_8_BITS_BUS = 0, + GPIO_APB_16_BITS_BUS = 1, + GPIO_APB_32_BITS_BUS = 2, + GPIO_APB_UNKNOWN_BUS_WIDTH = 3 +} gpio_apb_width_t; + +/*-------------------------------------------------------------------------*//** + Structure instance holding all data regarding the CoreGPIO + */ +typedef struct __gpio_instance_t +{ + addr_t base_addr; + gpio_apb_width_t apb_bus_width; +} gpio_instance_t; + +/*-------------------------------------------------------------------------*//** + GPIO ports definitions used to identify GPIOs as part of the parameter to + function GPIO_set_outputs(). + These definitions are also be used to identity GPIO through logical operations + on the return value of function GPIO_get_inputs(). + # GPIO_0_MASK + # GPIO_1_MASK + # GPIO_2_MASK + # GPIO_3_MASK + # GPIO_4_MASK + # GPIO_5_MASK + # GPIO_6_MASK + # GPIO_7_MASK + # GPIO_8_MASK + # GPIO_9_MASK + # GPIO_10_MASK + # GPIO_11_MASK + # GPIO_12_MASK + # GPIO_13_MASK + # GPIO_14_MASK + # GPIO_15_MASK + # GPIO_16_MASK + # GPIO_17_MASK + # GPIO_18_MASK + # GPIO_19_MASK + # GPIO_20_MASK + # GPIO_21_MASK + # GPIO_22_MASK + # GPIO_23_MASK + # GPIO_24_MASK + # GPIO_25_MASK + # GPIO_26_MASK + # GPIO_27_MASK + # GPIO_28_MASK + # GPIO_29_MASK + # GPIO_30_MASK + # GPIO_31_MASK + */ +#define GPIO_0_MASK 0x00000001UL +#define GPIO_1_MASK 0x00000002UL +#define GPIO_2_MASK 0x00000004UL +#define GPIO_3_MASK 0x00000008UL +#define GPIO_4_MASK 0x00000010UL +#define GPIO_5_MASK 0x00000020UL +#define GPIO_6_MASK 0x00000040UL +#define GPIO_7_MASK 0x00000080UL +#define GPIO_8_MASK 0x00000100UL +#define GPIO_9_MASK 0x00000200UL +#define GPIO_10_MASK 0x00000400UL +#define GPIO_11_MASK 0x00000800UL +#define GPIO_12_MASK 0x00001000UL +#define GPIO_13_MASK 0x00002000UL +#define GPIO_14_MASK 0x00004000UL +#define GPIO_15_MASK 0x00008000UL +#define GPIO_16_MASK 0x00010000UL +#define GPIO_17_MASK 0x00020000UL +#define GPIO_18_MASK 0x00040000UL +#define GPIO_19_MASK 0x00080000UL +#define GPIO_20_MASK 0x00100000UL +#define GPIO_21_MASK 0x00200000UL +#define GPIO_22_MASK 0x00400000UL +#define GPIO_23_MASK 0x00800000UL +#define GPIO_24_MASK 0x01000000UL +#define GPIO_25_MASK 0x02000000UL +#define GPIO_26_MASK 0x04000000UL +#define GPIO_27_MASK 0x08000000UL +#define GPIO_28_MASK 0x10000000UL +#define GPIO_29_MASK 0x20000000UL +#define GPIO_30_MASK 0x40000000UL +#define GPIO_31_MASK 0x80000000UL + +/*-------------------------------------------------------------------------*//** + * GPIO modes + * # GPIO_INPUT_MODE + * # GPIO_OUTPUT_MODE + * # GPIO_INOUT_MODE + */ +#define GPIO_INPUT_MODE 0x0000000002UL +#define GPIO_OUTPUT_MODE 0x0000000005UL +#define GPIO_INOUT_MODE 0x0000000003UL + +/*-------------------------------------------------------------------------*//** + * Possible GPIO inputs interrupt configurations. + * # GPIO_IRQ_LEVEL_HIGH + * # GPIO_IRQ_LEVEL_LOW + * # GPIO_IRQ_EDGE_POSITIVE + * # GPIO_IRQ_EDGE_NEGATIVE + * # GPIO_IRQ_EDGE_BOTH + */ +#define GPIO_IRQ_LEVEL_HIGH 0x0000000000UL +#define GPIO_IRQ_LEVEL_LOW 0x0000000020UL +#define GPIO_IRQ_EDGE_POSITIVE 0x0000000040UL +#define GPIO_IRQ_EDGE_NEGATIVE 0x0000000060UL +#define GPIO_IRQ_EDGE_BOTH 0x0000000080UL + +/*-------------------------------------------------------------------------*//** + * Possible states for GPIO configured as INOUT + */ +typedef enum gpio_inout_state +{ + GPIO_DRIVE_LOW = 0, + GPIO_DRIVE_HIGH, + GPIO_HIGH_Z +} gpio_inout_state_t; + +/*-------------------------------------------------------------------------*//** + The GPIO_init() function initializes a CoreGPIO hardware instance and the data + structure associated with the CoreGPIO hardware instance. + Note that a CoreGPIO hardware instance is generated with a fixed configuration + for some or all of its IOs as part of the hardware flow. + Attempting to modify the configuration of such a hardware-configured IO using + the GPIO_config() function has no effect. + + @param this_gpio + Pointer to the gpio_instance_t data structure instance holding all data + regarding the CoreGPIO hardware instance being initialized. A pointer to the + same data structure is used in subsequent calls to the CoreGPIO driver + functions in order to identify the CoreGPIO instance that must perform the + operation implemented by the called driver function. + + @param base_addr + The base_addr parameter is the base address in the memory map of the + processor for the registers of the GPIO instance being initialized. + + @param bus_width + The bus_width parameter informs the driver of the APB bus width selected + during the hardware flow configuration of the CoreGPIO hardware instance. It + indicates to the driver whether the CoreGPIO hardware registers are visible + as 8, 16, or 32-bits registers. Allowed values are: + - GPIO_APB_8_BITS_BUS + - GPIO_APB_16_BITS_BUS + - GPIO_APB_32_BITS_BUS + + @return + none. + + @example + @code + #define COREGPIO_BASE_ADDR 0xC2000000 + + gpio_instance_t g_gpio; + + void system_init( void ) + { + GPIO_init( &g_gpio, COREGPIO_BASE_ADDR, GPIO_APB_32_BITS_BUS ); + } + @endcode + */ +void GPIO_init +( + gpio_instance_t * this_gpio, + addr_t base_addr, + gpio_apb_width_t bus_width +); + +/*-------------------------------------------------------------------------*//** + The GPIO_config() function is used to configure an individual GPIO port. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO port to be configured. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @param config + The config parameter specifies the configuration to be applied to the GPIO + port identified by the first parameter. It is a logical OR of GPIO mode and + interrupt mode. The interrupt mode is only relevant if the GPIO is + configured as an input. + - Possible modes are: + - GPIO_INPUT_MODE, + - GPIO_OUTPUT_MODE, + - GPIO_INOUT_MODE. + - Possible interrupt modes are: + - GPIO_IRQ_LEVEL_HIGH, + - GPIO_IRQ_LEVEL_LOW, + - GPIO_IRQ_EDGE_POSITIVE, + - GPIO_IRQ_EDGE_NEGATIVE, + - GPIO_IRQ_EDGE_BOTH + + @return + none. + + @example + For example, the following call configures GPIO 4 as an input that generates + interrupts on a low-to-high transition of the input: + @code + GPIO_config( &g_gpio, GPIO_4, GPIO_INPUT_MODE | GPIO_IRQ_EDGE_POSITIVE ); + @endcode + */ +void GPIO_config +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint32_t config +); + +/*-------------------------------------------------------------------------*//** + The GPIO_set_outputs() function is used to set the state of the GPIO ports + configured as outputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param value + The value parameter specifies the state of the GPIO ports configured as + outputs. It is a bit mask of the form (GPIO_n_MASK | GPIO_m_MASK), where n + and m are numbers identifying GPIOs. + For example, (GPIO_0_MASK | GPIO_1_MASK | GPIO_2_MASK ) specifies that the + first, second, and third GPIO must be set high and all other outputs set + low. + + @return + none. + + @example + Set GPIO 0 and 8 outputs high and all other GPIO outputs low. + @code + GPIO_set_outputs( &g_gpio, GPIO_0_MASK | GPIO_8_MASK ); + @endcode + + @example + Set GPIO 2 and 4 outputs low without affecting the other GPIO outputs. + @code + uint32_t gpio_outputs; + gpio_outputs = GPIO_get_outputs( &g_gpio ); + gpio_outputs &= ~( GPIO_2_MASK | GPIO_4_MASK ); + GPIO_set_outputs( &g_gpio, gpio_outputs ); + @endcode + + @see GPIO_get_outputs() + */ +void GPIO_set_outputs +( + gpio_instance_t * this_gpio, + uint32_t value +); + +/*-------------------------------------------------------------------------*//** + The GPIO_set_output() function is used to set the state of a single GPIO port + configured as an output. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter specifies the GPIO port that has its output set by a + call to this function. + + @param value + The value parameter specifies the desired state for the GPIO output. A value + of 0 sets the output low, and a value of 1 sets the port high. + + @return + none. + */ +void GPIO_set_output +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint8_t value +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_inputs() function is used to read the state of all GPIOs + configured as inputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @return + This function returns a 32-bit unsigned integer, where each bit represents + the state of an input. The least significant bit represents the state of + GPIO 0, and the most significant bit represents the state of GPIO 31. + */ +uint32_t GPIO_get_inputs +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_outputs() function is used to read the current state of all + GPIO outputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @return + This function returns a 32-bit unsigned integer where each bit represents + the state of an output. The least significant bit represents the state + of GPIO 0, and the most significant bit represents the state of GPIO 31. + */ +uint32_t GPIO_get_outputs +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_drive_inout() function is used to set the output state of a + GPIO configured as INOUT. An INOUT GPIO is in one of three states: + - high + - low + - high impedance + + An INOUT output is typically be used where several devices drive the state of + a signal. The high and low states are equivalent to the high and low states of + a GPIO configured as an output. The high impedance state is used to prevent + the GPIO from driving the state of the output and therefore allow reading the + state of the GPIO as an input. + Note that the GPIO port you wish to use as INOUT through this function + must be configurable through software. Therefore, the GPIO ports used as INOUT + must not have a fixed configuration selected as part of the hardware flow. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO for which this function will + change the output state. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @param inout_state + The inout_state parameter specifies the state of the I/O identified by the + first parameter. Possible states are: + - GPIO_DRIVE_HIGH, + - GPIO_DRIVE_LOW, + - GPIO_HIGH_Z (high impedance) + + @return + none. + + @example + The call to GPIO_drive_inout() below will set the GPIO 7 output to + high impedance state. + @code + GPIO_drive_inout( &g_gpio, GPIO_7, GPIO_HIGH_Z ); + @endcode + */ +void GPIO_drive_inout +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + gpio_inout_state_t inout_state +); + +/*-------------------------------------------------------------------------*//** + The GPIO_enable_irq() function is used to enable an interrupt to be + generated based on the state of the input identified as a parameter. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO input that the call to + GPIO_enable_irq() enables to generate interrupts. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + @example + The call to GPIO_enable_irq() below allows GPIO 8 to generate interrupts. + + @code + GPIO_enable_irq( &g_gpio, GPIO_8 ); + @endcode + */ +void GPIO_enable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_disable_irq() function is used to disable interrupts from being + generated based on the state of the input specified as a parameter. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO input that the call to + GPIO_disable_irq() disables from generating interrupts. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + @example + The call to GPIO_disable_irq() below prevents GPIO 8 from generating + interrupts. + @code + GPIO_disable_irq( &g_gpio, GPIO_8 ); + @endcode + */ +void GPIO_disable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_clear_irq() function is used to clear the interrupt generated by + the GPIO specified as a parameter. The GPIO_clear_irq() function must be + called as part of a GPIO interrupt service routine (ISR) in order to prevent + the same interrupt event from re-triggering a call to the GPIO ISR. + Note that interrupts may also need to be cleared in the processor's + interrupt controller. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO input for which to clear the + interrupt. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + @example + The example below demonstrates the use of the GPIO_clear_irq() function as + part of the GPIO-9 interrupt service routine. + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + GPIO_clear_irq( &g_gpio, GPIO_9 ); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +void GPIO_clear_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_irq_sources() function is used to identify the source of the + interrupt. i.e. to That is the GPIO input line, whose state change triggered + the interrupt. The GPIO_get_irq_sources() function must be called as part of + a GPIO interrupt service routine (ISR) in order to determine the interrupt + source. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @return + This function returns a 32-bit unsigned integer, where each bit represents + the pin number of a GPIO. + + @example + The example below demonstrates the use of the GPIO_get_irq_sources() + function as part of the GPIO-9 interrupt service routine. + + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + GPIO_clear_all_irq_sources(g_p_mygpio, GPIO_get_irq_sources(g_p_mygpio)); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +uint32_t GPIO_get_irq_sources +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_clear_all_irq_sources() function is used to clear all the active + interrupts generated by the GPIO specified as a parameter. The + GPIO_clear_all_irq_sources() function must be called as part of a GPIO + interrupt service routine (ISR) in order to prevent the same interrupt event + from re-triggering a call to the GPIO ISR. + Note that interrupts may also need to be cleared in the processor's + interrupt controller. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param bitmask + This bitmask parameter is a 32-bit unsigned integer where each bit + represents the GPIO pin used to clear the interrupt bit register of the + corresponding GPIO bit. The least significant bit represents the status of + GPIO 0, and the most significant bit represents the status of GPIO 31. + + @return + none. + + @example + The example below demonstrates the use of the GPIO_clear_all_irq_sources() + function as part of the GPIO-9 interrupt service routine. + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + do_interrupt_processing(); + + GPIO_clear_all_irq_sources(g_p_mygpio, GPIO_get_irq_sources(g_p_mygpio)); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +void GPIO_clear_all_irq_sources +( + gpio_instance_t * this_gpio, + uint32_t bitmask +); + +#ifdef __cplusplus +} +#endif + +#endif /* CORE_GPIO_H_ */ diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h new file mode 100644 index 0000000..41f5b7c --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h @@ -0,0 +1,45 @@ +/******************************************************************************* + * (c) Copyright 2008-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file coregpio_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreGPIO register definitions + * + */ + +#ifndef __CORE_GPIO_REGISTERS_H +#define __CORE_GPIO_REGISTERS_H 1 + +/*------------------------------------------------------------------------------ + * + */ +#define IRQ_REG_OFFSET 0x80 + +#define IRQ0_REG_OFFSET 0x80 +#define IRQ1_REG_OFFSET 0x84 +#define IRQ2_REG_OFFSET 0x88 +#define IRQ3_REG_OFFSET 0x8C + +/*------------------------------------------------------------------------------ + * + */ +#define GPIO_IN_REG_OFFSET 0x90 + +#define GPIO_IN0_REG_OFFSET 0x90 +#define GPIO_IN1_REG_OFFSET 0x94 +#define GPIO_IN2_REG_OFFSET 0x98 +#define GPIO_IN3_REG_OFFSET 0x9C + +/*------------------------------------------------------------------------------ + * + */ +#define GPIO_OUT_REG_OFFSET 0xA0 + +#define GPIO_OUT0_REG_OFFSET 0xA0 +#define GPIO_OUT1_REG_OFFSET 0xA4 +#define GPIO_OUT2_REG_OFFSET 0xA8 +#define GPIO_OUT3_REG_OFFSET 0xAC + +#endif /* __CORE_GPIO_REGISTERS_H */ diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c new file mode 100644 index 0000000..1fd3dd6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c @@ -0,0 +1,1495 @@ +/******************************************************************************* + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * CoreI2C software driver implementation. + * + */ + +#include "core_smbus_regs.h" +#include "core_i2c.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * I2C transaction direction. + */ +#define WRITE_DIR 0u +#define READ_DIR 1u + +/* -- TRANSACTIONS TYPES -- */ +#define NO_TRANSACTION 0u +#define MASTER_WRITE_TRANSACTION 1u +#define MASTER_READ_TRANSACTION 2u +#define MASTER_RANDOM_READ_TRANSACTION 3u +#define WRITE_SLAVE_TRANSACTION 4u +#define READ_SLAVE_TRANSACTION 5u + +/* -- SMBUS H/W STATES -- */ +/* -- MASTER STATES -- */ +#define ST_BUS_ERROR 0x00u /* Bus error during MST or selected slave modes */ +#define ST_I2C_IDLE 0xF8u /* No activity and no interrupt either... */ +#define ST_START 0x08u /* start condition sent */ +#define ST_RESTART 0x10u /* repeated start */ +#define ST_SLAW_ACK 0x18u /* SLA+W sent, ack received */ +#define ST_SLAW_NACK 0x20u /* SLA+W sent, nack received */ +#define ST_TX_DATA_ACK 0x28u /* Data sent, ACK'ed */ +#define ST_TX_DATA_NACK 0x30u /* Data sent, NACK'ed */ +#define ST_LOST_ARB 0x38u /* Master lost arbitration */ +#define ST_SLAR_ACK 0x40u /* SLA+R sent, ACK'ed */ +#define ST_SLAR_NACK 0x48u /* SLA+R sent, NACK'ed */ +#define ST_RX_DATA_ACK 0x50u /* Data received, ACK sent */ +#define ST_RX_DATA_NACK 0x58u /* Data received, NACK sent */ +#define ST_RESET_ACTIVATED 0xD0u /* Master reset is activated */ +#define ST_STOP_TRANSMIT 0xE0u /* Stop has been transmitted */ + +/* -- SLAVE STATES -- */ +#define ST_SLAVE_SLAW 0x60u /* SLA+W received */ +#define ST_SLAVE_SLAR_ACK 0xA8u /* SLA+R received, ACK returned */ +#define ST_SLV_LA 0x68u /* Slave lost arbitration */ +#define ST_GCA 0x70u /* GCA received */ +#define ST_GCA_LA 0x78u /* GCA lost arbitration */ +#define ST_RDATA 0x80u /* Data received */ +#define ST_SLA_NACK 0x88u /* Slave addressed, NACK returned */ +#define ST_GCA_ACK 0x90u /* Previously addresses with GCA, data ACKed */ +#define ST_GCA_NACK 0x98u /* GCA addressed, NACK returned */ +#define ST_RSTOP 0xA0u /* Stop received */ +#define ST_SLARW_LA 0xB0u /* Arbitration lost */ +#define ST_RACK 0xB8u /* Byte sent, ACK received */ +#define ST_SLAVE_RNACK 0xC0u /* Byte sent, NACK received */ +#define ST_FINAL 0xC8u /* Final byte sent, ACK received */ +#define ST_SLV_RST 0xD8u /* Slave reset state */ + + +/* I2C Channel base offset */ +#define CHANNEL_BASE_SHIFT 5u +#define CHANNEL_MASK 0x1E0u + +/* + * Maximum address offset length in slave write-read transactions. + * A maximum of two bytes will be interpreted as address offset within the slave + * tx buffer. + */ +#define MAX_OFFSET_LENGTH 2u + +/*------------------------------------------------------------------------------ + * I2C interrupts control functions implemented "i2c_interrupt.c". + * the implementation of these functions depend on the underlying hardware + * design and how the CoreI2C interrupt line is connected to the system's + * interrupt controller. + */ +void I2C_enable_irq( i2c_instance_t * this_i2c ); +void I2C_disable_irq( i2c_instance_t * this_i2c ); +static void enable_slave_if_required(i2c_instance_t * this_i2c); + +/*------------------------------------------------------------------------------ + * I2C_init() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_init +( + i2c_instance_t * this_i2c, + addr_t base_address, + uint8_t ser_address, + i2c_clock_divider_t ser_clock_speed +) +{ + psr_t saved_psr; + uint_fast16_t clock_speed = (uint_fast16_t)ser_clock_speed; + + /* + * We need to disable ints while doing this as there is no guarantee we + * have not been called already and the ISR is active. + */ + saved_psr = HAL_disable_interrupts(); + + /* + * Initialize all items of the this_i2c data structure to zero. This + * initializes all state variables to their init value. It relies on + * the fact that NO_TRANSACTION, I2C_SUCCESS and I2C_RELEASE_BUS all + * have an actual value of zero. + */ + memset(this_i2c, 0, sizeof(i2c_instance_t)); + + /* + * Set base address of I2C hardware used by this instance. + */ + this_i2c->base_address = base_address; + + /* + * Update Serial address of the device + */ + this_i2c->ser_address = ((uint_fast8_t)ser_address << 1u); + + /* + * Configure hardware. + */ + HAL_set_8bit_reg_field(this_i2c->base_address, ENS1, 0x00); /* Reset I2C hardware. */ + HAL_set_8bit_reg_field(this_i2c->base_address, ENS1, 0x01); /* set enable bit */ + HAL_set_8bit_reg_field(this_i2c->base_address, CR2, ( (clock_speed >> 2) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c->base_address, CR1, ( (clock_speed >> 1) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c->base_address, CR0, ( clock_speed & 0x01) ); + + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS, this_i2c->ser_address); + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, this_i2c->ser_address); + + /* + * Finally safe to enable interrupts. + */ + HAL_restore_interrupts( saved_psr ); +} +/*------------------------------------------------------------------------------ + * I2C_channel_init() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_channel_init +( + i2c_instance_t * this_i2c_channel, + i2c_instance_t * this_i2c, + i2c_channel_number_t channel_number, + i2c_clock_divider_t ser_clock_speed +) +{ + psr_t saved_psr; + uint_fast16_t clock_speed = (uint_fast16_t)ser_clock_speed; + + HAL_ASSERT(channel_number < I2C_MAX_CHANNELS); + HAL_ASSERT(I2C_CHANNEL_0 != channel_number); + + /* + * Cannot allow channel 0 in this function as we will trash the hardware + * base address and slave address. + */ + if ((channel_number < I2C_MAX_CHANNELS) && + (I2C_CHANNEL_0 != channel_number)) + { + /* + * We need to disable ints while doing this as the hardware should already + * be active at this stage. + */ + saved_psr = HAL_disable_interrupts(); + + /* + * Initialize channel data. + */ + memset(this_i2c_channel, 0, sizeof(i2c_instance_t)); + + this_i2c_channel->base_address = + ((this_i2c->base_address) & ~((addr_t)CHANNEL_MASK)) + | (((addr_t)channel_number) << CHANNEL_BASE_SHIFT); + + this_i2c_channel->ser_address = this_i2c->ser_address; + + HAL_set_8bit_reg_field(this_i2c_channel->base_address, ENS1, 0x00); /* Reset I2C channel hardware. */ + HAL_set_8bit_reg_field(this_i2c_channel->base_address, ENS1, 0x01); /* set enable bit */ + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR2, ( (clock_speed >> 2) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR1, ( (clock_speed >> 1) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR0, ( clock_speed & 0x01) ); + /* + * Finally safe to enable interrupts. + */ + HAL_restore_interrupts( saved_psr ); + } +} + +/*------------------------------------------------------------------------------ + * I2C_write() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_write +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * write_buffer, + uint16_t write_size, + uint8_t options +) +{ + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + saved_psr = HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_WRITE_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_WRITE_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + this_i2c->dir = WRITE_DIR; + this_i2c->master_tx_buffer = write_buffer; + this_i2c->master_tx_size = write_size; + this_i2c->master_tx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_read() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +) +{ + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + saved_psr = HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_READ_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_READ_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + + this_i2c->dir = READ_DIR; + + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_write_read() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_write_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * addr_offset, + uint16_t offset_size, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +) +{ + HAL_ASSERT(offset_size > 0u); + HAL_ASSERT(addr_offset != (uint8_t *)0); + HAL_ASSERT(read_size > 0u); + HAL_ASSERT(read_buffer != (uint8_t *)0); + + this_i2c->master_status = I2C_FAILED; + + if((read_size > 0u) && (offset_size > 0u)) + { + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + saved_psr = HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_RANDOM_READ_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_RANDOM_READ_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + + this_i2c->dir = WRITE_DIR; + + this_i2c->master_tx_buffer = addr_offset; + this_i2c->master_tx_size = offset_size; + this_i2c->master_tx_idx = 0u; + + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + + HAL_restore_interrupts( saved_psr ); + } +} + +/*------------------------------------------------------------------------------ + * I2C_get_status() + * See "core_i2c.h" for details of how to use this function. + */ +i2c_status_t I2C_get_status +( + i2c_instance_t * this_i2c +) +{ + i2c_status_t i2c_status ; + + i2c_status = this_i2c->master_status ; + + return i2c_status; +} + +/*------------------------------------------------------------------------------ + * I2C_wait_complete() + * See "core_i2c.h" for details of how to use this function. + */ +i2c_status_t I2C_wait_complete +( + i2c_instance_t * this_i2c, + uint32_t timeout_ms +) +{ + i2c_status_t i2c_status; + psr_t saved_psr; + /* + * Because we have no idea of what CPU we are supposed to be running on + * we need to guard this write to the timeout value to avoid ISR/user code + * interaction issues. Checking the status below should be fine as only a + * single byte should change in that. + */ + saved_psr = HAL_disable_interrupts(); + this_i2c->master_timeout_ms = timeout_ms; + HAL_restore_interrupts( saved_psr ); + + /* Run the loop until state returns I2C_FAILED or I2C_SUCESS*/ + do { + i2c_status = this_i2c->master_status; + } while(I2C_IN_PROGRESS == i2c_status); + return i2c_status; +} + +/*------------------------------------------------------------------------------ + * I2C_system_tick() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_system_tick +( + i2c_instance_t * this_i2c, + uint32_t ms_since_last_tick +) +{ + if(this_i2c->master_timeout_ms != I2C_NO_TIMEOUT) + { + if(this_i2c->master_timeout_ms > ms_since_last_tick) + { + this_i2c->master_timeout_ms -= ms_since_last_tick; + } + else + { + psr_t saved_psr; + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + /* + * Mark current transaction as having timed out. + */ + this_i2c->master_status = I2C_TIMED_OUT; + this_i2c->transaction = NO_TRANSACTION; + this_i2c->is_transaction_pending = 0; + + HAL_restore_interrupts( saved_psr ); + + /* + * Make sure we do not incorrectly signal a timeout for subsequent + * transactions. + */ + this_i2c->master_timeout_ms = I2C_NO_TIMEOUT; + } + } +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_tx_buffer() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_tx_buffer +( + i2c_instance_t * this_i2c, + const uint8_t * tx_buffer, + uint16_t tx_size +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + this_i2c->slave_tx_buffer = tx_buffer; + this_i2c->slave_tx_size = tx_size; + this_i2c->slave_tx_idx = 0u; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_rx_buffer() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_rx_buffer +( + i2c_instance_t * this_i2c, + uint8_t * rx_buffer, + uint16_t rx_size +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + this_i2c->slave_rx_buffer = rx_buffer; + this_i2c->slave_rx_size = rx_size; + this_i2c->slave_rx_idx = 0u; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_mem_offset_length() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_mem_offset_length +( + i2c_instance_t * this_i2c, + uint8_t offset_length +) +{ + HAL_ASSERT(offset_length <= MAX_OFFSET_LENGTH); + + /* + * Single byte update, should be interrupt safe + */ + if(offset_length > MAX_OFFSET_LENGTH) + { + this_i2c->slave_mem_offset_length = MAX_OFFSET_LENGTH; + } + else + { + this_i2c->slave_mem_offset_length = offset_length; + } +} + +/*------------------------------------------------------------------------------ + * I2C_register_write_handler() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_register_write_handler +( + i2c_instance_t * this_i2c, + i2c_slave_wr_handler_t handler +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + this_i2c->slave_write_handler = handler; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_enable_slave() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_enable_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register and slave mode flag without the I2C ISR interrupting + * us. + */ + saved_psr = HAL_disable_interrupts(); + + /* Set the Assert Acknowledge bit. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + /* Enable slave mode */ + this_i2c->is_slave_enabled = 1u; + + HAL_restore_interrupts( saved_psr ); + + /* Enable I2C IRQ*/ + I2C_enable_irq( this_i2c ); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_slave() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_disable_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + /* Reset the assert acknowledge bit. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + + /* Disable slave mode with IRQ blocked to make whole change atomic */ + this_i2c->is_slave_enabled = 0u; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * + */ +static void enable_slave_if_required +( + i2c_instance_t * this_i2c +) +{ + /* + * This function is only called from within the ISR and so does not need + * guarding on the register access. + */ + if( 0 != this_i2c->is_slave_enabled ) + { + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x01u ); + } +} +/*------------------------------------------------------------------------------ + * I2C_set_slave_second_addr() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_slave_second_addr +( + i2c_instance_t * this_i2c, + uint8_t second_slave_addr +) +{ + uint8_t second_slave_address; + + /* + This function does not support CoreI2C hardware configured with a fixed + second slave address. The current implementation of the ADDR1[0] register + bit makes it difficult for the driver to support both programmable and + fixed second slave address, so we choose to support programmable only. + With the programmable configuration, ADDR1[0] and ADDR0[0] both control + enable/disable of GCA recognition, as an effective OR of the 2 bit fields. + Therefore we set ADDR1[0] to 0 here, so that only ADDR0[0] controls GCA. + */ + second_slave_address = (uint8_t)((second_slave_addr << 1u) & (~SLAVE1_EN_MASK)); + + /* + * Single byte register write, should be interrupt safe + */ + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, second_slave_address); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_slave_second_addr() + * See "i2c.h" for details of how to use this function. + */ +void I2C_disable_slave_second_addr +( + i2c_instance_t * this_i2c +) +{ + /* + We are disabling the second slave address by setting the value of the 2nd + slave address to the primary slave address. The reason for using this method + of disabling 2nd slave address is that ADDRESS1[0] has different meaning + depending on hardware configuration. Its use would likely interfere with + the intended GCA setting. + */ + /* + * Single byte register write, should be interrupt safe + */ + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, this_i2c->ser_address); +} + +/*------------------------------------------------------------------------------ + * i2C_set_gca() + * See "i2c.h" for details of how to use this function. + */ + +void I2C_set_gca +( + i2c_instance_t * this_i2c +) +{ + /* + * This read modify write access should be interrupt safe as the address + * register is not written to in the ISR. + */ + /* accept GC addressing. */ + HAL_set_8bit_reg_field(this_i2c->base_address, GC, 0x01u); +} + +/*------------------------------------------------------------------------------ + * I2C_clear_gca() + * See "i2c.h" for details of how to use this function. + */ +void I2C_clear_gca +( + i2c_instance_t * this_i2c +) +{ + /* + * This read modify write access should be interrupt safe as the address + * register is not written to in the ISR. + */ + /* Clear GC addressing. */ + HAL_set_8bit_reg_field(this_i2c->base_address, GC, 0x00u); +} + +/*------------------------------------------------------------------------------ + * I2C_isr() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_isr +( + i2c_instance_t * this_i2c +) +{ + volatile uint8_t status; + uint8_t data; + uint8_t hold_bus; + uint8_t clear_irq = 1u; + + status = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + + switch( status ) + { + /************** MASTER TRANSMITTER / RECEIVER *******************/ + + case ST_START: /* start has been xmt'd */ + case ST_RESTART: /* repeated start has been xmt'd */ + HAL_set_8bit_reg_field( this_i2c->base_address, STA, 0x00u); + HAL_set_8bit_reg( this_i2c->base_address, DATA, this_i2c->target_addr); /* write call address */ + HAL_set_8bit_reg_field( this_i2c->base_address, DIR, this_i2c->dir); /* set direction bit */ + if(this_i2c->dir == WRITE_DIR) + { + this_i2c->master_tx_idx = 0u; + } + else + { + this_i2c->master_rx_idx = 0u; + } + + /* + * Clear the pending transaction. This condition will be true if the slave + * has acquired the bus to carry out pending master transaction which + * it had received during its slave transmission or reception mode. + */ + if(this_i2c->is_transaction_pending) + { + this_i2c->is_transaction_pending = 0u; + } + + /* + * Make sure to update proper transaction after master START + * or RESTART + */ + if(this_i2c->transaction != this_i2c->pending_transaction) + { + this_i2c->transaction = this_i2c->pending_transaction; + } + break; + + case ST_LOST_ARB: + /* Set start bit. Let's keep trying! Don't give up! */ + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + break; + + case ST_STOP_TRANSMIT: + /* Stop has been transmitted. Do nothing */ + break; + + /******************* MASTER TRANSMITTER *************************/ + case ST_SLAW_NACK: + /* SLA+W has been transmitted; not ACK has been received - let's stop. */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_FAILED; + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + case ST_SLAW_ACK: + case ST_TX_DATA_ACK: + /* data byte has been xmt'd with ACK, time to send stop bit or repeated start. */ + if (this_i2c->master_tx_idx < this_i2c->master_tx_size) + { + HAL_set_8bit_reg(this_i2c->base_address, DATA, (uint_fast8_t)this_i2c->master_tx_buffer[this_i2c->master_tx_idx++]); + } + else if ( this_i2c->transaction == MASTER_RANDOM_READ_TRANSACTION ) + { + /* We are finished sending the address offset part of a random read transaction. + * It is is time to send a restart in order to change direction. */ + this_i2c->dir = READ_DIR; + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + else /* done sending. let's stop */ + { + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + hold_bus = this_i2c->options & I2C_HOLD_BUS; + + /* Store the information of current I2C bus status in the bus_status*/ + this_i2c->bus_status = hold_bus; + if ( hold_bus == 0u ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); /*xmt stop condition */ + enable_slave_if_required(this_i2c); + } + else + { + I2C_disable_irq( this_i2c ); + clear_irq = 0u; + } + this_i2c->master_status = I2C_SUCCESS; + } + break; + + case ST_TX_DATA_NACK: + /* data byte SENT, ACK to be received + * In fact, this means we've received a NACK (This may not be + * obvious, but if we've rec'd an ACK then we would be in state + * 0x28!) hence, let's send a stop bit + */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u);/* xmt stop condition */ + this_i2c->master_status = I2C_FAILED; + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + /********************* MASTER (or slave?) RECEIVER *************************/ + + /* STATUS codes 08H, 10H, 38H are all covered in MTX mode */ + case ST_SLAR_ACK: /* SLA+R tx'ed. */ + /* Let's make sure we ACK the first data byte received (set AA bit in CTRL) unless + * the next byte is the last byte of the read transaction. + */ + if(this_i2c->master_rx_size > 1u) + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + } + else if(1u == this_i2c->master_rx_size) + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + else /* this_i2c->master_rx_size == 0u */ + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_SUCCESS; + this_i2c->transaction = NO_TRANSACTION; + } + break; + + case ST_SLAR_NACK: /* SLA+R tx'ed; let's release the bus (send a stop condition) */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_FAILED; + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + case ST_RX_DATA_ACK: /* Data byte received, ACK returned */ + /* First, get the data */ + this_i2c->master_rx_buffer[this_i2c->master_rx_idx++] = HAL_get_8bit_reg(this_i2c->base_address, DATA); + if( this_i2c->master_rx_idx >= (this_i2c->master_rx_size - 1u)) + { + /* If we're at the second last byte, let's set AA to 0 so + * we return a NACK at the last byte. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + break; + + case ST_RX_DATA_NACK: /* Data byte received, NACK returned */ + /* Get the data, then send a stop condition */ + this_i2c->master_rx_buffer[this_i2c->master_rx_idx] = HAL_get_8bit_reg(this_i2c->base_address, DATA); + + hold_bus = this_i2c->options & I2C_HOLD_BUS; + + /* Store the information of current I2C bus status in the bus_status*/ + this_i2c->bus_status = hold_bus; + if ( hold_bus == 0u ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); /*xmt stop condition */ + + /* Bus is released, now we can start listening to bus, if it is slave */ + enable_slave_if_required(this_i2c); + } + else + { + I2C_disable_irq( this_i2c ); + clear_irq = 0u; + } + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + this_i2c->master_status = I2C_SUCCESS; + break; + + /******************** SLAVE RECEIVER **************************/ + case ST_GCA_NACK: /* NACK after, GCA addressing */ + case ST_SLA_NACK: /* Re-enable AA (assert ack) bit for future transmissions */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + this_i2c->transaction = NO_TRANSACTION; + this_i2c->slave_status = I2C_SUCCESS; + + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + break; + + case ST_GCA_LA: /* Arbitr. lost (GCA rec'd) */ + case ST_SLV_LA: /* Arbitr. lost (SLA rec'd) */ + /* + * We lost arbitration and either the GCE or our address was the + * one received so pend the master operation we were starting. + */ + this_i2c->is_transaction_pending = 1u; + /* Fall through to normal ST processing as we are now in slave mode */ + + case ST_GCA: /* General call address received, ACK returned */ + case ST_SLAVE_SLAW: /* SLA+W received, ACK returned */ + this_i2c->transaction = WRITE_SLAVE_TRANSACTION; + this_i2c->slave_rx_idx = 0u; + this_i2c->random_read_addr = 0u; + /* + * If Start Bit is set clear it, but store that information since it is because of + * pending transaction + */ + if(HAL_get_8bit_reg_field(this_i2c->base_address, STA)) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + this_i2c->is_transaction_pending = 1u; + } + this_i2c->slave_status = I2C_IN_PROGRESS; +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + /* Fall through to put address as first byte in payload buffer */ +#else + /* Only break from this case if the slave address must NOT be included at the + * beginning of the received write data. */ + break; +#endif + case ST_GCA_ACK: /* DATA received; ACK sent after GCA */ + case ST_RDATA: /* DATA received; must clear DATA register */ + if((this_i2c->slave_rx_buffer != (uint8_t *)0) + && (this_i2c->slave_rx_idx < this_i2c->slave_rx_size)) + { + data = HAL_get_8bit_reg(this_i2c->base_address, DATA); + this_i2c->slave_rx_buffer[this_i2c->slave_rx_idx++] = data; + +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + if((ST_RDATA == status) || (ST_GCA_ACK == status)) + { + /* Ignore the slave address byte in the random read address + computation in the case where INCLUDE_SLA_IN_RX_PAYLOAD + is defined. */ +#endif + this_i2c->random_read_addr = (this_i2c->random_read_addr << 8) + data; +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + } +#endif + } + + if(this_i2c->slave_rx_idx >= this_i2c->slave_rx_size) + { + /* Rx buffer is full. NACK next received byte. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + break; + + case ST_RSTOP: + /* STOP or repeated START occurred. */ + /* We cannot be sure if the transaction has actually completed as + * this hardware state reports that either a STOP or repeated START + * condition has occurred. We assume that this is a repeated START + * if the transaction was a write from the master to this point.*/ + if ( this_i2c->transaction == WRITE_SLAVE_TRANSACTION ) + { + if ( this_i2c->slave_rx_idx == this_i2c->slave_mem_offset_length ) + { + this_i2c->slave_tx_idx = this_i2c->random_read_addr; + } + /* Call the slave's write transaction handler if it exists. */ + if ( this_i2c->slave_write_handler != 0u ) + { + i2c_slave_handler_ret_t h_ret; + h_ret = this_i2c->slave_write_handler( this_i2c, this_i2c->slave_rx_buffer, (uint16_t)this_i2c->slave_rx_idx ); + if ( I2C_REENABLE_SLAVE_RX == h_ret ) + { + /* There is a small risk that the write handler could + * call I2C_disable_slave() but return + * I2C_REENABLE_SLAVE_RX in error so we only enable + * ACKs if still in slave mode. */ + enable_slave_if_required(this_i2c); + } + else + { + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x0u ); + /* Clear slave mode flag as well otherwise in mixed + * master/slave applications, the AA bit will get set by + * subsequent master operations. */ + this_i2c->is_slave_enabled = 0u; + } + } + else + { + /* Re-enable address acknowledge in case we were ready to nack the next received byte. */ + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x01u ); + } + } + else /* A stop or repeated start outside a write/read operation */ + { + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * See if we need to re-enable acknowledgement as some error conditions, such + * as a master prematurely ending a transfer, can see us get here with AA set + * to 0 which will disable slave operation if we are not careful. + */ + enable_slave_if_required(this_i2c); + } + + /* Mark any previous master write transaction as complete. */ + this_i2c->slave_status = I2C_SUCCESS; + + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + + break; + + case ST_SLV_RST: /* SMBUS ONLY: timeout state. must clear interrupt */ + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction. + */ + this_i2c->transaction = NO_TRANSACTION; + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * Clear status to I2C_FAILED only if there was an operation in progress. + */ + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->slave_status = I2C_FAILED; + } + + enable_slave_if_required(this_i2c); /* Make sure AA is set correctly */ + + break; + + /****************** SLAVE TRANSMITTER **************************/ + case ST_SLAVE_SLAR_ACK: /* SLA+R received, ACK returned */ + case ST_SLARW_LA: /* Arbitration lost, and: */ + case ST_RACK: /* Data tx'ed, ACK received */ + if ( status == ST_SLAVE_SLAR_ACK ) + { + this_i2c->transaction = READ_SLAVE_TRANSACTION; + this_i2c->random_read_addr = 0u; + this_i2c->slave_status = I2C_IN_PROGRESS; + /* If Start Bit is set clear it, but store that information since it is because of + * pending transaction + */ + if(HAL_get_8bit_reg_field(this_i2c->base_address, STA)) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + this_i2c->is_transaction_pending = 1u; + } + } + if (this_i2c->slave_tx_idx >= this_i2c->slave_tx_size) + { + /* Ensure 0xFF is returned to the master when the slave specifies + * an empty transmit buffer. */ + HAL_set_8bit_reg(this_i2c->base_address, DATA, 0xFFu); + } + else + { + /* Load the data the data byte to be sent to the master. */ + HAL_set_8bit_reg(this_i2c->base_address, DATA, (uint_fast8_t)this_i2c->slave_tx_buffer[this_i2c->slave_tx_idx++]); + } + /* Determine if this is the last data byte to send to the master. */ + if (this_i2c->slave_tx_idx >= this_i2c->slave_tx_size) /* last byte? */ + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + /* Next read transaction will result in slave's transmit buffer + * being sent from the first byte. */ + this_i2c->slave_tx_idx = 0u; + } + break; + + case ST_SLAVE_RNACK: /* Data byte has been transmitted; not-ACK has been received. */ + case ST_FINAL: /* Last Data byte tx'ed, ACK received */ + /* We assume that the transaction will be stopped by the master. + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. */ + this_i2c->slave_tx_idx = 0u; + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + /* Mark previous state as complete */ + this_i2c->slave_status = I2C_SUCCESS; + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + + break; + + /* Master Reset has been activated Wait 35 ms for interrupt to be set, + * clear interrupt and proceed to 0xF8 state. */ + case ST_RESET_ACTIVATED: + case ST_BUS_ERROR: /* Bus error during MST or selected slave modes */ + default: + /* Some undefined state has encountered. Clear Start bit to make + * sure, next good transaction happen */ + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction. + */ + this_i2c->transaction = NO_TRANSACTION; + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * Clear statuses to I2C_FAILED only if there was an operation in progress. + */ + if(I2C_IN_PROGRESS == this_i2c->master_status) + { + this_i2c->master_status = I2C_FAILED; + } + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->slave_status = I2C_FAILED; + } + + break; + } + + if ( clear_irq ) + { + /* clear interrupt. */ + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + /* Read the status register to ensure the last I2C registers write took place + * in a system built around a bus making use of posted writes. */ + status = HAL_get_8bit_reg( this_i2c->base_address, STATUS); +} + +/*------------------------------------------------------------------------------ + * I2C_smbus_init() + * See "i2c.h" for details of how to use this function. + */ + +/* + * SMBSUS_NO = 1 + * SMBALERT_NO = 1 + * SMBus enable = 1 + */ +#define INIT_AND_ENABLE_SMBUS 0x54u +void I2C_smbus_init +( + i2c_instance_t * this_i2c +) +{ + /* + * Single byte register write, should be interrupt safe + */ + /* Enable SMBUS */ + HAL_set_8bit_reg(this_i2c->base_address, SMBUS, INIT_AND_ENABLE_SMBUS); +} + +/*------------------------------------------------------------------------------ + * I2C_enable_smbus_irq() + * See "i2c.h" for details of how to use this function. + */ +void I2C_enable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + if ( irq_type & I2C_SMBALERT_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_IE, 0x01u); + } + if ( irq_type & I2C_SMBSUS_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_IE, 0x01u); + } + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_smbus_irq() + * See "i2c.h" for details of how to use this function. + */ +void I2C_disable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + if ( irq_type & I2C_SMBALERT_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_IE, 0x00u); + } + if (irq_type & I2C_SMBSUS_IRQ ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_IE, 0x00u); + } + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_suspend_smbus_slave() + * See "i2c.h" for details of how to use this function. + */ +void I2C_suspend_smbus_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_NO_CONTROL, 0x00u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_resume_smbus_slave() + * See "i2c.h" for details of how to use this function. + */ +void I2C_resume_smbus_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_NO_CONTROL, 0x01u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_reset_smbus() + * See "i2c.h" for details of how to use this function. + */ +void I2C_reset_smbus +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + HAL_set_8bit_reg_field(this_i2c->base_address, SMBUS_MST_RESET, 0x01u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_smbus_alert() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_smbus_alert +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_NO_CONTROL, 0x00u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_clear_smbus_alert() + * See "i2c.h" for details of how to use this function. + */ +void I2C_clear_smbus_alert +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_NO_CONTROL, 0x01u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_get_irq_status() + * See "i2c.h" for details of how to use this function. + */ +uint8_t I2C_get_irq_status +( + i2c_instance_t * this_i2c +) +{ + uint8_t status ; + uint8_t irq_type = I2C_NO_IRQ ; + + status = HAL_get_8bit_reg(this_i2c->base_address, SMBUS); + + if( status & (uint8_t)SMBALERT_NI_STATUS_MASK ) + { + irq_type |= I2C_SMBALERT_IRQ ; + } + + if( status & (uint8_t)SMBSUS_NI_STATUS_MASK ) + { + irq_type |= I2C_SMBSUS_IRQ ; + } + + status = HAL_get_8bit_reg(this_i2c->base_address, CONTROL); + + if( status & (uint8_t)SI_MASK ) + { + irq_type |= I2C_INTR_IRQ ; + } + return(irq_type); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_addr2() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_user_data +( + i2c_instance_t * this_i2c, + void * p_user_data +) +{ + this_i2c->p_user_data = p_user_data ; +} + +/*------------------------------------------------------------------------------ + * I2C_get_user_data() + * See "i2c.h" for details of how to use this function. + */ +void * I2C_get_user_data +( + i2c_instance_t * this_i2c +) +{ + return( this_i2c->p_user_data); +} + +#ifdef __cplusplus +} +#endif + diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h new file mode 100644 index 0000000..3891ce0 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h @@ -0,0 +1,2306 @@ +/***************************************************************************//** + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * CoreI2C software driver Application Programming Interface. + * This file contains defines and function declarations allowing to interface + * with the CoreI2C software driver. + * + */ +/*=========================================================================*//** + @mainpage CoreI2C Bare Metal Driver. + The CoreI2C bare metal software driver supports I2C master and slave + operations. + + ============================================================================== + Introduction + ============================================================================== + The CoreI2C driver provides a set of functions for controlling the Microchip + CoreI2C hardware IP. The driver supports up to 16 separate I2C channels per + CoreI2C instance, with common slave address settings shared between channels + on a device. + + Optional features of the CoreI2C allow it to operate with I2C based protocols + such as System Management Bus (SMBus), Power Management Bus (PMBus), and + Intelligent Platform Management Interface (IPMI). This driver provides support + for these features when enabled in the CoreI2C IP. + + The major features provided by CoreI2C driver: + - Provides support to configuring the I2C channels of each CoreI2C peripheral device. + - I2C master operations. + - I2C slave operations. + - SMBus related operations. + + This driver is used as part of a bare metal system where no operating + system is available. The driver gets adapted as a part of an operating system, + but the implementation of the adaptation layer between the driver and the operating + system's driver model is outside the scope of this driver. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + Your application software should configure the CoreI2C driver through + calls to the I2C_init() function for each CoreI2C instance in the + hardware design. The configuration parameters include the CoreI2C hardware + instance base address and other runtime parameters, such as the I2C serial + clock frequency and the I2C device address. + + Once channel 0 of a CoreI2C peripheral has been initialized by I2C_init(), + any additional channels present should be configured by calling + I2C_channel_init() for each of the remaining channels. + + Apart from the CoreI2C hardware instance base address, no CoreI2C hardware configuration + parameters are used by the driver. Hence, no additional configuration files are required + to use the driver. + + -------------------------------- + Interrupt Control + -------------------------------- + The CoreI2C driver has to enable and disable the generation of interrupts by + CoreI2C at various times when it is operating. This enabling and disabling of + interrupts must be done through the system’s interrupt controller. For that + reason, the method of controlling the CoreI2C interrupt is system specific + and it is necessary to customize the I2C_enable_irq() and I2C_disable_irq() + functions. These functions are available in the i2c_interrupt.c file. + The default implementation calls HAL_ASSERT(0) to indicate to the application + developer that a suitable implementations for these functions must be provided. + + The implementation of the I2C_enable_irq() function should permit interrupts + generated by a CoreI2C instance to interrupt the processor. The implementation + of the I2C_disable_irq() function should prevent interrupts generated by a + CoreI2C instance from interrupting the processor. See the provided example + projects for a working implementation of these functions. + + The I2C_register_write_handler() function registers a write handler + function with the CoreI2C driver that calls on completion of an I2C write + transaction by the CoreI2C slave. It is your responsibility to create and + register the implementation of this handler function that processes or + trigger the processing of the received data. + + The SMBSUS and SMBALERT interrupts are related to the SMBus interface and are + enabled and disabled through I2C_enable_smbus_irq() and + I2C_disable_smbus_irq() respectively. It is your responsibility to create + interrupt handler functions in your application to get the desired response + for the SMBus interrupts. + + Note: You must include the path to any application header files that are + included in the i2c_interrupt.c file, as an include path in your + project's compiler settings. The details of how to do this will depend + on your development software. + + -------------------------------- + SMBus Logic Options + -------------------------------- + SMBus related APIs does not have any effect if the "Generate SMBus Logic" + is not enabled in the CoreI2C hardware configuration. Following are API's + that does not give the desired results if SMBus Logic is disabled. + + - I2C_smbus_init() + - I2C_reset_smbus() + - I2C_enable_smbus_irq() + - I2C_disable_smbus_irq() + - I2C_suspend_smbus_slave() + - I2C_resume_smbus_slave() + - I2C_set_smsbus_alert() + - I2C_clear_smsbus_alert() + - I2C_get_irq_status() + + -------------------------------- + Fixed Baud Rate Values + -------------------------------- + The serial clock frequency parameter passed to the I2C_init() and + I2C_channel_init() functions may not have any effect if fixed values were + selected for Baud rate in the hardware configuration of CoreI2C. When fixed + values are selected for these baud rates, the driver cannot overwrite + the fixed values. + + ----------------------------------- + Fixed Slave Address Options Values + ----------------------------------- + The primary slave address parameter passed to the I2C_init() function and + secondary address value passed to the I2C_set_slave_second_addr() function, + may not have the desired effect if fixed values were selected for the slave 0 + address and slave 1 address respectively. Proper operation of this version of + the driver requires the slave addresses to be programmable. + + ============================================================================== + Theory of Operation + ============================================================================== + The CoreI2C software driver is designed to allow the control of multiple + instances of CoreI2C with one or more I2C channels. Each channel in an + instance of CoreI2C in the hardware design is associated with a single + instance of the i2c_instance_t structure in the software. You must allocate + memory for one unique i2c_instance_t structure instance for each channel of + each CoreI2C hardware instance. The contents of these data structures are + initialised by calling I2C_init() and if necessary I2C_channel_init(). + A pointer to the structure is passed to the subsequent driver functions in order + to identify the CoreI2C hardware instance and channel to perform the + requested operation. + + Note: Do not attempt to directly manipulate the contents of i2c_instance_t + structures. These structures are only intended to be modified by the driver + functions. + + The CoreI2C driver functions are grouped into the following categories: + - Initialization and configuration functions + - Interrupt control + - I2C slave addressing functions + - I2C master operations functions to handle write, read, and write-read + transactions + - I2C slave operations functions to handle write, read, and write-read + transactions + - Mixed master-slave operations + - SMBus interface configuration and control + + -------------------------------- + Initialization and Configuration + -------------------------------- + The CoreI2C device is first initialized by calling the I2C_init() + function. Since each CoreI2C peripheral supports up to 16 channels, an + additional function, I2C_channel_init(), is required to initialize the + remaining channels with their own data structures. + + I2C_init() function initializes channel 0 of a CoreI2C and the i2c_instance_t + for channel 0 acts as the basis for further channel initialization as the + hardware base address and I2C serial address are same across all the channels. + Ensure to call I2C_init() function before calling any other I2C driver function + calls. The I2C_init() call for each CoreI2C takes the I2C serial address assigned + to the I2C and the serial clock divider to generate its I2C clock as configuration + parameters. + + I2C_channel_init() function takes as input parameters a pointer to the CoreI2C + i2c_instance_t which has been initialized by calling the I2C_init() and a pointer + to a separate i2c_instance_t which represents this new channel. Another input + parameter which is required by this function is serial clock divider which generates + its I2C clock. + + -------------------------------- + Interrupt Control + -------------------------------- + The CoreI2C driver is interrupt driven and it uses each channels INT + interrupt to drive the state machine which is at the heart of the driver. + The application is responsible for providing the link between the interrupt + generating hardware and the CoreI2C interrupt handler and must ensure that + the I2C_isr() function is called with the correct i2c_instance_t structure + pointer for the CoreI2C channel initiating the interrupt. + + The driver enables and disables the generation of INT interrupts by CoreI2C + at various times when it is operating through the user supplied + I2C_enable_irq() and I2C_disable_irq() functions. + + The I2C_register_write_handler() function is used to register a write + handler function with the CoreI2C driver which is called on completion + of an I2C write transaction by the CoreI2C slave. It is the user + applications responsibility to create and register the implementation of + this handler function that processes or triggers the processing of the + received data. + + The other two interrupt sources in the CoreI2C are related to SMBus + operation and are enabled and disabled through I2C_enable_smbus_irq() and + I2C_disable_smbus_irq() respectively. Due to the application specific + nature of the response to SMBus interrupts, you must design interrupt + handler functions in the application to get the desired behaviour for + SMBus related interrupts. + + If enabled, the SMBA_INT signal from the CoreI2C is asserted if an + SMBALERT condition is signalled on the SMBALERT_NI input for the channel. + + If enabled, the SMBS_INT signal from the CoreI2C is asserted if an + SMBSUSPEND condition is signalled on the SMBSUS_NI input for the channel. + + ## I2C Slave Addressing Functions + A CoreI2C peripheral responds to the following three slave addresses: + - Slave address 0 - This is the primary slave address that accesses + a CoreI2C channel when it acts as a slave in + I2C transactions. You must configure the primary slave + address using I2C_init(). + + - Slave address 1 - This is the secondary slave address which might be + required in certain application specific scenarios. + The secondary slave address is configured by + I2C_set_slave_second_addr() and is disabled by + I2C_disable_slave_second_addr(). + + - General call address - A CoreI2C slave can be configured to respond to + a broadcast command by a master transmitting the + general call address of 0x00. Use the I2C_set_gca() + function to enable the slave to respond to the general + call address. If the CoreI2C slave is not required to + respond to the general call address, disable this + address by calling I2C_clear_gca(). + + Note: All channels on a CoreI2C instance share the same slave address logic. + This means that they cannot have separate slave addresses and rely on + the separate physical I2C bus connections to distinguish them. + + -------------------------------- + Transaction Types + -------------------------------- + The I2C driver is designed to handle three types of I2C transaction: + - Write transactions + - Read transactions + - Write-read transactions + + ## Write Transaction + The master I2C device initiates a write transaction by sending a START bit + as soon as the bus becomes free. The START bit is followed by the 7-bit + serial address of the target slave device followed by the read/write bit + indicating the direction of the transaction. The slave acknowledges the + receipt of it's address with an acknowledge bit. The master sends data one + byte at a time to the slave, which must acknowledge the receipt of each byte + for the next byte to be sent. The master sends a STOP bit to complete the + transaction. The slave can abort the transaction by replying with a + non-acknowledge bit instead of an acknowledge bit. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ## Read Transaction + The master I2C device initiates a read transaction by sending a START bit + as soon as the bus becomes free. The START bit is followed by the 7-bit + serial address of the target slave device followed by the read/write bit + indicating the direction of the transaction. The slave acknowledges the + receipt of it's slave address with an acknowledge bit. The slave sends + data one byte at a time to the master, which must acknowledge the receipt of + each byte for the next byte to be sent. The master sends a non-acknowledge + bit following the last byte it wishes to read followed by a STOP bit. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ## Write-Read Transaction + The write-read transaction is a combination of a write transaction + immediately followed by a read transaction. There is no STOP bit in between + the write and read phases of a write-read transaction. A repeated START + bit is sent between the write and read phases. + + Whilst the write handler is being executed, the slave holds the clock line + low to stretch the clock until the response is ready. + + The write-read transaction is typically used to send a command or offset + in the write transaction specifying the logical data to be transferred + during the read phase. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ## Master Operations + The application can use the I2C_write(), I2C_read(), and I2C_write_read() + functions to initiate an I2C bus transaction. The application can then wait + for the transaction to complete using the I2C_wait_complete() function + or poll the status of the I2C transaction using the I2C_get_status() + function until it returns a value different from I2C_IN_PROGRESS. The + I2C_system_tick() function is used to set a time base for the + I2C_wait_complete() function's time out delay. + + ## Slave Operations + To configure the I2C driver to operate as an I2C slave requires the use + of the following functions: + - I2C_set_slave_tx_buffer() + - I2C_set_slave_rx_buffer() + - I2C_set_slave_mem_offset_length() + - I2C_register_write_handler() + - I2C_enable_slave() + + Use of all functions is not required if the slave I2C does not need to support + all types of I2C read transactions. The subsequent sections list the functions + that must be used to support each transaction type. + + ## Responding to Read Transactions + The following functions are used to configure the CoreI2C driver to + respond to I2C read transactions: + • I2C_set_slave_tx_buffer() + • I2C_enable_slave() + + The I2C_set_slave_tx_buffer() function specifies the data buffer that + is transmitted when the I2C slave is the target of an I2C read + transaction. It is then up to the application to manage the content of + that buffer to control the data that will be transmitted to the I2C + master as a result of the read transaction. + + The I2C_enable_slave() function enables the I2C hardware instance + to respond to the I2C transactions. It must be called after the I2C driver + has been configured to respond to the required transaction types. + + ## Responding to Write Transactions + The following functions are used to configure the I2C driver to respond + to I2C write transactions: + • I2C_set_slave_rx_buffer() + • I2C_register_write_handler() + • I2C_enable_slave() + + The I2C_set_slave_rx_buffer() function specifies the data buffer that + stored the data received by the I2C slave when it targets an I2C write + transaction. + + The I2C_register_write_handler() function specifies the handler function + that must be called on completion of the I2C write transaction. It is this + handler function that processes or triggers the processing of the received + data. + + The I2C_enable_slave() function enables the I2C hardware instance + to respond to I2C transactions. It must be called after the I2C driver + has been configured to respond to the required transaction types. + + ## Responding to Write-Read Transactions + The following functions are used to configure the CoreI2C driver to + respond to write-read transactions: + - I2C_set_slave_mem_offset_length() + - I2C_set_slave_tx_buffer() + - I2C_set_slave_rx_buffer() + - I2C_register_write_handler() + - I2C_enable_slave() + + The I2C_set_slave_mem_offset_length() function specifies the number of + bytes expected by the I2C slave during the write phase of the write-read + transaction. + + The I2C_set_slave_tx_buffer() function specifies the data that is + transmitted to the I2C master during the read phase of the write-read + transaction. The value received by the I2C slave during the write phase of + the transaction will be used as an index into the transmit buffer + specified by this function. It decides which part of the transmit buffer + will be transmitted to the I2C master as part of the read phase of the + write-read transaction. + + The I2C_set_slave_rx_buffer() function specifies the data buffer that + stores the data received by the I2C slave during the write phase of + the write-read transaction. This buffer must be large enough to accommodate + the number of bytes specified through the I2C_set_slave_mem_offset_length() + function. + + The I2C_register_write_handler() function can optionally be used to + specify a handler function that is called on completion of the write phase + of the I2C write-read transaction. If a handler function is registered, it + is responsible for processing the received data in the slave receive + buffer and populating the slave transmit buffer with the data that will be + transmitted to the I2C master as part of the read phase of the write-read + transaction. + + The I2C_enable_slave() function enables the CoreI2C hardware instance to + respond to the I2C transactions. It must be called after configuring the + CoreI2C driver to respond to the required transaction types. + + ## Mixed Master-Slave Operations + The CoreI2C device supports mixed master and slave operations. If the + CoreI2C slave has a transaction in progress and your application attempts to + begin a master mode transaction, the CoreI2C driver queues the master mode + transaction until the bus is released and the CoreI2C can switch to master + mode and acquire the bus. The CoreI2C master then starts the previously + queued master transaction. + + ## SMBus Control + The CoreI2C driver enables the CoreI2C peripheral’s SMBus functionality + using the I2C_smbus_init() function. + + The I2C_suspend_smbus_slave() function is used with a master mode CoreI2C + to force slave devices on the SMBus to enter their Power-Down/Suspend mode. + The I2C_resume_smbus_slave() function is used to end the suspend operation + on the SMBus. + + The I2C_reset_smbus() function is used with a master mode CoreI2C to force + all devices on the SMBus to reset their SMBUs interface. + + The I2C_set_smsbus_alert() function is used by a slave mode CoreI2C to + force communication with the SMBus master. Once communications with the + master is initiated, the I2C_clear_smsbus_alert() function clears the alert + condition. + + The I2C_enable_smbus_irq() and I2C_disable_smbus_irq() functions are used to + enable and disable the SMBSUS and SMBALERT SMBus interrupts. + + *//*=========================================================================*/ + +#ifndef CORE_I2C_H_ +#define CORE_I2C_H_ + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#include "hal_assert.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + I2C_RELEASE_BUS + ======================================= + The I2C_RELEASE_BUS constant is used to specify the options parameter to + functions I2C_read(), I2C_write() and I2C_write_read() to indicate + that a STOP bit must be generated at the end of the I2C transaction to release + the bus. + */ +#define I2C_RELEASE_BUS 0x00u + +/*-------------------------------------------------------------------------*//** + I2C_HOLD_BUS + ======================================= + The I2C_HOLD_BUS constant specify the options parameter to functions I2C_read(), + I2C_write(), and I2C_write_read() to indicate that a STOP bit must not be + generated at the end of the I2C transaction in order to retain the bus ownership. + This causes the next transaction to begin with a repeated START bit and no STOP + bit between the transactions. + */ +#define I2C_HOLD_BUS 0x01u + +/*-------------------------------------------------------------------------*//** + Interrupt Identifier Number + ======================================= + The following constants specify the interrupt identifier number which is + solely used by the driver API. This has nothing to do with hardware interrupt + line. I2C_INTR_IRQ is the primary interrupt signal which drives the state machine + of the CoreI2C driver. The I2C_SMBALERT_IRQ and I2C_SMBSUS_IRQ are used by + SMBus interrupt enable and disable functions. These IRQ numbers are also used + by I2C_get_irq_status(). + + | Constant | Description | + |--------------------|--------------------------------------------------------| + | I2C_NO_IRQ | No interrupt | + | I2C_SMBALERT_IRQ | Used by SMBus interrupt enable functions | + | I2C_SMBSUS_IRQ | Used by SMBus interrupt disable functions | + | I2C_INTR_IRQ | Primary interrupt signal which drives the state machine| + + */ +#define I2C_NO_IRQ 0x00u +#define I2C_SMBALERT_IRQ 0x01u +#define I2C_SMBSUS_IRQ 0x02u +#define I2C_INTR_IRQ 0x04u + +/*-------------------------------------------------------------------------*//** + I2C_NO_TIMEOUT + ======================================= + The I2C_wait_complete() function uses I2C_NO_TIMEOUT constant as a parameter + to indicate that the wait for completion of the transaction should not time out. + */ +#define I2C_NO_TIMEOUT 0u + +/***************************************************************************//** + The i2c_channel_number_t type is used to specify the channel number of a + CoreI2C instance. + */ +typedef enum i2c_channel_number { + I2C_CHANNEL_0 = 0u, + I2C_CHANNEL_1, + I2C_CHANNEL_2, + I2C_CHANNEL_3, + I2C_CHANNEL_4, + I2C_CHANNEL_5, + I2C_CHANNEL_6, + I2C_CHANNEL_7, + I2C_CHANNEL_8, + I2C_CHANNEL_9, + I2C_CHANNEL_10, + I2C_CHANNEL_11, + I2C_CHANNEL_12, + I2C_CHANNEL_13, + I2C_CHANNEL_14, + I2C_CHANNEL_15, + I2C_MAX_CHANNELS = 16u +} i2c_channel_number_t; + +/***************************************************************************//** + The i2c_clock_divider_t type specifies the divider to be applied + to the I2C PCLK or BCLK signal in order to generate the I2C clock. + The I2C_BCLK_DIV_8 value selects a clock frequency based on division of BCLK, + all other values select a clock frequency based on division of PCLK. + */ +typedef enum i2c_clock_divider { + I2C_PCLK_DIV_256 = 0u, + I2C_PCLK_DIV_224, + I2C_PCLK_DIV_192, + I2C_PCLK_DIV_160, + I2C_PCLK_DIV_960, + I2C_PCLK_DIV_120, + I2C_PCLK_DIV_60, + I2C_BCLK_DIV_8 +} i2c_clock_divider_t; + +/***************************************************************************//** + The i2c_status_t type is used to report the status of I2C transactions. + */ +typedef enum i2c_status +{ + I2C_SUCCESS = 0u, + I2C_IN_PROGRESS, + I2C_FAILED, + I2C_TIMED_OUT +} i2c_status_t; + +/***************************************************************************//** + The i2c_slave_handler_ret_t type is used by slave write handler functions + to indicate whether or not the received data buffer should be released. + */ +typedef enum i2c_slave_handler_ret { + I2C_REENABLE_SLAVE_RX = 0u, + I2C_PAUSE_SLAVE_RX = 1u +} i2c_slave_handler_ret_t; + +/***************************************************************************//** + This structure identifies various CoreI2C hardware instances in the system + and the I2C channels within them. The application software should declare + one instance of this structure for each channel of each instance of CoreI2C + in your system. I2C_init() and I2C_channel_init() functions initialize this + structure depending on whether it is channel 0 or one of the additional + channels, respectively. A pointer to an initialized instance of the + structure should be passed as the first parameter to the CoreI2C driver + functions, to identify which CoreI2C hardware instance and channel should + perform the requested operation. + + The contents of this data structure should not be modified or used outside of + the CoreI2C driver. Software using the CoreI2C driver should only need to + create one single instance of this data structure for each channel of each + CoreI2C hardware instance in the system then pass a pointer to these data + structures with each call to the CoreI2C driver in order to identify which + CoreI2C hardware instance to use. + */ +typedef struct i2c_instance i2c_instance_t ; +/***************************************************************************//* + Slave write handler functions prototype +/***************************************************************************//** + This defines the function prototype that must be followed by I2C slave write + handler functions. These functions are registered with the CoreI2C driver + through the I2C_register_write_handler() function. + + Declaring and Implementing Slave Write Handler Functions: + + Slave write handler functions should follow the following prototype: + @code + i2c_slave_handler_ret_t write_handler + ( + i2c_instance_t *instance, uint8_t * data, uint16_t size + ); + @endcode + + The instance parameter is a pointer to the i2c_instance_t for which this + slave write handler has been declared. + + The data parameter is a pointer to a buffer (received data buffer) holding + the data written to the I2C slave. + + Define the INCLUDE_SLA_IN_RX_PAYLOAD macro for the driver to insert the + actual address used to access the slave as the first byte in the buffer. + This allows the applications to tailor their response based on the actual + address used to access the slave (primary address, secondary address, or GCA). + + The size parameter is the number of bytes held in the received data buffer. + Handler functions must return one of the following values: + - I2C_REENABLE_SLAVE_RX + - I2C_PAUSE_SLAVE_RX + + If the handler function returns I2C_REENABLE_SLAVE_RX, the driver releases + the received data buffer and allows further I2C write transactions to the + I2C slave. + + If the handler function returns I2C_PAUSE_SLAVE_RX, the I2C slave responds + to subsequent write requests with a non-acknowledge bit (NACK), until the + received data buffer content gets processed by some other part of the + software application. + + Call the I2C_enable_slave() after returning the I2C_PAUSE_SLAVE_RX to release + the received data buffer in order to store the data received by the subsequent + I2C write transactions. + */ +typedef i2c_slave_handler_ret_t (*i2c_slave_wr_handler_t)(i2c_instance_t *instance, uint8_t *, uint16_t ); + +/***************************************************************************//** + This structure is used to identify the various CoreI2C hardware instances in + your system and the I2C channels within them. Your application software should + declare one instance of this structure for each channel of each instance of + CoreI2C in your system. The functions I2C_init() and I2C_channel_init() + initialize this structure depending on whether it is channel 0 or one of the + additional channels respectively. A pointer to an initialized instance of the + structure should be passed as the first parameter to the CoreI2C driver + functions, to identify which CoreI2C hardware instance and channel should + perform the requested operation. + + The contents of this data structure should not be modified or used outside of + the CoreI2C driver. Software using the CoreI2C driver should only need to + create one single instance of this data structure for each channel of each + CoreI2C hardware instance in the system then pass a pointer to these data + structures with each call to the CoreI2C driver in order to identify the + CoreI2C hardware instance it wishes to use. + */ +struct i2c_instance +{ + addr_t base_address; + uint_fast8_t ser_address; + + /* Transmit related info:*/ + uint_fast8_t target_addr; + + /* Current transaction type (WRITE, READ, RANDOM_READ)*/ + uint8_t transaction; + + uint_fast16_t random_read_addr; + + uint8_t options; + + /* Master TX INFO: */ + const uint8_t * master_tx_buffer; + uint_fast16_t master_tx_size; + uint_fast16_t master_tx_idx; + uint_fast8_t dir; + + /* Master RX INFO: */ + uint8_t * master_rx_buffer; + uint_fast16_t master_rx_size; + uint_fast16_t master_rx_idx; + + /* Master Status */ + volatile i2c_status_t master_status; + uint32_t master_timeout_ms; + + /* Slave TX INFO */ + const uint8_t * slave_tx_buffer; + uint_fast16_t slave_tx_size; + uint_fast16_t slave_tx_idx; + + /* Slave RX INFO */ + uint8_t * slave_rx_buffer; + uint_fast16_t slave_rx_size; + uint_fast16_t slave_rx_idx; + /* Slave Status */ + volatile i2c_status_t slave_status; + + /* Slave data: */ + uint_fast8_t slave_mem_offset_length; + i2c_slave_wr_handler_t slave_write_handler; + uint8_t is_slave_enabled; + + /* user specific data */ + void *p_user_data ; + + /* I2C bus status */ + uint8_t bus_status; + + /* Is transaction pending flag */ + uint8_t is_transaction_pending; + + /* I2C Pending transaction */ + uint8_t pending_transaction; +}; + +/*------------------------Public Function-------------------------------------*/ + +/***************************************************************************//** + The I2C_init() function configures channel 0 of a CoreI2C instance. It sets + the base hardware address which is used to locate the CoreI2C instance + in memory and also used internally by I2C_channel_init() to calculate the + register addresses for any additional channels. The slave serial address set + is shared by all channels on a CoreI2C instance. + + If only one channel is configured in a CoreI2C, the address of the + i2c_instance_t used in I2C_Init() will also be used in subsequent calls to the + CoreI2C driver functions. If more than one channel is configured in the + CoreI2C, I2C_channel_init() will be called after I2C_init(), which initializes + the i2c_instance_t data structure for a specific channel. + + @param this_i2c + Pointer to the i2c_instance_t data structure that holds all the data + related to channel 0 of the CoreI2C instance is initialized. A pointer + to this structure is used in all subsequent calls to the CoreI2C driver + functions which operates on channel 0 of this CoreI2C instance. + + @param base_address + Base address in the processor's memory map of the registers of the CoreI2C + instance being initialized. + + @param ser_address + This parameter sets the primary I2C serial address (SLAVE0 address) for the + CoreI2C to initialize. It is the principal I2C bus address to which the + CoreI2C instance will respond. CoreI2C can operate in master mode or slave + mode and the serial address is significant only in the case of I2C slave + mode. In master mode, CoreI2C does not require a serial address and the + value of this parameter is not important. If you do not intend to use the + CoreI2C device in slave mode, then provide any dummy slave address value + to this parameter. However, in systems where the CoreI2C is expected to + switch from master mode to slave mode, it is advisable to initialize the + CoreI2C device with a valid serial slave address. Call the I2C_init() + function whenever it is required to change the primary slave address as + there is no separate function to set the primary slave address of the + I2C device. The serial address initialized through this function is + basically the primary slave address or slave address0. + I2C_set_slave_second_addr() is used to set the secondary slave address + or slave address 1. + Note : ser_address parameter does not have any affect if fixed slave + address is enabled in CoreI2C hardware design. CoreI2C will + be always addressed with the hardware configured fixed slave + address. + Note : ser_address parameter will not have any affect if the CoreI2C + instance is only used in master mode. + + @param ser_clock_speed + This parameter sets the I2C serial clock frequency. It selects the divider + that generates the serial clock from the APB PCLK or from the BCLK. + It can be one of the following: + - I2C_PCLK_DIV_256 + - I2C_PCLK_DIV_224 + - I2C_PCLK_DIV_192 + - I2C_PCLK_DIV_160 + - I2C_PCLK_DIV_960 + - I2C_PCLK_DIV_120 + - I2C_PCLK_DIV_60 + - I2C_BCLK_DIV_8 + Note: serial_clock_speed value does not have any affect if the fixed baud + rate is enabled in CoreI2C hardware instance configuration dialogue + window. The fixed baud rate divider value overrides the value passed + as parameter in this function. + Note: serial_clock_speed value is not critical for devices that only operate + as slaves and can be set to any of the above values. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void system_init( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + } + @endcode + */ +void I2C_init +( + i2c_instance_t * this_i2c, + addr_t base_address, + uint8_t ser_address, + i2c_clock_divider_t ser_clock_speed +); + +/***************************************************************************//** + The I2C_channel_init() function initializes and configures hardware and data + structures of one of the additional channels of a CoreI2C instance. + I2C_init() must be called before calling this function to set the CoreI2C + instance hardware base address and I2C serial address. I2C_channel_init() also + initializes I2C serial clock divider to set the serial clock baud rate. + The pointer to data structure i2c_instance_t used for a particular channel + is used as an input parameter to subsequent CoreI2C driver functions + which operate on this channel. + + @param this_i2c_channel + Pointer to the i2c_instance_t data structure that holds all data related to + the CoreI2C channel gets initialized. A pointer to the same data structure + is used in subsequent calls to the CoreI2C driver functions in order to + identify the CoreI2C channel instance that should perform the operation + implemented by the called driver function. + + @param this_i2c + This is a pointer to an i2c_instance_t structure, previously initialized by + I2C_init(). It holds information regarding the hardware base address and + I2C serial address for the CoreI2C containing the channel to be + initialized. This information is required by I2C_channel_init() to + initialize the i2c_instance_t structure pointed by this_i2c_channel as + all channels in a CoreI2C instance share the same base address and serial + address. It is very important that the i2c_instance_t structure pointed + by this_i2c must be previously initialized by calling I2C_init(). + + @param channel_number + This parameter of type i2c_channel_number_t identifies the channel to be + initialized. + + @param ser_clock_speed + This parameter sets the I2C serial clock frequency. It selects the divider + that is used to generate the serial clock from the APB PCLK or from + the BCLK. It can be one of the following: + - I2C_PCLK_DIV_256 + - I2C_PCLK_DIV_224 + - I2C_PCLK_DIV_192 + - I2C_PCLK_DIV_160 + - I2C_PCLK_DIV_960 + - I2C_PCLK_DIV_120 + - I2C_PCLK_DIV_60 + - I2C_BCLK_DIV_8 + Note: serial_clock_speed value does not have any affect if the fixed baud + rate is enabled in CoreI2C hardware instance configuration dialogue + window. The fixed baud rate divider value will supersede the value + passed as parameter in this function. + Note: ser_clock_speed value is not critical for devices that only operate + as slaves and can be set to any of the above values. + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_SER_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + i2c_instance_t g_i2c_channel_1_inst; + + uint8_t tx_buffer[DATA_LENGTH]; + uint8_t write_length = DATA_LENGTH; + + void system_init( void ) + { + uint8_t target_slave_addr = 0x12; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize CoreI2C channel 1 with different clock speed + I2C_channel_init( &g_i2c_channel_1_inst, &g_i2c_inst, I2C_CHANNEL_1, + I2C_PCLK_DIV_224 ); + + // Write data to Channel 1 of CoreI2C instance. + I2C_write( &g_i2c_channel_1_inst, target_slave_addr, tx_buffer, + write_length, I2C_RELEASE_BUS ); + } + @endcode + +*/ +void I2C_channel_init +( + i2c_instance_t * this_i2c_channel, + i2c_instance_t * this_i2c, + i2c_channel_number_t channel_number, + i2c_clock_divider_t ser_clock_speed +); + +/***************************************************************************//** + The I2C_isr function is the CoreI2C interrupt service routine. User must + call this function from their application level CoreI2C interrupt handler + function. This function runs the I2C state machine based on previous and + current status. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREINTERRUPT_BASE_ADDR 0xCC000000u + #define COREI2C_SER_ADDR 0x10u + #define I2C_IRQ_NB 2u + + i2c_instance_t g_i2c_inst; + + void core_i2c_isr( void ) + { + I2C_isr( &g_i2c_inst ); + } + + void main( void ) + { + CIC_init( COREINTERRUPT_BASE_ADDR ); + NVIC_init(); + CIC_set_irq_handler( I2C_IRQ_NB, core_i2c_isr ); + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + NVIC_enable_interrupt( NVIC_IRQ_0 ); + } + @endcode + */ +void I2C_isr +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//* + #Master Specific Functions + + The following functions are only used within an I2C master's implementation. +/***************************************************************************//** + This function initiates an I2C master write transaction. This function returns + immediately after initiating the transaction. The content of the write buffer + passed as parameter should not be modified until the write transaction + completes. It also means that the memory allocated for the write buffer should + not be freed or should not go out of scope before the write completes. You can + check for the write transaction completion using the I2C_status() function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr + This parameter specifies the serial address of the target I2C device. + + @param write_buffer + This parameter is a pointer to a buffer holding the data to be written to + the target I2C device. Do not to release the memory used by this buffer + before the write transaction completes. For example, it is not appropriate + to return from a function allocating this buffer as an auto array variable + before the write transaction completes as this would result in the buffer's + memory being de-allocated from the stack when the function returns. This + memory could then be subsequently reused and modified causing unexpected + data to be written to the target I2C device. + + @param write_size + Number of bytes held in the write_buffer to be written to the target I2C + device. + + @param options + The options parameter is used to indicate if the I2C bus should be released + on completion of the write transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the write transaction causing the bus to be released for other I2C + devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the write + transaction, preventing other I2C devices from initiating a bus transaction. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t tx_buffer[DATA_LENGTH]; + uint8_t write_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Write data to Channel 0 of CoreI2C instance. + I2C_write( &g_i2c_inst, target_slave_addr, tx_buffer, write_length, + I2C_RELEASE_BUS ); + + // Wait for completion and record the outcome + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_write +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * write_buffer, + uint16_t write_size, + uint8_t options +); + +/***************************************************************************//** + This function initiates an I2C master read transaction. This function returns + immediately after initiating the transaction. + The contents of the read buffer passed as parameter should not be modified + until the read transaction completes. It also means that the memory allocated + for the read buffer should not be freed or should not go out of scope before + the read completes. You can check for the read transaction completion using + the I2C_status() function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr + This parameter specifies the serial address of the target I2C device. + + @param read_buffer + This is a pointer to a buffer where the data received from the target device + gets stored. Do not to release the memory used by this buffer before the read + transaction completes. For example, it is not appropriate to return from a + function allocating this buffer as an auto array variable before the read + transaction completes as this would result in the buffer's memory being + de-allocated from the stack when the function returns. This memory could + then be subsequently reallocated resulting in the read transaction + corrupting the newly allocated memory. + + @param read_size + This parameter specifies the number of bytes to read from the target device. + This size must not exceed the size of the read_buffer buffer. + + @param options + The options parameter is used to indicate if the I2C bus should be released + on completion of the read transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the read transaction causing the bus to be released for other I2C + devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the read transaction, + preventing other I2C devices from initiating a bus transaction. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t rx_buffer[DATA_LENGTH]; + uint8_t read_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Read data from target slave Channel 0 of CoreI2C instance. + I2C_read( &g_i2c_inst, target_slave_addr, rx_buffer, read_length, + I2C_RELEASE_BUS ); + + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +); + +/***************************************************************************//** + This function initiates an I2C write-read transaction where data is first + written to the target device before issuing a restart condition and changing + the direction of the I2C transaction in order to read from the target device. + + The same warnings about buffer allocation in I2C_write() and I2C_read() + applies to this function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr + This parameter specifies the serial address of the target I2C device. + + @param addr_offset + This parameter is a pointer to the buffer containing the data that is sent + to the slave during the write phase of the write-read transaction. This + data is typically used to specify an address offset specifying to the I2C + slave device what data it must return during the read phase of the + write-read transaction. + + @param offset_size + This parameter specifies the number of offset bytes to be written during the + write phase of the write-read transaction. This is typically the size of the + buffer pointed by the addr_offset parameter. + + @param read_buffer + This parameter is a pointer to the buffer where the data read from the I2C + slave will be stored. + + @param read_size + This parameter specifies the number of bytes to read from the target I2C + slave device. This size must not exceed the size of the buffer pointed by + the read_buffer parameter. + + @param options + The options parameter is used to indicate if the I2C bus should be released + on completion of the write-read transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the write-read transaction causing the bus to be released for other + I2C devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the write-read + transaction, preventing other I2C devices from initiating a bus transaction. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define TX_LENGTH 16u + #define RX_LENGTH 8u + + i2c_instance_t g_i2c_inst; + uint8_t rx_buffer[RX_LENGTH]; + uint8_t read_length = RX_LENGTH; + uint8_t tx_buffer[TX_LENGTH]; + uint8_t write_length = TX_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + I2C_write_read( &g_i2c_inst, target_slave_addr, tx_buffer, write_length, + rx_buffer, read_length, I2C_RELEASE_BUS ); + + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_write_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * addr_offset, + uint16_t offset_size, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +); + +/***************************************************************************//** + This function indicates the current state of a CoreI2C channel. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + The return value indicates the current state of a CoreI2C channel or the + outcome of the previous transaction if no transaction is in progress. + Following are the return values are: + - I2C_SUCCESS + The last I2C transaction has completed successfully. + - I2C_IN_PROGRESS + There is an I2C transaction in progress. + - I2C_FAILED + The last I2C transaction failed. + - I2C_TIMED_OUT + The request has failed to complete in the allotted time. + + @example + @code + i2c_instance_t g_i2c_inst; + + while( I2C_IN_PROGRESS == I2C_get_status( &g_i2c_inst ) ) + { + // Do something useful while waiting for I2C operation to complete + our_i2c_busy_task(); + } + + if( I2C_SUCCESS != I2C_get_status( &g_i2c_inst ) ) + { + // Something went wrong... + our_i2c_error_recovery( &g_i2c_inst ); + } + @endcode + */ +i2c_status_t I2C_get_status +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + This function waits for the current I2C transaction to complete. The return + value indicates whether the last I2C transaction was successful or not. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + @param timeout_ms + The timeout_ms parameter specifies the delay within which the current I2C + transaction should complete. The time out delay is given in + milliseconds. I2C_wait_complete() will return I2C_TIMED_OUT if the current + transaction has not completed after the time out delay has expired. This + parameter can be set to I2C_NO_TIMEOUT to indicate that I2C_wait_complete() + must not time out. + + @return + The return value indicates the outcome of the last I2C transaction. It can + be one of the following: + - I2C_SUCCESS + The last I2C transaction has completed successfully. + - I2C_FAILED + The last I2C transaction failed. + - I2C_TIMED_OUT + The last transaction failed to complete within the time out delay given + as second parameter. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t rx_buffer[DATA_LENGTH]; + uint8_t read_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Read data from Channel 0 of CoreI2C instance. + I2C_read( &g_i2c_inst, target_slave_addr, rx_buffer, read_length, + I2C_RELEASE_BUS ); + + // Wait for completion and record the outcome + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +i2c_status_t I2C_wait_complete +( + i2c_instance_t * this_i2c, + uint32_t timeout_ms +); + +/***************************************************************************//** + This function is used to control the expiration of the time out delay + specified as a parameter to the I2C_wait_complete() function. It must be + called from the interrupt service routine of a periodic interrupt source such + as the SysTick timer interrupt. It takes the period of the interrupt + source as its ms_since_last_tick parameter and uses it as the time base for + the I2C_wait_complete() function's time out delay. + + Note: This function does not need to be called if the I2C_wait_complete() + function is called with a timeout_ms value of I2C_NO_TIMEOUT. + + Note: If this function is not called then the I2C_wait_complete() function + will behave as if its timeout_ms was specified as I2C_NO_TIMEOUT and it + will not time out. + + Note: If this function is being called from an interrupt handler (for example, + SysTick) it is important that the calling interrupt have a lower priority + than the CoreI2C interrupt(s) to ensure any updates to the shared data are + protected. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + @param ms_since_last_tick + The ms_since_last_tick parameter specifies the number of milliseconds that + elapsed since the last call to I2C_system_tick(). This parameter would + typically be a constant specifying the interrupt rate of a timer used to + generate system ticks. + + @return None. + + @example + The following example shows how the I2C_system_tick() function. I2C_system_tick() + is called for each I2C channel from the SysTick timer interrupt service routine. + The following example shows how the SysTick is configured to generate an interrupt + in every 10 milliseconds. + @code + #define SYSTICK_INTERVAL_MS 10 + + void SysTick_Handler(void) + { + I2C_system_tick(&g_core_i2c0, SYSTICK_INTERVAL_MS); + I2C_system_tick(&g_core_i2c2, SYSTICK_INTERVAL_MS); + } + @endcode + */ +void I2C_system_tick +( + i2c_instance_t * this_i2c, + uint32_t ms_since_last_tick +); + +/***************************************************************************//* + #Slave Specific Functions + + The following functions are only used within the implementation of an I2C slave device. + +/***************************************************************************//** + This function specifies the memory buffer holding the data that will be sent + to the I2C master when this CoreI2C channel is the target of an I2C read or + write-read transaction. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param tx_buffer + This parameter is a pointer to the memory buffer holding the data to be + returned to the I2C master when this CoreI2C channel is the target of an + I2C read or write-read transaction. + + @param tx_size + Size of the transmit buffer pointed by the tx_buffer parameter. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Specify the transmit buffer containing the data that will be + // returned to the master during read and write-read transactions. + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + } + @endcode + */ +void I2C_set_slave_tx_buffer +( + i2c_instance_t * this_i2c, + const uint8_t * tx_buffer, + uint16_t tx_size +); + +/***************************************************************************//** + This function specifies the memory buffer that is used by the CoreI2C channel + to receive data when it is a slave. This buffer is the memory where data gets + stored when the CoreI2C channel is the target of an I2C master write + transaction (that is, when it is the slave). + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param rx_buffer + This parameter is a pointer to the memory buffer allocated by the caller + software to be used as a slave receive buffer. + + @param rx_size + Size of the slave receive buffer. This is the amount of memory allocated + to the buffer pointed by rx_buffer. + Note: Indirectly, this buffer size specifies the maximum I2C write + transaction length this CoreI2C channel targets. This is because + this CoreI2C channel responds to further received bytes with + a non-acknowledge bit (NACK) as soon as its receive buffer is + full. This causes the write transaction to fail. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_RX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_rx_buffer[SLAVE_RX_BUFFER_SIZE]; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Specify the buffer used to store the data written by the I2C master. + I2C_set_slave_rx_buffer( &g_i2c_inst, g_slave_rx_buffer, + sizeof(g_slave_rx_buffer) ); + } + @endcode + */ +void I2C_set_slave_rx_buffer +( + i2c_instance_t * this_i2c, + uint8_t * rx_buffer, + uint16_t rx_size +); + +/***************************************************************************//** + This function is used as part of the configuration of a CoreI2C channel to + operate as a slave supporting write-read transactions. It specifies the + number of bytes expected as part of the write phase of a write-read + transaction. The bytes received during the write phase of a write-read + transaction will be interpreted as an offset into the slave's transmit buffer. + This allows random access into the I2C slave transmit buffer from a remote + I2C master. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param offset_length + The offset_length parameter configures the number of bytes to be interpreted + by the CoreI2C slave as a memory offset value during the write phase of + write-read transactions. The maximum value for the offset_length parameter + is two. The value of offset_length has the following effect on the + interpretation of the received data. + • If offset_length is 0, the offset into the transmit buffer is fixed at 0. + • If offset_length is 1, a single byte of received data is interpreted as an + unsigned 8-bit offset value in the range 0 to 255. + • If offset_length is 2, 2 bytes of received data are interpreted as an + unsigned 16-bit offset value in the range 0 to 65535. The first byte + received in this case provides the high order bits of the offset and + the second byte provides the low order bits. + If the number of bytes received does not match the non 0 value of + offset_length, the transmit buffer offset is set to 0. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + I2C_set_slave_mem_offset_length( &g_i2c_inst, 1 ); + } + @endcode + */ +void I2C_set_slave_mem_offset_length +( + i2c_instance_t * this_i2c, + uint8_t offset_length +); + +/***************************************************************************//** + Register the function that is called to process the data written to this + CoreI2C channel when it is the slave in an I2C write transaction. + + Note: If a write handler is registered, it is called on completion of the + write phase of a write-read transaction and responsible for processing + the received data in the slave receive buffer and populating the slave + transmit buffer with the data that is transmitted to the I2C master + as part of the read phase of the write-read transaction. If a write + handler is not registered, the write data of a write-read transaction is + interpreted as an offset into the slave’s transmit buffer and handled by + the driver. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param handler + Pointer to the function that processes the I2C write request. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + // local function prototype + void slave_write_handler + ( + i2c_instance_t * this_i2c, + uint8_t * p_rx_data, + uint16_t rx_size + ); + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + I2C_set_slave_mem_offset_length( &g_i2c_inst, 1 ); + I2C_register_write_handler( &g_i2c_inst, slave_write_handler ); + } + @endcode +*/ +void I2C_register_write_handler +( + i2c_instance_t * this_i2c, + i2c_slave_wr_handler_t handler +); + +/***************************************************************************//** + This function enables slave mode operation for a CoreI2C channel. It enables + the CoreI2C slave to receive data when it is the target of an I2C read, write, + or write-read transaction. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + // Enable I2C slave + I2C_enable_slave( &g_i2c_inst ); + @endcode + */ +void I2C_enable_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + This function disables the slave mode operation for a CoreI2C channel. It stops + the CoreI2C slave that acknowledges the I2C read, write, or write-read + transactions targeted at it. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + // Disable I2C slave + I2C_disable_slave( &g_i2c_inst ); + @endcode + */ +void I2C_disable_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_slave_second_addr() function sets the secondary slave address for + a CoreI2C slave device. This is an additional slave address required in certain + applications, for example, to enable fail-safe operation in a system. As the + CoreI2C device supports 7-bit addressing, the highest value assigned to second + slave address is 127 (0x7F). + + Note: This function does not support CoreI2C hardware configured with a fixed + second slave address. The current implementation of the ADDR1[0] register + bit makes it difficult for the driver to support both programmable and + fixed second slave address, so we choose to support programmable only. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param second_slave_addr + The second_slave_addr parameter is the secondary slave address of the I2C + device. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SECOND_SLAVE_ADDR 0x20u + + i2c_instance_t g_i2c_inst; + void main( void ) + { + // Initialize the CoreI2C driver with its base address, primary I2C + // serial address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_second_addr( &g_i2c_inst, SECOND_SLAVE_ADDR ); + } + @endcode + */ +void I2C_set_slave_second_addr +( + i2c_instance_t * this_i2c, + uint8_t second_slave_addr +); + +/***************************************************************************//** + The I2C_disable_slave_second_addr() function disables the secondary slave + address of the CoreI2C slave device. + + Note: This version of the driver only supports CoreI2C hardware configured + with a programmable second slave address. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + i2c_instance_t g_i2c_inst; + I2C_disable_slave_second_addr( &g_i2c_inst); + @endcode + */ +void I2C_disable_slave_second_addr +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_gca() function is used to set the general call acknowledgement bit + of a CoreI2C slave device. This allows all channels of the CoreI2C slave + device to respond to a general call or broadcast message from an I2C master. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + i2c_instance_t g_i2c_inst; + + // Enable recognition of the General Call Address + I2C_set_gca( &g_i2c_inst ); + @endcode + */ +void I2C_set_gca +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_clear_gca() function is used to clear the general call acknowledgement + bit of a CoreI2C slave device. This will stop all channels of the I2C slave + device responding to any general call or broadcast message from the master. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + i2c_instance_t g_i2c_inst; + + // Disable recognition of the General Call Address + I2C_clear_gca( &g_i2c_inst ); + @endcode + */ + +void I2C_clear_gca +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//* + #I2C SMBUS Specific APIs + +/***************************************************************************//** + The I2C_smbus_init() function enables SMBus timeouts and status logic for a + CoreI2C channel. + + Note: This and any of the other SMBus related functionality will only have an + effect if the CoreI2C was instantiated with the Generate SMBus Logic + option checked. + + Note: If the CoreI2C was instantiated with the Generate IPMI Logic option + checked this function then enables the IPMI 3mS SCL low timeout but + none of the other SMBus functions will have any effect. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void system_init( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst); + } + @endcode + */ +void I2C_smbus_init +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_enable_smbus_irq() function is used to enable the CoreI2C channel’s + SMBSUS and SMBALERT SMBus interrupts. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param irq_type + The irq_type specify the SMBUS interrupt(s) which will be enabled. + The two possible interrupts are: + - I2C_SMBALERT_IRQ + - I2C_SMBSUS_IRQ + To enable both interrupts in one call, use I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ. + + @return + None + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both I2C_SMBALERT_IRQ & I2C_SMBSUS_IRQ interrupts + I2C_enable_smbus_irq( &g_i2c_inst, + (uint8_t)(I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ) ); + } + @endcode + */ +void I2C_enable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +); + +/***************************************************************************//** + The I2C_disable_smbus_irq() function disable the CoreI2C channel’s SMBSUS and + SMBALERT SMBus interrupts. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param irq_type + The irq_type specifies the SMBUS interrupt(s) which are disabled. + The two possible interrupts are: + • I2C_SMBALERT_IRQ + • I2C_SMBSUS_IRQ + To disable both ints in one call, use I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both SMBALERT & SMBSUS interrupts + I2C_enable_smbus_irq( &g_i2c_inst, + (uint8_t)(I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ)); + + ... + + // Disable the SMBALERT interrupt + I2C_disable_smbus_irq( &g_i2c_inst, I2C_SMBALERT_IRQ ); + } + @endcode + */ +void I2C_disable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +); + +/***************************************************************************//** + The I2C_suspend_smbus_slave() function forces any SMBUS slave devices + connected to a CoreI2C channel into Power-Down or Suspend mode by asserting + the channel's SMBSUS signal. The CoreI2C channel is the SMBus master in this + case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // suspend SMBus slaves + I2C_suspend_smbus_slave( &g_i2c_inst ); + + ... + + // Re-enable SMBus slaves + I2C_resume_smbus_slave( &g_i2c_inst ); + } + @endcode + */ +void I2C_suspend_smbus_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_resume_smbus_slave() function de-asserts the CoreI2C channel's SMBSUS + signal to take any connected slave devices out of the Suspend mode. The CoreI2C + channel is the SMBus master in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // suspend SMBus slaves + I2C_suspend_smbus_slave( &g_i2c_inst ); + + ... + + // Re-enable SMBus slaves + I2C_resume_smbus_slave( &g_i2c_inst ); + } + @endcode + */ +void I2C_resume_smbus_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_reset_smbus() function resets the CoreI2C channel's SMBus connection + by forcing SCLK low for 35 mS. The reset that automatically cleares after 35 ms + gets elapsed. The CoreI2C channel is the SMBus master in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Make sure the SMBus channel is in a known state by resetting it + I2C_reset_smbus( &g_i2c_inst ); + } + @endcode + */ +void I2C_reset_smbus +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_smbus_alert() function is used to force master communication with + an I2C slave device by asserting the CoreI2C channel's SMBALERT signal. The + CoreI2C channel is the SMBus slave in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Get the SMBus masters attention + I2C_set_smbus_alert( &g_i2c_inst ); + + ... + + // Once we are happy, drop the alert + I2C_clear_smbus_alert( &g_i2c_inst ); + } + @endcode + */ +void I2C_set_smbus_alert +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_clear_smbus_alert() function is used to de-assert the CoreI2C channel's + SMBALERT signal once a slave device gets a response from the master. The + CoreI2C channel is the SMBus slave in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Get the SMBus masters attention + I2C_set_smbus_alert( &g_i2c_inst ); + + ... + + // Once we are happy, drop the alert + I2C_clear_smbus_alert( &g_i2c_inst ); + } + @endcode + */ +void I2C_clear_smbus_alert +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_get_irq_status function returns information about which interrupts are + currently pending in a CoreI2C channel. + The interrupts supported by CoreI2C are: + • SMBUSALERT + • SMBSUS + • INTR + + The macros I2C_NO_IRQ, I2C_SMBALERT_IRQ, I2C_SMBSUS_IRQ, and I2C_INTR_IRQ are + provided to use with this function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + This function returns the status of the CoreI2C channel's interrupts as a + single byte bitmap where a bit is set to indicate a pending interrupt. + The following are the bit positions associated with each interrupt type: + Bit 0 - SMBUS_ALERT_IRQ + Bit 1 - SMBSUS_IRQ + Bit 2 - INTR_IRQ + It returns 0, if there are no pending interrupts. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + uint8_t irq_to_enable = I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ; + uint8_t pending_irq = 0u; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both I2C_SMBALERT_IRQ & I2C_SMBSUS_IRQ irq + I2C_enable_smbus_irq( &g_i2c_inst, irq_to_enable ); + + // Get I2C IRQ type + pending_irq = I2C_get_irq_status( &g_i2c_inst ); + + // Let's assume, in system, INTR and SMBALERT IRQ is pending. + // So pending_irq will return status of both the IRQs + + if( pending_irq & I2C_SMBALERT_IRQ ) + { + // if true, it means SMBALERT_IRQ is there in pending IRQ list + } + if( pending_irq & I2C_INTR_IRQ ) + { + // if true, it means I2C_INTR_IRQ is there in pending IRQ list + } + } + @endcode + */ +uint8_t I2C_get_irq_status +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_user_data() function allows the association of a block of application + specific data with a CoreI2C channel. The composition of the data block is an + application matter and the driver simply provides the means for the application + to set and retrieve the pointer. For example, this is used to provide additional + channel specific information to the slave write handler. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param p_user_data + The p_user_data parameter is a pointer to the user specific data block for + this channel. It is defined as void * as the driver does not know the actual + type of data being pointed to and simply stores the pointer for later + retrieval by the application. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + app_data_t channel_xdata; + + void main( void ) + { + app_data_t *p_xdata; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Store location of user data in instance structure + I2C_set_user_data( &g_i2c_inst, (void *)&channel_xdata ); + + ... + + // Retrieve location of user data and do some work on it + p_xdata = (app_data_t *)I2C_get_user_data( &g_i2c_inst ); + if( NULL != p_xdata ) + { + p_xdata->foo = 123; + } + } + @endcode + */ +void I2C_set_user_data +( + i2c_instance_t * this_i2c, + void * p_user_data +); + +/***************************************************************************//** + The I2C_get_user_data() function is used to allows the retrieval of the address + of a block of application specific data associated with a CoreI2C channel. + The composition of the data block is an application matter and the driver + simply provides the means for the application to set and retrieve the pointer. + For example, this is used to provide additional channel specific information + to the slave write handler. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + This function returns a pointer to the user specific data block for this + channel. It is defined as void * as the driver does not know the actual type + of data being pointed. If no user data has been registered for this channel + a NULL pointer is returned. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + app_data_t channel_xdata; + + void main( void ) + { + app_data_t *p_xdata; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Store location of user data in instance structure + I2C_set_user_data( &g_i2c_inst, (void *)&channel_xdata ); + + ... + + // Retrieve location of user data and do some work on it + p_xdata = (app_data_t *)I2C_get_user_data( &g_i2c_inst ); + if( NULL != p_xdata ) + { + p_xdata->foo = 123; + } + } + @endcode + */ +void * I2C_get_user_data +( + i2c_instance_t * this_i2c +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h new file mode 100644 index 0000000..b1d872d --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h @@ -0,0 +1,190 @@ +/******************************************************************************* + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + */ + +#ifndef __CORE_SMBUS_REGISTERS +#define __CORE_SMBUS_REGISTERS 1 + +/*------------------------------------------------------------------------------ + * CONTROL register details + */ +#define CONTROL_REG_OFFSET 0x00u + +/* + * CR0 bits. + */ +#define CR0_OFFSET 0x00u +#define CR0_MASK 0x01u +#define CR0_SHIFT 0u + +/* + * CR1 bits. + */ +#define CR1_OFFSET 0x00u +#define CR1_MASK 0x02u +#define CR1_SHIFT 1u + +/* + * AA bits. + */ +#define AA_OFFSET 0x00u +#define AA_MASK 0x04u +#define AA_SHIFT 2u + +/* + * SI bits. + */ +#define SI_OFFSET 0x00u +#define SI_MASK 0x08u +#define SI_SHIFT 3u + +/* + * STO bits. + */ +#define STO_OFFSET 0x00u +#define STO_MASK 0x10u +#define STO_SHIFT 4u + +/* + * STA bits. + */ +#define STA_OFFSET 0x00u +#define STA_MASK 0x20u +#define STA_SHIFT 5u + +/* + * ENS1 bits. + */ +#define ENS1_OFFSET 0x00u +#define ENS1_MASK 0x40u +#define ENS1_SHIFT 6u + +/* + * CR2 bits. + */ +#define CR2_OFFSET 0x00u +#define CR2_MASK 0x80u +#define CR2_SHIFT 7u + +/*------------------------------------------------------------------------------ + * STATUS register details + */ +#define STATUS_REG_OFFSET 0x04u + +/*------------------------------------------------------------------------------ + * DATA register details + */ +#define DATA_REG_OFFSET 0x08u + +/* + * TARGET_ADDR bits. + */ +#define TARGET_ADDR_OFFSET 0x08u +#define TARGET_ADDR_MASK 0xFEu +#define TARGET_ADDR_SHIFT 1u + +/* + * DIR bit. + */ +#define DIR_OFFSET 0x08u +#define DIR_MASK 0x01u +#define DIR_SHIFT 0u + + +/*------------------------------------------------------------------------------ + * ADDRESS register details + */ +#define ADDRESS_REG_OFFSET 0x0Cu + +/* + * GC bits. + */ +#define GC_OFFSET 0x0Cu +#define GC_MASK 0x01u +#define GC_SHIFT 0u + +/* + * ADR bits. + */ +#define OWN_SLAVE_ADDR_OFFSET 0x0Cu +#define OWN_SLAVE_ADDR_MASK 0xFEu +#define OWN_SLAVE_ADDR_SHIFT 1u + +/*------------------------------------------------------------------------------ + * SMBUS register details + */ +#define SMBUS_REG_OFFSET 0x10u + +/* + * SMBALERT_IE bits. + */ +#define SMBALERT_IE_OFFSET 0x10u +#define SMBALERT_IE_MASK 0x01u +#define SMBALERT_IE_SHIFT 0u + +/* + * SMBSUS_IE bits. + */ +#define SMBSUS_IE_OFFSET 0x10u +#define SMBSUS_IE_MASK 0x02u +#define SMBSUS_IE_SHIFT 1u + +/* + * SMB_IPMI_EN bits. + */ +#define SMB_IPMI_EN_OFFSET 0x10u +#define SMB_IPMI_EN_MASK 0x04u +#define SMB_IPMI_EN_SHIFT 2u + +/* + * SMBALERT_NI_STATUS bits. + */ +#define SMBALERT_NI_STATUS_OFFSET 0x10u +#define SMBALERT_NI_STATUS_MASK 0x08u +#define SMBALERT_NI_STATUS_SHIFT 3u + +/* + * SMBALERT_NO_CONTROL bits. + */ +#define SMBALERT_NO_CONTROL_OFFSET 0x10u +#define SMBALERT_NO_CONTROL_MASK 0x10u +#define SMBALERT_NO_CONTROL_SHIFT 4u + +/* + * SMBSUS_NI_STATUS bits. + */ +#define SMBSUS_NI_STATUS_OFFSET 0x10u +#define SMBSUS_NI_STATUS_MASK 0x20u +#define SMBSUS_NI_STATUS_SHIFT 5u + +/* + * SMBSUS_NO_CONTROL bits. + */ +#define SMBSUS_NO_CONTROL_OFFSET 0x10u +#define SMBSUS_NO_CONTROL_MASK 0x40u +#define SMBSUS_NO_CONTROL_SHIFT 6u + +/* + * SMBUS_MST_RESET bits. + */ +#define SMBUS_MST_RESET_OFFSET 0x10u +#define SMBUS_MST_RESET_MASK 0x80u +#define SMBUS_MST_RESET_SHIFT 7u + +/*------------------------------------------------------------------------------ + * SLAVE ADDRESS 1 register details + */ + +#define ADDRESS1_REG_OFFSET 0x1Cu + +/* + * SLAVE1_EN bit of Slave Address 1 . + */ +#define SLAVE1_EN_OFFSET 0x1Cu +#define SLAVE1_EN_MASK 0x01u +#define SLAVE1_EN_SHIFT 0u + +#endif /* __CORE_SMBUS_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c new file mode 100644 index 0000000..12e352d --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * CoreI2C driver interrupt control. + * + */ +#include "core_i2c.h" + +/*------------------------------------------------------------------------------ + * This function must be modified to enable interrupts generated from the + * CoreI2C instance identified as parameter. + */ +void I2C_enable_irq( i2c_instance_t * this_i2c ) +{ + HAL_ASSERT(0) +} + +/*------------------------------------------------------------------------------ + * This function must be modified to disable interrupts generated from the + * CoreI2C instance identified as parameter. + */ +void I2C_disable_irq( i2c_instance_t * this_i2c ) +{ + HAL_ASSERT(0) +} diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreSPI/core_spi.c b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreSPI/core_spi.c new file mode 100644 index 0000000..2e11750 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreSPI/core_spi.c @@ -0,0 +1,1345 @@ +/***************************************************************************//** + * Copyright 2013-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * CoreSPI bare metal driver implementation for CoreSPI. + * + * This Core SPI driver provides functions for implementing SPI master or + * SPI slave operations with the CoreSPI version 4.2.xxx It is not compatible + * with CoreSPI version 3.0.xxx. + * + * @file core_spi.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreSPI software configuration + * + */ + +#include "core_spi.h" +#include "corespi_regs.h" +#include + +/******************************************************************************* + * Null parameters with appropriate type definitions + */ +#define NULL_ADDR ( ( addr_t ) 0u ) +#define NULL_INSTANCE ( ( spi_instance_t * ) 0u ) +#define NULL_BUFF ( ( uint8_t * ) 0u ) +#define NULL_FRAME_HANDLER ( ( spi_frame_rx_handler_t ) 0u ) +#define NULL_BLOCK_HANDLER ( ( spi_block_rx_handler_t ) 0u ) +#define NULL_SLAVE_TX_UPDATE_HANDLER ( ( spi_slave_frame_tx_handler_t ) 0u ) +#define NULL_SLAVE_CMD_HANDLER NULL_BLOCK_HANDLER + +#define SPI_ALL_INTS (0xFFu) /* For clearing all active interrupts */ + +/******************************************************************************* + * Possible states for different register bit fields + */ + +#define DISABLE 0u +#define ENABLE 1u + + +/******************************************************************************* + * Function return values + */ +enum { + FAILURE = 0u, + SUCCESS = 1u +}; + +/******************************************************************************* + * Local function declarations + */ +static void fill_slave_tx_fifo( spi_instance_t * this_spi ); +static void read_slave_rx_fifo( spi_instance_t * this_spi ); +static void recover_from_rx_overflow( const spi_instance_t * this_spi ); + +/******************************************************************************* + * SPI_init() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_init +( + spi_instance_t * this_spi, + addr_t base_addr, + uint16_t fifo_depth +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( NULL_ADDR != base_addr ); + HAL_ASSERT( SPI_MAX_FIFO_DEPTH >= fifo_depth ); + HAL_ASSERT( SPI_MIN_FIFO_DEPTH <= fifo_depth ); + + if( ( NULL_INSTANCE != this_spi ) && ( base_addr != NULL_ADDR ) ) + { + /* + * Initialize all transmit / receive buffers and handlers + * + * Relies on the fact that byte filling with 0x00 will equate + * to 0 for any non byte sized items too. + */ + + /* First fill struct with 0s */ + memset( this_spi, 0, sizeof(spi_instance_t) ); + + /* Configure CoreSPI instance attributes */ + this_spi->base_addr = (addr_t)base_addr; + + /* Store FIFO depth or fall back to minimum if out of range */ + if( ( SPI_MAX_FIFO_DEPTH >= fifo_depth ) && ( SPI_MIN_FIFO_DEPTH <= fifo_depth ) ) + { + this_spi->fifo_depth = fifo_depth; + } + else + { + this_spi->fifo_depth = SPI_MIN_FIFO_DEPTH; + } + /* Make sure the CoreSPI is disabled while we configure it */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Ensure all slaves are deselected */ + HAL_set_8bit_reg( this_spi->base_addr, SSEL, 0u ); + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Ensure RXAVAIL, TXRFM, SSEND and CMDINT are disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, 0u ); + /* + * Enable the CoreSPI in the reset default of master mode + * with TXUNDERRUN, RXOVFLOW and TXDONE interrupts disabled. + * The driver does not currently use interrupts in master mode. + */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL1, ENABLE | CTRL1_MASTER_MASK ); + } +} + +/***************************************************************************//** + * SPI_configure_slave_mode() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_configure_slave_mode +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Don't yet know what slave transfer mode will be used */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_NONE; + + /* Make sure the CoreSPI is disabled while we configure it */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Ensure RXAVAIL, TXRFM, SSEND and CMDINT are disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, 0u ); + /* + * Enable the CoreSPI in slave mode with TXUNDERRUN, RXOVFLOW and TXDONE + * interrupts disabled. The appropriate interrupts will be enabled later + * on when the transfer mode is configured. + */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL1, ENABLE ); + } +} + +/***************************************************************************//** + * SPI_configure_master_mode() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_configure_master_mode +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Disable the CoreSPI for a little while, while we configure the CoreSPI */ + HAL_set_8bit_reg_field(this_spi->base_addr, CTRL1_ENABLE, DISABLE); + + /* Reset slave transfer mode to unknown in case it has been set previously */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_NONE; + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Ensure RXAVAIL, TXRFM, SSEND and CMDINT are disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, 0u ); + + /* Enable the CoreSPI in master mode with TXUNDERRUN, RXOVFLOW and TXDONE interrupts disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL1, ENABLE | CTRL1_MASTER_MASK ); + } +} + +/***************************************************************************//** + * SPI_set_slave_select() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +) +{ + spi_slave_t temp = (spi_slave_t)(0x00u) ; + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( SPI_MAX_NB_OF_SLAVES > slave ); + + if( ( NULL_INSTANCE != this_spi ) && ( SPI_MAX_NB_OF_SLAVES > slave ) ) + { + /* This function is only intended to be used with an SPI master */ + if( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW ) ) + { + recover_from_rx_overflow( this_spi ); + } + /* Set the correct slave select bit */ + temp = (spi_slave_t)( HAL_get_8bit_reg( this_spi->base_addr, SSEL ) | ((uint32_t)1u << (uint32_t)slave) ); + HAL_set_8bit_reg( this_spi->base_addr, SSEL, (uint_fast8_t)temp ); + } + } +} + +/***************************************************************************//** + * SPI_clear_slave_select() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_clear_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +) +{ + spi_slave_t temp = (spi_slave_t) (0x00u) ; + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( SPI_MAX_NB_OF_SLAVES > slave ); + + if( ( NULL_INSTANCE != this_spi ) && ( SPI_MAX_NB_OF_SLAVES > slave ) ) + { + /* This function is only intended to be used with an SPI master. */ + if( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW) ) + { + recover_from_rx_overflow( this_spi ); + } + /* Clear the correct slave select bit */ + temp = (spi_slave_t)( HAL_get_8bit_reg( this_spi->base_addr, SSEL ) & ~((uint32_t)1u << (uint32_t)slave) ); + HAL_set_8bit_reg( this_spi->base_addr, SSEL, (uint_fast8_t)temp ) ; + } + } +} + +/***************************************************************************//** + * SPI_transfer_frame() + * See "core_spi.h" for details of how to use this function. + */ +uint32_t SPI_transfer_frame +( + spi_instance_t * this_spi, + uint32_t tx_bits +) +{ + volatile uint32_t rx_data = 0u; /* Ensure consistent return value if in slave mode */ + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI master. */ + if( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Flush the receive and transmit FIFOs by resetting both */ + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK); + + /* Send frame. */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, tx_bits ); + + /* Wait for frame Tx to complete. */ + while ( ENABLE != HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_DONE ) ) + { + ; + } + + /* Read received frame. */ + rx_data = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + } + } + + /* Finally, return the frame we received from the slave or 0 */ + return( rx_data ); +} + + +/***************************************************************************//** + * SPI_transfer_block() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_transfer_block +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_buffer, + uint16_t rx_byte_size +) +{ + uint32_t transfer_size = 0U; /* Total number of bytes to transfer. */ + uint16_t transfer_idx = 0U; /* Number of bytes transferred so far */ + uint16_t tx_idx = 0u; /* Number of valid data bytes sent */ + uint16_t rx_idx = 0u; /* Number of valid response bytes received */ + uint16_t transit = 0U; /* Number of bytes "in flight" to avoid FIFO errors */ + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI master. */ + if( ( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) && + /* Check for empty transfer as well */ + ( 0u != ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) ) ) + { + /* + * tansfer_size is one less than the real amount as we have to write + * the last frame separately to trigger the slave deselect in case + * the SPS option is in place. + */ + transfer_size = ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) - 1u; + /* Flush the receive and transmit FIFOs */ + HAL_set_8bit_reg(this_spi->base_addr, CMD, (uint32_t)(CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK )); + + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW) ) + { + recover_from_rx_overflow( this_spi ); + } + + /* Disable the Core SPI for a little bit, while we load the TX FIFO */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + while( ( tx_idx < transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out 0s to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + } + ++transit; + ++tx_idx; + } + + /* If room left to put last frame in before the off, then do it */ + if( ( tx_idx == transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data, not expecting any reply this time */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out last 0 to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + } + + ++transit; + ++tx_idx; + } + + /* FIFO is all loaded up so enable Core SPI to start transfer */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + + /* Perform the remainder of the transfer by sending a byte every time a byte + * has been received. This should ensure that no Rx overflow can happen in + * case of an interrupt occurring during this function. + * + * We break the transfer down into stages to minimise the processing in + * each loop as the SPI interface is very demanding at higher clock rates. + * This works well with FIFOs but might be less efficient if there is only + * a single frame buffer. + * + * First stage transfers remaining command bytes (if any). + * At this stage anything in the RX FIFO can be discarded as it is + * not part of a valid response. + */ + while( tx_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + /* Send another byte. */ + if( tx_idx == transfer_size ) /* Last frame is special... */ + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Read and discard. */ + HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now, we are writing dummy bytes to push through the response from + * the slave but we still have to keep discarding any read data that + * corresponds with one of our command bytes. + */ + while( transfer_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + if( tx_idx < transfer_size ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Read and discard. */ + HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now we are now only sending dummy data to push through the + * valid response data which we store in the response buffer. + */ + while( tx_idx < transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received byte. */ + rx_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* If we still need to send the last frame */ + while( tx_idx == transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received byte. */ + rx_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* + * Finally, we are now finished sending data and are only reading + * valid response data which we store in the response buffer. + */ + while( transfer_idx <= transfer_size ) + { + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received byte. */ + rx_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + } + } + } + } +} + +/***************************************************************************//** + * SPI_transfer_block_store_all_resp() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_transfer_block_store_all_resp +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_data_buffer, + uint16_t rx_byte_size, + uint8_t * cmd_response_buffer +) +{ + uint32_t transfer_size = 0U; /* Total number of bytes to transfer. */ + uint16_t transfer_idx = 0U; /* Number of bytes transferred so far */ + uint16_t tx_idx = 0u; /* Number of valid data bytes sent */ + uint16_t rx_idx = 0u; /* Number of valid response bytes received */ + uint16_t transit = 0U; /* Number of bytes "in flight" to avoid FIFO errors */ + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI master. */ + if( ( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) && + /* Check for empty transfer as well */ + ( 0u != ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) ) ) + { + /* + * tansfer_size is one less than the real amount as we have to write + * the last frame separately to trigger the slave deselect in case + * the SPS option is in place. + */ + transfer_size = ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) - 1u; + /* Flush the receive and transmit FIFOs */ + HAL_set_8bit_reg(this_spi->base_addr, CMD, (uint32_t)(CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK )); + + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW) ) + { + recover_from_rx_overflow( this_spi ); + } + + /* Disable the Core SPI for a little bit, while we load the TX FIFO */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + while( ( tx_idx < transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out 0s to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + } + ++transit; + ++tx_idx; + } + + /* If room left to put last frame in before the off, then do it */ + if( ( tx_idx == transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data, not expecting any reply this time */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out last 0 to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + } + + ++transit; + ++tx_idx; + } + + /* FIFO is all loaded up so enable Core SPI to start transfer */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + + /* Perform the remainder of the transfer by sending a byte every time a byte + * has been received. This should ensure that no Rx overflow can happen in + * case of an interrupt occurring during this function. + * + * We break the transfer down into stages to minimise the processing in + * each loop as the SPI interface is very demanding at higher clock rates. + * This works well with FIFOs but might be less efficient if there is only + * a single frame buffer. + * + * First stage transfers remaining command bytes (if any). + * At this stage anything in the RX FIFO can be discarded as it is + * not part of a valid response. + */ + while( tx_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + /* Send another byte. */ + if( tx_idx == transfer_size ) /* Last frame is special... */ + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received command byte. */ + cmd_response_buffer[transfer_idx] = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now, we are writing dummy bytes to push through the response from + * the slave, which we store in the command response buffer. + */ + while( transfer_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + if( tx_idx < transfer_size ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received command byte. */ + cmd_response_buffer[transfer_idx] = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now we are now only sending dummy data to push through the + * valid response data which we store in the data response buffer. + */ + while( tx_idx < transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received data byte. */ + rx_data_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* If we still need to send the last frame */ + while( tx_idx == transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received data byte. */ + rx_data_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* + * Finally, we are now finished sending data and are only reading + * valid response data which we store in the data response buffer. + */ + while( transfer_idx <= transfer_size ) + { + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received data byte. */ + rx_data_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + } + } + } + } +} +/***************************************************************************//** + * SPI_set_frame_rx_handler() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_frame_rx_handler +( + spi_instance_t * this_spi, + spi_frame_rx_handler_t rx_handler +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if(NULL_INSTANCE != this_spi) + { + /* This function is only intended to be used with an SPI slave. */ + if(DISABLE == HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER)) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Disable SSEND and CMD interrupts as we are not doing block transfers */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTSSEND, DISABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + + /* Disable block Rx handler as they are mutually exclusive. */ + this_spi->block_rx_handler = 0U; + + /* Keep a copy of the pointer to the Rx handler function. */ + this_spi->frame_rx_handler = rx_handler; + + if( SPI_SLAVE_XFER_FRAME != this_spi->slave_xfer_mode ) + { + /* + * Either just coming from init or were previously in block mode + * so no tx frame handler is set at this point in time... + * + * Don't allow TXDONE interrupts. + */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXDONE, DISABLE ); + } + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK); + + /* Enable Rx and FIFO error interrupts */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTRXOVFLOW, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXURUN, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTRXDATA, ENABLE ); + + /* Make sure correct mode is selected */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_FRAME; + + /* Finally re-enable the CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } + } +} + +/***************************************************************************//** + * SPI_set_slave_tx_frame() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_slave_tx_frame +( + spi_instance_t * this_spi, + uint32_t frame_value, + spi_slave_frame_tx_handler_t slave_tx_frame_handler +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI slave. */ + if( DISABLE == HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Disable SSEND and CMD interrupts as we are not doing block transfers */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTSSEND, DISABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + + if( SPI_SLAVE_XFER_FRAME != this_spi->slave_xfer_mode ) + { + /* + * Either just coming from init or were previously in block mode + * so no rx frame handler is set at this point in time... + * + * Don't allow RXDATA interrupts. + */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTRXDATA, DISABLE ); + } + + /* Disable slave block tx buffer as it is mutually exclusive with frame + * level handling. */ + this_spi->slave_tx_buffer = NULL_BUFF; + this_spi->slave_tx_size = 0U; + this_spi->slave_tx_idx = 0U; + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK); + + /* Assign the slave frame update handler - NULL_SLAVE_TX_UPDATE_HANDLER for none */ + this_spi->slave_tx_frame_handler = slave_tx_frame_handler; + + /* Keep a copy of the slave Tx frame value. */ + this_spi->slave_tx_frame = frame_value; + + /* Load one frame into Tx data register. */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, this_spi->slave_tx_frame ); + + /* Enable Tx Done interrupt in order to reload the slave Tx frame after each + * time it has been sent. */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXDONE, ENABLE ); + + /* Make sure correct mode is selected */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_FRAME; + + /* Ready to go so enable CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } + } +} + +/***************************************************************************//** + * SPI_set_slave_block_buffers() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_slave_block_buffers +( + spi_instance_t * this_spi, + const uint8_t * tx_buffer, + uint32_t tx_buff_size, + uint8_t * rx_buffer, + uint32_t rx_buff_size, + spi_block_rx_handler_t block_rx_handler +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI slave. */ + if( DISABLE == HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Make sure correct mode is selected */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_BLOCK; + /* + * No command handler should be setup at this stage so fake this + * to ensure 0 padding works. + */ + this_spi->cmd_done = 1u; + + /* Disable frame handlers as they are mutually exclusive with block Rx handler. */ + this_spi->frame_rx_handler = NULL_FRAME_HANDLER; + this_spi->slave_tx_frame_handler = NULL_SLAVE_TX_UPDATE_HANDLER; + + /* Keep a copy of the pointer to the block Rx handler function. */ + this_spi->block_rx_handler = block_rx_handler; + + /* Assign slave receive buffer */ + this_spi->slave_rx_buffer = rx_buffer; + this_spi->slave_rx_size = rx_buff_size; + this_spi->slave_rx_idx = 0U; + + /* Assign slave transmit buffer*/ + this_spi->slave_tx_buffer = tx_buffer; + this_spi->slave_tx_size = tx_buff_size; + this_spi->slave_tx_idx = 0U; + + /* Flush the receive and transmit FIFOs */ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Preload the transmit FIFO. */ + while( !(HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_TXFULL)) && + ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->slave_tx_buffer[this_spi->slave_tx_idx] ); + ++this_spi->slave_tx_idx; + } + /* + * Disable TXDATA interrupt as we will look after transmission in rx handling + * because we know that once we have read a frame it is safe to send another one. + */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTTXDATA, DISABLE ); + + /* Enable Rx, FIFO error and SSEND interrupts */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTRXOVFLOW, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXURUN, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTRXDATA, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTSSEND, ENABLE ); + + /* Disable command handler until it is set explicitly */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + + /* Now enable the CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } + } +} + +/***************************************************************************//** + * SPI_set_cmd_handler() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_cmd_handler +( + spi_instance_t * this_spi, + spi_block_rx_handler_t cmd_handler, + uint32_t cmd_size +) +{ + uint32_t ctrl2 = 0u; + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( NULL_SLAVE_CMD_HANDLER != cmd_handler ); + HAL_ASSERT( 0u < cmd_size ); + + if( ( NULL_INSTANCE != this_spi ) && ( 0u < cmd_size ) && + ( NULL_SLAVE_CMD_HANDLER != cmd_handler ) ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + /* + * Note we don't flush the FIFOs as this has been done already when + * block mode was configured. + * + * Clear this flag so zero padding is disabled until command response + * has been taken care of. + */ + this_spi->cmd_done = 0u; + + /* Assign user handler for Command received interrupt */ + this_spi->cmd_handler = cmd_handler; + + /* Configure the command size and Enable Command received interrupt */ + ctrl2 = HAL_get_8bit_reg( this_spi->base_addr, CTRL2 ); + + /* First clear the count field then insert count and int enables */ + ctrl2 &= ~(uint32_t)CTRL2_CMDSIZE_MASK; + ctrl2 |= (uint32_t)((cmd_size & CTRL2_CMDSIZE_MASK) | CTRL2_INTCMD_MASK | CTRL2_INTRXDATA_MASK); + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, ctrl2 ); + + /* Now enable the CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } +} + +/***************************************************************************//** + * SPI_set_cmd_response() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_cmd_response +( + spi_instance_t * this_spi, + const uint8_t * resp_tx_buffer, + uint32_t resp_buff_size +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( NULL_BUFF != resp_tx_buffer ); + HAL_ASSERT( 0u < resp_buff_size ); + + if( ( NULL_INSTANCE != this_spi ) && ( 0u < resp_buff_size ) && + ( NULL_BUFF != resp_tx_buffer ) ) + { + this_spi->resp_tx_buffer = resp_tx_buffer; + this_spi->resp_buff_size = resp_buff_size; + this_spi->resp_buff_tx_idx = 0u; + + fill_slave_tx_fifo(this_spi); + } +} + + +/***************************************************************************//** + * SPI_enable() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_enable +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } +} + + +/***************************************************************************//** + * SPI_disable() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_disable +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + } +} + + +/***************************************************************************//** + * SPI interrupt service routine. + */ +void SPI_isr +( + spi_instance_t * this_spi +) +{ + uint32_t rx_frame; + int32_t guard; + +/* + * The assert and the NULL check here can be commented out to reduce the interrupt + * latency once you are sure the interrupt vector code is correct. + */ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + if( NULL_INSTANCE != this_spi ) + { + /* Handle receive. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_RXDATA ) ) + { + /* + * Service receive data according to transfer mode in operation. + * + * We check block mode first as this is most likely to have back to back + * transfers with multiple bytes. + * + * Note the order of the checks here will effect interrupt latency and + * for critical timing the mode you are using most often should probably be + * be the first checked. + */ + if( SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode ) /* Block handling mode. */ + { + while( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Read irrespective to clear the RX IRQ */ + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + if( this_spi->slave_rx_idx < this_spi->slave_rx_size ) + { + this_spi->slave_rx_buffer[this_spi->slave_rx_idx] = (uint8_t)rx_frame; + } + ++this_spi->slave_rx_idx; + } + /* + * Now handle updating of tx FIFO to keep the data flowing. + * First see if there is anything in slave_tx_buffer to send. + */ + while( ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) + && ( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->slave_tx_buffer[this_spi->slave_tx_idx] ); + ++this_spi->slave_tx_idx; + } + /* + * Next see if there is anything in resp_tx_buffer to send. + */ + if( this_spi->slave_tx_idx >= this_spi->slave_tx_size ) + { + while( ( this_spi->resp_buff_tx_idx < this_spi->resp_buff_size ) + && ( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->resp_tx_buffer[this_spi->resp_buff_tx_idx] ); + ++this_spi->resp_buff_tx_idx; + } + } + /* + * Lastly, see if we are ready to pad with 0s . + */ + if( this_spi->cmd_done && ( this_spi->slave_tx_idx >= this_spi->slave_tx_size ) && + ( this_spi->resp_buff_tx_idx >= this_spi->resp_buff_size ) ) + { + guard = 1 + ((int32_t)this_spi->fifo_depth / 4); + while( ( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) + && ( 0 != guard ) ) + { + /* + * Pad TX FIFO with 0s for consistent behaviour if the master + * tries to transfer more than we expected. + */ + HAL_set_32bit_reg(this_spi->base_addr, TXDATA, 0x00u); + /* + * We use the guard count to cover the event that we are never + * seeing the TX FIFO full because the data is being pulled + * out as fast as we can stuff it in. In this case we never spend + * more than our allocated time spinning here. + */ + guard--; + } + } + } + else if( SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode ) /* Single frame handling mode. */ + { + while( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + if( NULL_FRAME_HANDLER != this_spi->frame_rx_handler ) + { + this_spi->frame_rx_handler( rx_frame ); + } + } + } + else /* Slave transfer mode not set up so discard anything in RX FIFO */ + { + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_RXFIFORST_MASK ); + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_RXDATA, ENABLE ); + } + + /* Handle transmit. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_TXDONE ) ) + { + /* + * Note, the driver only currently uses the txdone interrupt when + * in frame transmit mode. In block mode all TX handling is done by the + * receive interrupt handling code as we know that for every frame received + * a frame must be placed in the TX FIFO. + */ + if( SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode ) + { + /* Execute the user callback to update the slave_tx_frame */ + if( NULL_SLAVE_TX_UPDATE_HANDLER != this_spi->slave_tx_frame_handler ) + { + this_spi->slave_tx_frame_handler ( this_spi ); + } + + /* Reload slave tx frame into Tx data register. */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, this_spi->slave_tx_frame ); + } + else if( SPI_SLAVE_XFER_BLOCK != this_spi->slave_xfer_mode ) + { + /* Slave transfer mode not set up so discard anything in TX FIFO */ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK ); + } + else + { + /* Nothing to do, no slave mode configured */ + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_TXDONE, ENABLE ); + } + + + /* Handle receive overflow. */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, INTMASK_RXOVERFLOW)) + { + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_RXFIFORST_MASK); + HAL_set_8bit_reg_field(this_spi->base_addr, INTCLR_RXOVERFLOW, ENABLE); + } + + /* Handle transmit under run. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_TXUNDERRUN ) ) + { + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK ); + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_TXUNDERRUN, ENABLE ); + } + + /* Handle command interrupt. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_CMDINT ) ) + { + read_slave_rx_fifo( this_spi ); + + /* + * Call the command handler if one exists. + */ + if( NULL_SLAVE_CMD_HANDLER != this_spi->cmd_handler ) + { + this_spi->cmd_handler( this_spi->slave_rx_buffer, this_spi->slave_rx_idx ); + } + this_spi->cmd_done = 1u; + /* Disable command interrupt until slave select becomes de-asserted to avoid retriggering. */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_CMDINT, ENABLE ); + } + + /* Handle slave select becoming de-asserted. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_SSEND) ) + { + /* Only supposed to do all this if transferring blocks... */ + if(SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode) + { + uint32_t rx_size; + + /* Empty any remaining bytes in RX FIFO */ + read_slave_rx_fifo( this_spi ); + rx_size = this_spi->slave_rx_idx; + /* + * Re-enable command interrupt if required. + * Must be done before re loading FIFO to ensure stale response + * data is not pushed into the FIFO. + */ + if(NULL_SLAVE_CMD_HANDLER != this_spi->cmd_handler) + { + this_spi->cmd_done = 0u; + this_spi->resp_tx_buffer = 0u; + this_spi->resp_buff_size = 0u; + this_spi->resp_buff_tx_idx = 0u; + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_CMDINT, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, ENABLE ); + } + /* + * Reset the transmit index to 0 to restart transmit at the start of the + * transmit buffer in the next transaction. This also requires flushing + * the Tx FIFO and refilling it with the start of Tx data buffer. + */ + this_spi->slave_tx_idx = 0u; + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + fill_slave_tx_fifo( this_spi ); + + /* Prepare to receive next packet. */ + this_spi->slave_rx_idx = 0u; + /* + * Call the receive handler if one exists. + */ + if( NULL_BLOCK_HANDLER != this_spi->block_rx_handler ) + { + this_spi->block_rx_handler( this_spi->slave_rx_buffer, rx_size ); + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_RXDATA, ENABLE ); + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_SSEND, ENABLE ); + } + } +} + +/******************************************************************************* + * Local function definitions + */ + +/***************************************************************************//** + * Fill the transmit FIFO (used for slave block transfers). + */ +static void fill_slave_tx_fifo +( + spi_instance_t * this_spi +) +{ + /* First see if slave_tx_buffer needs transmitting */ + while( ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) && + !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->slave_tx_buffer[this_spi->slave_tx_idx] ); + ++this_spi->slave_tx_idx; + } + + /* Then see if it is safe to look at putting resp_tx_buffer in FIFO? */ + if( this_spi->slave_tx_idx >= this_spi->slave_tx_size ) + { + while( ( this_spi->resp_buff_tx_idx < this_spi->resp_buff_size ) && + !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->resp_tx_buffer[this_spi->resp_buff_tx_idx] ); + ++this_spi->resp_buff_tx_idx; + } + } +} + +/***************************************************************************//** + * + */ +static void read_slave_rx_fifo +( + spi_instance_t * this_spi +) +{ + uint32_t rx_frame; + + if( SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode ) /* Block handling mode. */ + { + while( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); /* Read irresepective to clear the RX IRQ */ + if( this_spi->slave_rx_idx < this_spi->slave_rx_size ) + { + this_spi->slave_rx_buffer[this_spi->slave_rx_idx] = (uint8_t)rx_frame; + } + ++this_spi->slave_rx_idx; + } + } + else if( SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode ) /* Frame handling mode */ + { + while( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Single frame handling mode. */ + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + if( NULL_FRAME_HANDLER != this_spi->frame_rx_handler ) + { + this_spi->frame_rx_handler( rx_frame ); + } + } + } + else /* Slave transfer mode not set up so discard anything in RX FIFO */ + { + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_RXFIFORST_MASK ); + } +} + +/***************************************************************************//** + * This function is to recover the CoreSPI from receiver overflow. + * It temporarily disables the CoreSPI from interacting with external world, flushes + * the transmit and receiver FIFOs, clears all interrupts and then re-enables + * the CoreSPI instance referred by this_spi parameter. + */ +static void recover_from_rx_overflow +( + const spi_instance_t * this_spi +) +{ + /* Disable CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Reset TX and RX FIFOs */ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Enable CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); +} + + diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreSPI/core_spi.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreSPI/core_spi.h new file mode 100644 index 0000000..c6873f7 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreSPI/core_spi.h @@ -0,0 +1,1324 @@ +/***************************************************************************//** + * Copyright 2013-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Core SPI bare metal software driver public API. + * + * This Core SPI driver provides functions for implementing SPI master or + * SPI slave operations with the CoreSPI version 4.2.xxx It is not compatible + * with CoreSPI version 3.0.xxx. + * + * The Core SPI driver supports two classes of data transfer operation: + * SPI frame operation or SPI block transfer operations. + * + * Frame operations allow transferring individual SPI frames from 4 to 32-bits + * in length. Block operations allow transferring blocks of data organized as + * 8-bit frames. + * + * @file core_spi.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreSPI prototypes + * + */ + +/*=========================================================================*//** + @mainpage Core SPI Bare Metal Driver. + + ============================================================================== + Introduction + ============================================================================== + CoreSPI is an IP component that implements a full-duplex, synchronous, and + configurable serial peripheral interface (SPI) with frame sizes from 4 to 32 + bits and bus interface sizes of 8-, 16-, or 32-bit. Each CoreSPI instance + communicates with up to eight slave devices. + + This driver provides a set of functions for controlling CoreSPI as part of + the bare metal system where no operating system is available. These drivers + can be adapted to be used as a part of an operating system, but the + implementation of the adaptation layer between driver and the operating + system's driver model is outside the scope of this User's Guide. + + ============================================================================== + Driver Configuration + ============================================================================== + Your application software should configure the CoreSPI driver through calls + to the SPI_init() function for each CoreSPI instance in the hardware design. + This function configures a default set of parameters that include a CoreSPI + hardware instance base address and the depth of the FIFOs for this instance. + + The CoreSPI instance is configured at the time of instantiation in hardware + design for APB width, frame size, FIFO depth, serial clock speed, serial + clock polarity, serial clock phase, and slave select state parameters. + + CoreSPI can communicate with up to eight different slave devices that match + the CoreSPI configuration at the time of hardware instantiation. + + The functions SPI_configure_slave_mode() and SPI_configure_master_mode() are + used to configure the CoreSPI instance as a master or slave as required by + the application. + + When CoreSPI wishes to communicate with a specific slave device, call + the SPI_set_slave_select() function with the slave number as an argument. + This function selects the slave device. A previously selected slave gets + unselected by calling the SPI_clear_slave_select() function. + + ============================================================================== + Theory of Operation + ============================================================================== + The CoreSPI driver functions are grouped into the following categories: + • Initialization + • Configuration for either master or slave operations + • SPI master frame transfer control + • SPI master block transfer control + • SPI slave frame transfer control + • SPI slave block transfer control + + Frame transfers allow CoreSPI to write or read up to 32-bits of data in a + single SPI transaction. For example, a frame transfer of 12-bits might be used + to read the result of an ADC conversion from a SPI analog to digital converter. + + Block transfers allow CoreSPI to write and/or read a number of bytes in a single + SPI transaction. With the driver as is, block transfer transactions allow data + transfers in multiples of 8-bits (8, 16, 24, 32, 40,...) and the CoreSPI instance + has to be configured for 8-bit frames. For other frame sizes, the + SPI_transfer_block() code can act as a template for developing a frame block + transfer function. + Block transfers are typically used with byte oriented devices like SPI + FLASH devices. + + Note: The CoreSPI instance in the hardware design must be configured for + the frame size required by the application; configuration by driver is + not possible. + + -------------------------------- + Initialization + -------------------------------- + The CoreSPI driver is initialized through a call to the SPI_init() function. + The SPI_init() function takes a pointer to the global CoreSPI instance data + structure of type spi_instance_t and the base address of the CoreSPI instance + as defined by the hardware design. The CoreSPI instance global data structure + is used by the driver to store state information for each CoreSPI instance. + A pointer to these data structures is also used as the first parameter to + any of the driver functions to identify which CoreSPI will be used by the + called function. It is the responsibility of the application programmer to + create and maintain these global CoreSPI instance data structures. Any call + to a CoreSPI driver function should be of the form SPI_function_name + ( &g_core_spi0, ... ). + The SPI_init() function resets the transmit and receives FIFOs of CoreSPI + instance being initialized. + The SPI_init() function must be called before any other CoreSPI driver + functions can be called. + + ---------------------------------------------------- + Configuration + ---------------------------------------------------- + A CoreSPI instance can operate either as a master or as a slave SPI device. + There are two distinct functions for configuring a CoreSPI instance for + master or slave operations. + + ## Master Configuration + The SPI_configure_master_mode() function configures the specified CoreSPI + block for operations as an SPI master. This function must be called once + before the CoreSPI block communicates with an SPI slave device. + + ## Slave Configuration + The SPI_configure_slave_mode() function configures the specified CoreSPI + block for operations as a SPI slave. This function must be called after + calling the SPI_init() to configure the CoreSPI instance referred by this_spi + parameter to operate in the slave mode. + + ------------------------------------- + SPI Master Frame Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI master frame transfers: + • SPI_set_slave_select() + • SPI_transfer_frame() + • SPI_clear_slave_select() + + The master must first select the target slave or slaves to be addressed by + calling the SPI_set_slave_select() function. This causes the relevant select + line(s) to become asserted while data is clocked out onto the SPI data line. + + A function call is then made to SPI_transfer_frame() specifying the value + of the data frame to be sent and returning the value read. + + After the transfer is complete, use the SPI_clear_slave_select() function + to prevent this slave select line from being asserted during subsequent SPI + transactions. A call to this function is required only if the master is + communicating with multiple slave devices. + + ------------------------------------- + SPI Master Block Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI master block transfers: + • SPI_set_slave_select() + • SPI_transfer_block() + • SPI_clear_slave_select() + + The master must first select the target slave or slaves by calling + SPI_set_slave_select(). This causes the relevant slave select line(s) to + become asserted while data is clocked out onto the SPI data line. + Alternatively, a general purpose input/output (GPIO) can be used to control + the state of the target slave device's chip select signal. + + A call is then made to the SPI_transfer_block() function. The parameters of + this function specify the following: + • The number of bytes to be transmitted + • A pointer to the buffer containing the data to be transmitted + • The number of bytes to be received + • A pointer to the buffer where the received data gets stored + + The number of bytes to be transmitted can be set to zero to indicate that the + transfer is purely a block read transfer. The number of bytes to be received + can be set to zero to specify that the transfer is purely a block write + transfer. + + Block mode transfers as implemented by the driver are effectively half duplex + as we do not store the values received from the slave device whilst we are + transmitting. If full duplex operation is required, the driver + SPI_transfer_block() function can serve as a starting point for implementing + full duplex block transfers. + + The SPI_clear_slave_select() function can be used after the transfer is + complete to prevent this slave select line from being asserted during + subsequent SPI transactions. A call to this function is only required if + the master is communicating with multiple slave devices. + + ------------------------------------- + SPI Slave Frame Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI slave frame transfers: + • SPI_set_frame_rx_handler() + • SPI_set_slave_tx_frame() + + The SPI_set_frame_rx_handler() function specifies the receive handler + function that is called when a frame of data has been received by the + SPI when it is configured as a slave. The receive handler function specified + through this call processes the frame data written over the SPI bus to the + SPI slave by the remote SPI master. The receive handler function must be + implemented as part of the application. It is only required if the SPI slave + is the target of SPI frame write transactions. + + The SPI_set_slave_tx_frame() function specifies the frame data that is + returned to the SPI master. The frame data specified through this function + is the value that will be read over the SPI bus by the remote SPI master, + when it initiates a transaction. Call the SPI_set_slave_tx_frame() function + only if the SPI slave is the target of SPI read transactions. That is, if + data is meant to be read over CoreSPI. + + If both frame handlers are required, call the SPI_set_frame_rx_handler() + first, otherwise the initial TX frame gets discarded when SPI_set_frame_rx_handler() + clears the FIFOs as part of its initialization. + + ------------------------------------- + SPI Slave Block Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI slave block transfers: + • SPI_set_slave_block_buffers() + • SPI_set_cmd_handler() + • SPI_set_cmd_response() + + The SPI_set_slave_block_buffers() function is used to configure an SPI slave + for block transfer operations. It specifies the following: + • The buffer containing the data that will be returned to the remote SPI + master + • The buffer where data received from the remote SPI master will be + stored + • The optional handler function that will be called after the receive + buffer is filled + + The SPI_set_cmd_handler() function specifies a command handler function that + is called by the driver once a specific number of frames have been + received after the SPI chip select signal becomes active. The number of + bytes making up the command part of the transaction is specified as part of + the parameters to the SPI_set_cmd_handler() function. The command handler + function is implemented as a part of the application making use of the SPI + driver and typically calls the SPI_set_cmd_response() function. + + The SPI_set_cmd_response() function specifies the data that gets returned + to the master. Typically, the SPI_set_slave_block_buffers() function is + called as a part of the system initialisation to specify the data sent to + the master while the command bytes are being received. The transmit buffer + specified through calling the SPI_set_slave_block_buffers() function would + also typically include one or more bytes allowing the turn around time + for the command handler function to execute and call the + SPI_set_cmd_response() function. + + *//*=========================================================================*/ +#ifndef CORE_SPI_H_ +#define CORE_SPI_H_ + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#include "hal_assert.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + SPI FIFO Depth + ======================================= + SPI_MAX_FIFO_DEPTH & SPI_MIN_FIFO_DEPTH constants define the maximum and minimum + FIFO depths allowed for the CoreSPI instance. User need to inform the driver of + the FIFO depth for each CoreSPI instance to ensure that the FIFOs are managed correctly. + + | Constant | Description | + |--------------------|----------------------------------------------------| + | SPI_MAX_FIFO_DEPTH | Maximum FIFO depth allowed for the CoreSPI instance| + | SPI_MIN_FIFO_DEPTH | Minimum FIFO depth allowed for the CoreSPI instance| + + */ +#define SPI_MAX_FIFO_DEPTH 32u +#define SPI_MIN_FIFO_DEPTH 1u + +/***************************************************************************//** + Instances of this structure are used to identify the specific CoreSPI hardware + instances. A pointer to an instance of the spi_instance_t structure is passed + as the first parameter to the CoreSPI driver functions to identify which SPI + performs the requested operation. + */ +typedef struct spi_instance spi_instance_t; + +/***************************************************************************//** + This function pointer type is to assign a callback function for TX interrupt + when slave wants to send the next updated frame. + + Declaring and Implementing Slave Frame Transmit Handler Functions: + Slave transmit frame update handler functions should follow the following + prototype: + void slave_tx_frame_update_handler ( spi_instance_t * this_spi ); + The actual name of the transmit handler is unimportant. You can use any name + of your choice for the frame update handler. + + A common handler function may be used when multiple CoreSPI instances are + configured as slave, as the particular slave device currently requiring + service is indicated by the function parameter. + */ +typedef void (*spi_slave_frame_tx_handler_t)( spi_instance_t * this_spi ); + +/***************************************************************************//** + This defines the function prototype that must be followed by the SPI slave + frame receive handler functions. These functions are registered with the SPI + driver through the SPI_set_frame_rx_handler() function. + + Declaring and Implementing the Slave Frame Receive Handler Functions: + The Slave frame receive handler functions should follow the following + prototype: + void slave_frame_receive_handler(uint32_t rx_frame); + The actual name of the receive handler is unimportant. You can use any name + of your choice for the receive frame handler. The rx_frame parameter contains + the value of the received frame. + + Separate handler functions are required for each slave instance as there is + no indication of the slave requiring service passed to the handler. + + */ +typedef void (*spi_frame_rx_handler_t)( uint32_t rx_frame ); + +/***************************************************************************//** + This defines the function prototype that must be followed by SPI slave + block receive handler functions. These functions are registered with the + SPI driver through the SPI_set_slave_block_buffers() function. + + Declaring and Implementing Slave Block Receive Handler Functions: + Slave block receive handler functions should follow the following prototype: + void spi_block_rx_handler ( uint8_t * rx_buff, uint16_t rx_size ); + The actual name of the receive handler is unimportant. You can use any name + of your choice for the receive frame handler. The rx_buff parameter contains + a pointer to the start of the received block. The rx_size parameter contains + the number of bytes of the received block. + + Separate handler functions are required for each slave instance as there is + no indication of the slave requiring service passed to the handler. + + */ +typedef void (*spi_block_rx_handler_t)( uint8_t * rx_buff, uint32_t rx_size ); + +/***************************************************************************//** + This enumeration is used to select a specific SPI slave device (0 to 7). It is + used as a parameter to the SPI_configure_master_mode(), SPI_set_slave_select(), + and SPI_clear_slave_select() functions. + */ +typedef enum __spi_slave_t +{ + SPI_SLAVE_0 = 0, + SPI_SLAVE_1 = 1, + SPI_SLAVE_2 = 2, + SPI_SLAVE_3 = 3, + SPI_SLAVE_4 = 4, + SPI_SLAVE_5 = 5, + SPI_SLAVE_6 = 6, + SPI_SLAVE_7 = 7, + SPI_MAX_NB_OF_SLAVES = 8 +} spi_slave_t; + +/***************************************************************************//** + This enumeration is used to indicate the current slave mode transfer type so + that we are not relying on buffer comparisons to dictate the logic of the driver. + */ +typedef enum __spi_sxfer_mode_t +{ + SPI_SLAVE_XFER_NONE = 0, /* Not configured yet */ + SPI_SLAVE_XFER_BLOCK = 1, /* Block transfers, with SSEND delimiting end of block */ + SPI_SLAVE_XFER_FRAME = 2 /* Single frame transfers */ +} spi_sxfer_mode_t; + +/***************************************************************************//** + There is one instance of this structure for each of the core SPIs. Instances + of this structure are used to identify a specific SPI. A pointer to an + instance of the spi_instance_t structure is passed as the first parameter to + SPI driver functions to identify which SPI should perform the requested operation. + */ +struct spi_instance{ + + /* Base address in the processor's memory map for the + registers of the CoreSPI instance being initialized */ + addr_t base_addr; /* Base address of SPI hardware instance */ + + uint32_t rx_frame; /* received data */ + + /* Internal transmit state: */ + const uint8_t * slave_tx_buffer; /* Pointer to slave transmit buffer */ + uint32_t slave_tx_size; /* Size of slave transmit buffer */ + uint32_t slave_tx_idx; /* Current index into slave transmit buffer */ + + /* Slave command response buffer: */ + const uint8_t * resp_tx_buffer; + uint32_t resp_buff_size; + uint32_t resp_buff_tx_idx; + spi_block_rx_handler_t cmd_handler; + uint32_t cmd_done; /* Flag which indicates response has been set up and + it is safe to pad with 0s once the response is sent */ + + /* Internal receive state: */ + uint8_t * slave_rx_buffer; /* Pointer to buffer where data received by a slave will be stored */ + uint32_t slave_rx_size; /* Slave receive buffer size */ + uint32_t slave_rx_idx; /* Current index into slave receive buffer */ + + /* Slave received frame handler: */ + spi_frame_rx_handler_t frame_rx_handler; /* Pointer to function that will be called when a frame + is received when the SPI block is configured as slave */ + /* Slave transmitted frame handler: */ + uint32_t slave_tx_frame; /* Value of the data frame that will be transmitted + when the SPI block is configured as slave */ + spi_slave_frame_tx_handler_t slave_tx_frame_handler; /* Callback function pointer to update slave_tx_frame */ + + /* Slave block rx handler: */ + spi_block_rx_handler_t block_rx_handler; /* Pointer to the function that will be called when a data block has been received */ + + /* Per instance specific hardware information that the driver needs to know */ + uint16_t fifo_depth; /* Depth of RX and TX FIFOs in frames */ + + /* How we are expecting to deal with slave transfers */ + spi_sxfer_mode_t slave_xfer_mode; /* Current slave mode transfer configuration */ +}; + +/*------------------------Public Function-------------------------------------*/ + +/***************************************************************************//** + The SPI_init() function initializes the hardware and data structures of a + CoreSPI instance referenced by this_spi parameter. This function must be + called for each CoreSPI instance with a unique this_spi and base_addr + parameter combination. The SPI_init() function must be called before any + other CoreSPI driver functions are called. + + After calling the SPI_init() the CoreSPI is configured as a master, + all interrupt sources will be masked and all the slaves are deselected. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to be initialized. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @param base_addr + The base_addr parameter is the base address in the processor's memory map for + the registers of the CoreSPI instance being initialized. It is assumed that + any non NULL value passed in here points to a valid instance of a CoreSPI as + the driver has no way of verifying this. Failure to pass in a valid address + can result in system instability. + + @param fifo_depth + The fifo_depth parameter specifies the number of frames in the receive + and transmit FIFOs of the CoreSPI instance being initialized. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + @endcode + */ +void SPI_init +( + spi_instance_t * this_spi, + addr_t base_addr, + uint16_t fifo_depth +); + +/***************************************************************************//** + The SPI_configure_slave_mode() function is used when a CoreSPI instance is + to be configured as a SPI slave. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to be configured. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + + int main(void) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_slave_mode ( &g _spi0 ); + } + @endcode + */ +void SPI_configure_slave_mode +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_configure_master_mode() function is used when a CoreSPI instance is + to be configured as a SPI master. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to be configured. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + + int main(void) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_master_mode ( &g _spi0 ); + } + @endcode + */ +void SPI_configure_master_mode +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_set_slave_select() function is used by a CoreSPI master to select a + specific slave. This function causes the relevant slave select signal to be + asserted while data is clocked out onto the SPI data line. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param slave + The slave parameter is one of the spi_slave_t enumerated constants + identifying a slave. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + const uint32_t master_tx_frame = 0x0100A0E1; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0 ); + SPI_transfer_frame( &g_spi0, master_tx_frame ); + SPI_clear_slave_select( &g_spi0, SPI_SLAVE_0 ); + + @endcode + */ +void SPI_set_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +); + +/***************************************************************************//** + The SPI_clear_slave_select() function is used by a CoreSPI master to + deselect a specific slave. This function causes the relevant slave select + signal to be de-asserted. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param slave + The slave parameter is one of the spi_slave_t enumerated constants + identifying a slave. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + const uint32_t master_tx_frame = 0x0100A0E1; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0 ); + SPI_transfer_frame( &g_spi0, master_tx_frame ); + SPI_clear_slave_select( &g_spi0, SPI_SLAVE_0 ); + @endcode + */ +void SPI_clear_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +); + +/***************************************************************************//** + The SPI_transfer_frame() function is used by a SPI master to transmit and + receive a single frame of the size that has been configured at the time of + CoreSPI hardware instantiation. This function is typically used for + transactions with a SPI slave where the number of transmit and receive bits + are not divisible by 8 or where full duplex exchange of frames is required. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param tx_bits + The tx_bits parameter is a 32-bit word containing the value that will be + transmitted. If the frame size configured for the CoreSPI is less than 32-bits, + the upper bits will be ignored. + Note: The bit length of the value to be transmitted to the slave is + set when the CoreSPI is instantiated in the hardware design. + + @return + This function returns a 32-bit word containing the value that is received + from the slave. If the frame size configured for the CoreSPI in question is + less that 32-bits, the upper bits will be 0. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + const uint32_t master_tx_frame = 0x0100A0E1; + uint32_t master_rx; + + SPI_init(&g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ); + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0 ); + master_rx = SPI_transfer_frame( &g_spi0, master_tx_frame ); + SPI_clear_slave_select( &g_spi0, SPI_SLAVE_0 ); + @endcode + */ +uint32_t SPI_transfer_frame +( + spi_instance_t * this_spi, + uint32_t tx_bits +); + +/***************************************************************************//** + The SPI_transfer_block() function is used by the SPI master to transmit and + receive blocks of data organized as a specified number of 8-bit frames. It + can be used for the following: + • Writing a data block to a slave + • Reading a data block from a slave + • Sending a command to a slave followed by reading the outcome of + the command in a single SPI transaction. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param cmd_buffer + The cmd_buffer parameter is a pointer to the buffer that contains the data + sent by the master from the beginning of the transfer. This pointer can be + null (0) if the master does not need to send a command before reading data. + + @param cmd_byte_size + The cmd_byte_size parameter specifies the number of bytes in cmd_buffer that + will be sent. A value ‘0’ indicates that no data needs to be sent to the slave. + + @param rx_buffer + The rx_buffer parameter is a pointer to the buffer that stores the data received + from the slave after sending the command. This pointer can be null (0) if the + master does not receive any data from the slave. + + @param rx_byte_size + The rx_byte_size parameter specifies the number of bytes received from + the slave and stored in the rx_buffer. A value ‘0’ indicates that no data is + to be read from the slave. + + @return + This function does not return any value. + + @example + @code + Polled write transfer example + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + + uint8_t master_tx_buffer[MASTER_TX_BUFFER] = + { + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A + }; + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0) ; + SPI_transfer_block + ( + &g_spi0, + master_tx_buffer, + sizeof(master_tx_buffer), + 0, + 0 + ); + SPI_clear_slave_select(&g_spi0, SPI_SLAVE_0 ); + @endcode + */ +void SPI_transfer_block +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_buffer, + uint16_t rx_byte_size +); + +/***************************************************************************//** + The SPI_transfer_block_store_all_resp() function is used by the SPI master + to transmit and receive blocks of data organized as a specified number + of 8-bit frames. It can be used for the following: + • Writing a data block to a slave + • Reading a data block from a slave + • Sending a command to a slave followed by reading the outcome of + the command in a single SPI transaction + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param cmd_buffer + The cmd_buffer parameter is a pointer to the buffer that contains the data sent by + the master from the beginning of the transfer. This pointer can be null (0) + if the master does not need to send a command before reading data. + + @param cmd_byte_size + The cmd_byte_size parameter specifies the number of bytes contained in + cmd_buffer that will be sent. A value ‘0’ indicates that no data needs + to be sent to the slave. + + @param rx_data_buffer + The rx_data_buffer parameter is a pointer to the buffer that stores the data received + from the slave after sending the command. This pointer can be null (0) if the + master does not receive any data from the slave. + + @param rx_byte_size + The rx_byte_size parameter specifies the number of bytes received from + the slave and stores in the rx_buffer. A value ‘0’ indicates that no data is + to be read from the slave. + + @param cmd_response_buffer + The cmd_response_buffer parameter is a pointer to the buffer which stores the + command response from the slave, while the master is transmitting the number + of bytes indicated by cmd_byte_size parameter. + + @return + This function does not return any value. + + @example + @code + Polled write transfer example + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + + uint8_t master_tx_buffer[MASTER_TX_BUFFER] = + { + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A + }; + + uint8_t cmd_rx_buffer[CMD_RX_BUFFER]={0}; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0) ; + SPI_transfer_block_store_all_resp + ( + &g_spi0, + master_tx_buffer, + sizeof(master_tx_buffer), + 0, + 0, + cmd_response_buffer + ); + SPI_clear_slave_select(&g_spi0, SPI_SLAVE_0 ); + @endcode + */ +void SPI_transfer_block_store_all_resp +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_data_buffer, + uint16_t rx_byte_size, + uint8_t * cmd_response_buffer +); + +/***************************************************************************//** + The SPI_set_frame_rx_handler() function is used by the SPI slaves to specify + the receive handler function that is called by the SPI driver interrupt + handler when a frame of data is received by the SPI slave. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param rx_handler + The rx_handler parameter is a pointer to the frame receive handler that must + be called when a frame is received by the CoreSPI slave. Passing in a NULL + pointer disables the receive handler but does enable the receive interrupt to + ensure the RX FIFO is empty each time a frame is received. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + uint32_t g_slave_rx_frame = 0; + spi_instance_t g_spi0; + + void slave_frame_handler(uint32_t rx_frame) + { + g_slave_rx_frame = rx_frame; + } + int setup_slave( void ) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_slave_mode( &g_spi0 ); + SPI_set_frame_rx_handler( &g_spi0, slave_frame_handler ); + } + @endcode + */ +void SPI_set_frame_rx_handler +( + spi_instance_t * this_spi, + spi_frame_rx_handler_t rx_handler +); + +/***************************************************************************//** + The SPI_set_slave_tx_frame() function is used by the SPI slaves to specify + the frame that gets transmitted when a transaction is initiated by the SPI + master. This function allows you to assign a slave_tx_frame_handler function, + which will be executed upon transmit interrupt when the SPI is in slave mode. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param frame_value + The frame_value parameter contains the value of the frame to be sent to the + master. + Note: The bit length of the value to be transmitted to the master is + set when the CoreSPI is instantiated in the hardware design. + + @param slave_tx_frame_handler + The slave_tx_frame_handler function pointer is executed upon occurrence of + transmit interrupt when CoreSPI is operating in slave mode. This parameter + is optional and if set to NULL it is assumed that the frame value is static or + updated asynchronously. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + const uint32_t slave_tx_frame[2] = { 0x0110F761, 0x0110F671 }; + uint32_t master_rx; + uint32_t slave_frame_idx = 0 ; + + slave_frame_update( spi_instance_t * this_spi ) + { + this_spi->slave_tx_frame = slave_tx_frame[slave_frame_idx++]; + if( slave_frame_idx > 2 ) + slave_frame_idx = 0; + } + main() + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ) ; + SPI_set_slave_tx_frame( &g_spi0, slave_tx_frame[slave_frame_idx++], + &slave_frame_update ); + } + @endcode + */ +void SPI_set_slave_tx_frame +( + spi_instance_t * this_spi, + uint32_t frame_value, + spi_slave_frame_tx_handler_t slave_tx_frame_handler +); + +/***************************************************************************//** + The SPI_set_slave_block_buffers() function is used to configure an SPI slave + for block transfer operations. It specifies one or more of the following: + • The data that is transmitted when accessed by a master. + • The buffer where the data received from a master is stored. + • The handler function that must be called after the receive buffer has + been filled. + • The number of bytes that must be received from the master before calling + the recieve handler function. + These parameters allow the following use cases: + • Slave performing an action after receiving a block of data from a + master containing a command. This action is performed by the + receive handler based on the content of the receive data buffer. + • Slave returning a block of data to the master. The type of information + is always the same but the actual values change over time. For example, + returning the voltage of a predefined set of analog inputs. + • Slave returning data based on a command contained in the first part of + the SPI transaction. For example, reading the voltage of the analog + input specified by the first data byte by the master. This is achieved + by using the SPI_set_slave_block_buffers() function in conjunction with + functions SPI_set_cmd_handler() and SPI_set_cmd_response(). + + See the SPI_set_cmd_handler() function description for details of + this use case. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param tx_buffer + The tx_buffer parameter is a pointer to a buffer containing the data that + will be sent to the master. This parameter can be set to ‘0’ if the SPI + slave is not intended to be the target of SPI read transactions. + + @param tx_buff_size + The tx_buff_size parameter specifies the number of bytes that are + transmitted by the SPI slave. It is the number of bytes contained in the + tx_buffer. This parameter can be set to ‘0’ if the SPI slave is not + intended to be the target of SPI read transactions. The driver returns 0s + to the master if there is no buffer specified or the master reads beyond the + end of the buffer. + Note: If SPI_transfer_block() is used to read from this slave and there is + no command handler involved, the buffer size here must be at least the + combined length of the command and response specified by the master. + On receiving this data, the master discards the data bytes equal to + command length bytes from the start of the received buffer. + + @param rx_buffer + The rx_buffer parameter is a pointer to the buffer where data received + from the master is stored. This parameter can be set to ‘0’ if the + SPI slave is not intended to be the target of SPI write or write-read + transactions. + + @param rx_buff_size + The rx_buff_size parameter specifies the size of the receive buffer. It is + also the number of bytes that must be received before the receive handler + is called, if a receive handler is specified using the block_rx_handler + parameter. Any bytes received in excess of the size specified by the + rx_buff_size parameter are discarded. This parameter can be set to ‘0’ + if the SPI slave is not intended to be the target of SPI write or + write-read transactions. + + @param block_rx_handler + The block_rx_handler parameter is a pointer to a function that is called + when receive buffer has been filled or the slave select has been de-asserted. + This parameter can be set to ‘0’ if the SPI slave is not intended to be the + target of SPI write or write-read transactions. + + @return + This function does not return any value. + + @example + @code + Slave Performing Operation Based on Master Command: + In this example the SPI slave is configured to receive 10 bytes of data + or command from the SPI slave, and process the data received from the master. + + #define SPI0_BASE_ADDR 0xC2000000 + + uint32_t nb_of_rx_handler_calls = 0; + spi_instance_t g_spi0; + + void spi1_block_rx_handler_b + ( + uint8_t * rx_buff, + uint16_t rx_size + ) + { + ++nb_of_rx_handler_calls; + } + + void setup_slave( void ) + { + uint8_t slave_rx_buffer[10] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_slave_mode( &g_spi0 ); + + SPI_set_slave_block_buffers + ( + &g_spi0, + 0, + 0, + slave_rx_buffer, + sizeof( master_tx_buffer ), + spi1_block_rx_handler_b + ); + } + @endcode + */ +void SPI_set_slave_block_buffers +( + spi_instance_t * this_spi, + const uint8_t * tx_buffer, + uint32_t tx_buff_size, + uint8_t * rx_buffer, + uint32_t rx_buff_size, + spi_block_rx_handler_t block_rx_handler +); + +/***************************************************************************//** + The SPI_isr() function is the top level interrupt handler function for the + CoreSPI driver. You must call SPI_isr() from the system level + (CoreInterrupt and NVIC level) interrupt handler assigned to the interrupt + triggered by the CoreSPI SPIINT signal. Your system level interrupt handler + must also clear the system level interrupt triggered by the CoreSPI SPIINT + signal before returning, to prevent a re-assertion of the same interrupt. + + This function supports all types of interrupt triggered by CoreSPI. It is not + a complete interrupt handler by itself; rather, it is a top level wrapper that + abstracts CoreSPI command interrupt and slave mode transmit interrupt handling + by calling lower level handler functions specific to each type of CoreSPI + interrupt. You must create the lower level handler functions to suit your + application and register them with the driver through calling the + SPI_set_cmd_handler(), SPI_set_cmd_response(), and SPI_set_slave_tx_frame() + functions. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + + @example + @code + + Example of configuring a CoreInterrupt connected to the Fabric Interrupt on a + SmartFusion device to handle CoreSPI interrupt. + + #define #define SPI1_INT_IRQ_NB 0 + spi_instance_t g_spi0; + + Void CIC_irq1_handler(void) + { + SPI_isr( &g_spi0 ); + } + + void Fabric_IRQHandler( void ) + { + // Call the CoreInterrupt driver ISR to determine the source of the + // interrupt and call the relevant ISR registered to it. + CIC_irq_handler(); + + // Clear NVIC interrupt status to allow further interrupts + NVIC_ClearPendingIRQ( Fabric_IRQn ); + } + + main() + { + ... + + CIC_init( CIC_BASE_ADDR ); + + // Install handler for SPI IRQ + CIC_set_irq_handler( SPI0_INT_IRQ_NB, CIC_irq1_handler ); + + NVIC_ClearPendingIRQ( Fabric_IRQn ); + NVIC_EnableIRQ( Fabric_IRQn ); + + CIC_enable_irq( SPI1_INT_IRQ_NB ); + + ... + } + @endcode + */ +void SPI_isr +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_set_cmd_handler() function specifies a command handler function that + will be called when the number of bytes received reaches the command size + specified as cmd_size parameter. + + This function is used by the SPI slaves performing block transfers. Its + purpose is to allow an SPI slave to decide the data that will be returned to + the master while an SPI transaction is taking place. Typically, one or more + command bytes are sent by the master to request some specific data. The slave + interprets the command byte(s) while one or more turn-around bytes are + transmitted. The slave adjusts its transmit data buffer based on the command + during the turn around time. + + The following table provides an example of the use of this function where the + SPI slave returns data bytes D0 to D6 based on the value of a command. The + 3 bytes long command is made up of a command opcode byte followed by an + address byte followed by a size byte. The cmd_handler() function specified + through an earlier call to SPI_set_cmd_handler() is called by the CoreSPI + driver once the third byte is received. The cmd_handler() function + interprets the command bytes and calls SPI_set_cmd_response() to set the SPI + slave's response transmit buffer with the data to be transmitted after the + turnaround bytes (T0 to T3). The number of turnaround bytes must be + sufficient to give enough time for the cmd_handler() to execute. The number + of turnaround bytes is specified by the protocol used on top of the SPI + transport layer so that master and slave agree on the number of turn around + bytes. + +|Timestamp| SPI Transaction | Bytes | Comments | +|---------|-------------|----------------------|---------------| +| t0|COMMAND|C A S |C - command opcode byte, A - address byte, S - size byte| +|t1| TURN-AROUND|T0 T1 |cmd_handler() called here (T0 to T3 are TURN-AROUND bytes)| +|t2|TURN-AROUND|T2 T3|SPI_set_cmd_response() called here by implementation of cmd_handler() +|| | |to set the data that will be transmitted by the SPI slave.| +|t3| DATA | D0 D1 D2 D3 D4 D5 D6 |Data transmition (SPI slave return data bytes)| + + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure identifying + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @param cmd_handler + The cmd_handler parameter is a pointer to a function with the prototype: + void cmd_handler(uint8_t * rx_buff, uint32_t rx_size); + It specifies the function that will be called when the number of bytes + specified by the cmd_size parameter has been received. + + @param cmd_size + The cmd_size parameter specifies the number of bytes that must be received + before calling the command handler function specified by the cmd_handler. + The CoreSPI supports cmd_size values in the range 1 to 7. + + @return + This function does not return any value. + + @example + @code + The following example demonstrates how to configure CoreSPI to implement + the protocol given as an example above. The configure_slave() function + configures CoreSPI. It sets receive and transmit buffers. The transmit + buffer specified through the call to SPI_set_slave_block_buffers() function + specifies the data that will be returned to the master in bytes between + t0 and t3. These bytes will be sent to the master while the master transmits + the command and dummy bytes. The spi_slave_cmd_handler() function will be + called by the driver at time t1 after the 3 command bytes have been received. + The spi_block_rx_handler() function will be called by the driver at time t4, + when the transaction completes and the slave select signal becomes + de-asserted. + + #define SPI0_BASE_ADDR 0xC2000000 + #define COMMAND_SIZE 3 + #define NB_OF_DUMMY_BYTES 4 + #define MAX_TRANSACTION_SIZE 16 + + spi_instance_t g_spi0; + uint8_t slave_tx_buffer[COMMAND_SIZE + NB_OF_DUMMY_BYTES]; + uint8_t slave_rx_buffer[MAX_TRANSACTION_SIZE]; + + void configure_slave( void ) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_slave_mode( &g_spi0 ); + SPI_set_slave_block_buffers + ( + &g_spi0, + slave_tx_buffer, + COMMAND_SIZE + NB_OF_DUMMY_BYTES, + slave_rx_buffer, + sizeof(slave_rx_buffer), + spi_block_rx_handler + ); + + SPI_set_cmd_handler + ( + &g_spi0, + spi_slave_cmd_handler, + COMMAND_SIZE + ); + } + + void spi_slave_cmd_handler + ( + uint8_t * rx_buff, + uint32_t rx_size + ) + { + uint8_t command; + uint8_t address; + uint8_t size; + uint8_t * p_response; + uint32_t response_size; + + command = rx_buff[0]; + address = rx_buff[1]; + size = rx_buff[2]; + + p_response = get_response_data( command, address, size, &response_size ); + SPI_set_cmd_response( &g_spi0, p_response, response_size ); + } + + void spi_block_rx_handler + ( + uint8_t * rx_buff, + uint32_t rx_size + ) + { + process_rx_data( rx_buff, rx_size ); + } + @endcode + */ +void SPI_set_cmd_handler +( + spi_instance_t * this_spi, + spi_block_rx_handler_t cmd_handler, + uint32_t cmd_size +); + +/***************************************************************************//** + The SPI_set_cmd_response() function specifies the data that will be returned + to the master. See the description of SPI_set_cmd_handler() for details. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param resp_tx_buffer + The resp_tx_buffer parameter is a pointer to the buffer containing the data + that must be returned to the host in the data phase of an SPI transaction. + + @param resp_buff_size + The resp_buff_size parameter specifies the size of the buffer pointed by the + resp_tx_buffer parameter. + + @return + This function does not return any value. + */ +void SPI_set_cmd_response +( + spi_instance_t * this_spi, + const uint8_t * resp_tx_buffer, + uint32_t resp_buff_size +); + +/***************************************************************************//** + The SPI_enable() function enables the CoreSPI and allows it to respond to the external + signals. It is usually called to re-enable a CoreSPI instance which has been + disabled previously via by calling the SPI_disable() as the normal state of a CoreSPI + after enabling the initialization. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + */ +void SPI_enable +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_disable() function disables the CoreSPI and stops responding to the + external signals. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + */ +void SPI_disable +( + spi_instance_t * this_spi +); + +#ifdef __cplusplus +} +#endif + +#endif /* CORE_SPI_H_*/ diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreSPI/corespi_regs.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreSPI/corespi_regs.h new file mode 100644 index 0000000..a3e5b2a --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreSPI/corespi_regs.h @@ -0,0 +1,270 @@ +/***************************************************************************//** + * Copyright 2011-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file corespi_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreSPI memory map + * + */ + +#ifndef CORESPI_REGS_H_ +#define CORESPI_REGS_H_ + +/******************************************************************************* + * Control register 1: + *------------------------------------------------------------------------------ + */ +#define CTRL1_REG_OFFSET 0x00u + +#define CTRL1_ENABLE_OFFSET 0x00u +#define CTRL1_ENABLE_MASK 0x01u +#define CTRL1_ENABLE_SHIFT 0x00 + +#define CTRL1_MASTER_OFFSET 0x00u +#define CTRL1_MASTER_MASK 0x02u +#define CTRL1_MASTER_SHIFT 0x01 + +#define CTRL1_INTRXDATA_OFFSET 0x00u +#define CTRL1_INTRXDATA_MASK 0x04u +#define CTRL1_INTRXDATA_SHIFT 0x02 + +#define CTRL1_INTTXDONE_OFFSET 0x00u +#define CTRL1_INTTXDONE_MASK 0x08u +#define CTRL1_INTTXDONE_SHIFT 0x03 + +#define CTRL1_INTRXOVFLOW_OFFSET 0x00u +#define CTRL1_INTRXOVFLOW_MASK 0x10u +#define CTRL1_INTRXOVFLOW_SHIFT 0x04 + +#define CTRL1_INTTXURUN_OFFSET 0x00u +#define CTRL1_INTTXURUN_MASK 0x20u +#define CTRL1_INTTXURUN_SHIFT 0x05 + +#define CTRL1_FRAMEURUN_OFFSET 0x00u +#define CTRL1_FRAMEURUN_MASK 0x40u +#define CTRL1_FRAMEURUN_SHIFT 0x06 + +#define CTRL1_OENOFF_OFFSET 0x00u +#define CTRL1_OENOFF_MASK 0x80u +#define CTRL1_OENOFF_SHIFT 0x07 + +/******************************************************************************* + * Interrupt clear register: + *------------------------------------------------------------------------------ + */ +#define INTCLR_REG_OFFSET 0x04u + +#define INTCLR_TXDONE_OFFSET 0x04u +#define INTCLR_TXDONE_MASK 0x01u +#define INTCLR_TXDONE_SHIFT 0x00 + +#define INTCLR_RXDONE_OFFSET 0x04u +#define INTCLR_RXDONE_MASK 0x02u +#define INTCLR_RXDONE_SHIFT 0x01 + +#define INTCLR_RXOVERFLOW_OFFSET 0x04u +#define INTCLR_RXOVERFLOW_MASK 0x04u +#define INTCLR_RXOVERFLOW_SHIFT 0x02 + +#define INTCLR_TXUNDERRUN_OFFSET 0x04u +#define INTCLR_TXUNDERRUN_MASK 0x08u +#define INTCLR_TXUNDERRUN_SHIFT 0x03 + +#define INTCLR_CMDINT_OFFSET 0x04u +#define INTCLR_CMDINT_MASK 0x10u +#define INTCLR_CMDINT_SHIFT 0x04 + +#define INTCLR_SSEND_OFFSET 0x04u +#define INTCLR_SSEND_MASK 0x20u +#define INTCLR_SSEND_SHIFT 0x05 + +#define INTCLR_RXDATA_OFFSET 0x04u +#define INTCLR_RXDATA_MASK 0x40u +#define INTCLR_RXDATA_SHIFT 0x06 + +#define INTCLR_TXDATA_OFFSET 0x04u +#define INTCLR_TXDATA_MASK 0x80u +#define INTCLR_TXDATA_SHIFT 0x07 + +/******************************************************************************* + * Receive data register: + *------------------------------------------------------------------------------ + */ +#define RXDATA_REG_OFFSET 0x08u + +/******************************************************************************* + * Transmit data register: + *------------------------------------------------------------------------------ + */ +#define TXDATA_REG_OFFSET 0x0Cu + +/******************************************************************************* + * Masked interrupt status register: + *------------------------------------------------------------------------------ + */ +#define INTMASK_REG_OFFSET 0x10u + +#define INTMASK_TXDONE_OFFSET 0x10u +#define INTMASK_TXDONE_MASK 0x01u +#define INTMASK_TXDONE_SHIFT 0x00 + +#define INTMASK_RXDONE_OFFSET 0x10u +#define INTMASK_RXDONE_MASK 0x02u +#define INTMASK_RXDONE_SHIFT 0x01 + +#define INTMASK_RXOVERFLOW_OFFSET 0x10u +#define INTMASK_RXOVERFLOW_MASK 0x04u +#define INTMASK_RXOVERFLOW_SHIFT 0x02 + +#define INTMASK_TXUNDERRUN_OFFSET 0x10u +#define INTMASK_TXUNDERRUN_MASK 0x08u +#define INTMASK_TXUNDERRUN_SHIFT 0x03 + +#define INTMASK_CMDINT_OFFSET 0x10u +#define INTMASK_CMDINT_MASK 0x10u +#define INTMASK_CMDINT_SHIFT 0x04 + +#define INTMASK_SSEND_OFFSET 0x10u +#define INTMASK_SSEND_MASK 0x20u +#define INTMASK_SSEND_SHIFT 0x05 + +#define INTMASK_RXDATA_OFFSET 0x10u +#define INTMASK_RXDATA_MASK 0x40u +#define INTMASK_RXDATA_SHIFT 0x06 + +#define INTMASK_TXDATA_OFFSET 0x10u +#define INTMASK_TXDATA_MASK 0x80u +#define INTMASK_TXDATA_SHIFT 0x07 + +/******************************************************************************* + * Raw interrupt status register: + *------------------------------------------------------------------------------ + */ +#define INTRAW_REG_OFFSET 0x14u + +#define INTRAW_TXDONE_OFFSET 0x14u +#define INTRAW_TXDONE_MASK 0x01u +#define INTRAW_TXDONE_SHIFT 0x00 + +#define INTRAW_RXDONE_OFFSET 0x14u +#define INTRAW_RXDONE_MASK 0x02u +#define INTRAW_RXDONE_SHIFT 0x01 + +#define INTRAW_RXOVERFLOW_OFFSET 0x14u +#define INTRAW_RXOVERFLOW_MASK 0x04u +#define INTRAW_RXOVERFLOW_SHIFT 0x02 + +#define INTRAW_TXUNDERRUN_OFFSET 0x14u +#define INTRAW_TXUNDERRUN_MASK 0x08u +#define INTRAW_TXUNDERRUN_SHIFT 0x03 + +#define INTRAW_CMDINT_OFFSET 0x14u +#define INTRAW_CMDINT_MASK 0x10u +#define INTRAW_CMDINT_SHIFT 0x04 + +#define INTRAW_SSEND_OFFSET 0x14u +#define INTRAW_SSEND_MASK 0x20u +#define INTRAW_SSEND_SHIFT 0x05 + +#define INTRAW_RXDATA_OFFSET 0x14u +#define INTRAW_RXDATA_MASK 0x40u +#define INTRAW_RXDATA_SHIFT 0x06 + +#define INTRAW_TXDATA_OFFSET 0x14u +#define INTRAW_TXDATA_MASK 0x80u +#define INTRAW_TXDATA_SHIFT 0x07 + +/******************************************************************************* + * Control register 2: + *------------------------------------------------------------------------------ + */ +#define CTRL2_REG_OFFSET 0x18u + +#define CTRL2_CMDSIZE_OFFSET 0x18u +#define CTRL2_CMDSIZE_MASK 0x07u +#define CTRL2_CMDSIZE_SHIFT 0x00 + +#define CTRL2_INTCMD_OFFSET 0x18u +#define CTRL2_INTCMD_MASK 0x10u +#define CTRL2_INTCMD_SHIFT 0x04 + +#define CTRL2_INTSSEND_OFFSET 0x18u +#define CTRL2_INTSSEND_MASK 0x20u +#define CTRL2_INTSSEND_SHIFT 0x05 + +#define CTRL2_INTRXDATA_OFFSET 0x18u +#define CTRL2_INTRXDATA_MASK 0x40u +#define CTRL2_INTRXDATA_SHIFT 0x06 + +#define CTRL2_INTTXDATA_OFFSET 0x18u +#define CTRL2_INTTXDATA_MASK 0x80u +#define CTRL2_INTTXDATA_SHIFT 0x07 + +/******************************************************************************* + * Command register: + *------------------------------------------------------------------------------ + */ +#define CMD_REG_OFFSET 0x1Cu + +#define CMD_RXFIFORST_OFFSET 0x1Cu +#define CMD_RXFIFORST_MASK 0x01u +#define CMD_RXFIFORST_SHIFT 0x00 + +#define CMD_TXFIFORST_OFFSET 0x1Cu +#define CMD_TXFIFORST_MASK 0x02u +#define CMD_TXFIFORST_SHIFT 0x01 + +/******************************************************************************* + * Status register: + *------------------------------------------------------------------------------ + */ +#define STATUS_REG_OFFSET 0x20u + +#define STATUS_FIRSTFRAME_OFFSET 0x20u +#define STATUS_FIRSTFRAME_MASK 0x01u +#define STATUS_FIRSTFRAME_SHIFT 0x00 + +#define STATUS_DONE_OFFSET 0x20u +#define STATUS_DONE_MASK 0x02u +#define STATUS_DONE_SHIFT 0x01 + +#define STATUS_RXEMPTY_OFFSET 0x20u +#define STATUS_RXEMPTY_MASK 0x04u +#define STATUS_RXEMPTY_SHIFT 0x02 + +#define STATUS_TXFULL_OFFSET 0x20u +#define STATUS_TXFULL_MASK 0x08u +#define STATUS_TXFULL_SHIFT 0x03 + +#define STATUS_RXOVFLOW_OFFSET 0x20u +#define STATUS_RXOVFLOW_MASK 0x10u +#define STATUS_RXOVFLOW_SHIFT 0x04 + +#define STATUS_TXUNDERRUN_OFFSET 0x20u +#define STATUS_TXUNDERRUN_MASK 0x20u +#define STATUS_TXUNDERRUN_SHIFT 0x05 + +#define STATUS_SSEL_OFFSET 0x20u +#define STATUS_SSEL_MASK 0x40u +#define STATUS_SSEL_SHIFT 0x06 + +#define STATUS_ACTIVE_OFFSET 0x20u +#define STATUS_ACTIVE_MASK 0x80u +#define STATUS_ACTIVE_SHIFT 0x07 + +/******************************************************************************* + * Slave select register: + *------------------------------------------------------------------------------ + */ +#define SSEL_REG_OFFSET 0x24u + +/******************************************************************************* + * Transmit data last register: + *------------------------------------------------------------------------------ + */ +#define TXLAST_REG_OFFSET 0x28u + + +#endif /*CORESPI_REGS_H_*/ diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.c b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.c new file mode 100644 index 0000000..b8adaed --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.c @@ -0,0 +1,889 @@ +/******************************************************************************* + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * PF_System_Services driver implementation. See file "core_syservices_pf.h" for + * description of the functions implemented in this file. + * + */ + +#include "core_sysservices_pf.h" +#include "coresysservicespf_regs.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define NULL_BUFFER (( uint8_t* ) 0) + +static uint8_t execute_ss_command +( + uint8_t cmd_opcode, + const uint8_t* cmd_data, + uint16_t cmd_data_size, + const uint8_t* p_response, + uint16_t response_size, + uint16_t mb_offset, + uint16_t response_offset +); + +uint32_t g_css_pf_base_addr = 0u; + +/***************************************************************************//** + * SYS_init() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +void +SYS_init +( + uint32_t base_addr +) +{ + g_css_pf_base_addr = base_addr; +} + +/***************************************************************************//** + * SYS_get_serial_number() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_serial_number +( + const uint8_t * p_serial_number, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if (p_serial_number == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(SERIAL_NUMBER_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_serial_number, + SERIAL_NUMBER_RESP_LEN, + mb_offset, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_get_user_code() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_user_code +( + const uint8_t * p_user_code, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_user_code == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(USERCODE_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_user_code, + USERCODE_RESP_LEN, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_get_design_info() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_design_info +( + const uint8_t * p_design_info, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_design_info == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(DESIGN_INFO_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_design_info, + DESIGN_INFO_RESP_LEN, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_get_device_certificate() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_device_certificate +( + const uint8_t * p_device_certificate, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_device_certificate == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(DEVICE_CERTIFICATE_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_device_certificate, + DEVICE_CERTIFICATE_RESP_LEN, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_read_digest() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_read_digest +( + const uint8_t * p_digest, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_digest == NULL_BUFFER) + { + return status; + } + +#ifndef CORESYSSERVICES_MPFS + status = execute_ss_command(READ_DIGEST_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_digest, + READ_DIGEST_RESP_LEN, + mb_offset, + 0u); +#else + status = execute_ss_command(READ_DIGEST_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_digest, + READ_DIGEST_MPFS_RESP_LEN, + mb_offset, + 0u); +#endif + return status; + +} + +/***************************************************************************//** + * SYS_query_security() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_query_security +( + uint8_t * p_security_locks, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint8_t idx = 0u; + + if(p_security_locks == NULL_BUFFER) + { + return status; + } + +#ifndef CORESYSSERVICES_MPFS + uint8_t buf[12] = {0}; + /* Actual QUERY_SECURITY_RESP_LEN is 9 or 33 but PF_System_Services core + * needs number of words instead of number of bytes to be written to or read + * from MailBox */ + status = execute_ss_command(QUERY_SECURITY_REQUEST_CMD, + NULL_BUFFER, + 0u, + buf, + (QUERY_SECURITY_RESP_LEN + 3u), + mb_offset, + 0u); + + for (idx = 0u; idx < 9u; idx++) + { + *(p_security_locks+idx) = buf[idx]; + } + +#else + uint8_t buf[36] = {0}; + + status = execute_ss_command(QUERY_SECURITY_REQUEST_CMD, + NULL_BUFFER, + 0u, + buf, + (QUERY_SECURITY_MPFS_RESP_LEN + 3u), + mb_offset, + 0u); + + for (idx = 0u; idx < 33u; idx++) + { + *(p_security_locks+idx) = buf[idx]; + } + +#endif + + return status; +} + +/***************************************************************************//** + * SYS_read_debug_info() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_read_debug_info +( + const uint8_t * p_debug_info, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_debug_info == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(READ_DEBUG_INFO_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_debug_info, + READ_DEBUG_INFO_RESP_LEN, + mb_offset, + 0u); + return status; +} + +#ifdef CORESYSSERVICES_MPFS +/***************************************************************************//** + * SYS_read_envm_parameter() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_read_envm_parameter +( + uint8_t * p_envm_param, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_envm_param == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(READ_ENVM_PARAM_REQUEST_CMD, + NULL_BUFFER, + 0, + p_envm_param, + READ_ENVM_PARAM_RESP_LEN, + mb_offset, + 0); + return status; +} + +#endif + +/***************************************************************************//** + * SYS_puf_emulation_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_puf_emulation_service +( + const uint8_t * p_challenge, + uint8_t op_type, + uint8_t* p_response, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint8_t mb_format[20] = {0x00}; + uint8_t index = 0u; + + if((p_response == NULL_BUFFER) || (p_challenge == NULL_BUFFER)) + { + return status; + } + + /* Frame the data required for mailbox */ + mb_format[index] = op_type; + + for (index = 4u; index < 20u; index++) + { + mb_format[index] = p_challenge[index - 4u]; + } + + status = execute_ss_command(PUF_EMULATION_SERVICE_REQUEST_CMD, + mb_format, + PUF_EMULATION_SERVICE_CMD_LEN, + p_response, + PUF_EMULATION_SERVICE_RESP_LEN, + mb_offset, + 5u); /* mentioning offset to number of words instead of bytes */ + + return status; +} + +/***************************************************************************//** + * SYS_digital_signature_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_digital_signature_service +( + const uint8_t* p_hash, + uint8_t format, + uint8_t* p_response, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if((p_hash == NULL_BUFFER) || (p_response == NULL_BUFFER)) + { + return status; + } + + if (format == DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD) + { + status = execute_ss_command(DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD, + p_hash, + DIGITAL_SIGNATURE_HASH_LEN, + p_response, + DIGITAL_SIGNATURE_RAW_FORMAT_RESP_SIZE, + mb_offset, + 12u); /* mentioning offset to number of words instead of bytes */ + } + else + { + status = execute_ss_command(DIGITAL_SIGNATURE_DER_FORMAT_REQUEST_CMD, + p_hash, + DIGITAL_SIGNATURE_HASH_LEN, + p_response, + DIGITAL_SIGNATURE_DER_FORMAT_RESP_SIZE, + mb_offset, + 12u); /* mentioning offset to number of words instead of bytes */ + } + + return status; +} + +/***************************************************************************//** + * SYS_secure_nvm_write() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_secure_nvm_write +( + uint8_t format, + uint8_t snvm_module, + const uint8_t* p_data, + const uint8_t* p_user_key, + uint16_t mb_offset +) +{ + uint8_t frame[256] = {0x00}; + uint8_t* p_frame = &frame[0]; + uint16_t index = 0u; + uint8_t status = SYS_PARAM_ERR; + + HAL_ASSERT(!(NULL_BUFFER == p_data)); + HAL_ASSERT(!(snvm_module >= 221u)); + if (format != SNVM_NON_AUTHEN_TEXT_REQUEST_CMD) + { + HAL_ASSERT(!(NULL_BUFFER == p_user_key)); + } + + if ((p_data == NULL_BUFFER) || (snvm_module >= 221)) + { + return status; + } + + if ((format != SNVM_NON_AUTHEN_TEXT_REQUEST_CMD) + && (p_user_key == NULL_BUFFER)) + { + return status; + } + + if ((format != SNVM_NON_AUTHEN_TEXT_REQUEST_CMD) + && (format != SNVM_AUTHEN_TEXT_REQUEST_CMD) + && (format != SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD)) + { + return status; + } + + *p_frame = snvm_module; /* SNVMADDR - SNVM module */ + + p_frame += 4u; /* Next 3 bytes RESERVED - For alignment */ + + /* Copy user key and send the command/data to mailbox. */ + if ((format == SNVM_AUTHEN_TEXT_REQUEST_CMD) || + (format == SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD)) + { + /* Copy user data */ + for (index = 0u; index < (AUTHENTICATED_TEXT_DATA_LEN - USER_SECRET_KEY_LEN - 4u); index++) + { + *p_frame = p_data[index]; + p_frame++; + } + + /* Copy user key */ + for (index = 0u; index < USER_SECRET_KEY_LEN; index++) + { + *p_frame = p_user_key[index]; + p_frame++; + } + + status = execute_ss_command(format, + &frame[0], + AUTHENTICATED_TEXT_DATA_LEN, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + } + else + { + /* Copy user data */ + for (index = 0u; index < (NON_AUTHENTICATED_TEXT_DATA_LEN - 4u); index++) + { + *(p_frame+index) = p_data[index]; + } + + status = execute_ss_command(format, + &frame[0], + NON_AUTHENTICATED_TEXT_DATA_LEN, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + } + + return status; +} + +/***************************************************************************//** + * SYS_secure_nvm_read() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_secure_nvm_read +( + uint8_t snvm_module, + const uint8_t* p_user_key, + uint8_t* p_admin, + uint8_t* p_data, + uint16_t data_len, + uint16_t mb_offset +) +{ + /* Frame the message. */ + uint8_t frame[16] = {0x00u}; + uint8_t* p_frame = &frame[0u]; + uint8_t status = SYS_PARAM_ERR; + uint8_t response[256] = {0x00u}; + uint16_t index = 0u; + + HAL_ASSERT(!(NULL_BUFFER == p_data)); + HAL_ASSERT(!(NULL_BUFFER == p_admin)); + HAL_ASSERT(!(snvm_module > 221u)); + + HAL_ASSERT(data_len == 236u || data_len == 252u); + + if((p_data == NULL_BUFFER) || + (snvm_module >= 221) || + (p_admin == NULL_BUFFER)) + { + return status; + } + + *p_frame = snvm_module; /* SNVMADDR - SNVM module */ + + p_frame += 4u; /* RESERVED - For alignment */ + + /* Copy user key */ + if (236u == data_len) + { + HAL_ASSERT(p_user_key != NULL_BUFFER); + + if(p_user_key == NULL_BUFFER) + { + return status; + } + + for (index = 0u; index < 12u; index++) + { + *p_frame = p_user_key[index]; + p_frame++; + } + } + else + { + p_frame += 12u; + } + + status = execute_ss_command(SNVM_READ_REQUEST_CMD, + &frame[0], + 16u, + response, + (data_len + 4u), + mb_offset, + 4u); /* mentioning offset to number of words instead of bytes */ + + if (SYS_SUCCESS == status) + { + for (index = 0u; index < 4u; index++) + { + *(p_admin+index) = (uint32_t)response[index]; + } + + + /* Copy data into user buffer. */ + for (index = 4u; index < (data_len + 4u); index++) + { + *(p_data + (index - 4u)) = response[index]; + } + } + else + { + ; + } + + return status; +} + +/***************************************************************************//** + * SYS_nonce_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_nonce_service +( + const uint8_t * p_nonce, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if((p_nonce == NULL_BUFFER)) + { + return status; + } + + status = execute_ss_command(NONCE_SERVICE_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_nonce, + NONCE_SERVICE_RESP_LEN, + mb_offset, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_bitstream_authenticate_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_bitstream_authenticate_service +( + uint32_t spi_flash_address, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint32_t l_spi_flash_address = spi_flash_address; + status = execute_ss_command(BITSTREAM_AUTHENTICATE_CMD, + (uint8_t* )&l_spi_flash_address, + 4u, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_IAP_image_authenticate_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_IAP_image_authenticate_service +( + uint8_t spi_idx +) +{ + uint8_t status = SYS_PARAM_ERR; + + HAL_ASSERT(!(spi_idx == 1u)); + + if (spi_idx == 1u) + { + return status; + } + + status = execute_ss_command(IAP_BITSTREAM_AUTHENTICATE_CMD, + NULL_BUFFER, + 0u, + NULL_BUFFER, + 0u, + spi_idx, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_digest_check_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_digest_check_service +( + uint32_t options, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint32_t l_options = options; + + status = execute_ss_command(DIGEST_CHECK_CMD, + (uint8_t* )&l_options, + 4u, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_iap_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_iap_service +( + uint8_t iap_cmd, + uint32_t spiaddr, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint16_t l_mb_offset = 0u; + uint16_t cmd_data_size = 0u; + uint8_t* cmd_data = NULL_BUFFER; + bool invalid_param = false; + + if (((IAP_PROGRAM_BY_SPIIDX_CMD == iap_cmd) + || (IAP_VERIFY_BY_SPIIDX_CMD == iap_cmd)) + && (1u == spiaddr)) + { + invalid_param = true; + HAL_ASSERT(!invalid_param); + } + + if (!invalid_param) + { + switch(iap_cmd) + { + case IAP_PROGRAM_BY_SPIIDX_CMD: + case IAP_VERIFY_BY_SPIIDX_CMD: + /*In SPI_IDX based program and verify commands, + * Mailbox is not Required. Instead of mailbox offset + * SPI_IDX is passed as parameter.*/ + l_mb_offset = (uint16_t)(0xFFu & spiaddr); + break; + + case IAP_PROGRAM_BY_SPIADDR_CMD: + case IAP_VERIFY_BY_SPIADDR_CMD: + /*In SPI_ADDR based program and verify commands, + * Mailbox is Required*/ + l_mb_offset = mb_offset; + /*command data size is four bytes holding the + * SPI Address in it.*/ + cmd_data_size = 4u; + cmd_data = (uint8_t*)&spiaddr; + break; + + case IAP_AUTOUPDATE_CMD: + /*In auto update command Mailbox is not Required*/ + l_mb_offset = 0u; + break; + + default: + l_mb_offset = 0u; + + } + + status = execute_ss_command( + (uint8_t)iap_cmd, + cmd_data, + cmd_data_size, + NULL_BUFFER, + 0, + (uint16_t)l_mb_offset, + 0); + } + + return status; +} + +/***************************************************************************//** + Internal functions. +*/ +/* +This function executes the SS command. If Mailbox input data is required by the +it will first load it from cmd_data into the Mailbox. If the service requires +the response data to be read from mailbox, it will do so and store it in p_response. +*/ +static uint8_t execute_ss_command +( + uint8_t cmd_opcode, + const uint8_t* cmd_data, + uint16_t cmd_data_size, + const uint8_t* p_response, + uint16_t response_size, + uint16_t mb_offset, + uint16_t response_offset +) +{ + /* Pointer used during Writing to Mailbox memory. */ + uint32_t status = 0u; + uint16_t idx = 0u; + uint16_t ss_command = 0u; + uint32_t* word_buf; + uint16_t timeout_count = SS_TIMEOUT_COUNT; + + /* making sure that the system controller is not executing any service i.e. + SS_USER_BUSY is gone 0 */ + + while (1u == HAL_get_32bit_reg_field(g_css_pf_base_addr, SS_USER_BUSY)) + { + --timeout_count; + + if (timeout_count == 0) + { + return SS_USER_BUSY_TIMEOUT; + } + } + + /* Form the SS command: bit 0to6 is the opcode, bit 7to15 is the Mailbox offset + For some services this field has another meaning + (e.g. for IAP bitstream auth. it means spi_idx) */ + ss_command = ((mb_offset << 7u) | (cmd_opcode & 0x7Fu)); + + /* Load the command register with the SS request command code*/ + HAL_set_32bit_reg(g_css_pf_base_addr, SS_CMD, ss_command); + + if (cmd_data_size > 0u) + { + HAL_ASSERT(!(NULL_BUFFER == cmd_data)); + HAL_ASSERT(!(cmd_data_size % 4u)); + + /* Load the MBX_WCNT register with number of words */ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_WCNT, (cmd_data_size/4u)); + + /* Load the MBX_WADDR register with offset of input data (write to Mailbox) + For all the services this offset remains either 0 or Not applicable + for the services in which no Mailbox write is required.*/ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_WADDR, (0x00u + mb_offset)); + + } + + if (response_size > 0u) + { + HAL_ASSERT(!(NULL_BUFFER == p_response)); + HAL_ASSERT(!(response_size % 4u)); + + /* + Load the MBX_RWCNT register with number of words to be read from Mailbox + */ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_RCNT, (response_size/4u)); + + /* + Load the MBX_RADRDESC register with offset address within the mailbox + format for that particular service. + It will be 0 for the services where there is no output data from G5CONTROL + is expected. + This function assumes that this value is pre-calculated by service specific + functions as this value is fixed for each service. + */ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_RADDR, (response_offset + mb_offset)); + } + + /*Set the request bit in SYS_SERV_REQ register to start the service*/ + HAL_set_32bit_reg_field(g_css_pf_base_addr, SS_REQ_REQ, 0x01u); + + if (cmd_data_size > 0u) + { + word_buf = (uint32_t*)cmd_data; + + /* Write the user data into mail box. */ + for (idx = 0u; idx < (cmd_data_size/4u); idx++) + { + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_WDATA, word_buf[idx]); + } + } + + timeout_count = SS_TIMEOUT_COUNT; + if (response_size > 0u) + { + word_buf = (uint32_t*)p_response; + + for (idx = 0u; idx < (response_size/4u); idx++) + { + while (0u == HAL_get_32bit_reg_field(g_css_pf_base_addr, + SS_USER_RDVLD)) + { + --timeout_count; + + if (timeout_count == 0) + { + return SS_USER_RDVLD_TIMEOUT; + } + } + word_buf[idx] = HAL_get_32bit_reg(g_css_pf_base_addr, MBX_RDATA); + } + } + + timeout_count = SS_TIMEOUT_COUNT; + /* make sure that service is complete i.e. SS_USER_BUSY is gone 0 */ + while (1u == HAL_get_32bit_reg_field(g_css_pf_base_addr, SS_USER_BUSY)) + { + --timeout_count; + + if (timeout_count == 0) + { + return SS_USER_RDVLD_TIMEOUT; + } + } + + /* Read the status returned by System Controller */ + status = HAL_get_32bit_reg(g_css_pf_base_addr, SS_STAT); + + return (uint8_t)status; +} + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h new file mode 100644 index 0000000..8e0ebb6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h @@ -0,0 +1,1249 @@ +/******************************************************************************* + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the + * CoreSysServices_PF bare metal driver. + */ +/*=========================================================================*//** + @mainpage CoreSysServices_PF Bare Metal Driver. + + @section intro_sec Introduction + The PolarFire System Services (PF_SYSTEM_SERVICES) SgCore enables executing + the system services on the PolarFire and PolarFire SoC device. The system services + are the system controller actions initiated by the System Controller's System + Service Interface (SSI). The PolarFire System Services "SgCore" provides a + method to initiate these system services. The PF_SYSTEM_SERVICES interacts + with the system controller on SSI and Mailbox interface to initiate system + services, exchange data required for that services, and to know the successful + completion or error status. + + The PF_SYSTEM_SERVICES provides an APB interface for controlling the registers + functions for controlling the PF_SYSTEM_SERVICES as part of a bare metal system + register implemented within it. This software driver provides a set of where no + part of an operating system but the implementation of the adaptation layer + operating system is available. This driver is adapted for use in + between this driver and the operating system's driver model is outside the + scope of this driver. + + ## Features + The CoreSysServices_PF driver provides the following features: + - Executing device and design information services + - Executing design services + - Executing data security services + - Executing Fabric services + + The CoreSysServices_PF driver is provided as C source code. + + @section Driver Configuration + The application software should configure the CoreSysServices_PF driver through + calling the SYS_init() function. Only one instance of PF_SYSTEM_SERVICES SgCore is + supported. No additional configuration files are required to use the driver. + If using this driver on RT PolarFire device FPGA, define RT_DEVICE_FAMILY + macro in application. + + @section theory_op Theory of Operation + The CoreSysServices_PF driver provides access to the PolarFire system services. + These system services are grouped into the following categories: + + Device and Design Information Service + - Serial Number Service + - USERCODE Service + - Design Info Service + - Device Certificate Services + - Read Digests + - Query Security + - Read Debug Info + - Read eNVM param + + Design Services + - Bitstream authentication service + - IAP bitstream authentication service + + Data Security Services + - Digital Signature Service + - Secure NVM (SNVM) Functions + - PUF Emulation Service + - Nonce Service + + Fabric Services + - Digest Check Service + - In Application programming(IAP)/Auto-Update service + + Initialization and Configuration + + The CoreSysServices_PF driver is initialized by calling the SYS_init() + function. The SYS_init() function must be called before calling any other + CoreSysServices_PF driver functions. + + Device and Design Information Services + + The CoreSysServices_PF driver is used to read information about the device + and the design using the following functions: + - SYS_get_serial_number() + - SYS_get_user_code() + - SYS_get_design_info() + - SYS_get_device_certificate() + - SYS_read_digest() + - SYS_query_security() + - SYS_read_debug_info() + + Design Authentication Services + + The CoreSysServices_PF driver is used to execute design services using the + following functions: + - SYS_bitstream_authenticate_service() + - SYS_IAP_image_authenticate_service() + + Data Security Services + + The CoreSysServices_PF driver is used to execute data security services + using the following functions: + - SYS_digital_signature_service() + - SYS_secure_nvm_write() + - SYS_secure_nvm_read() + - SYS_puf_emulation_service () + - SYS_nonce_service () + + Executing Fabric Services + + The CoreSysServices_PF driver is used to execute fabric services using the + following functions: + - SYS_digest_check_service() + - SYS_iap_service() + + All the service execution functions return the 8-bit status, which is returned + by the system controller on executing the given service. A '0' value indicates + successful execution of that service. A non-zero value indicates error. + The error codes for each service are different. See individual function + description to know the exact meanings of the error codes for each service. + + The function descriptions in this file mainly focus on the details required + by the user to use the APIs provided by this driver to execute the services. + To know the complete details of the system services, see the + PolarFire FPGA and PolarFire SoC FPGA System Services [document](https://onlinedocs.microchip.com/pr/GUID-1409CF11-8EF9-4C24-A94E-70979A688632-en-US-3/index.html) + + *//*=========================================================================*/ +#ifndef __CORE_SYSSERV_PF_H +#define __CORE_SYSSERV_PF_H 1 + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#include "hal_assert.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** +* # Service Execution Success and Error Status Codes +* +* The following status codes are the return values from the system service functions. +* For any service, a return value '0' indicates that the service was executed +* successfully. A non-zero return value indicates that the service was not +* executed successfully. For all the services, the return value represents the +* status code returned by the system controller for the respective service, +* except the values SYS_PARAM_ERR, SS_USER_BUSY_TIMEOUT, and SS_USER_RDVLD_TIMEOUT. +* These three values indicate the error conditions detected by this driver and +* they do not overlap with the status code returned by the system controller for +* any of the system service. +* +* SYS_SUCCESS +* System service executed successfully +* +* SYS_PARAM_ERR +* System service cannot be executed as one or more parameters are not as +* expected by this driver. No read/write access is performed with the +* IP. +* +* SS_USER_BUSY_TIMEOUT +* The System service request is initiated and the driver timed-out while +* waiting for the system service to complete. The System Service +* completion is indicated by de-assertion of the SS_USER_BUSY bit by the +* IP. +* +* SS_USER_RDVLD_TIMEOUT +* The System service request is initiated and the driver timed-out while +* waiting for SS_USER_RDVLD bit, which indicates availability of data to +* be read from the mailbox, to become active. +*/ +#define SYS_SUCCESS 0u +#define SYS_PARAM_ERR 0xFFu +#define SS_USER_BUSY_TIMEOUT 0xFAu +#define SS_USER_RDVLD_TIMEOUT 0xFBu + +/** +* # System Service Timeout Count +* +* The SS_TIMEOUT_COUNT value is used by the driver as a timeout count +* while waiting for either the SS_USER_BUSY or SS_USER_RDVLD. This empirical +* value is sufficiently large so that the operations are falsely +* timeout in the normal circumstance. It is provided as a way to provide +* more debug information to the application in case there are some +* unforeseen issues. You may change this value for your need based on your +* system design. +*/ +#define SS_TIMEOUT_COUNT 40000u +/* + * SYS_DCF_DEVICE_MISMATCH + * Public key or FSN do not match device + * + * + * SYS_DCF_INVALID_SIGNATURE + * Certificate signature is invalid + * + * SYS_DCF_SYSTEM_ERROR + * PUF or storage failure + */ +#define SYS_DCF_DEVICE_MISMATCH 1u +#define SYS_DCF_INVALID_SIGNATURE 2u +#define SYS_DCF_SYSTEM_ERROR 3u + +/* + * SYS_NONCE_PUK_FETCH_ERROR + * Error fetching PUK + * + * SYS_NONCE_SEED_GEN_ERROR + * Error generating seed + */ +#define SYS_NONCE_PUK_FETCH_ERROR 1u +#define SYS_NONCE_SEED_GEN_ERROR 2u + +/** + * # Secure Nvm Write Error Codes + * + * SNVM_WRITE_INVALID_SNVMADDR + * Illegal page address + * + * SNVM_WRITE_FAILURE + * PNVM program/verify failed + * + * SNVM_WRITE_SYSTEM_ERROR + * PUF or storage failure + * + * SNVM_WRITE_NOT_PERMITTED + * Write is not permitted + */ +#define SNVM_WRITE_INVALID_SNVMADDR 1u +#define SNVM_WRITE_FAILURE 2u +#define SNVM_WRITE_SYSTEM_ERROR 3u +#define SNVM_WRITE_NOT_PERMITTED 4u + +/** + * # Secure Nvm Read Error Codes + * + * SNVM_READ_INVALID_SNVMADDR + * Illegal page address + * + * SNVM_READ_AUTHENTICATION_FAILURE + * Storage corrupt or incorrect USK + * + * SNVM_READ_SYSTEM_ERROR + * PUF or storage failure + * + */ +#define SNVM_READ_INVALID_SNVMADDR 1u +#define SNVM_READ_AUTHENTICATION_FAILURE 2u +#define SNVM_READ_SYSTEM_ERROR 3u + +/** + * # Digital Signature Service Error Codes + * + * DIGITAL_SIGNATURE_FEK_FAILURE_ERROR + * Error retrieving FEK + * + * DIGITAL_SIGNATURE_DRBG_ERROR + * Failed to generate nonce + * + * DIGITAL_SIGNATURE_ECDSA_ERROR + * ECDSA failed + */ +#define DIGITAL_SIGNATURE_FEK_FAILURE_ERROR 1u +#define DIGITAL_SIGNATURE_DRBG_ERROR 2u +#define DIGITAL_SIGNATURE_ECDSA_ERROR 3u + +/** + * # Digest Check Error Codes + * + * NOTE: When these error occur, the DIGEST tamper flag is triggered. + * + * DIGEST_CHECK_FABRICERR + * Fabric digest check error + * + * DIGEST_CHECK_CCERR + * UFS Fabric Configuration (CC) segment digest check error + * + * DIGEST_CHECK_SNVMERR + * ROM digest in SNVM segment digest check error + * + * DIGEST_CHECK_ULERR + * UFS UL segment digest check error + * + * DIGEST_CHECK_UK0ERR + * UKDIGEST0 in User Key segment digest check error + * + * DIGEST_CHECK_UK1ERR + * UKDIGEST1 in User Key segment digest check error + * + * DIGEST_CHECK_UK2ERR + * UKDIGEST2 in User Key segment (UPK1) digest check error + * + * DIGEST_CHECK_UK3ERR + * UKDIGEST3 in User Key segment (UK1) digest check error + * + * DIGEST_CHECK_UK4ERR + * UKDIGEST4 in User Key segment (DPK) digest check error + * + * DIGEST_CHECK_UK5ERR + * UKDIGEST5 in User Key segment (UPK2) digest check error + * + * DIGEST_CHECK_UK6ERR + * UKDIGEST6 in User Key segment (UK2) digest check error + * + * DIGEST_CHECK_UPERR + * UFS Permanent Lock (UPERM) segment digest check error + * + * DIGEST_CHECK_SYSERR + * M3 ROM, Factory and Factory Key Segments digest check error + * + */ +#define DIGEST_CHECK_FABRICERR 0x00u +#define DIGEST_CHECK_CCERR 0x01u +#define DIGEST_CHECK_SNVMERR 0x02u +#define DIGEST_CHECK_ULERR 0x03u +#define DIGEST_CHECK_UK0ERR 0x04u +#define DIGEST_CHECK_UK1ERR 0x05u +#define DIGEST_CHECK_UK2ERR 0x06u +#define DIGEST_CHECK_UK3ERR 0x07u +#define DIGEST_CHECK_UK4ERR 0x08u +#define DIGEST_CHECK_UK5ERR 0x09u +#define DIGEST_CHECK_UK6ERR 0x10u +#define DIGEST_CHECK_UPERR 0x11u +#define DIGEST_CHECK_SYSERR 0x12u + +/** + * # Bitstream Authentication and Iap Bitstream Authentication Return Status + * + * BSTREAM_AUTH_CHAINING_MISMATCH_ERR + * Validator or hash chaining mismatch. Incorrectly constructed bitstream or + * wrong key used. + * + * BSTREAM_AUTH_UNEXPECTED_DATA_ERR + * Unexpected data received. + * Additional data received after end of EOB component. + * + * BSTREAM_AUTH_INVALID_ENCRY_KEY_ERR + * Invalid/corrupt encryption key. + * The requested key mode is disabled or the key could not be read/reconstructed. + * + * BSTREAM_AUTH_INVALID_HEADER_ERR + * Invalid component header + * + * BSTREAM_AUTH_BACK_LEVEL_NOT_SATISFIED_ERR + * Back level not satisfied + * + * BSTREAM_AUTH_ILLEGAL_BITSTREAM_MODE_ERR + * Illegal bitstream mode. + * Requested bitstream mode is disabled by user security. + * + * BSTREAM_AUTH_DNS_BINDING_MISMATCH_ERR + * DSN binding mismatch + * + * BSTREAM_AUTH_ILLEGAL_COMPONENT_SEQUENCE_ERR + * Illegal component sequence + * + * BSTREAM_AUTH_INSUFF_DEVICE_CAPAB_ERR + * Insufficient device capabilities + * + * BSTREAM_AUTH_INCORRECT_DEVICEID_ERR + * Incorrect DEVICEID + * + * BSTREAM_AUTH_PROTOCOL_VERSION_ERR + * Unsupported bitstream protocol version (regeneration required) + * + * BSTREAM_AUTH_VERIFY_ERR + * Verify not permitted on this bitstream + * + * BSTREAM_AUTH_INVALID_DEV_CERT_ERR + * Invalid Device Certificate. + * Device SCAC is invalid or not present. + * + * BSTREAM_AUTH_INVALID_DIB_ERR + * Invalid DIB + * + * BSTREAM_AUTH_SPI_NOT_MASTER_ERR + * Device not in SPI Master Mode. + * Error may occur only when bitstream is executed through IAP mode. + * + * BSTREAM_AUTH_AUTOIAP_NO_VALID_IMAGE_ERR + * No valid images found. + * Error may occur when bitstream is executed through Auto Update mode. + * Occurs when no valid image pointers are found. + * + * BSTREAM_AUTH_INDEXIAP_NO_VALID_IMAGE_ERR + * No valid images found. + * Error may occur when bitstream is executed through IAP mode via Index Mode. + * Occurs when No valid image pointers are found. + * + * BSTREAM_AUTH_NEWER_DESIGN_VERSION_ERR + * Programmed design version is newer than AutoUpdate image found. + * Error may occur when bitstream is executed through Auto Update mode. + * + * BSTREAM_AUTH_INVALID_IMAGE_ERR + * Selected image was invalid and no recovery was performed due to valid design + * in device. + * Error may occur only when bitstream is executed through Auto Update or IAP mode + * (This error is here for completeness but only can be observed by running the + * READ_DEBUG_INFO instruction and looking at IAP Error code field). + * + * BSTREAM_AUTH_IMAGE_PROGRAM_FAILED_ERR + * Selected and Recovery image failed to program. + * Error may occur only when bitstream is executed through Auto Update or + * IAP mode + * (This error is here for completeness but only can be observed by running the + * READ_DEBUG_INFO instruction and looking at IAP Error code field). + * + * BSTREAM_AUTH_ABORT_ERR + * Abort. + * Non-bitstream instruction executed during bitstream loading. + * + * BSTREAM_AUTH_NVMVERIFY_ERR + * Fabric/UFS verification failed (min or weak limit) + * + * BSTREAM_AUTH_PROTECTED_ERR + * Device security prevented modification of non-volatile memory + * + * BSTREAM_AUTH_NOTENA + * Programming mode not enabled + * + * BSTREAM_AUTH_PNVMVERIFY + * pNVM verify operation failed + * + * BSTREAM_AUTH_SYSTEM + * System hardware error (PUF or DRBG) + * + * BSTREAM_AUTH_BADCOMPONENT + * An internal error was detected in a component payload + * + * BSTREAM_AUTH_HVPROGERR + * HV programming subsystem failure (pump failure) + * + * BSTREAM_AUTH_HVSTATE + * HV programming subsystem in unexpected state (internal error) + * + */ +#define BSTREAM_AUTH_CHAINING_MISMATCH_ERR 1 +#define BSTREAM_AUTH_UNEXPECTED_DATA_ERR 2 +#define BSTREAM_AUTH_INVALID_ENCRY_KEY_ERR 3 +#define BSTREAM_AUTH_INVALID_HEADER_ERR 4 +#define BSTREAM_AUTH_BACK_LEVEL_NOT_SATISFIED_ERR 5 +#define BSTREAM_AUTH_ILLEGAL_BITSTREAM_MODE_ERR 6 +#define BSTREAM_AUTH_DNS_BINDING_MISMATCH_ERR 7 +#define BSTREAM_AUTH_ILLEGAL_COMPONENT_SEQUENCE_ERR 8 +#define BSTREAM_AUTH_INSUFF_DEVICE_CAPAB_ERR 9 +#define BSTREAM_AUTH_INCORRECT_DEVICEID_ERR 10 +#define BSTREAM_AUTH_PROTOCOL_VERSION_ERR 11 +#define BSTREAM_AUTH_VERIFY_ERR 12 +#define BSTREAM_AUTH_INVALID_DEV_CERT_ERR 13 +#define BSTREAM_AUTH_INVALID_DIB_ERR 14 +#define BSTREAM_AUTH_SPI_NOT_MASTER_ERR 21 +#define BSTREAM_AUTH_AUTOIAP_NO_VALID_IMAGE_ERR 22 +#define BSTREAM_AUTH_INDEXIAP_NO_VALID_IMAGE_ERR 23 +#define BSTREAM_AUTH_NEWER_DESIGN_VERSION_ERR 24 +/* 25 Reserved */ +#define BSTREAM_AUTH_INVALID_IMAGE_ERR 26 +#define BSTREAM_AUTH_IMAGE_PROGRAM_FAILED_ERR 27 +#define BSTREAM_AUTH_ABORT_ERR 127 +#define BSTREAM_AUTH_NVMVERIFY_ERR 128 +#define BSTREAM_AUTH_PROTECTED_ERR 129 +#define BSTREAM_AUTH_NOTENA 130 +#define BSTREAM_AUTH_PNVMVERIFY 131 +#define BSTREAM_AUTH_SYSTEM 132 +#define BSTREAM_AUTH_BADCOMPONENT 133 +#define BSTREAM_AUTH_HVPROGERR 134 +#define BSTREAM_AUTH_HVSTATE 135 + +/***************************************************************************//** + * # Mailbox ECC Status + * Provides ECC status when the mailbox is read. The values are as follows: + * 00: No ECC errors detected, data is correct. + * 01: Exactly one bit error occurred and has been corrected. + * 10: Exactly two bits error occurred and no correction performed. + * 11: Reserved. + */ +#define SYS_MBOX_ECC_NO_ERROR_MASK 0x00u +#define SYS_MBOX_ONEBIT_ERROR_CORRECTED_MASK 0x40u +#define SYS_MBOX_TWOBIT_ERROR_MASK 0xC0u + +/***************************************************************************//** + * Service request command opcodes: +*/ +#define SERIAL_NUMBER_REQUEST_CMD 0x00u +#define USERCODE_REQUEST_CMD 0x01u +#define DESIGN_INFO_REQUEST_CMD 0x02u +#define DEVICE_CERTIFICATE_REQUEST_CMD 0x03u +#define READ_DIGEST_REQUEST_CMD 0x04u +#define QUERY_SECURITY_REQUEST_CMD 0x05u +#define READ_DEBUG_INFO_REQUEST_CMD 0x06u +#define READ_ENVM_PARAM_REQUEST_CMD 0x07u +#define SNVM_NON_AUTHEN_TEXT_REQUEST_CMD 0x10u +#define SNVM_AUTHEN_TEXT_REQUEST_CMD 0x11u +#define SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD 0x12u +#define SNVM_READ_REQUEST_CMD 0x18u +#define DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD 0x19u +#define PUF_EMULATION_SERVICE_REQUEST_CMD 0x20u +#define NONCE_SERVICE_REQUEST_CMD 0x21u +#define DIGITAL_SIGNATURE_DER_FORMAT_REQUEST_CMD 0x1Au + +#define BITSTREAM_AUTHENTICATE_CMD 0x23u +#define IAP_BITSTREAM_AUTHENTICATE_CMD 0x22u + +#define DIGEST_CHECK_CMD 0x47u + +#define IAP_PROGRAM_BY_SPIIDX_CMD 0x42u +#define IAP_VERIFY_BY_SPIIDX_CMD 0x44u +#define IAP_PROGRAM_BY_SPIADDR_CMD 0x43u +#define IAP_VERIFY_BY_SPIADDR_CMD 0x45u +#define IAP_AUTOUPDATE_CMD 0x46u + +/***************************************************************************//** + * Service request Mailbox return data length + */ +#define SERIAL_NUMBER_RESP_LEN 16u +#define USERCODE_RESP_LEN 4u +#define DESIGN_INFO_RESP_LEN 36u +#define DEVICE_CERTIFICATE_RESP_LEN 1024u +#define READ_DIGEST_RESP_LEN 416u +#define QUERY_SECURITY_RESP_LEN 9u +#define READ_DEBUG_INFO_RESP_LEN 76u +#define READ_ENVM_PARAM_RESP_LEN 256u +#define NONCE_SERVICE_RESP_LEN 32u + +#define PUF_EMULATION_SERVICE_CMD_LEN 20u +#define PUF_EMULATION_SERVICE_RESP_LEN 32u + +#define DIGITAL_SIGNATURE_HASH_LEN 48u +#define DIGITAL_SIGNATURE_RAW_FORMAT_RESP_SIZE 96u +#define DIGITAL_SIGNATURE_DER_FORMAT_RESP_SIZE 104u + +#define USER_SECRET_KEY_LEN 12u + +/* Same driver can be used on PolarFire SoC platform and the response length + * is different for PolarFire SoC. Constants defined below are used only when the + * PF System services driver is used with PolarFire SoC Platform. + */ +#define READ_DIGEST_MPFS_RESP_LEN 576u +#define QUERY_SECURITY_MPFS_RESP_LEN 33u + +/* SNVM Input data length from sNVM write. */ +#ifndef RT_DEVICE_FAMILY +/* SNVMADDR + RESERVED + PT + USK */ +#define NON_AUTHENTICATED_TEXT_DATA_LEN 256u + +/* SNVMADDR + RESERVED + PT */ +#define AUTHENTICATED_TEXT_DATA_LEN 252u +#else +/* SNVMADDR + RESERVED + PT + USK */ +#define NON_AUTHENTICATED_TEXT_DATA_LEN 224u + +/* SNVMADDR + RESERVED + PT */ +#define AUTHENTICATED_TEXT_DATA_LEN 220u +#endif + +/** + * # Digest Check Input Options + * + * DIGEST_CHECK_FABRIC + * Carry out digest check on Fabric + * + * DIGEST_CHECK_CC + * Carry out digest check on UFS Fabric Configuration (CC) segment + * + * DIGEST_CHECK_SNVM + * Carry out digest check on ROM digest in SNVM segment + * + * DIGEST_CHECK_UL + * Carry out digest check on UFS UL segment + * + * DIGEST_CHECK_UKDIGEST0 + * Carry out digest check on UKDIGEST0 in User Key segment + * + * DIGEST_CHECK_UKDIGEST1 + * Carry out digest check on UKDIGEST1 in User Key segment + * + * DIGEST_CHECK_UKDIGEST2 + * Carry out digest check on UKDIGEST2 in User Key segment (UPK1) + * + * DIGEST_CHECK_UKDIGEST3 + * Carry out digest check on UKDIGEST3 in User Key segment (UK1) + * + * DIGEST_CHECK_UKDIGEST4 + * Carry out digest check on UKDIGEST4 in User Key segment (DPK) + * + * DIGEST_CHECK_UKDIGEST5 + * Carry out digest check on UKDIGEST5 in User Key segment (UPK2) + * + * DIGEST_CHECK_UKDIGEST6 + * Carry out digest check on UKDIGEST6 in User Key segment (UK2) + * + * DIGEST_CHECK_UPERM + * Carry out digest check on UFS Permanent lock (UPERM) segment + * + * DIGEST_CHECK_SYS + * Carry out digest check on Factory and Factory Key Segments + * + */ +#define DIGEST_CHECK_FABRIC (0x01<<0x00u) /*Fabric digest*/ +#define DIGEST_CHECK_CC (0x01<<0x01u) /*UFS Fabric Configuration (CC) segment*/ +#define DIGEST_CHECK_SNVM (0x01<<0x02u) /*ROM digest in SNVM segment*/ +#define DIGEST_CHECK_UL (0x01<<0x03u) /*UFS UL segment*/ +#define DIGEST_CHECK_UKDIGEST0 (0x01<<0x04u) /*UKDIGEST0 in User Key segment*/ +#define DIGEST_CHECK_UKDIGEST1 (0x01<<0x05u) /*UKDIGEST1 in User Key segment*/ +#define DIGEST_CHECK_UKDIGEST2 (0x01<<0x06u) /*UKDIGEST2 in User Key segment (UPK1)*/ +#define DIGEST_CHECK_UKDIGEST3 (0x01<<0x07u) /*UKDIGEST3 in User Key segment (UK1)*/ +#define DIGEST_CHECK_UKDIGEST4 (0x01<<0x08u) /*UKDIGEST4 in User Key segment (DPK)*/ +#define DIGEST_CHECK_UKDIGEST5 (0x01<<0x09u) /*UKDIGEST5 in User Key segment (UPK2)*/ +#define DIGEST_CHECK_UKDIGEST6 (0x01<<0x0au) /*UKDIGEST6 in User Key segment (UK2)*/ +#define DIGEST_CHECK_UPERM (0x01<<0x0bu) /*UFS Permanent lock (UPERM) segment*/ +#define DIGEST_CHECK_SYS (0x01<<0x0cu) /*Factory and Factory Key Segments.*/ + +/***************************************************************************//** + * The function SYS_init() is used to initialize the internal data structures of + * this driver. Currently this function is empty. + * + * @param base_addr The base_addr parameter specifies the base address of the + * PF_System_services core. + * + * @return This function does not return a value. + */ +void +SYS_init +( + uint32_t base_addr +); + +/***************************************************************************//** + * The function SYS_get_serial_number() is used to execute "serial number" system + * service. + * + * @param p_serial_number The p_serial_number parameter is a pointer to a buffer + * in which the data returned by system controller + * is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t +SYS_get_serial_number +( + const uint8_t * p_serial_number, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_get_user_code() is used to execute "USERCODE" system + * service. + * @param p_user_code The p_user_code parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t +SYS_get_user_code +( + const uint8_t * p_user_code, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_get_design_info() is used to execute "Get Design Info" system + * service. + * + * @param p_design_info The p_design_info parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. Total size of debug information is 36 bytes. + * The data from the system controller includes the 256-bit + * user-defined design ID, 16-bit design version, and 16-bit + * design back level. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t +SYS_get_design_info +( + const uint8_t * p_design_info, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_get_device_certificate() is used to execute "Get Device + * Certificate" system service. + * + * @param p_device_certificate The p_device_certificate parameter is a pointer + * to a buffer in which the data returned by the + * system controller is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code means that + * the service was executed successfully. + * + */ +uint8_t +SYS_get_device_certificate +( + const uint8_t * p_device_certificate, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_read_digest() is used to execute "Read Digest" system service. + * + * @param p_digest The p_digest parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t SYS_read_digest +( + const uint8_t * p_digest, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_query_security() is used to execute "Query Security" system + * service. + * + * @param p_security_locks The p_security_locks parameter is a pointer to a buffer + * in which the data returned by system controller is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code means that + * the service was executed successfully. + */ +uint8_t SYS_query_security +( + uint8_t * p_security_locks, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_read_debug_info() is used to execute "Read Debug info" system + * service. + * + * @param p_debug_info The p_debug_info parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t SYS_read_debug_info +( + const uint8_t * p_debug_info, + uint16_t mb_offset +); + +#ifdef CORESYSSERVICES_PFSOC +/***************************************************************************//** + * The function SYS_read_envm_parameter() is used to retrieve all parameters needed + * for the eNVM operation and programming. + * + * NOTE: This service is available only on PolarFire SoC Platform. + * This service is not yet supported by PF_SYSTEM_SERVICES 3.0.100. + * + * @param p_envm_param The p_envm_param parameter is a pointer to a buffer + * in which the data returned by system controller is copied. + * This buffer stores all the eNVM parameters. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_read_envm_parameter service will return zero if the + * service executed successfully, otherwise, it will return + * one indicating error. + */ +uint8_t SYS_read_envm_parameter +( + uint8_t * p_envm_param, + uint16_t mb_offset +); +#endif +/***************************************************************************//** + * The function SYS_puf_emulation_service() is used to authenticate a device. + * + * The SYS_puf_emulation_service() function accept a challenge comprising a + * 8-bit optype and 128-bit challenge and return a 256-bit response unique to + * the given challenge and the device. + * + * @param p_challenge The p_challenge parameter specifies the 128-bit challenge + * to generate the 256-bits unique response. + * + * @param op_type The op_type parameter specifies the operational parameter + * to generate the 256-bits unique response. + * + * @param p_response The p_response parameter is a pointer to a buffer where + * the data returned which is the response by system controller + * is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_puf_emulation_service function will return zero + * if the service executed successfully, otherwise, it will + * return one indicating error. + */ +uint8_t SYS_puf_emulation_service +( + const uint8_t * p_challenge, + uint8_t op_type, + uint8_t* p_response, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_digital_signature_service() function is used to generate P-384 ECDSA + * signature based on SHA384 hash value. + * + * @param p_hash The p_hash parameter is a pointer to the buffer which + * contain the 48 bytes SHA384 Hash value (input value). + * + * @param format The format parameter specifies the output format of + * generated SIGNATURE field. The different types of output + * signature formats are as follow: + * - DIGITAL_SIGNATURE_RAW_FORMAT + * - DIGITAL_SIGNATURE_DER_FORMAT + * + * @param p_response The p_response parameter is a pointer to a buffer that + * contains the generated ECDSA signature. The field may be + * 96 bytes or 104 bytes depending upon the output format. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digital_signature_service function returns + * zero if the service executed successfully, otherwise, it + * returns non-zero values indicating error. + */ +uint8_t SYS_digital_signature_service +( + const uint8_t* p_hash, + uint8_t format, + uint8_t* p_response, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_secure_nvm_write() function writes data in the sNVM region. + * Data gets stored in the following format: + * - Non-authenticated plaintext + * - Authenticated plaintext + * - Authenticated ciphertext + * + * Note: If you are executing this function with Authenticated plaintext + * or Authenticated ciphertext on a device whose sNVM was never previously + * written to, then the service may fail. For it to work, you must first write + * Authenticated data to the sNVM using Libero along with USK client and + * custom security. This flow generates the SMK. See UG0753 PolarFire FPGA + * Security User Guide for further details. + + * @param format The format parameter specifies the format used to write + * data in sNVM region. The different type of text formats + * are as follow: + * - NON_AUTHENTICATED_PLAINTEXT_FORMAT + * - AUTHENTICATED_PLAINTEXT_FORMAT + * - AUTHENTICATED_CIPHERTEXT_FORMAT + * + * @param snvm_module The snvm_module parameter specifies the the sNVM module + * in which the data need to be written. + * + * @param p_data The p_data parameter is a pointer to a buffer which + * contains the data to be stored in sNVM region. The data + * length to be written is fixed depending on the format + * parameter. If NON_AUTHENTICATED_PLAINTEXT_FORMAT is + * selected, then you can write 252 bytes in the sNVM module. + * For other two formats the data length is 236 bytes. + * + * @param p_user_key The p_user_key parameter is a pointer to a buffer which + * contain the 96-bit key USK (user secret key). This user + * secret key will enhance the security when authentication + * is used. That is, when Authenticated plaintext and + * Authenticated ciphertext format is selected. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digital_signature_service function returns + * zero if the service executed successfully, otherwise, it + * returns non-zero values indicating error. + */ +uint8_t SYS_secure_nvm_write +( + uint8_t format, + uint8_t snvm_module, + const uint8_t* p_data, + const uint8_t* p_user_key, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_secure_nvm_read() function is used to read data present in sNVM region. + * User should provide USK key, if the data was programmed using authentication. + * If the data was written in the sNVM using the authenticated plaintext or the + * authenticated ciphertext service option then this service will return the + * valid data only when authentication is successful. For more details, see + * SYS_secure_nvm_write() function. If the data was written in + * the sNVM using the authenticated plaintext or the authenticated ciphertext + * service option then this service will return the valid data only when + * authentication is successful. For more details, see SYS_secure_nvm_write() + * function and its parameter description. + * + * @param snvm_module The snvm_module parameter specifies the sNVM module + * from which the data need to be read. + * + * @param p_user_key The p_user_key parameter is a pointer to a buffer which + * contain the 96-bit key USK (user secret key). User should + * provide same secret key which is previously used for + * authentication while writing data in sNVM region. + * + * @param p_admin The p_admin parameter is a pointer to the buffer where + * the output page admin data is stored. The page admin + * data is 4 bytes long. + * + * @param p_data The p_data parameter is a pointer to a buffer which + * contains the data read from sNVM region. User should + * provide the buffer large enough to store the read data. + * + * @param data_len The data_len parameter specifies the number of bytes to be + * read from sNVM. + * The application should know whether the data written in the + * chose sNVM module was previously stored using Authentication + * or not. + * The data_len should be 236 bytes, for authenticated data. + * For not authenticated data the data_len should be 252 bytes. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digital_signature_service function returns + * zero if the service executed successfully, otherwise, it + * returns non-zero values indicating error. + */ +uint8_t SYS_secure_nvm_read +( + uint8_t snvm_module, + const uint8_t* p_user_key, + uint8_t* p_admin, + uint8_t* p_data, + uint16_t data_len, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_nonce_service() is used to issue "Nonce Service" system + * service to the system controller. + * + * @param p_nonce The p_nonce parameter is a pointer to a buffer + * in which the data returned by system controller is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code means + * that the service was executed successfully and a non-zero + * value indicates error. See the document link + * provided in the theory of operation section to know more + * about the service and service response. + */ +uint8_t SYS_nonce_service +( + const uint8_t * p_nonce, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_bitstream_authenticate_service() function is used to authenticate + * the Bitstream which is located in SPI through a system service routine. Prior + * to using the IAP service, it may be required to first validate the new + * bitstream before committing the device to reprogramming, thus avoiding the + * need to invoke recovery procedures if the bitstream is invalid. + * + * This service is applicable to bitstreams stored in SPI Flash memory only. + * + * @param spi_flash_address + * The spi_flash_address parameter specifies the address within + * SPI Flash memory where the bit-stream is stored. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_bitstream_authenticate_service function will return + * zero if the service executed successfully and the non-zero + * response from system controller indicates error. See + * the document link provided in the theory of + * operation section to know more about the service and service + * response. + */ +uint8_t SYS_bitstream_authenticate_service +( + uint32_t spi_flash_address, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_IAP_image_authenticate_service() function is used to authenticate + * the IAP image which is located in SPI through a system service routine. The + * service checks the image descriptor and the referenced bitstream and optional + * initialization data. If the image is authenticated successfully, then the + * image is guaranteed to be valid when used by an IAP function. + * + * This service is applicable to bitstreams stored in SPI Flash memory only. + * + * @param spi_idx + * The spi_idx parameter specifies the index in the SPI directory to + * be used where the IAP bit-stream is stored. + * Note: To support recovery SPI_IDX=1 should be an empty slot and the recovery + * image should be located in SPI_IDX=0. Since SPI_IDX=1 should be an + * empty slot, it shouldn’t be passed into the system service. + * + * @return The SYS_IAP_image_authenticate_service function will return + * zero if the service executed successfully the non-zero + * response from system controller indicates error. Please + * refer to the document link provided in the theory of + * operation section to know more about the service and service + * response. + */ +uint8_t SYS_IAP_image_authenticate_service +( + uint8_t spi_idx +); + +/***************************************************************************//** + * The SYS_digest_check_service() function is used to Recalculates and compares + * digests of selected non-volatile memories. If the fabric digest is to be + * checked, then the user design must follow all prerequisite steps for the + * FlashFreeze service before invoking this service. + * This service is applicable to bitstreams stored in SPI Flash memory only. + * @param options + * The options parameter specifies the digest check options which + * indicate the area on which the digest check should be performed. + * Below is the list of options. You can OR these options to indicate + * to perform digest check on multiple segments. + * Note: The options parameter is of 2 bytes when used with PF + * device and 4 bytes when used with PolarFire SoC device. + * Options[i] | Description + * ---------------|---------------------------------- + * 0x01 | Fabric digest + * 0x02 | Fabric Configuration (CC) segment + * 0x04 | ROM digest in SNVM segment + * 0x08 | UL segment + * 0x10 | UKDIGEST0 in User Key segment + * 0x20 | UKDIGEST1 in User Key segment + * 0x40 | UKDIGEST2 in User Key segment (UPK1) + * 0x80 | UKDIGEST3 in User Key segment (UK1) + * 0x100 | UKDIGEST4 in User Key segment (DPK) + * 0x200 | UKDIGEST5 in User Key segment (UPK2) + * 0x400 | UKDIGEST6 in User Key segment (UK2) + * 0x800 | UFS Permanent lock (UPERM) segment + * 0x1000 | Factory and Factory Key Segments. + * 0x2000 | UKDIGEST7 in User Key segment (HWM) (PFSoC) + * 0x4000 | ENVMDIGEST (PFSoC only) + * 0x8000 | UKDIGEST8 for MSS Boot Info (PFSoC only) + * 0x10000 | SNVM_RW_ACCESS_MAP Digest (PFSoC only) + * 0x20000 | SBIC revocation digest (PFSoC only) + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digest_check_service function will return + * zero if the service executed successfully the non-zero + * response from system controller indicates error. Pleaes + * refer to the document link provided in the theory of + * operation section to know more about the service and service + * response. + */ +uint8_t SYS_digest_check_service +( + uint32_t options, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_iap_service() function is used to IAP service. The IAP service allows + * the user to reprogram the device without the need for an external master. The + * user design writes the bitstream to be programmed into a SPI Flash connected + * to the SPI port. When the service is invoked, the System Controller + * automatically reads the bitstream from the SPI flash and programs the device. + * The service allows the image to be executed in either VERIFY or PROGRAM modes. + * Another option for IAP is to perform the auto-update sequence. In this case + * the newest image of the first two images in the SPI directory is chosen to be + * programmed. + * + * @param iap_cmd + * The iap_cmd parameter specifies the specific IAP command which + * depends upon VERIFY or PROGRAM modes and the SPI address method. + * iap_cmd | Description + * -----------------------|------------ + * IAP_PROGRAM_BY_SPIIDX_CMD | IAP program. + * IAP_VERIFY_BY_SPIIDX_CMD | Fabric Configuration (CC) segment + * IAP_PROGRAM_BY_SPIADDR_CMD | ROM digest in SNVM segment + * IAP_VERIFY_BY_SPIADDR_CMD | UL segment + * IAP_AUTOUPDATE_CMD | UKDIGEST0 in User Key segment + * + * @param spiaddr + * The spiaddr parameter specifies either the index + * in the SPI directory or the SPI address in the SPI Flash memory. + * Below is the list of the possible meaning of spiaddr parameter + * in accordance with the iap_cmd parameter. + * iap_cmd | spiaddr + * ----------------------|----------------- + * IAP_PROGRAM_BY_SPIIDX_CMD | Index in the SPI directory. + * IAP_VERIFY_BY_SPIIDX_CMD | Index in the SPI directory. + * IAP_PROGRAM_BY_SPIADDR_CMD | SPI address in the SPI Flash memory + * IAP_VERIFY_BY_SPIADDR_CMD | SPI address in the SPI Flash memory + * IAP_AUTOUPDATE_CMD | spiaddr is ignored as No index/address required for this command. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * Note: For the IAP services with command IAP_PROGRAM_BY_SPIIDX_CMD and + * IAP_VERIFY_BY_SPIIDX_CMD To support recovery SPI_IDX=1 should be an + * empty slot and the recovery image should be located in SPI_IDX=0. + * Since SPI_IDX=1 should be an empty slot it shouldn’t be passed into + * the system service. + * + * @return The SYS_iap_service function will return zero if the service + * executed successfully and the non-zero response from system + * controller indicates error. Please refer to the document + * link provided in the theory of operation section to know + * more about the service and service response. + */ +uint8_t SYS_iap_service +( + uint8_t iap_cmd, + uint32_t spiaddr, + uint16_t mb_offset +); + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_SYSSERV_PF_H */ diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h new file mode 100644 index 0000000..8b14b7e --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h @@ -0,0 +1,149 @@ +/******************************************************************************* + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Register bit offsets and masks definitions for CoreSysServices_PF driver. + */ + +#ifndef __CORE_SYSSERV_PF_REGISTERS +#define __CORE_SYSSERV_PF_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * SYS_SERV_CMD (offset 0x04) register details + */ +#define SS_CMD_REG_OFFSET 0x04u + +#define SS_CMD_OFFSET 0x04 +#define SS_CMD_MASK 0x0000FFFFu +#define SS_CMD_SHIFT 0u + +/*------------------------------------------------------------------------------ + * SYS_SERV_STAT (offset 0x08) register details + */ +#define SS_STAT_REG_OFFSET 0x08u + +#define SS_STAT_OFFSET 0x08 +#define SS_STAT_MASK 0x0000FFFFu +#define SS_STAT_SHIFT 0u + +/*------------------------------------------------------------------------------ + * SYS_SERV_REQ (offset 0x0C) register details + */ +#define SS_REQ_REG_OFFSET 0x0Cu + + +#define SS_REQ_REQ_OFFSET 0x0Cu +#define SS_REQ_REQ_MASK 0x00000001UL +#define SS_REQ_REQ_SHIFT 0u + +#define SS_REQ_ABUSY_OFFSET 0x0Cu +#define SS_REQ_ABUSY_MASK 0x00000002UL +#define SS_REQ_ABUSY_SHIFT 1u + +#define SS_REQ_NABUSY_OFFSET 0x0Cu +#define SS_REQ_NABUSY_MASK 0x00000004UL +#define SS_REQ_NABUSY_SHIFT 2u + +#define SS_REQ_SSBUSY_OFFSET 0x0Cu +#define SS_REQ_SSBUSY_MASK 0x00000008UL +#define SS_REQ_SSBUSY_SHIFT 3u + +#define SS_REQ_AREQ_OFFSET 0x0Cu +#define SS_REQ_AREQ_MASK 0x00000010UL +#define SS_REQ_AREQ_SHIFT 4u + +#define SS_REQ_NAREQ_OFFSET 0x0Cu +#define SS_REQ_NAREQ_MASK 0x00000020UL +#define SS_REQ_NAREQ_SHIFT 5u +/*------------------------------------------------------------------------------ + * MBX_ECCSTATUS (offset 0x10) register details + */ +#define MBX_ECCSTATUS_REG_OFFSET 0x10u + +#define MBX_ECCSTATUS_OFFSET 0x10 +#define MBX_ECCSTATUS_MASK 0x03u +#define MBX_ECCSTATUS_SHIFT 0u + + +/*------------------------------------------------------------------------------ + * MBX_WCNT (offset 0x14) register details + */ +#define MBX_WCNT_REG_OFFSET 0x14u + +#define MBX_WCNT_OFFSET 0x14 +#define MBX_WCNT_MASK 0x000001FFu +#define MBX_WCNT_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_RWCNT (offset 0x18) register details + */ +#define MBX_RCNT_REG_OFFSET 0x18u + +#define MBX_RCNT_OFFSET 0x18 +#define MBX_RCNT_MASK 0x000001FFu +#define MBX_RCNT_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_WADRDESC (offset 0x1C) register details + */ +#define MBX_WADDR_REG_OFFSET 0x1Cu + +#define MBX_WADDR_OFFSET 0x1C +#define MBX_WADDR_MASK 0x000001FFu +#define MBX_WADDR_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_RADRDESC (offset 0x20) register details + */ +#define MBX_RADDR_REG_OFFSET 0x20u + +#define MBX_RADDR_OFFSET 0x20 +#define MBX_RADDR_MASK 0x000001FFu +#define MBX_RADDR_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_WDATA (offset 0x28) register details + */ +#define MBX_WDATA_REG_OFFSET 0x28u + +#define MBX_WDATA_OFFSET 0x28 +#define MBX_WDATA_MASK 0xFFFFFFFFu +#define MBX_WDATA_SHIFT 0u + + +/*------------------------------------------------------------------------------ + * MBX_RDATA (offset 0x2C) register details + */ +#define MBX_RDATA_REG_OFFSET 0x2Cu + +#define MBX_RDATA_OFFSET 0x2C +#define MBX_RDATA_MASK 0xFFFFFFFFu +#define MBX_RDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * SS_USER (offset 0x30) register details + */ +#define SS_USER_REG_OFFSET 0x30u + +#define SS_USER_BUSY_OFFSET 0x30 +#define SS_USER_BUSY_MASK 0x00000001u +#define SS_USER_BUSY_SHIFT 0u + +#define SS_USER_RDVLD_OFFSET 0x30 +#define SS_USER_RDVLD_MASK 0x00000002u +#define SS_USER_RDVLD_SHIFT 1u + +#define SS_USER_CMDERR_OFFSET 0x30 +#define SS_USER_CMDERR_MASK 0x00000004u +#define SS_USER_CMDERR_SHIFT 2u + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_SYSSERV_PF_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c new file mode 100644 index 0000000..0c0a866 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c @@ -0,0 +1,297 @@ +/******************************************************************************* + * (c) Copyright 2007-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file core_uart_apb.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreUARTapb driver implementation. See file "core_uart_apb.h" for + * description of the functions implemented in this file. + * + */ + +#include "coreuartapb_regs.h" +#include "core_uart_apb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define NULL_INSTANCE ( ( UART_instance_t* ) 0 ) +#define NULL_BUFFER ( ( uint8_t* ) 0 ) + +#define MAX_LINE_CONFIG ( ( uint8_t )( DATA_8_BITS | ODD_PARITY ) ) +#define MAX_BAUD_VALUE ( ( uint16_t )( 0x1FFF ) ) +#define STATUS_ERROR_MASK ( ( uint8_t )( STATUS_PARITYERR_MASK | \ + STATUS_OVERFLOW_MASK | \ + STATUS_FRAMERR_MASK ) ) +#define BAUDVALUE_LSB ( (uint16_t) (0x00FF) ) +#define BAUDVALUE_MSB ( (uint16_t) (0xFF00) ) +#define BAUDVALUE_SHIFT ( (uint8_t) (5) ) + +#define STATUS_ERROR_OFFSET STATUS_PARITYERR_SHIFT + +/***************************************************************************//** + * UART_init() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_init +( + UART_instance_t * this_uart, + addr_t base_addr, + uint16_t baud_value, + uint8_t line_config +) +{ + uint8_t rx_full; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( line_config <= MAX_LINE_CONFIG ) + HAL_ASSERT( baud_value <= MAX_BAUD_VALUE ) + + if( ( this_uart != NULL_INSTANCE ) && + ( line_config <= MAX_LINE_CONFIG ) && + ( baud_value <= MAX_BAUD_VALUE ) ) + { + /* + * Store lower 8-bits of baud value in CTRL1. + */ + HAL_set_8bit_reg( base_addr, CTRL1, (uint_fast8_t)(baud_value & + BAUDVALUE_LSB ) ); + + /* + * Extract higher 5-bits of baud value and store in higher 5-bits + * of CTRL2, along with line configuration in lower 3 three bits. + */ + HAL_set_8bit_reg( base_addr, CTRL2, (uint_fast8_t)line_config | + (uint_fast8_t)((baud_value & + BAUDVALUE_MSB) >> BAUDVALUE_SHIFT ) ); + + this_uart->base_address = base_addr; +#ifndef NDEBUG + { + uint8_t config; + uint8_t temp; + uint16_t baud_val; + baud_val = HAL_get_8bit_reg( this_uart->base_address, CTRL1 ); + config = HAL_get_8bit_reg( this_uart->base_address, CTRL2 ); + /* + * To resolve operator precedence between & and << + */ + temp = ( config & (uint8_t)(CTRL2_BAUDVALUE_MASK ) ); + baud_val |= (uint16_t)( (uint16_t)(temp) << BAUDVALUE_SHIFT ); + config &= (uint8_t)(~CTRL2_BAUDVALUE_MASK); + HAL_ASSERT( baud_val == baud_value ); + HAL_ASSERT( config == line_config ); + } +#endif + + /* + * Flush the receive FIFO of data that may have been received before the + * driver was initialized. + */ + rx_full = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_RXFULL_MASK; + while ( rx_full ) + { + HAL_get_8bit_reg( this_uart->base_address, RXDATA ); + rx_full = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_RXFULL_MASK; + } + + /* + * Clear status of the UART instance. + */ + this_uart->status = (uint8_t)0; + } +} + +/***************************************************************************//** + * UART_send() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_send +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +) +{ + size_t char_idx; + uint8_t tx_ready; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( tx_buffer != NULL_BUFFER ) + HAL_ASSERT( tx_size > 0 ) + + if( (this_uart != NULL_INSTANCE) && + (tx_buffer != NULL_BUFFER) && + (tx_size > (size_t)0) ) + { + for ( char_idx = (size_t)0; char_idx < tx_size; char_idx++ ) + { + /* Wait for UART to become ready to transmit. */ + do { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( !tx_ready ); + /* Send next character in the buffer. */ + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)tx_buffer[char_idx] ); + } + } +} + +/***************************************************************************//** + * UART_fill_tx_fifo() + * See "core_uart_apb.h" for details of how to use this function. + */ +size_t +UART_fill_tx_fifo +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +) +{ + uint8_t tx_ready; + size_t size_sent = 0u; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( tx_buffer != NULL_BUFFER ) + HAL_ASSERT( tx_size > 0 ) + + /* Fill the UART's Tx FIFO until the FIFO is full or the complete input + * buffer has been written. */ + if( (this_uart != NULL_INSTANCE) && + (tx_buffer != NULL_BUFFER) && + (tx_size > 0u) ) + { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + if ( tx_ready ) + { + do { + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)tx_buffer[size_sent] ); + size_sent++; + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( (tx_ready) && ( size_sent < tx_size ) ); + } + } + return size_sent; +} + +/***************************************************************************//** + * UART_get_rx() + * See "core_uart_apb.h" for details of how to use this function. + */ +size_t +UART_get_rx +( + UART_instance_t * this_uart, + uint8_t * rx_buffer, + size_t buff_size +) +{ + uint8_t new_status; + uint8_t rx_full; + size_t rx_idx = 0u; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( rx_buffer != NULL_BUFFER ) + HAL_ASSERT( buff_size > 0 ) + + if( (this_uart != NULL_INSTANCE) && + (rx_buffer != NULL_BUFFER) && + (buff_size > 0u) ) + { + rx_idx = 0u; + new_status = HAL_get_8bit_reg( this_uart->base_address, STATUS ); + this_uart->status |= new_status; + rx_full = new_status & STATUS_RXFULL_MASK; + while ( ( rx_full ) && ( rx_idx < buff_size ) ) + { + rx_buffer[rx_idx] = HAL_get_8bit_reg( this_uart->base_address, + RXDATA ); + rx_idx++; + new_status = HAL_get_8bit_reg( this_uart->base_address, STATUS ); + this_uart->status |= new_status; + rx_full = new_status & STATUS_RXFULL_MASK; + } + } + return rx_idx; +} + +/***************************************************************************//** + * UART_polled_tx_string() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_polled_tx_string +( + UART_instance_t * this_uart, + const uint8_t * p_sz_string +) +{ + uint32_t char_idx; + uint8_t tx_ready; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( p_sz_string != NULL_BUFFER ) + + if( ( this_uart != NULL_INSTANCE ) && ( p_sz_string != NULL_BUFFER ) ) + { + char_idx = 0U; + while( 0U != p_sz_string[char_idx] ) + { + /* Wait for UART to become ready to transmit. */ + do { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( !tx_ready ); + /* Send next character in the buffer. */ + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)p_sz_string[char_idx] ); + char_idx++; + } + } +} + +/***************************************************************************//** + * UART_get_rx_status() + * See "core_uart_apb.h" for details of how to use this function. + */ +uint8_t +UART_get_rx_status +( + UART_instance_t * this_uart +) +{ + uint8_t status = UART_APB_INVALID_PARAM; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + /* + * Extract UART error status and place in lower bits of "status". + * Bit 0 - Parity error status + * Bit 1 - Overflow error status + * Bit 2 - Frame error status + */ + if( this_uart != NULL_INSTANCE ) + { + status = ( ( this_uart->status & STATUS_ERROR_MASK ) >> + STATUS_ERROR_OFFSET ); + /* + * Clear the sticky status for this instance. + */ + this_uart->status = (uint8_t)0; + } + return status; +} + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h new file mode 100644 index 0000000..c016403 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h @@ -0,0 +1,451 @@ +/******************************************************************************* + * (c) Copyright 2007-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file core_uart_apb.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief This file contains the application programming interface for the + * CoreUARTapb bare metal driver. + * + */ +/*=========================================================================*//** + @mainpage CoreUARTapb Bare Metal Driver. + + @section intro_sec Introduction + CoreUARTapb is an implementation of the Universal Asynchronous + Receiver/Transmitter aimed at minimal FPGA tile usage within a Microchip FPGA. + The CoreUARTapb bare metal software driver is designed to be used in systems + with no operating system. + + The CoreUARTapb driver provides functions for basic polled transmitting and + receiving operations. It also provide functions that allow the use of the + CoreUARTapb in interrupt-driven mode but leaves the management of interrupts + to the calling application, as interrupt enabling and disabling are not + controlled through the CoreUARTapb registers. The CoreUARTapb driver is + provided as C source code. + + @section driver_configuration Driver Configuration + Your application software should configure the CoreUARTapb driver by calling + the UART_init() function for each CoreUARTapb instance in the hardware design. + The configuration parameters include the CoreUARTapb hardware instance base + address and other runtime parameters, such as baud rate, bit width, and + parity. No CoreUARTapb hardware configuration parameters are needed by the + driver, apart from the CoreUARTapb hardware instance base address. Hence, no + additional configuration files are required to use the driver. + + A CoreUARTapb hardware instance is generated with fixed baud rate, character + size, and parity configuration settings as part of the hardware flow. The + baud_value and line_config parameter values passed to the UART_init() function + have no effect if fixed values were selected for the baud rate, character + size, and parity in the hardware configuration of CoreUARTapb. When fixed + values are selected for these hardware configuration parameters, the driver is + unable to overwrite the fixed values in the CoreUARTapb control registers, + CTRL1 and CTRL2. + + @section theory_op Theory of Operation + The CoreUARTapb software driver is designed to allow the control of multiple + instances of CoreUARTapb. Each instance of CoreUARTapb in the hardware design + is associated with a single instance of the UART_instance_t structure in the + software. You need to allocate memory for one unique UART_instance_t structure + instance for each CoreUARTapb hardware instance. The contents of these data + structures are initialized while calling the UART_init() function. A pointer + to the structure is passed to the subsequent driver functions in order to + identify the CoreUARTapb hardware instance you wish to perform the requested + operation on. + + Note: Do not attempt to directly manipulate the content of UART_instance_t + structures. This structure is only intended to be modified by the driver + function. + + Once initialized, the driver transmits and receives data. Transmit is + performed using the UART_send() function. If this function blocks, then it + returns only when the data passed to it has been sent to the CoreUARTapb + hardware. Data received by the CoreUARTapb hardware is read by the user + application using the UART_get_rx() function. + + The UART_fill_tx_fifo() function is also provided as a part of the + interrupt-driven transmit. This function fills the CoreUARTapb hardware + transmit FIFO with the content of a data buffer passed as a parameter before + returning. The control of the interrupts must be implemented outside the + driver, as the CoreUARTapb hardware does not provide the ability to enable + or disable its interrupt sources. + + The UART_polled_tx_string() function is provided to transmit a NULL-terminated + string in polled mode. If this function blocks, then it returns only when the + data passed to it has been sent to the CoreUARTapb hardware. + + The UART_get_rx_status() function returns the error status of the CoreUARTapb + receiver. This is used by applications to take appropriate action in case of + receiver errors. +*//*=========================================================================*/ +#ifndef __CORE_UART_APB_H +#define __CORE_UART_APB_H 1 + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + Data Bits Length Defines + ======================== + These constants define the data length in a UART packet. + | Constant | Description | + |-------------|---------------------------------------| + | DATA_7_BITS | Data length is 7-bits | + | DATA_8_BITS | Data length is 8-bits | + */ +#define DATA_7_BITS 0x00u +#define DATA_8_BITS 0x01u + +/***************************************************************************//** + Parity Defines + ============== + These constants define parity check options. + | Constant | Description | + |-------------|---------------------------------------| + | NO_PARITY | No Parity bit | + | EVEN_PARITY | Even Parity bit | + | ODD_PARITY | ODD Parity bit | + */ +#define NO_PARITY 0x00u +#define EVEN_PARITY 0x02u +#define ODD_PARITY 0x06u + +/***************************************************************************//** + Error Status Definitions + ======================== + These constants define the different types of possible errors in UART + transmission of data. + | Constant | Description | + |-------------------------|---------------------------------------| + | UART_APB_PARITY_ERROR | Data parity error | + | UART_APB_OVERFLOW_ERROR | Data overflow error | + | UART_APB_FRAMING_ERROR | Data framing error | + | UART_APB_NO_ERROR | No error | + | UART_APB_INVALID_PARAM | Invalid parameter | + */ +#define UART_APB_PARITY_ERROR 0x01u +#define UART_APB_OVERFLOW_ERROR 0x02u +#define UART_APB_FRAMING_ERROR 0x04u +#define UART_APB_NO_ERROR 0x00u +#define UART_APB_INVALID_PARAM 0xFFu + +/***************************************************************************//** + * There should be one instance of this structure for each instance of + * CoreUARTapb in your system. This structure instance identifies various UARTs + * in a system and should be passed as first parameter to UART functions to + * identify which UART performs the requested operation. The 'status' element in + * the structure is used to provide sticky status information. + */ +typedef struct +{ + addr_t base_address; + uint8_t status; +} UART_instance_t; + +/***************************************************************************//** + * The UART_init() function initializes the UART with the configuration passed + * as parameters. The configuration parameters are the baud_value that generates + * the baud rate and the line configuration (bit length and parity). + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data regarding + * this instance of the CoreUARTapb. This pointer is used to + * identify the target CoreUARTapb hardware instance in + * subsequent calls to the CoreUARTapb functions. + * @param base_addr The base_address parameter is the base address in the + * processor's memory map for the registers of the + * CoreUARTapb instance being initialized. + * @param baud_value The baud_value parameter selects the baud rate for the + * UART. The baud value is calculated from the frequency of + * the system clock in hertz and the desired baud rate using + * the following equation: + * baud_value = (clock / (baud_rate * 16)) - 1. + * The baud_value parameter must be a value in the range 0 + * to 8191 (or 0x0000 to 0x1FFF). + * @param line_config This parameter is the line configuration, specifies the + * bit length and parity settings. This is the logical OR of: + * - DATA_7_BITS + * - DATA_8_BITS + * - NO_PARITY + * - EVEN_PARITY + * - ODD_PARITY + * For example, 8 bits even parity would be specified as + * (DATA_8_BITS | EVEN_PARITY). + * @return This function does not return a value. + * @example + * @code + * #define BAUD_VALUE_57600 25 + * + * #define COREUARTAPB0_BASE_ADDR 0xC3000000UL + * + * UART_instance_t g_uart; + * int main() + * { + * UART_init(&g_uart, COREUARTAPB0_BASE_ADDR, + BAUD_VALUE_57600, (DATA_8_BITS | EVEN_PARITY)); + * } + * @endcode + */ +void +UART_init +( + UART_instance_t * this_uart, + addr_t base_addr, + uint16_t baud_value, + uint8_t line_config +); + +/***************************************************************************//** + * The UART_send() function is used to transmit data. It transfers the content + * of the transmitter data buffer, passed as a function parameter, into the + * UART's hardware transmitter FIFO. It returns when the full content of the + * transmitter data buffer has been transferred to the UART's transmitter FIFO. + * + * Note: You should not assume that the data you are sending using this function + * has been received at the other end by the time this function returns. The + * actual transmission over the serial connection is still be taking place at + * the time of the function return. It is safe to release or reuse the memory + * used as the transmit buffer once this function returns. + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data + * regarding this instance of the CoreUARTapbUART. + * @param tx_buffer The tx_buffer parameter is a pointer to a buffer that + * contains the data to be transmitted. + * @param tx_size The tx_size parameter is the size in bytes of the + * transmitted data. + * + * @return This function does not return a value. + * + * @example + * @code + * uint8_t testmsg1[] = {"\n\r\n\r\n\rUART_send() test message 1"}; + * UART_send(&g_uart,(const uint8_t *)&testmsg1,sizeof(testmsg1)); + * @endcode + */ +void +UART_send +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +); + +/***************************************************************************//** + * The UART_fill_tx_fifo() function fills the UART's transmitter hardware FIFO + * with the data found in the transmitter buffer that is passed in as a + * function parameter. The function returns either when the FIFO is full or + * when the complete contents of the transmitter buffer have been copied into + * the FIFO. It returns the number of bytes copied into the UART's transmitter + * hardware FIFO. This function is intended to be used as part of + * interrupt-driven transmission. + * + * Note: You should not assume that the data you transmit using this function + * has been received at the other end by the time this function returns. The + * actual transmission over the serial connection is still be taking place at + * the time of the function return. + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data + * regarding this instance of the UART. + * @param tx_buffer The tx_buffer parameter is a pointer to a buffer that + * contains the data to be transmitted. + * @param tx_size The tx_size parameter is the size in bytes of the + * transmitted data. + * @return This function returns the number of bytes copied into + * the UART's transmitter hardware FIFO. + * + * @example + * @code + * void send_using_interrupt + * ( + * uint8_t * pbuff, + * size_t tx_size + * ) + * { + * size_t size_in_fifo; + * size_in_fifo = UART_fill_tx_fifo( &g_uart, pbuff, tx_size ); + * } + * @endcode + */ +size_t +UART_fill_tx_fifo +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +); + +/***************************************************************************//** + * The UART_get_rx() function reads the content of the UART's receiver hardware + * FIFO and stores it in the receiver buffer that is passed in as a function + * parameter. It copies either the full contents of the FIFO into the receiver + * buffer, or just enough data from the FIFO to fill the receiver buffer, + * depending on the size of the receiver buffer. The size of the receiver + * buffer is passed in as a function parameter. UART_get_rx() returns the number + * of bytes copied into the receiver buffer. If no data was received at the time + * the function is called, the function returns 0. + * + * Note: This function reads and accumulates the receiver status of the + * CoreUARTapb instance before reading each byte from the receiver's + * data register/FIFO. This allows the driver to maintain a sticky + * record of any receiver errors that occur as the UART receives each + * data byte; receiver errors would otherwise be lost after each read + * from the receiver's data register. A call to the UART_get_rx_status() + * function returns any receiver errors accumulated during the execution + * of the UART_get_rx() function. + * + * Note: When FIFO mode is disabled in the CoreUARTapb hardware configuration, + * the driver accumulates a sticky record of any parity errors, framing + * errors, or overflow errors. When FIFO mode is enabled, the driver + * accumulates a sticky record of overflow errors only; in this case, + * interrupts must be used to handle parity errors or framing errors. + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data + * regarding this instance of the UART. + * @param rx_buffer The rx_buffer parameter is a pointer to a buffer where + * the received data is copied. + * @param buff_size The buff_size parameter is the size of the receive + * buffer in bytes. + * @return This function returns the number of bytes copied into + * the receive buffer. + * + * @example + * @code + * #define MAX_RX_DATA_SIZE 256 + * + * uint8_t rx_data[MAX_RX_DATA_SIZE]; + * uint8_t rx_size = 0; + * + * rx_size = UART_get_rx( &g_uart, rx_data, sizeof(rx_data) ); + * @endcode + */ +size_t +UART_get_rx +( + UART_instance_t * this_uart, + uint8_t * rx_buffer, + size_t buff_size +); + +/***************************************************************************//** + * The UART_polled_tx_string() function is used to transmit a NULL ('\0') + * terminated string. Internally, it polls for the transmit ready status and + * transfers the text starting at the address pointed by p_sz_string into + * the UART's hardware transmitter FIFO. It is a blocking function and returns + * only when the complete string has been transferred to the UART's transmit + * FIFO. + * + * Note: You should not assume that the data you transmit using this function + * has been received at the other end by the time this function returns. The + * actual transmission over the serial connection is still be taking place at + * the time of the function return. + * + * @param this_uart The this_uart parameter is the pointer to a + * UART_instance_t structure, which holds all data + * regarding this instance of the UART. + * @param p_sz_string The p_sz_string parameter is a pointer to a buffer + * containing the NULL ('\0') terminated string to be + * transmitted. + * @return This function does not return a value. + * + * @example + * @code + * uint8_t testmsg1[] = {"\r\n\r\nUART_polled_tx_string() test message 1\0"}; + * UART_polled_tx_string(&g_uart,(const uint8_t *)&testmsg1); + * @endcode + */ +void +UART_polled_tx_string +( + UART_instance_t * this_uart, + const uint8_t * p_sz_string +); + +/***************************************************************************//** + * The UART_get_rx_status() function returns the receiver error status of the + * CoreUARTapb instance. It reads both the current error status of the receiver + * and the accumulated error status from preceding calls to the UART_get_rx() + * function and combines them using a bitwise OR. It returns the cumulative + * parity, framing, and overflow error status of the receiver, since the + * previous call to UART_get_rx_status() as an 8-bit encoded value. + * + * Note: The UART_get_rx() function reads and accumulates the receiver status + * of the CoreUARTapb instance before reading each byte from the receiver's data + * register/FIFO. The driver maintains a sticky record of the cumulative error + * status, which persists after the UART_get_rx() function returns. The + * UART_get_rx_status() function clears this accumulated record of receiver + * errors before returning. + * + * @param this_uart The this_uart parameter is a pointer to a + * UART_instance_t structure which holds all data regarding + * this instance of the UART. + * @return This function returns the UART receiver error status as + * an 8-bit encoded value. The return value is 0, if there + * are no receiver errors occurred. The driver provides a + * set of bit mask constants, which should be compared with + * and/or used to mask the returned value to determine the + * receiver error status. + * When the return value is compared to the following bit + * masks, a non-zero result indicates that the + * corresponding error occurred: + * UART_APB_PARITY_ERROR (bit mask = 0x01) + * UART_APB_OVERFLOW_ERROR (bit mask = 0x02) + * UART_APB_FRAMING_ERROR (bit mask = 0x04) + * When the return value is compared to the following bit + * mask, a non-zero result indicates that no error + * occurred: + * UART_APB_NO_ERROR (0x00) + * + * @example + * @code + * UART_instance_t g_uart; + * uint8_t rx_data[MAX_RX_DATA_SIZE]; + * uint8_t err_status; + * err_status = UART_get_err_status(&g_uart); + * + * if(UART_APB_NO_ERROR == err_status ) + * { + * rx_size = UART_get_rx( &g_uart, rx_data, MAX_RX_DATA_SIZE ); + * } + * @endcode + */ +uint8_t +UART_get_rx_status +( + UART_instance_t * this_uart +); + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_UART_APB_H */ diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h new file mode 100644 index 0000000..c123cc3 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h @@ -0,0 +1,133 @@ +/******************************************************************************* + * (c) Copyright 2007-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file coreuartapb_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreUARTapb register definitions + */ + +#ifndef __CORE_UART_APB_REGISTERS +#define __CORE_UART_APB_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * TxData register details + */ +#define TXDATA_REG_OFFSET 0x0u + +/* + * TxData bits. + */ +#define TXDATA_OFFSET 0x0u +#define TXDATA_MASK 0xFFu +#define TXDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * RxData register details + */ +#define RXDATA_REG_OFFSET 0x4u + +/* + * RxData bits. + */ +#define RXDATA_OFFSET 0x4u +#define RXDATA_MASK 0xFFu +#define RXDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * ControReg1 register details + */ +#define CTRL1_REG_OFFSET 0x8u + +/* + * Baud value (Lower 8-bits) + */ +#define CTRL1_BAUDVALUE_OFFSET 0x8u +#define CTRL1_BAUDVALUE_MASK 0xFFu +#define CTRL1_BAUDVALUE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * ControReg2 register details + */ +#define CTRL2_REG_OFFSET 0xCu + +/* + * Bit length + */ +#define CTRL2_BIT_LENGTH_OFFSET 0xCu +#define CTRL2_BIT_LENGTH_MASK 0x01u +#define CTRL2_BIT_LENGTH_SHIFT 0u + +/* + * Parity enable. + */ +#define CTRL2_PARITY_EN_OFFSET 0xCu +#define CTRL2_PARITY_EN_MASK 0x02u +#define CTRL2_PARITY_EN_SHIFT 1u + +/* + * Odd/even parity selection. + */ +#define CTRL2_ODD_EVEN_OFFSET 0xCu +#define CTRL2_ODD_EVEN_MASK 0x04u +#define CTRL2_ODD_EVEN_SHIFT 2u + +/* + * Baud value (Higher 5-bits) + */ +#define CTRL2_BAUDVALUE_OFFSET 0xCu +#define CTRL2_BAUDVALUE_MASK 0xF8u +#define CTRL2_BAUDVALUE_SHIFT 3u + +/*------------------------------------------------------------------------------ + * StatusReg register details + */ +#define StatusReg_REG_OFFSET 0x10u + +#define STATUS_REG_OFFSET 0x10u + +/* + * Transmit ready. + */ +#define STATUS_TXRDY_OFFSET 0x10u +#define STATUS_TXRDY_MASK 0x01u +#define STATUS_TXRDY_SHIFT 0u + +/* + * Receive full. + */ +#define STATUS_RXFULL_OFFSET 0x10u +#define STATUS_RXFULL_MASK 0x02u +#define STATUS_RXFULL_SHIFT 1u + +/* + * Parity error. + */ +#define STATUS_PARITYERR_OFFSET 0x10u +#define STATUS_PARITYERR_MASK 0x04u +#define STATUS_PARITYERR_SHIFT 2u + +/* + * Overflow. + */ +#define STATUS_OVERFLOW_OFFSET 0x10u +#define STATUS_OVERFLOW_MASK 0x08u +#define STATUS_OVERFLOW_SHIFT 3u + +/* + * Frame Error. + */ +#define STATUS_FRAMERR_OFFSET 0x10u +#define STATUS_FRAMERR_MASK 0x10u +#define STATUS_FRAMERR_SHIFT 4u + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_UART_APB_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.c b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.c new file mode 100644 index 0000000..a2f4911 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.c @@ -0,0 +1,765 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Mi-V I2C Soft IP bare-metal driver. This module is delivered as part of + * Extended Sub System(ESS) MIV_ESS. + * Please refer to miv_i2c.h file for more information. + */ + +#include "miv_i2c.h" + +#define MIV_I2C_ERROR 0xFFu + +/*------------------------------------------------------------------------------ + * MIV I2C transaction direction. + */ +#define MIV_I2C_WRITE_DIR 0u +#define MIV_I2C_READ_DIR 1u + +/* -- TRANSACTIONS TYPES -- */ +#define MIV_I2C_NO_TRANSACTION 0u +#define MIV_I2C_MASTER_WRITE_TRANSACTION 1u +#define MIV_I2C_MASTER_READ_TRANSACTION 2u +#define MIV_I2C_MASTER_SEQUENTIAL_READ_TRANSACTION 3u + +/*------------------------------------------------------------------------------ + * MIV I2C HW states + */ +#define MIV_I2C_IDLE 0x00u +#define MIV_I2C_TX_STA_CB 0x01u +#define MIV_I2C_TX_DATA 0x02u +#define MIV_I2C_RX_DATA 0x03u + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_disable_irq() disables the Mi-V I2C interrupt. + */ +void +MIV_I2C_disable_irq +( + void +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_enable_irq() enables the Mi-V I2C interrupt. + */ +void +MIV_I2C_enable_irq +( + void +); + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_init +( + miv_i2c_instance_t *this_i2c, + addr_t base_addr +) +{ + /* Assign the base address + * Clock Prescale value set + * MIV_I2C interrupt enabled + * I2C core enable + */ + psr_t processor_state; + + /* Disabling the interrupts */ + processor_state = HAL_disable_interrupts(); + + /* + * Initialize all items of the this_miv_i2c data structure to zero. This + * initializes all state variables to their init value. It relies on + * the fact that NO_TRANSACTION, MIV_I2C_SUCCESS and I2C_RELEASE_BUS all + * have an actual value of zero. + */ + memset(this_i2c, 0, sizeof(miv_i2c_instance_t)); + + this_i2c->base_addr = base_addr; + + HAL_restore_interrupts(processor_state); +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_config +( + miv_i2c_instance_t *this_i2c, + uint16_t clk_prescale +) +{ + /* Assign the base address + * Clock Prescale value set + * MIV_I2C interrupt enabled + * I2C core enable + */ + psr_t processor_state; + + /* Disabling the interrupts */ + processor_state = HAL_disable_interrupts(); + + /* Before writing to prescale reg, the core enable must be zero */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CTRL_CORE_EN, 0x00u); + + /* Set the prescale value */ + HAL_set_16bit_reg(this_i2c->base_addr, PRESCALE, clk_prescale); + + /* Enable the MIV I2C interrupts */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CTRL_IRQ_EN, 0x01u); + + /* Enable the MIV I2C core */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CTRL_CORE_EN, 0x01u); + + this_i2c->master_state = MIV_I2C_IDLE; + + HAL_restore_interrupts(processor_state); +} + +/* + * Please refer to miv_i2c.h for more info + */ +uint8_t +MIV_I2C_start +( + miv_i2c_instance_t *this_i2c +) +{ + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + /* Generate I2C start condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + HAL_restore_interrupts(processor_state); + + return 0u; +} + +/* + * Please refer to miv_i2c.h for more info + */ +uint8_t +MIV_I2C_stop +( + miv_i2c_instance_t *this_i2c +) +{ + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + /* Generate I2C stop condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + HAL_restore_interrupts(processor_state); + + return 0u; +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_write +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t bus_options, + uint8_t ack_polling_options +) +{ + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + /* I2C write flow + * + * Check I2C status for ongoing transaction + * Populate the structure with input data + * Generate start condition + * Set the write_direction and target address. + */ + + /* Update the transaction only when there is no ongoing I2C transaction */ + if (this_i2c->transaction == MIV_I2C_NO_TRANSACTION) + { + this_i2c->transaction = MIV_I2C_MASTER_WRITE_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MIV_I2C_MASTER_WRITE_TRANSACTION ; + + /* Populate the i2c instance structure */ + + /* Set the target addr */ + this_i2c->target_addr = i2c_target_addr; + this_i2c->dir = MIV_I2C_WRITE_DIR; + + /* Set up the tx buffer */ + this_i2c->master_tx_buffer = write_buffer; + this_i2c->master_tx_size = write_size; + this_i2c->master_tx_idx = 0u; + + /* Set the I2C status in progress and setup the options */ + this_i2c->bus_options = bus_options; + this_i2c->ack_polling_options = ack_polling_options; + this_i2c->master_status = MIV_I2C_IN_PROGRESS; + + + /* Generate I2C start condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* write target address and write bit */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, MIV_I2C_WRITE_DIR); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, i2c_target_addr); + + /* Set WR bit to transmit start condition and control byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + /* Set current master hw state -> transmitted start condition and + * control byte + */ + this_i2c->master_state = MIV_I2C_TX_STA_CB; + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( MIV_I2C_HOLD_BUS == this_i2c->bus_status ) + { + /* Must toggle IACK bit to clear the MIV_I2C IRQ*/ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00); + } + + MIV_I2C_enable_irq(); + + HAL_restore_interrupts(processor_state); + +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_read +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +) +{ + psr_t processor_state; + uint8_t status = MIV_I2C_SUCCESS; + + processor_state = HAL_disable_interrupts(); + + /* MIV I2C Read operation flow + * + * Check for ongoing transaction + * Populate the i2c instance structure + * Generate the start condition + * Set the READ_direction bit and target addr + */ + + uint8_t read_stat = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_TIP); + + /* Update the transaction only when there is no ongoing I2C transaction */ + if (this_i2c->transaction == MIV_I2C_NO_TRANSACTION) + { + this_i2c->transaction = MIV_I2C_MASTER_READ_TRANSACTION; + } + + this_i2c->pending_transaction = MIV_I2C_MASTER_READ_TRANSACTION; + + /* Populate the MIV I2C instance structure */ + + this_i2c->target_addr = i2c_target_addr; + this_i2c->dir = MIV_I2C_READ_DIR; + + /* Populate read buffer */ + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set the BUS and ACK polling options */ + this_i2c->bus_options = bus_options; + this_i2c->ack_polling_options = ack_polling_options; + + /* Generate the start condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* Set the DIR bit and target addr */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, MIV_I2C_READ_DIR); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, i2c_target_addr); + + /* Set the WR bit to transmit the start condition and command byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + /* Set the i2c master state and status transmitting STA and Command Byte */ + this_i2c->master_state = MIV_I2C_TX_STA_CB; + this_i2c->master_status = MIV_I2C_IN_PROGRESS; + + /* Toggle the IACK bit if required */ + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( MIV_I2C_HOLD_BUS == this_i2c->bus_status ) + { + /* Must toggle IACK bit to clear the MIV_I2C IRQ*/ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00); + } + /* Enable the I2C interrupt */ + MIV_I2C_enable_irq(); + + HAL_restore_interrupts(processor_state); +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_write_read +( + miv_i2c_instance_t *this_i2c, + uint8_t target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +) +{ + uint8_t status = MIV_I2C_SUCCESS; + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + uint8_t read_stat = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_TIP); + + /* I2C write read operation flow + * + * Used to read the data from set address offset + * + * Configure the i2c instance structure + * generate the start and configure the dir and target addr + * set wr bit to transmit the start and command byte + * + */ + + /* Update the transaction only when there is no ongoing I2C transaction */ + if (this_i2c->transaction == MIV_I2C_NO_TRANSACTION) + { + this_i2c->transaction = MIV_I2C_MASTER_READ_TRANSACTION; + } + + this_i2c->pending_transaction = MIV_I2C_MASTER_READ_TRANSACTION; + + /* Populate the I2C instance */ + + this_i2c->target_addr = target_addr; + + /* setup the i2c direction */ + this_i2c->dir = MIV_I2C_WRITE_DIR; + + /* set up transmit buffer */ + this_i2c->master_tx_buffer = write_buffer; + this_i2c->master_tx_size = write_size; + this_i2c->master_tx_idx = 0u; + + /* set up receive buffer */ + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set the bus and ack polling options */ + this_i2c->bus_options = bus_options; + this_i2c->ack_polling_options = ack_polling_options; + + /* Generate the start command */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* Set the DIR and target addr */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + /* Set the WR bit to transmit the start command and command byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + /* Set the i2c master state and status transmitting STA and Command Byte */ + this_i2c->master_state = MIV_I2C_TX_STA_CB; + this_i2c->master_status = MIV_I2C_IN_PROGRESS; + + /* + * Clear interrupt if required + */ + if ( MIV_I2C_HOLD_BUS == this_i2c->bus_status ) + { + /* Must toggle IACK bit to clear the MIV_I2C IRQ*/ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00u); + } + + /* Enable the I2C interrupt */ + MIV_I2C_enable_irq(); + + HAL_restore_interrupts(processor_state); +} + +/* MIV_I2C_isr() + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_isr +( + miv_i2c_instance_t *this_i2c +) +{ + uint8_t i2c_state; + uint8_t i2c_ack_status; + uint8_t i2c_al_status; + uint8_t hold_bus; + + /* Read the I2C master state */ + i2c_state = this_i2c->master_state; + + /* Read the ack and al status */ + i2c_ack_status = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_RXACK); + i2c_al_status = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_AL); + + switch (i2c_state) + { + /* I2C ISR State Machine + * + * Cases: + * - Transmit start condition and control byte + * - Received ACK and bus arbitration was not lost (Read or Write) + * - Received NACK + * - Bus arbitration lost + * + * - Transmit data + * - Received ACK and bus arbitration was not lost (Read or Write) + * - Received NACK + * - Bus arbitration lost + * + * - Receive data + * - Received ACK and bus arbitration was not lost (Read or Write) + * - Bus arbitration lost + */ + + case MIV_I2C_TX_STA_CB: + + /* Received ACK from target and I2C bus arbitration is not lost */ + if (i2c_ack_status == 0u && i2c_al_status == 0u) + { + /* If I2C master write operation */ + if (this_i2c->dir == MIV_I2C_WRITE_DIR) + { + /* write first byte of data and set the WR bit to transfer the data */ + HAL_set_8bit_reg(this_i2c->base_addr, TRANSMIT, + this_i2c->master_tx_buffer[this_i2c->master_tx_idx]); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + /* Increment the index */ + this_i2c->master_tx_idx++; + + /* Set the master state to TX data */ + this_i2c->master_state = MIV_I2C_TX_DATA; + } + /* Master read operation */ + else + { + if (this_i2c->master_rx_size == 1u) + { + /* Send the ACK if the rx size is 1, transmit NACK to slave + * after receiving 1 byte to indicate slave to stop sending + * the data + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_ACK, 0x01u); + } + + /* Send the RD command to slave */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_RD, 0x01u); + + /* Increment the index */ + this_i2c->master_rx_idx++; + + /* Change state to receive data */ + this_i2c->master_state = MIV_I2C_RX_DATA; + } + } + else if (i2c_ack_status == 1u) + { + if (this_i2c->ack_polling_options == MIV_I2C_ACK_POLLING_ENABLE) + { + /* Target responded with NACK and ACK polling option is enabled + * + * Re-send the start condition and control byte + * + * TO-DO: This might become infinite loop check for timeout + * options. + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + this_i2c->master_tx_idx = 0u; + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + else + { + /* Target responded with NACK and ACK polling is disabled + * Abort the transaction and move to IDLE state + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + + this_i2c->master_status = MIV_I2C_FAILED; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + + this_i2c->master_state = MIV_I2C_IDLE; + } + } + + else if (i2c_al_status == 1u) + { + /* Arbitration was lost on the BUS during the transmission of + * previous start condition and control byte. + * Re-send the STA and CB + */ + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + break; + + /* Transmit master data */ + case MIV_I2C_TX_DATA: + + /* ACK received and arbitration was not lost */ + if (i2c_ack_status == 0u && i2c_al_status == 0u) + { + uint8_t tx_buff[this_i2c->master_tx_size]; + if (this_i2c->master_tx_idx < this_i2c->master_tx_size) + { + HAL_set_8bit_reg(this_i2c->base_addr, TRANSMIT, + this_i2c->master_tx_buffer[this_i2c->master_tx_idx]); + + tx_buff[this_i2c->master_tx_idx] = this_i2c->master_tx_buffer[this_i2c->master_tx_idx]; + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + /* Increment the index */ + this_i2c->master_tx_idx++; + + /* Set the master state to TX data */ + this_i2c->master_state = MIV_I2C_TX_DATA; + } + + /* All the bytes are transmitted */ + else if (this_i2c->master_tx_idx == this_i2c->master_tx_size) + { + /* If this is a MASTER_READ_TRANSACTION, hold bus and start a + new transfer in read mode now that the read address has been + written to the slave */ + if(this_i2c->transaction == MIV_I2C_MASTER_READ_TRANSACTION) + + { + //Switch direction to READ + this_i2c->dir = MIV_I2C_READ_DIR; + + // Set the STA bit + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* Set the DIR bit and target addr */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, MIV_I2C_READ_DIR); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, this_i2c->target_addr); + + /* Set the WR bit to transmit the start condition and command byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + // Reset the buffer index + this_i2c->master_tx_idx = 0u; + this_i2c->master_rx_idx = 0u; + + /* Set the master state to RX data */ + this_i2c->master_state = MIV_I2C_RX_DATA; + } + + else + { + /* If releasing the bus, transmit the stop condition at the end + * of the transfer. + */ + hold_bus = this_i2c->bus_status & MIV_I2C_HOLD_BUS; + + if (hold_bus == 0) + { + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + } + else + { + MIV_I2C_disable_irq(); + } + this_i2c->master_status = MIV_I2C_SUCCESS; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + this_i2c->master_state = MIV_I2C_IDLE; + } + } + } + + else if (i2c_ack_status == 1u) + { + /* Received NACK from target device + * + * Release the bus and end the transfer + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + + this_i2c->master_status = MIV_I2C_FAILED; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + + this_i2c->master_state = MIV_I2C_IDLE; + } + + else if (i2c_al_status == 1u) + { + /* Arbitration was lost on the BUS during the transmission of + * previous start condition and control byte. + * Re-send the STA and CB + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, + this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + break; + + /* Receive target device data */ + case MIV_I2C_RX_DATA: + + if (i2c_al_status == 0u) + { + if (this_i2c->master_rx_idx < this_i2c->master_rx_size) + { + this_i2c->master_rx_buffer[this_i2c->master_rx_idx - 1u] = + HAL_get_8bit_reg(this_i2c->base_addr, RECEIVE); + + /* If next byte is last one + * Send NACK to target device to stop sending data + */ + if (this_i2c->master_rx_idx == (this_i2c->master_rx_size - 1u)) + { + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_ACK, 0x01u); + } + + else + { + /* Send ACK to receive next bytes */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_ACK, 0x00u); + } + + /* Set RD bit to receive next byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_RD, 0x01u); + + this_i2c->master_rx_idx++; + } + + /* Received all bytes */ + else //if (this_i2c->master_rx_idx == this_i2c->master_rx_size) + { + this_i2c->master_rx_buffer[this_i2c->master_rx_idx - 1] = + HAL_get_8bit_reg(this_i2c->base_addr, RECEIVE); + + hold_bus = this_i2c->bus_status & MIV_I2C_HOLD_BUS; + + if (hold_bus == 0) + { + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + } + else + { + MIV_I2C_disable_irq(); + } + this_i2c->master_status = MIV_I2C_SUCCESS; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + + this_i2c->master_state = MIV_I2C_IDLE; + } + } + + else if (i2c_al_status == 1u) + { + /* Arbitration was lost on the BUS during the transmission of + * previous start condition and control byte. + * Re-send the STA and CB + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, + this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + break; + } + + /* Toggle the IACK bit to clear interrupt */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00u); +} + +/* + * Please refer to miv_i2c.h for more info + */ +uint8_t +MIV_I2C_get_status +( + miv_i2c_instance_t *this_i2c +) +{ + uint8_t i2c_status; + + i2c_status = HAL_get_8bit_reg(this_i2c->base_addr, STATUS); + + return i2c_status; +} diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.h new file mode 100644 index 0000000..c5e704d --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.h @@ -0,0 +1,854 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * I2C module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(MIV_ESS). + */ + +/*=========================================================================*//** + @mainpage Mi-V I2C Bare Metal Driver + + ============================================================================== + Introduction + ============================================================================== + The Mi-V I2C driver provides a set of functions for controlling the Mi-V I2C + Soft-IP module. This module is delivered as a part of the Mi-V Extended + Sub System(MIV_ESS). The driver provides a minimal APB-driven I2C interface, + supporting initiator read and write access to peripheral I2C devices. + + The major features provided by the Mi-V I2C driver are: + - Support for configuring the I2C instance. + - I2C master operations. + - I2C ISR. + + This driver can be used as part of a bare metal system where no operating + system is available. The driver can be adapted for use as part of an + operating system, but the implementation of the adaptation layer between the + driver and the operating system's driver model is outside the scope of this + driver. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + The application software should initialize and configure the Mi-V I2C through + the call to the MIV_I2C_init() and MIV_I2C_config() function for Mi-V I2C + instance in the design. The configuration parameter include base address and + Prescaler value. + + ------------------------------ + Interrupt Control + ------------------------------ + The Mi-V I2C driver has to enable and disable the generation of interrupts by + Mi-V I2C at various times while operating. This enabling and disabling of the + interrupts must be done through the Mi-V RV32 HAL provided interrupt handlers. + For that reason, the method controlling the Mi-V I2C interrupts is system + specific and it is necessary to customize the MIV_I2C_enable_irq() and + MIV_I2C_disable_irq() functions as per requirement. + + The implementation of MIV_I2C_enable_irq() should permit the interrupts + generated by the Mi-V I2C to the processor through a call to respective miv-hal + interrupt handler. The implementation of MIV_I2C_disable_irq() should prevent + the interrupts generated by a Mi-V I2C from interrupting the processor. + Please refer to the miv_i2c_interrupt.c for more information about the + implementation. + + No MIV_I2C hardware configuration parameters are used by the driver, apart + from the MIV_I2C base address. Hence, no additional configuration files + are required to use the driver. + + ============================================================================== + Theory of Operation + ============================================================================== + The Mi-V I2C software driver is designed to allow the control of multiple + instances of Mi-V I2C. Each instance of Mi-V I2C in the hardware design is + associated with a single instance of the miv_i2c_instance_t structure in the + software. User must allocate memory for one unique miv_i2c_instance_t + structure for each instance of Mi-V I2C in the hardware. + A pointer to the structure is passed to the subsequent driver functions in + order to identify the MIV_I2C hardware instance and to perform requested + operation. + + Note: Do not attempt to directly manipulate the contents of the + miv_i2c_instance_t structure. These structures are only intended to be modified + by the driver functions. + + The Mi-V I2C driver functions are grouped into following categories: + - Initialization and configuration + - I2C master operation functions to handle write, read and write_read + operations. + - Interrupt control + + -------------------------------- + Initialization and configuration + -------------------------------- + The Mi-V I2C device is first initialized by the call to MIV_I2C_init(). This + function initializes the instance of Mi-V I2C with the base address. + MIV_I2C_init() function must be called before any other Mi-V I2C driver API. + + The configuration of the Mi-V I2C instance is done via call to the + MIV_I2C_config() function. This function will set the prescale value which is + used to set the frequency of the I2C clock(SCLK) generated by I2C module. + + --------------------------------- + Transaction types + --------------------------------- + The driver is designed to handle three types of transactions: + - Write transactions + - Read transactions + - Write-Read transaction + + ### Write Transaction + The write transaction begins with master sending a start condition, followed + by device address byte with the R/W bit set to logic '0', and then by the + word address bytes. The slave acknowledges the receipt of its address with + acknowledge bit. The master sends one byte at a time to the slave, which must + acknowledge the receipt of each byte for the next byte to be sent. The master + sends STOP condition to complete the transaction. The slave can abort the + transaction by replying with negative acknowledge. + + The application programmer can choose not to send the STOP bit at the end of + the transaction causing repetitive start conditions. + + ### Read Transaction + The master I2C device initiates a read transaction by sending a START bit + as soon as the bus becomes free. The start condition is followed by the + control byte which contains 7-bit slave address followed by R/W bit set to + logic '1'. The slave sends data one byte at a time to the master, which must + acknowledge receipt of each byte for the next byte to be sent. The master + sends a non-acknowledge bit following the last byte it wishes to read + followed by a STOP bit. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ### Write-Read Transaction + The write read transaction is a combination of a write transaction + immediately followed by a read transaction. There is no STOP condition sent + between the write and read phase of write-read transaction. A repeated START + condition is sent between the write and read phases. + + Whilst the write handler is being executed, the slave holds the clock line + low to stretch the clock until the response is ready. + + The write-read transaction is typically used to send an memory/register + address in the write transaction specifying the start address of the data to + be transferred during the read phase. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ------------------------------------- + Interrupt Control + ------------------------------------- + The Mi-V I2C driver is interrupt driven and it uses the MIV_I2C_irq() function + to drive the ISR state machine which is at the heart of the driver. The + application is responsible for providing the link between the interrupt + generating hardware and the Mi-V I2C interrupt handler and must ensure that + the MIV_I2C_isr() function is called with the correct miv_i2c_instance_t + structure pointer for the Mi-V I2C instance initiating the interrupt. + +*//*=========================================================================*/ +#ifndef MIV_I2C_H_ +#define MIV_I2C_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "miv_i2c_regs.h" +#include + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#else +#include "hal.h" +#endif + +/*-------------------------------------------------------------------------*//** + The miv_i2c_status_t type is used to report the status of I2C transactions. + */ +typedef enum miv_i2c_status +{ + MIV_I2C_SUCCESS = 0u, + MIV_I2C_IN_PROGRESS, + MIV_I2C_FAILED, + MIV_I2C_TIMED_OUT +}miv_i2c_status_t; + +/*-------------------------------------------------------------------------*//** + This structure is used to identify the MIV_I2C hardware instances in a system. + Your application software should declare one instance of this structure for + each instance of the MIV_I2C in your system. The function MIV_I2C_init() + Initializes this structure. A pointer to an initialised instance of the structure + should be passed as the first parameter to the MIV_I2C driver functions, to + identify which MIV_I2C hardware instance should perform the requested operation. + + The contents of this data structure should not be modified or used outside of + the MIV_I2C driver. Software using the MIV_I2C driver should only need to + create one single instance of this data structure for each MIV_I2C hardware + instance in the system, then pass a pointer to these data structures with each + call to the MIV_I2C driver in order to identify the MIV_I2C hardware instance + it wishes to use. +*/ + +typedef struct miv_i2c_instance +{ + addr_t base_addr; + + /* Transmit related info:*/ + uint_fast8_t target_addr; + + /* Current transaction type */ + uint8_t transaction; + + uint8_t bus_options; + + uint8_t ack_polling_options; + + /* Current State of the I2C master */ + uint8_t master_state; + + /* Master TX INFO: */ + const uint8_t * master_tx_buffer; + uint_fast16_t master_tx_size; + uint_fast16_t master_tx_idx; + uint_fast8_t dir; + + /* Master RX INFO: */ + uint8_t * master_rx_buffer; + uint_fast16_t master_rx_size; + uint_fast16_t master_rx_idx; + + /* Master Status */ + volatile miv_i2c_status_t master_status; + uint32_t master_timeout_ms; + + /* user specific data */ + void *p_user_data ; + + /* I2C bus status */ + uint8_t bus_status; + + /* Is transaction pending flag */ + uint8_t is_transaction_pending; + + /* I2C Pending transaction */ + uint8_t pending_transaction; + +}miv_i2c_instance_t; + + +/*-------------------------------------------------------------------------*//** + MIV_I2C_RELEASE_BUS + ===================== + The MIV_I2C_RELEASE_BUS constant is used to specify the bus_options parameter + for MIV_I2C_read(), MIV_I2C_write() and MIV_I2C_write_read() to indicate + that a STOP bit must be generated at the end of the I2C transaction to release + the bus. + */ +#define MIV_I2C_RELEASE_BUS 0x00u + + +/*-------------------------------------------------------------------------*//** + MIV_I2C_HOLD_BUS + ===================== + The MIV_I2C_HOLD_BUS constant is used to specify the bus_optionsparameter + for MIV_I2C_read(), MIV_I2C_write() and MIV_I2C_write_read() to indicate + that a STOP bit must not be generated at the end of the I2C transaction in + order to retain the bus ownership. This causes the next transaction to + begin with a repeated START bit and no STOP bit between the transactions. + */ +#define MIV_I2C_HOLD_BUS 0x01u + +/*-------------------------------------------------------------------------*//** + MIV_I2C_ACK_POLLING_DISABLE + ===================== + The MIV_I2C_ACK_POLLING_DISABLE constant is used to specify the + ack_polling_options parameter to functions MIV_I2C_write(), + MIV_I2C_write_read() and MIV_I2C_read(). Acknowledgment polling is used when + working with I2C memory devices such as EEPROM, which feature an internal + write cycle. + + With acknowledgment polling disabled, if the target slave device responds to the + control byte with a NACK, the MIV_I2C will abort the transfer. + */ +#define MIV_I2C_ACK_POLLING_DISABLE 0x00u + +/*-------------------------------------------------------------------------*//** + MIV_I2C_ACK_POLLING_ENABLE + ===================== + The MIV_I2C_ACK_POLLING_ENABLE constant is used to specify the + ack_polling_options parameter to functions MIV_I2C_write(), + MIV_I2C_write_read() and MIV_I2C_read(). acknowledgment polling is used when + working with I2C memory devices such as EEPROM, which feature an internal + write cycle. + + With acknowledgment polling enabled, if the slave device responds to the + control byte with a NACK, the MIV_I2C will repeatedly transmit another control + byte until the slave device accepts the connection with an ACK, or the timeout + specified in the MIV_I2C_wait_complete() function is reached. Acknowledgment + polling allows for the next read/write operation to be started as soon as the + EEPROM has completed its internal write cycle. + */ +#define MIV_I2C_ACK_POLLING_ENABLE 0x01u + +/*--------------------------------Public APIs---------------------------------*/ + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_init() function is used to initialize the Mi-V I2C module instance + with the base address. + + Note: This function should be called before calling any other Mi-V I2C + functions. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + @param base_addr + Base address of the Mi-V I2C module instance in the MIV_ESS + soft IP. + + @return + This function does not return any value. + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + } + @endcode + */ +void +MIV_I2C_init +( + miv_i2c_instance_t *this_i2c, + addr_t base_addr +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_config() function is used to configure the Mi-V I2C module. This + function will set the prescale value which is used to set the frequency of + the I2C clock(SCLK) generated by I2C module and also enables the I2C core and + interrupts. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param clk_prescale + The value used to set the frequency of Mi-V I2C serial clock + (SCLK) generated by the Mi-V I2C module instance. The + prescaler value required to set particular frequency of + Mi-V I2C can be calculated using following formula: + + prescaler = (System Clock Frequency) / (5 * (Desired I2C Clock Frequency)) - 1 + + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + } + @endcode + */ +void +MIV_I2C_config +( + miv_i2c_instance_t *this_i2c, + uint16_t clk_prescale +); + + +uint8_t +MIV_I2C_start +( + miv_i2c_instance_t *this_i2c +); + + +uint8_t +MIV_I2C_stop +( + miv_i2c_instance_t *this_i2c +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_write() is used to set up and start the Mi-V I2C master write + transaction. This function is used for all Mi-V master write operation. + + For more information about the operation, please refer to the 'theory of + operations' section at the start of this document. + + This function returns immediately after initiating the transaction. The content + of the write buffer passed as parameter should not be modified until the write + transaction completes. It also means that the memory allocated for the write + buffer should not be freed or should not go out of scope before the write + completes. + You can check for the write transaction completion by polling the master_status + from miv_i2c_instance_t structure as shown in the sample code. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param i2c_target_addr + This parameter specifies the serial address for the slave + device. + + @param write_buffer + This parameter is a pointer to the buffer holding data to be + written to target I2C device. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param write_size + Number of bytes held in the write_buffer to be written to the + I2C device. + @param bus_options: + The bus_options parameter is used to indicate if the I2C bus + should be released on completion of the write transaction. + Using the MIV_I2C_RELEASE_BUS constant for the bus_options + parameter causes a STOP bit to be generated at the end of the + write transaction causing the bus to be released for other I2C + devices to use. Using the MIV_I2C_HOLD_BUS constant as + bus_options parameter prevents a STOP bit from being generated + at the end of the write transaction, preventing other I2C + devices from initiating a bus transaction. + + @param ack_polling_options: + The ack_polling_options parameter is used to indicate how the + MIV_I2C will respond if the slave device transmits a NACK to + the I2C control byte. Using the MIV_I2C_ACK_POLLING_DISABLE + constant for the ack_polling_options parameter causes the + MIV_I2C to abort the transfer if the slave device responds to + the I2C control byte with a NACK. Using the + MIV_I2C_ACK_POLLING_ENABLE constant for the ack_polling_options + parameter causes the MIV_I2C to repeatedly transmit a control + byte to the slave device until the slave device responds with + an ACK. + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + + MIV_I2C_write (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_tx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + } + @endcode + */ +void +MIV_I2C_write +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t bus_options, + uint8_t ack_polling_options +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_read() is used to set up and start the Mi-V I2C master read + transaction. This function is used for all MIV_I2C master read operation. + + For more information about the operation, please refer to the 'theory of + operations' section at the start of this document. + + This function returns immediately after initiating the transaction. The content + of the read buffer passed as parameter should not be modified until the write + transaction completes. It also means that the memory allocated for the read + buffer should not be freed or should not go out of scope before the read + completes. + You can check for the write transaction completion by polling the master_status + from miv_i2c_instance_t structure as shown in the sample code. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param i2c_target_addr + This parameter specifies the serial address for the slave + device. + + @param read_buffer + This parameter is a pointer to the buffer where the data + received from the I2C slave device is stored. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param read_size + Number of bytes held in the write_buffer to be read from the + I2C device. + + @param bus_options: + The bus_options parameter is used to indicate if the I2C bus + should be released on completion of the write transaction. + Using the MIV_I2C_RELEASE_BUS constant for the bus_options + parameter causes a STOP bit to be generated at the end of the + write transaction causing the bus to be released for other I2C + devices to use. Using the MIV_I2C_HOLD_BUS constant as + bus_options parameter prevents a STOP bit from being generated + at the end of the write transaction, preventing other I2C + devices from initiating a bus transaction. + + @param ack_polling_options: + The ack_polling_options parameter is used to indicate how the + MIV_I2C will respond if the slave device transmits a NACK to + the I2C control byte. Using the MIV_I2C_ACK_POLLING_DISABLE + constant for the ack_polling_options parameter causes the + MIV_I2C to abort the transfer if the slave device responds to + the I2C control byte with a NACK. Using the + MIV_I2C_ACK_POLLING_ENABLE constant for the ack_polling_options + parameter causes the MIV_I2C to repeatedly transmit a control + byte to the slave device until the slave device responds with + an ACK. + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + + MIV_I2C_write (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_tx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + + // reset miv_i2c_status variable + miv_i2c_status = 0u; + + MIV_I2C_read (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_rx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + } + @endcode + */ +void +MIV_I2C_read +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_write_read() is used to set up and start the Mi-V I2C master + write_read transaction. This function is used for all MIV_I2C master write_read + operation. + + This function is used in cases where data is being requested from a specific + address offset inside the target I2C slave device. + In this type of I2C operation, the I2C master starts by initiating a write + operation. During this write operation, the specific address offset is written + to the I2C slave. Once the address offset has been written to the I2C slave, + the I2C master transmits a repeated start, and initiates a read operation to + read data from the set address. + + For more information about the operation, please refer to the 'theory of + operations' section at the start of this document. + + This function returns immediately after initiating the transaction. The content + of the write and read buffer passed as parameter should not be modified until + the write transaction completes. It also means that the memory allocated for + the write and read buffer should not be freed or should not go out of scope + before the operation completes. + You can check for the write_read transaction completion by polling the + master_status from miv_i2c_instance_t structure. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param i2c_target_addr + This parameter specifies the serial address for the slave + device. + + @param write_buffer + This parameter is a pointer to the buffer holding data to be + written to target I2C device. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param write_size + Number of bytes held in the write_buffer to be written to the + I2C device. + + @param read_buffer + This parameter is a pointer to the buffer where the data + received from the I2C slave device is stored. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param read_size + Number of bytes held in the write_buffer to be read from the + I2C device. + + @param bus_options: + The bus_options parameter is used to indicate if the I2C bus + should be released on completion of the write transaction. + Using the MIV_I2C_RELEASE_BUS constant for the bus_options + parameter causes a STOP bit to be generated at the end of the + write transaction causing the bus to be released for other I2C + devices to use. Using the MIV_I2C_HOLD_BUS constant as + bus_options parameter prevents a STOP bit from being generated + at the end of the write transaction, preventing other I2C + devices from initiating a bus transaction. + + @param ack_polling_options: + The ack_polling_options parameter is used to indicate how the + MIV_I2C will respond if the slave device transmits a NACK to + the I2C control byte. Using the MIV_I2C_ACK_POLLING_DISABLE + constant for the ack_polling_options parameter causes the + MIV_I2C to abort the transfer if the slave device responds to + the I2C control byte with a NACK. Using the + MIV_I2C_ACK_POLLING_ENABLE constant for the ack_polling_options + parameter causes the MIV_I2C to repeatedly transmit a control + byte to the slave device until the slave device responds with + an ACK or the timeout specified in the MIV_I2C_wait_complete() + function is reached. + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + + MIV_I2C_write (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_tx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + + // reset miv_i2c_status variable + miv_i2c_status = 0u; + + uint8_t addr_offset[2] = {0x00, 0x00}; + MIV_I2C_write_read(&miv_i2c, + DUALEE_SLAVEADDRESS_1, + addr_offset, + sizeof(addr_offset), + i2c_rx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + } + @endcode + */ +void +MIV_I2C_write_read +( + miv_i2c_instance_t *this_i2c, + uint8_t target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_isr() function contains the MIV_I2C's interrupt service routine. + This ISR is at the heart of the MIV_I2C driver, and is used to control the + interrupt-driven, byte-by-byte I2C read and write operations. + + The ISR operates as a Finite State Machine (FSM), which uses the previously + completed I2C operation and its result to determine which I2C operation will + be performed next. + + The ISR operation is divided into following categories: + - MIV_I2C_IDLE + - MIV_I2C_TX_STA_CB + - MIV_I2C_TX_DATA + - MIV_I2C_RX_DATA + + ##### MIV_I2C_IDLE + The MIV_I2C_IDLE is entered on reset, or when an I2C master operation has been + completed or aborted. + Upon entering, the FSM will remain in this state until a write, read, or + write-read operation is requested + + ##### MIV_I2C_STA_CB + The MIV_I2C_TX_STA_CB operation is performed when the start condition and + control byte(i2c target address(7-bit) and direction of transaction(1-bit)) is + transmitted by the Mi-V I2C master device to the slave. + If the target I2C slave device responded to the previous START Condition + + Control Byte with an ACK, the MIV_I2C will start the requested I2C + read/write operation. + If the target slave I2C slave device responds with NACK, the MIV_I2C will + remain in this state or return to the idle state based on ack_polling + configuration. + + ##### MIV_I2C_TX_DATA + The MIV_I2C_TX_DATA state is entered after the target slave device accepts a + write request with an ACK. + This state is used to handle the byte-by-byte MIV_I2C write operations. + The FSM will remain in this state until either all data bytes have been + written to the target slave device, or an error occurs during the write + operation. + + ##### MIV_I2C_RX_DATA + The MIV_I2C_RX_DATA state is entered after the target slave device accepts a + read request with an ACK. + This state is used to handle the byte-by-byte MIV_I2C read operations. + The FSM will remain in this state until either all data bytes have been + received from the target slave device, or an error occurs. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + */ +void +MIV_I2C_isr +( + miv_i2c_instance_t *this_i2c +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_get_status() returns the 8-bit Mi-V I2C status register value. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + @return + This function returns 8-bit Mi-V I2C status register value. + */ +uint8_t +MIV_I2C_get_status +( + miv_i2c_instance_t *this_i2c +); + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_I2C_H_ */ diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_interrupt.c b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_interrupt.c new file mode 100644 index 0000000..871eafe --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_interrupt.c @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains functions used for MIV_I2C driver interrupt control. + * User should enable and disable the interrupts according to their design. + * Please refer to miv_i2c.h file for more information. + */ + +#include "miv_rv32_hal/miv_rv32_hal.h" + +void MIV_I2C_disable_irq(void) +{ +/* Disable I2C interrupt */ + MRV_disable_local_irq(MRV32_MSYS_EIE2_IRQn); +} + +void MIV_I2C_enable_irq(void) +{ +/* Enable I2C interrupt */ + MRV_enable_local_irq(MRV32_MSYS_EIE2_IRQn); +} + + diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_regs.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_regs.h new file mode 100644 index 0000000..9a4bfbf --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_regs.h @@ -0,0 +1,158 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP I2C module driver. This module is delivered as a part of Mi-V extended + * Sub-System(MIV_ESS). + */ + +#ifndef MIV_I2C_APB_REGISTERS +#define MIV_I2C_APB_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * Prescale register details + */ +#define PRESCALE_REG_OFFSET 0x00u + +/* Prescale register bits */ +#define PRESCALE_OFFSET 0x00u +#define PRESCALE_MASK 0xFFFFu +#define PRESCALE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Control register details + */ +#define CONTROL_REG_OFFSET 0x04u + +/* Control register bits */ +#define CONTROL_OFFSET 0x04u +#define CONTROL_MASK 0xC0u +#define CONTROL_SHIFT 0u + +/* Control register Core Enable Bit */ +#define CTRL_CORE_EN_OFFSET 0x04u +#define CTRL_CORE_EN_MASK 0x80u +#define CTRL_CORE_EN_SHIFT 7u + +/* Control register IRQ Enable bit */ +#define CTRL_IRQ_EN_OFFSET 0x04u +#define CTRL_IRQ_EN_MASK 0x40u +#define CTRL_IRQ_EN_SHIFT 6u + +/*------------------------------------------------------------------------------ + * Transmit register details + */ +#define TRANSMIT_REG_OFFSET 0x08u + +/* Transmit register bits */ +#define TRANSMIT_OFFSET 0x08u +#define TRANSMIT_MASK 0xFFu +#define TRANSMIT_SHIFT 0u + +/* Transmit register DIR bit */ +#define TX_DIR_OFFSET 0x08u +#define TX_DIR_MASK 0x01u +#define TX_DIR_SHIFT 0u + +/* Transmit register TARGET_ADDR bit */ +#define TX_TARGET_ADDR_OFFSET 0x08u +#define TX_TARGET_ADDR_MASK 0xFEu +#define TX_TARGET_ADDR_SHIFT 1u + +/*------------------------------------------------------------------------------ + * Receive register details + */ +#define RECEIVE_REG_OFFSET 0x0Cu + +/* Receive register bits */ +#define RECEIVE_OFFSET 0x0Cu +#define RECEIVE_MASK 0xFFu +#define RECEIVE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Command register details + */ +#define COMMAND_REG_OFFSET 0x10u + +/* Command register bits */ +#define COMMAND_OFFSET 0x10u +#define COMMAND_MASK 0xF9u +#define COMMAND_SHIFT 0u + +/* Command register IACK bit */ +#define CMD_IACK_OFFSET 0x10u +#define CMD_IACK_MASK 0x01u +#define CMD_IACK_SHIFT 0u + +/* Command register ACK bit */ +#define CMD_ACK_OFFSET 0x10u +#define CMD_ACK_MASK 0x08u +#define CMD_ACK_SHIFT 3u + +/* Command register WR bit */ +#define CMD_WR_OFFSET 0x10u +#define CMD_WR_MASK 0x10u +#define CMD_WR_SHIFT 4u + +/* Command register RD bit */ +#define CMD_RD_OFFSET 0x10u +#define CMD_RD_MASK 0x20u +#define CMD_RD_SHIFT 5u + +/* Command register STO bit */ +#define CMD_STO_OFFSET 0x10u +#define CMD_STO_MASK 0x40u +#define CMD_STO_SHIFT 6u + +/* Command register STA bit */ +#define CMD_STA_OFFSET 0x10u +#define CMD_STA_MASK 0x80u +#define CMD_STA_SHIFT 7u + +/*------------------------------------------------------------------------------ + * Status register details + */ +#define STATUS_REG_OFFSET 0x14u + +/* Command register bits */ +#define STATUS_OFFSET 0x14u +#define STATUS_MASK 0xFFu +#define STATUS_SHIFT 0u + +/* Status register Interrupt Flag(IF) bit */ +#define STAT_IF_OFFSET 0x14u +#define STAT_IF_MASK 0x01u +#define STAT_IF_SHIFT 0u + +/* Status register Transfer in Progress(TIP) bit */ +#define STAT_TIP_OFFSET 0x14u +#define STAT_TIP_MASK 0x02u +#define STAT_TIP_SHIFT 1u + +/* Status register Arbitration Lost(AL) bit */ +#define STAT_AL_OFFSET 0x14u +#define STAT_AL_MASK 0x20u +#define STAT_AL_SHIFT 5u + +/* Status register Busy(BUSY) bit */ +#define STAT_BUSY_OFFSET 0x14u +#define STAT_BUSY_MASK 0x40u +#define STAT_BUSY_SHIFT 6u + +/* Status register Ack received(RXACK) bit */ +#define STAT_RXACK_OFFSET 0x14u +#define STAT_RXACK_MASK 0x80u +#define STAT_RXACK_SHIFT 7u + + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_I2C_APB_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_plic/miv_plic.c b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_plic/miv_plic.c new file mode 100644 index 0000000..903f029 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_plic/miv_plic.c @@ -0,0 +1,283 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * MI-V Soft IP fabric bare-metal driver for Mi-V PLIC module. This module is + * delivered as a part of Mi-V Extended Sub System(MIV_ESS). + * Please refer to miv_plic.h file for more information. + */ + +#include "miv_plic.h" + +/***************************************************************************//** + * Mi-V PLIC interrupt handler function declaration. + * These functions are called by the external interrupt handler of the MIV_RV32 + * core base on the PLIC source causing the interrupt. + */ +uint8_t Invalid_IRQHandler(void); +uint8_t MIV_PLIC_EXT0_IRQHandler(void); +uint8_t MIV_PLIC_EXT1_IRQHandler(void); +uint8_t MIV_PLIC_EXT2_IRQHandler(void); +uint8_t MIV_PLIC_EXT3_IRQHandler(void); +uint8_t MIV_PLIC_EXT4_IRQHandler(void); +uint8_t MIV_PLIC_EXT5_IRQHandler(void); +uint8_t MIV_PLIC_EXT6_IRQHandler(void); +uint8_t MIV_PLIC_EXT7_IRQHandler(void); +uint8_t MIV_PLIC_EXT8_IRQHandler(void); +uint8_t MIV_PLIC_EXT9_IRQHandler(void); +uint8_t MIV_PLIC_EXT10_IRQHandler(void); +uint8_t MIV_PLIC_EXT11_IRQHandler(void); +uint8_t MIV_PLIC_EXT12_IRQHandler(void); +uint8_t MIV_PLIC_EXT13_IRQHandler(void); +uint8_t MIV_PLIC_EXT14_IRQHandler(void); +uint8_t MIV_PLIC_EXT15_IRQHandler(void); +uint8_t MIV_PLIC_EXT16_IRQHandler(void); +uint8_t MIV_PLIC_EXT17_IRQHandler(void); +uint8_t MIV_PLIC_EXT18_IRQHandler(void); +uint8_t MIV_PLIC_EXT19_IRQHandler(void); +uint8_t MIV_PLIC_EXT20_IRQHandler(void); +uint8_t MIV_PLIC_EXT21_IRQHandler(void); +uint8_t MIV_PLIC_EXT22_IRQHandler(void); +uint8_t MIV_PLIC_EXT23_IRQHandler(void); +uint8_t MIV_PLIC_EXT24_IRQHandler(void); +uint8_t MIV_PLIC_EXT25_IRQHandler(void); +uint8_t MIV_PLIC_EXT26_IRQHandler(void); +uint8_t MIV_PLIC_EXT27_IRQHandler(void); +uint8_t MIV_PLIC_EXT28_IRQHandler(void); +uint8_t MIV_PLIC_EXT29_IRQHandler(void); +uint8_t MIV_PLIC_EXT30_IRQHandler(void); + +/***************************************************************************//** + * MIV_PLIC interrupt handler for external interrupts. + * The array of the function pointers pointing to the weak handler of the Mi-V + * PLIC interrupt handlers. + * These functions are called by the external interrupt handler of the MIV_RV32 + * core base on the PLIC source causing the interrupt. + */ +uint8_t (* const ext_irq_handler_table[32]) (void) = +{ + Invalid_IRQHandler, + MIV_PLIC_EXT0_IRQHandler, + MIV_PLIC_EXT1_IRQHandler, + MIV_PLIC_EXT2_IRQHandler, + MIV_PLIC_EXT3_IRQHandler, + MIV_PLIC_EXT4_IRQHandler, + MIV_PLIC_EXT5_IRQHandler, + MIV_PLIC_EXT6_IRQHandler, + MIV_PLIC_EXT7_IRQHandler, + MIV_PLIC_EXT8_IRQHandler, + MIV_PLIC_EXT9_IRQHandler, + MIV_PLIC_EXT10_IRQHandler, + MIV_PLIC_EXT11_IRQHandler, + MIV_PLIC_EXT12_IRQHandler, + MIV_PLIC_EXT13_IRQHandler, + MIV_PLIC_EXT14_IRQHandler, + MIV_PLIC_EXT15_IRQHandler, + MIV_PLIC_EXT16_IRQHandler, + MIV_PLIC_EXT17_IRQHandler, + MIV_PLIC_EXT18_IRQHandler, + MIV_PLIC_EXT19_IRQHandler, + MIV_PLIC_EXT20_IRQHandler, + MIV_PLIC_EXT21_IRQHandler, + MIV_PLIC_EXT22_IRQHandler, + MIV_PLIC_EXT23_IRQHandler, + MIV_PLIC_EXT24_IRQHandler, + MIV_PLIC_EXT25_IRQHandler, + MIV_PLIC_EXT26_IRQHandler, + MIV_PLIC_EXT27_IRQHandler, + MIV_PLIC_EXT28_IRQHandler, + MIV_PLIC_EXT29_IRQHandler, + MIV_PLIC_EXT30_IRQHandler +}; + +/* Mi-V PLIC interrupt weak handlers */ +__attribute__((weak)) uint8_t Invalid_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT0_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT1_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT2_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT3_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT4_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT5_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT6_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT7_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT8_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT9_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT10_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT11_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT12_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT13_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT14_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT15_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT16_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT17_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT18_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT19_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT20_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT21_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT22_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT23_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT24_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT25_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT26_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT27_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT28_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT29_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT30_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +/*-------------------------------------------------------------------------*//** + * Please refer to miv_plic.h for more information about this function. +*/ +void +MIV_PLIC_isr +( + miv_plic_instance_t *this_plic +) +{ + unsigned long hart_id = read_csr(mhartid); + + /* claim the interrupt from PLIC controller */ + + uint32_t int_num = HAL_get_32bit_reg(this_plic->base_addr + + (0x1000 * hart_id), INT_CLAIM_COMPLETE); + + uint8_t disable = EXT_IRQ_KEEP_ENABLED; + disable = ext_irq_handler_table[int_num](); + + /* Indicate the PLIC controller that the interrupt is processed and claim is + * complete. */ + HAL_set_32bit_reg(this_plic->base_addr + + (0x1000 * hart_id), INT_CLAIM_COMPLETE, int_num); + + if (EXT_IRQ_DISABLE == disable) + { + MIV_PLIC_disable_irq(this_plic, (miv_plic_irq_num_t)int_num); + } +} diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_plic/miv_plic.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_plic/miv_plic.h new file mode 100644 index 0000000..f5d64cd --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_plic/miv_plic.h @@ -0,0 +1,425 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * PLIC module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(ESS). + */ + /*=========================================================================*//** + @mainpage Mi-V PLIC Bare Metal Driver + + ============================================================================== + Introduction + ============================================================================== + The Mi-V driver provides a set of functions for controlling the Mi-V PLIC + (platform level interrupt controller) soft-IP module. This module is delivered + as a part of the MIV_ESS. The PLIC multiplexes external interrupt signals into + a single interrupt signal that is connected to an external interrupt of the + processor. + + The major features provided by the driver are: + - Support for configuring the PLIC instances. + - Enabling and Disabling interrupts + - Interrupt Handling + + This driver can be used as part of a bare metal system where no operating + system is available. The driver can be adapted for use as part of an + operating system, but the implementation of the adaptation layer between the + driver and the operating system's driver model is outside the scope of this + driver. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + The application software should initialize the Mi-V PLIC through the call to + the MIV_PLIC_init() function for Mi-V PLIC instance in the design. + + No Mi-V PLIC hardware configuration parameters are used by the driver, apart + from the Mi-V PLIC base address. Hence, no additional configuration files + are required to use the driver. + + ============================================================================== + Theory of Operation + ============================================================================== + The operation of Mi-V PLIC driver is divided into following steps: + - Initialization + - Enabling and Disabling interrupts + - Interrupt control + + -------------------------------------------- + Initialization + -------------------------------------------- + The Mi-V PLIC module is first initialized by the call to MIV_PLIC_init(). This + function takes a pointer to the Mi-V PLIC instance data structure and the base + address of the Mi-V PLIC instance is defined by the hardware design. The + instance data structure is used to store the base address of the Mi-V PLIC + module and a pointer to the Mi-V PLIC register data structure. The Mi-V PLIC + register data structure maps the address of the Mi-V PLIC registers. + + --------------------------------------------- + Enabling and Disabling interrupts + --------------------------------------------- + The MIV_PLIC_enable_irq() function enables the specific interrupt provided by + user. A call to this function will allow the enabling of each of the global + interrupts corresponding to the bit in the interrupt enable register of Mi-V + PLIC. + The MIV_PLIC_disable_irq() function disables the specific interrupt provided + by the user. This function can be used to disable the interrupts from outside + of the external interrupt handler. + + ---------------------------------------- + Interrupt Control + ---------------------------------------- + When an interrupt occurs on an enabled interrupt, the PLIC gateway captures + the interrupt and asserts the corresponding interrupt pending bit. Once + the enable bit and pending bit are asserted, then the PLIC_IRQ signal asserts + until the interrupt is claimed by the driver interrupt handler MIV_PLIC_irq() + function. + When multiple interrupts assert then the lowest interrupt number will be + serviced first, for example, if interrupt 1 and 6 assert at the same time, + interrupt 1 will be serviced first, followed by interrupt 6. + +*/ + +#ifndef MIV_PLIC_H_ +#define MIV_PLIC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "miv_plic_regs.h" + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#include "miv_rv32_hal/miv_rv32_hal.h" +#else +#include "hal.h" +#include "miv_rv32_hal.h" +#endif + +/*-------------------------------------------------------------------------*//** + This enumeration is used to select a specific Mi-V PLIC interrupt. It is + used as a parameter to enable or disable the interrupt. +*/ +typedef enum miv_plic_irq_num +{ + NoInterrupt_IRQn = 0, + MIV_PLIC_EXT0_IRQn = 1, + MIV_PLIC_EXT1_IRQn = 2, + MIV_PLIC_EXT2_IRQn = 3, + MIV_PLIC_EXT3_IRQn = 4, + MIV_PLIC_EXT4_IRQn = 5, + MIV_PLIC_EXT5_IRQn = 6, + MIV_PLIC_EXT6_IRQn = 7, + MIV_PLIC_EXT7_IRQn = 8, + MIV_PLIC_EXT8_IRQn = 9, + MIV_PLIC_EXT9_IRQn = 10, + MIV_PLIC_EXT10_IRQn = 11, + MIV_PLIC_EXT11_IRQn = 12, + MIV_PLIC_EXT12_IRQn = 13, + MIV_PLIC_EXT13_IRQn = 14, + MIV_PLIC_EXT14_IRQn = 15, + MIV_PLIC_EXT15_IRQn = 16, + MIV_PLIC_EXT16_IRQn = 17, + MIV_PLIC_EXT17_IRQn = 18, + MIV_PLIC_EXT18_IRQn = 19, + MIV_PLIC_EXT19_IRQn = 20, + MIV_PLIC_EXT20_IRQn = 21, + MIV_PLIC_EXT21_IRQn = 22, + MIV_PLIC_EXT22_IRQn = 23, + MIV_PLIC_EXT23_IRQn = 24, + MIV_PLIC_EXT24_IRQn = 25, + MIV_PLIC_EXT25_IRQn = 26, + MIV_PLIC_EXT26_IRQn = 27, + MIV_PLIC_EXT27_IRQn = 28, + MIV_PLIC_EXT28_IRQn = 29, + MIV_PLIC_EXT29_IRQn = 30, + MIV_PLIC_EXT30_IRQn = 31 +} miv_plic_irq_num_t; + +/*--------------------------------------------------------------------------*//* + * This structure maps the priority threshold and claim complete register in + * the memory. + */ +typedef struct +{ + volatile uint32_t PRIORITY_THRESHOLD; + volatile uint32_t CLAIM_COMPLETE; + volatile uint32_t reserved[1022]; +} IRQ_Target_Type; + +/*--------------------------------------------------------------------------*//* + * This structure maps the Interrupt enable sources from 0 - 1023 for one + * context. + */ +typedef struct +{ + volatile uint32_t ENABLES[32]; +} Target_Enables_Type; + +/*-------------------------------------------------------------------------*//** + This structure holds the base address of the Mi-V PLIC module. This structure + is used by all the functions to access the Mi-V PLIC registers. +*/ +typedef struct miv_plic_instance +{ + addr_t base_addr; +} miv_plic_instance_t; + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_isr is the top level interrupt handler function for the Mi-V PLIC + * driver. You must call the MIV_PLIC_isr() from the system level interrupt + * handler(External_IRQHandler). + * This function must be called from the external interrupt handler function + * provided by the processor hardware abstraction layer. In case of MIV_RV32 + * soft processor, it must be called from External_IRQHandler() function + * provided by MIV_RV32 HAL. + * + * The MIV_PLIC_isr() function claims the interrupt number + * that triggered the interrupt and then invokes the appropriate PLIC interrupt + * handler. + * After handling the PLIC interrupt, this function will complete the interrupt + * by clearing the claim complete bit for the particular interrupt source. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * + * @return + * This function does not return any value. + * + * Example: + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * uint8_t MIV_PLIC_EXT0_IRQHandler(void) + * { + * *** ISR operation *** + * + * return(EXT_IRQ_KEEP_ENABLED); + * } + * + * void External_IRQHandler(void) + * { + * uint32_t reg_val = read_csr(mip); + * MIV_PLIC_isr(&g_plic); + * } + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * } + * @endcode + */ +void MIV_PLIC_isr(miv_plic_instance_t *this_plic); + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_init() function initializes the Mi-V PLIC instance with base + * address. This function resets the PLIC controller by disabling all the PLIC + * interrupts. + * + * Note: This function must be called before calling any other Mi-V PLIC driver + * function. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * + * @param base_addr + * Base address of the Mi-V PLIC instance in the MIV_ESS soft-IP. + * + * @param ext_intr_sources + * Number of interrupts initialized in the design. + * + * @return + * This function does not return any value. + * + * Example + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * } + * @endcode + */ +static inline void +MIV_PLIC_init +( + miv_plic_instance_t *this_plic, + addr_t base_addr, + uint8_t ext_intr_sources +) +{ + uint32_t inc; + unsigned long hart_id = read_csr(mhartid); + + this_plic->base_addr = base_addr; + + /* Disable all interrupts for the current hart. + * The PLIC_EXT_INTR_SOURCES should be defined in the hw_platform.h. This + * macro holds the number of PLIC interrupts enabled in the design. + */ + for(inc = 0; inc < ((ext_intr_sources + 32u) / 32u); ++inc) + { + HAL_set_32bit_reg( + (this_plic->base_addr + inc + (hart_id * 128)), INT_ENABLE , 0x0u); + } +} + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_enable_irq() function enables the PLIC interrupt provided with + * IRQn parameter. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * @param IRQn + * Number of PLIC interrupt to enable. + * + * @return + * This function does not return any value. + * + * Example + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * } + * @endcode + */ +static inline void +MIV_PLIC_enable_irq +( + miv_plic_instance_t *this_plic, + miv_plic_irq_num_t IRQn +) +{ + unsigned long hart_id = read_csr(mhartid); + + uint32_t current = HAL_get_32bit_reg( + (this_plic->base_addr + (IRQn/32) + (hart_id * 128)) , INT_ENABLE); + + current |= (uint32_t)1 << (IRQn % 32); + + HAL_set_32bit_reg( + (this_plic->base_addr + (IRQn/32) + (hart_id * 128)), INT_ENABLE, current); + +} + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_disable_irq() function disables the PLIC interrupt provided with + * IRQn parameter. + * + * NOTE: + * This function can be used to disable the PLIC interrupt from outside the + * external interrupt handler functions. + * If you wish to disable the PLIC interrupt from the external interrupt handler, + * you should use the return value of EXT_IRQ_DISABLE. This will disable the + * selected PLIC interrupt from the Mi-V PLIC driver interrupt handler. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * @param IRQn + * Number of PLIC interrupt to disable. + * + * @return + * This function does not return any value. + * + * Example + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * } + * @endcode + */ +static inline void +MIV_PLIC_disable_irq +( + miv_plic_instance_t *this_plic, + miv_plic_irq_num_t IRQn +) +{ + unsigned long hart_id = read_csr(mhartid); + + uint32_t current = HAL_get_32bit_reg((this_plic->base_addr + (IRQn/32) + (hart_id * 128)) , INT_ENABLE); + + current &= ~((uint32_t)1 << (IRQn % 32)); + + HAL_set_32bit_reg((this_plic->base_addr + (IRQn/32) + (hart_id * 128)), INT_ENABLE, current); + +} + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_PLIC_H_ */ diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_plic/miv_plic_regs.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_plic/miv_plic_regs.h new file mode 100644 index 0000000..76cbc0b --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_plic/miv_plic_regs.h @@ -0,0 +1,31 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP PLIC module driver. This module is delivered as a part of Mi-V extended + * Sub-System(MIV_ESS). + */ + +#ifndef MIV_PLIC_REGISTERS +#define MIV_PLIC_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Interrupt pending register offset */ +#define INT_PENDING_REG_OFFSET 0x1000u + +/* Interrupt enable register */ +#define INT_ENABLE_REG_OFFSET 0x2000u + +/* Interrupt claim complete register */ +#define INT_CLAIM_COMPLETE_REG_OFFSET 0x200004u + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_PLIC_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_timer/miv_timer.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_timer/miv_timer.h new file mode 100644 index 0000000..5f00889 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_timer/miv_timer.h @@ -0,0 +1,329 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Mi-V Timer Soft IP bare-metal driver. This module is delivered as part of + * the Mi-V Extended Sub System(ESS) MIV_ESS. + */ + +/*=========================================================================*//** + @mainpage Mi-V Timer Bare Metal Driver. + The Mi-V Timer bare metal software driver supports the timer module which + serves as a system timer for the Mi-V Extended Sub System(ESS). + + @section intro_sec Introduction + The MI-V Timer driver supports set of functions for controlling the Mi-V + Timer module. + The Mi-V Timer can generate a timer interrupt signal for the system based on + special system clock intervals specified by the parameters that can be passed + in by the user. + + The major features provided by Mi-V Timer driver are: + - Support for Mi-V Timer instance for each Mi-V Timer peripheral. + - Read current time + - Write to the machine time compare register + + @section hw_dependencies Hardware Flow dependency + The application should configure the Mi-V Timer driver through calls to + MIV_TIMER_init() functions for each MIV_TIMER instance in the hardware + design. The configuration parameter include the MIV_TIMER hardware instance, + base address and number of ticks to generate timer interrupt. + + MIV_RV32 core offers flexibility in terms of generating the MTIME and MTIMECMP + registers internal to the core or using external time reference. + When MIV_ESS is interfaced with MIV_RV32 core, the timer module in the MIV_ESS + can be configured as follows: + - Internal MTIME External MTIME IRQ + Generate the MTIME internally(MIV_RV32) and have a timer interrupt input + to the core as external pin(from MIV_ESS). + + - External MTIME Internal MTIME IRQ + Generate the time value externally(from MIV_ESS), in this case a 64-bit + port will open in the MIV_RV32 core as input and MIV_ESS will output the + 64-bit TIME_COUNT value. The generation of mtimecmp and interrupt is + done internally(MIV_RV32). + + - External MTIME External MTIME IRQ + Generate both the time and timer interrupt externally. + In this case 64-bit port will be available on the Mi-V RV32 core as input + and a 1 pin port will be available for timer interrupt. + + The design must be configured accordingly to use these combinations in the + firmware. + + No MIV_TIMER hardware configuration parameters are used by the driver, apart + from MIV_TIMER base address. Hence, no additional configuration files are + required to use the driver. + + @section theory_op Theory of Operation + + The MIV_TIMER module is a simple systick timer which can generate a timer + interrupt signal for the system at specific intervals specified by the + parameters that can be passed by the user. + These interrupt signal are then fed to the MIV_RV32 core via timer interrupt. + + The operation of MIV_TIMER is divided into following steps: + - Initialization + - Configuration + - Read/Write TIME + + ## Initialization + The MIV_TIMER is first initialized by a call to MIV_TIMER_init(). This + function initializes the instance of Mi-V TIMER with the base address. + The MIV_TIMER_init() function must be called before any other Mi-V Timer driver + function. + + ## Configuration + The Mi-V TIMER configuration includes writing the mtimecmp register with the + initial time value at which timer interrupt should be generated. + When the mtime register value becomes greater than or equal to mtimecmp value, + a timer interrupt signal(TIMER_IRQ) is generated. + + ## Read/Write TIME + The time value can be read by reading the mtime register via call to the + MIV_TIMER_read_mtime(). This function reads the MTIME register which contains + the 64-bit value of the timer count. The count increments by 1 every time the + prescale ticks. This function returns 64-bit MTIME_COUNT value which is the + current value of timer count. + + The time value read in the MIV_TIMER_read_mtime() function can be written to + the mtimecmp register by calling MIV_TIMER_write_mtimecmp() to generate + periodic interrupts. + The writing of the mtimecmp register should be done in the systick_handler() + function. + */ + +#ifndef MIV_TIMER_H_ +#define MIV_TIMER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#endif +/*-------------------------------------------------------------------------*//** +MIV_TIMER_SUCCESS +===================== + +The MIV_TIMER_SUCCESS constant indicates successful configuration of +Mi-V Timer module. +*/ +#define MIV_TIMER_SUCCESS 0u + +/*-------------------------------------------------------------------------*//** +MIV_TIMER_ERROR +===================== + +The MIV_TIMER_ERROR constant indicates that there is an error with +configuring the Mi-V Timer module. +*/ +#define MIV_TIMER_ERROR 1u + +/*-------------------------------------------------------------------------*//* +MIV_TIMER_MASK_32BIT +===================== + +32-bit mask constant used in calculation of 64-bit register value. +*/ +#define MIV_TIMER_MASK_32BIT 0xFFFFFFFFu + +/*-------------------------------------------------------------------------*//* +Mi-V Timer register offsets +===================== +The MTIMECMP is the 64-bit timer compare register, it pre-sets the threshold +which needs to be reached by the timer count register. +This 64-bit register is accessed with 2 32-bit address offset, lower 32-bits +and higher 32-bits. + - MIV_TIMER_MTIMECMP_L_REG_OFFSET + - MIV_TIMER_MTIMECMP_H_REG_OFFSET + +The MTIME is the 64-bit register that contains the 64-bit timer count. The +count increments by 1 every time the prescaler ticks. +This 64-bit register is accessed with 2 32-bit address offset, lower 32-bits +and higher 32-bits. + - MIV_TIMER_MTIME_L_REG_OFFSET + - MIV_TIMER_MTIME_H_REG_OFFSET + +The PRESCALE register is used to determine the amount of clock cycles the +selected clock needs to go through, for MTIME register to increment count. + - MIV_TIMER_PRESCALAR_REG_OFFSET +*/ + +/// @cond private +#define MIV_TIMER_MTIMECMP_L_REG_OFFSET 0x4000u +#define MIV_TIMER_MTIMECMP_H_REG_OFFSET 0x4004u + +#define MIV_TIMER_MTIME_L_REG_OFFSET 0xBFF8u +#define MIV_TIMER_MTIME_H_REG_OFFSET 0xBFFCu + +#define MIV_TIMER_PRESCALAR_REG_OFFSET 0x5000u +/// @endcond + +/*-------------------------------------------------------------------------*//** + This structure holds the base address of the Mi-V Timer module and instance + of the Mi-V Timer register structure. +*/ +typedef struct miv_timer_instance +{ + addr_t base_addr; +} miv_timer_instance_t; + +/** The MIV_TIMER_init() is used to initialize the Mi-V Timer module. This + function will assign the base addresses of the Mi-V Timer module. + User should call this function before calling any of the Mi-V Timer driver + APIs. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @param base_address + Base address of the Mi-V Timer module. + + @return + This function does not return any value. + */ +static inline void +MIV_TIMER_init +( + miv_timer_instance_t* this_timer, + addr_t base_addr +) +{ + this_timer->base_addr = base_addr; +} + +/** MIV_TIMER_read_current_time() is used to read the mtimecmp register values. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @return + This function returns 64-bit mtimecmp register value. + */ +static inline uint64_t +MIV_TIMER_read_current_time +( + miv_timer_instance_t* this_timer +) +{ + volatile uint64_t read_data = 0u; + volatile uint32_t mtime_hi = 0u; + volatile uint32_t mtime_lo = 0u; + + /* when mtime lower word is 0xFFFFFFFF, there will be rollover and + * returned value could be wrong. */ + do { + mtime_hi = HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIME_H); + mtime_lo = HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIME_L); + + } while(mtime_hi != HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIME_H)); + + read_data = mtime_hi; + + return(((read_data) << 32u) | mtime_lo); +} + +/** MIV_TIMER_write_compare_time() is used to write to the MTIMECMP register in + the event of interrupt. User must use this function in the interrupt handler + to de-assert the MIV_TIMER interrupt. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @param write_value + Value to write into the mtimecmp register. + + @return + This function does not return any value. + */ +static inline void +MIV_TIMER_write_compare_time +( + miv_timer_instance_t* this_timer, + uint64_t compare_reg_value +) +{ + HAL_set_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIMECMP_H, MIV_TIMER_MASK_32BIT); + + HAL_set_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIMECMP_L, + (compare_reg_value & MIV_TIMER_MASK_32BIT)); + + HAL_set_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIMECMP_H, + ((compare_reg_value >> 32u) & MIV_TIMER_MASK_32BIT)); +} + +/** The MIV_TIMER_config() is used to configure the MIV_ESS Timer module. The + prescale value serves to divide the count of clock cycles for the timer and + provides control over what point in time, the timer interrupt gets + asserted. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @param ticks + Number of ticks after which interrupt will be generated. + + @return + This function returns Mi-V Timer configuration status. + */ +static inline uint32_t +MIV_TIMER_config +( + miv_timer_instance_t* this_timer, + uint64_t ticks +) +{ + uint32_t ret_val = MIV_TIMER_ERROR; + uint64_t mtime_val = 0u; + uint32_t prescalar = 0u; + uint64_t miv_timer_increment = 0U; + + prescalar = HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_PRESCALAR); + + miv_timer_increment = (uint64_t)(ticks) / prescalar; + + if (miv_timer_increment > 0U) + { + mtime_val = MIV_TIMER_read_current_time(this_timer); + + MIV_TIMER_write_compare_time(this_timer ,(mtime_val + miv_timer_increment)); + + ret_val = MIV_TIMER_SUCCESS; + } + + return ret_val; +} + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_TIMER_H */ diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c new file mode 100644 index 0000000..cbd9652 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c @@ -0,0 +1,109 @@ +/******************************************************************************* + * (c) Copyright 2022-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Mi-V uDMA Soft IP bare-metal driver. This module is delivered as part of + * Mi-V Extended Sub System(MIV_ESS) + */ + +#include "miv_udma_regs.h" +#include "miv_udma.h" + +/***************************************************************************//** + * MIV_uDMA_init() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_init +( + miv_udma_instance_t* this_udma, + addr_t base_addr +) +{ + /* Assign the Mi-V uDMA base address to the uDMA instance structure */ + this_udma->base_address = base_addr; +} + +/***************************************************************************//** + * MIV_uDMA_config() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_config +( + miv_udma_instance_t* this_udma, + addr_t src_addr, + addr_t dest_addr, + uint32_t transfer_size, + uint32_t irq_config +) +{ + /* Source memory start address */ + HAL_set_32bit_reg(this_udma->base_address, SRC_START_ADDR, src_addr); + + /* Destination memory start address */ + HAL_set_32bit_reg(this_udma->base_address, DEST_START_ADDR, dest_addr); + + /* Data transfer size */ + HAL_set_32bit_reg(this_udma->base_address, BLK_SIZE, transfer_size); + + /* Configure the uDMA IRQ */ + HAL_set_32bit_reg(this_udma->base_address, IRQ_CFG, irq_config); +} + +/***************************************************************************//** + * MIV_uDMA_start() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_start +( + miv_udma_instance_t* this_udma +) +{ + /* Start the uDMA transfer */ + HAL_set_32bit_reg(this_udma->base_address, CONTROL_SR, CTRL_START_TX_MASK); +} + +/***************************************************************************//** + * MIV_uDMA_reset() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_reset +( + miv_udma_instance_t* this_udma +) +{ + /* Toggle the uDMA_reset bit to reset the uDMA. + * Resetting the uDMA will clear all the configuration made by + * MIV_uDMA_config(). + * + * This function should be called from the interrupt handler to clear the + * IRQ. + */ + HAL_set_32bit_reg_field(this_udma->base_address, CTRL_RESET_TX, 0x1u); + HAL_set_32bit_reg_field(this_udma->base_address, CTRL_RESET_TX, 0x0u); +} + +/***************************************************************************//** + * MIV_uDMA_read_status() + * See "miv_udma.h" for details of how to use this function. + */ +uint32_t +MIV_uDMA_read_status +( + miv_udma_instance_t* this_udma +) +{ + uint32_t status = 0u; + + /* Read the status of the uDMA transfer. + * The transfer status register can be Error or Busy depending on the + * current uDMA transfer. + */ + status = HAL_get_32bit_reg(this_udma->base_address, TX_STATUS); + + return status; +} diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h new file mode 100644 index 0000000..efa8731 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h @@ -0,0 +1,290 @@ +/******************************************************************************* + * Copyright 2022-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * uDMA module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(MIV_ESS). + */ + +/*=========================================================================*//** + @mainpage Mi-V uDMA Bare Metal Driver. + The Mi-V uDMA bare metal software driver. + + @section intro_sec Introduction + The Mi-V uDMA driver provides a set of functions to control the Mi-V uDMA + module in the Mi-V Extended Subsystem (MIV_ESS) soft-IP. The Mi-V uDMA module + allows peripherals with AHB interfaces to transfer data independently of the + MIV_RV32 RISC-V processor. + + Following are the major features provided by the Mi-V uDMA driver: + - Initialization and configuration + - Start and reset the transaction + + This driver can be used as part of a bare metal system where no operating + system is available. The driver can be adapted for use as part of an + operating system, but the implementation of the adaptation layer between the + driver and the operating system's driver model is outside the scope of this + driver. + + @section hw_dependencies Hardware Flow Dependency + The application software should initialize and configure the Mi-V uDMA through + calling the MIV_uDMA_init() and MIV_uDMA_config() functions for each Mi-V + uDMA instance in the design. + + The uDMA can operate in two possible transfer configurations: + + - AHBL Read -> AHBL Write: + In this configuration, the uDMA reads data from the source memory over an + AHBL (mirrored main/initiator) read interface and writes data to the + destination memory over an AHBL (mirrored main/initiator) write interface. + + - AHBL Read -> TAS Write: + In this configuration, the uDMA reads data from the source memory over an + AHBL (mirrored main/initiator) read interface and writes data to the + destination memory over the TAS (mirrored main/initiator) write interface. + + Note: The AHBL Read -> TAS Write configuration is out of scope for this + driver. + + @section theory_op Theory of Operation + The uDMA module in the Mi-V Extended Sub System (MIV_ESS) is a single-channel + uDMA module that allows peripherals to perform read-write operations between + source and destination memory. The Mi-V uDMA driver is used in + interrupt-driven mode and uses the Mi-V uDMA IRQ signal to drive the + interrupt service routine (ISR), which signifies a transfer has completed. + The status is checked in the ISR to ensure the transfer is completed + successfully. + The reset operation in the ISR resets the Mi-V uDMA controller. Once the Mi-V + uDMA transfer is complete, Mi-V uDMA retires. To initiate another + transaction, Mi-V uDMA needs to be configured again. + + The operation of the Mi-V uDMA driver is divided into the following + categories: + - Initialization + - Configuration + - Start and reset the transfer + + Initialization and configuration: + Mi-V uDMA is first initialized by calling MIV_uDMA_init() function. This + function initializes the instance of Mi-V uDMA with the base address. The + MIV_uDMA_init() function must be called before calling any other Mi-V uDMA + driver functions. + + The Mi-V uDMA is configured by calling MIV_uDMA_config() function. This + function configures the source_addr and dest_addr registers of the Mi-V + uDMA with source and destination addresses for Mi-V uDMA transfers. + This function also configures the transfer size and interrupt preference for + successful transfers using Mi-V uDMA. + + Start and reset the transfer: + Once the Mi-V uDMA is configured, initiate the transfers by calling the + MIV_uDMA_start() function. Once the Mi-V uDMA transfer is started, it cannot + be aborted, and the status of the transfer should be read from the ISR by + calling the MIV_uDMA_read_status() function. + + Reset the Mi-V uDMA to the default state by calling the MIV_uDMA_reset() + function. After performing the reset operation, reconfigure the Mi-V uDMA to + perform transfers as MIV_uDMA_reset() resets the Mi-V uDMA controller. + */ + +#ifndef MIV_uDMA_H_ +#define MIV_uDMA_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#include "hal/cpu_types.h" + +#else +#include "hal.h" +#include "cpu_types.h" +#endif + +/*-------------------------------------------------------------------------*//** + MIV_uDMA_CTRL_IRQ_CONFIG + ===================== + + The MIV_uDMA_CTRL_IRQ_CONFIG macro is used to assert the uDMA IRQ when an error + occurs during a uDMA transfer or on the completion of a uDMA transfer. + */ +#define MIV_uDMA_CTRL_IRQ_CONFIG 1u + +/*-------------------------------------------------------------------------*//** + MIV_uDMA_STATUS_BUSY + ===================== + + The MIV_uDMA_STATUS_BUSY macro is used to indicate that the uDMA transfer is + in progress. + */ +#define MIV_uDMA_STATUS_BUSY 1u + +/*-------------------------------------------------------------------------*//** + MIV_uDMA_STATUS_ERROR + ===================== + + The MIV_uDMA_STATUS_ERROR macro is used to indicate that the last uDMA + transfer has caused an error. + */ +#define MIV_uDMA_STATUS_ERROR 2u + +/***************************************************************************//** + * This structure holds the base of the Mi-V uDMA module, which is used in the + * other functions of the driver to access the uDMA registers. + */ +typedef struct miv_udma_instance +{ + addr_t base_address; +} miv_udma_instance_t; + +/***************************************************************************//** + * The MIV_uDMA_init() function assigns the base address of the Mi-V uDMA module + * to the uDMA instance structure. + * This address is used in a later part of the driver to access the uDMA + * registers. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure. + * + * @param base_addr + * Base address of the Mi-V uDMA module. + * + * @return + * This function does not return a value. + */ +void +MIV_uDMA_init +( + miv_udma_instance_t* this_udma, + addr_t base_addr +); + +/***************************************************************************//** + * The MIV_uDMA_config() function is used to configure the Mi-V uDMA controller. + * This function will set the source address, destination address, block size, + * and IRQ configuration register. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @param base_addr + * Base address of the Mi-V uDMA. + * + * @param src_addr + * Source address of memory from where the uDMA reads the data. + * + * @param dest_addr + * Destination address where the data is written from src_addr. + * + * @param transfer_size + * Number of 32-bit words to transfer. + * + * @param irq_config + * uDMA IRQ configuration + * - When set, the IRQ is asserted when an error occurs during a uDMA + * transfer or on the completion of the uDMA transfer. + * - When clear, the IRQ is only asserted when an error occurs during a + * uDMA transfer. + * + * @return + * This function does not return any value. + */ +void +MIV_uDMA_config +( + miv_udma_instance_t* this_udma, + addr_t src_addr, + addr_t dest_addr, + uint32_t transfer_size, + uint32_t irq_config +); + +/***************************************************************************//** + * The MIV_uDMA_start() function is used to start the uDMA transfer. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @return + * This function does not return any value. + */ +void +MIV_uDMA_start +( + miv_udma_instance_t* this_udma +); + +/***************************************************************************//** + * The MIV_uDMA_reset() function is used to clear the uDMA interrupt and reset + * the uDMA transfer. + * + * This function should be called from the interrupt handler to reset the values + * set during MIV_uDMA_config(). + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @return + * This function does not return any value. + */ +void +MIV_uDMA_reset +( + miv_udma_instance_t* this_udma +); + +/***************************************************************************//** + * The MIV_uDMA_read_status() function is used to read the status of the uDMA + * transfer. When interrupt is enabled, this function can be called from the + * interrupt handler to know the reason for a uDMA interrupt. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @return + * The return value indicates an error due to the busy status of the uDMA + * channel. + * + * |Bit Number| Name | Description | + * |----------|---------|------------------------------------------------------| + * | 0 | Busy | When set indicates that uDMA transfer is in progress| + * | 1 | Error | When set indicates that last uDMA transfer caused an| + * | | | error. | + */ +uint32_t +MIV_uDMA_read_status +( + miv_udma_instance_t* this_pdma +); + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_uDMA_H_ */ diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h new file mode 100644 index 0000000..14d0759 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h @@ -0,0 +1,94 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP uDMA module driver. This module is delivered as a part of Mi-V + * extended Sub-System(ESS) MIV_ESS. + */ + +#ifndef MIV_UDMA_APB_REGISTERS +#define MIV_UDMA_APB_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/**************************************************************************//** + * Control start/Reset register details + */ + +#define CONTROL_SR_REG_OFFSET 0x0u + +/* Control start/Reset register bits */ +#define CONTROL_SR_OFFSET 0x00u +#define CONTROL_SR_MASK 0x03u +#define CONTROL_SR_SHIFT 0u + +/* uDMA Control Start Transfer */ + +#define CTRL_START_TX_OFFSET 0x00u +#define CTRL_START_TX_MASK 0x01u +#define CTRL_START_TX_SHIFT 0u + +/* uDMA Control Reset Transfer */ +#define CTRL_RESET_TX_OFFSET 0x00u +#define CTRL_RESET_TX_MASK 0x02u +#define CTRL_RESET_TX_SHIFT 1u + +/**************************************************************************//** + * IRQ Configuration register details + */ +#define IRQ_CFG_REG_OFFSET 0x4u + +/* Control start/Reset register bits */ +#define IRQ_CFG_OFFSET 0x04u +#define IRQ_CFG_MASK 0x01u +#define IRQ_CFG_SHIFT 0u + +/***************************************************************************//** + * Transfer Status register details + */ +#define TX_STATUS_REG_OFFSET 0x08u + +/* Transfer status register bits */ +#define TX_STATUS_OFFSET 0x08u +#define TX_STATUS_MASK 0x03u +#define TX_STATUS_SHIFT 0u + +/***************************************************************************//** + * Source Memory Start Address Register + */ +#define SRC_START_ADDR_REG_OFFSET 0x0cu + +/* Source Memory Start Address Register bits */ +#define SRC_START_ADDR_OFFSET 0x0cu +#define SRC_START_ADDR_MASK 0xFFFFFFFFu +#define SRC_START_ADDR_SHIFT 0u + +/***************************************************************************//** + * Destination Memory Start Address register details + */ +#define DEST_START_ADDR_REG_OFFSET 0x10u + +/* Destination Memory Start Address register bits */ +#define DEST_START_ADDR_OFFSET 0x10u +#define DEST_START_ADDR_MASK 0xFFFFFFFFu +#define DEST_START_ADDR_SHIFT 0x0u + +/***************************************************************************//** + * Block Size register details + */ +#define BLK_SIZE_REG_OFFSET 0x14u + +/* Destination Memory Start Address register bits */ +#define BLK_SIZE_OFFSET 0x14u +#define BLK_SIZE_MASK 0xFFFFFFFFu +#define BLK_SIZE_SHIFT 0x0u + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_UDMA_APB_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c new file mode 100644 index 0000000..525928a --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Mi-V Watchdog Soft IP bare-metal driver. This module is delivered as part of + * Extended Sub System(ESS) MIV_ESS. + * Please refer to miv_watchdog.h file for more information. + */ + +#include "miv_watchdog.h" + +addr_t g_this_wdog; + +/***************************************************************************//* + * Please refer to miv_watchdog.h for more info about this function + */ +void +MIV_WDOG_init +( + addr_t base_addr +) +{ + /* Register the Mi-V Watchdog base address to the driver */ + g_this_wdog = base_addr; +} + +/***************************************************************************//* + * Please refer to miv_watchdog.h for more info about this function + */ +uint8_t MIV_WDOG_configure +( + const miv_wdog_config_t *config +) +{ + uint8_t error = 0u; + + /* check load value and trigger max value */ + if (config->timeout_val <= MIV_WDOG_TRIGGER_MAX) + { + HAL_set_32bit_reg(g_this_wdog, WDOGTRIG,(config->timeout_val)); + } + else + { + error = 1u; + } + + if (config->time_val <= MIV_WDOG_TIMER_MAX) + { + HAL_set_32bit_reg(g_this_wdog, WDOGMSVP,(config->mvrp_val)); + } + else + { + error = 1u; + } + + HAL_set_32bit_reg_field(g_this_wdog, WDOGCNTL_NEXT_ENFORBIDDEN, + config->forbidden_en); + + /* Reload watchdog with new load if it is not in forbidden window */ + if (!(WDOGSTAT_FORBIDDEN_MASK & (HAL_get_32bit_reg(g_this_wdog, WDOGSTAT)))) + { + HAL_set_32bit_reg(g_this_wdog, WDOGRFSH, MIV_WDOG_REFRESH_KEY); + } + else + { + error = 1u; + } + + return (error); +} + +/***************************************************************************//* + * Please refer to miv_watchdog.h for more info about this function + */ +void MIV_WDOG_get_config +( + miv_wdog_config_t *config +) +{ + if (0 != g_this_wdog) + { + + config->time_val = HAL_get_32bit_reg(g_this_wdog, WDOGTIME); + + config->timeout_val = HAL_get_32bit_reg(g_this_wdog, WDOGTRIG); + + config->mvrp_val = HAL_get_32bit_reg(g_this_wdog, WDOGMSVP); + + config->forbidden_en = HAL_get_32bit_reg_field(g_this_wdog, + WDOGCNTL_NEXT_ENFORBIDDEN); + } +} + diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h new file mode 100644 index 0000000..8877e55 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h @@ -0,0 +1,553 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * Watchdog module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(MIV_ESS). + */ +/*=========================================================================*//** + @mainpage MiV Watchdog Bare Metal Driver + + ============================================================================== + Introduction + ============================================================================== + The Mi-V Watchdog module in the MIV_ESS is used to generate a reset for the + system automatically if the software doesn't periodically update or refresh + the timer countdown register. This software driver provides set of functions + for controlling Mi-V Watchdog module as a part of bare metal system where no + operating system is available. The driver can be adapted for use as a part of + an operating system, but the implementation of the adaptation layer between + the driver and the operating system's driver model is outside the scope of the + driver. + + Mi-V Watchdog provides following features: + - Initializing the Mi-V Watchdog + - Reading current value and status of watchdog timer + - Refreshing the watchdog timer value + - Enabling, disabling and clearing timeout and Maximum Value up to which + Refresh is Permitted (MVRP) interrupts. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + The application software should initialize and configure the Mi-V Watchdog + module the the call to the MIV_WDOG_init() and MIV_WDOG_configure() functions. + + No MIV_WDOG hardware configuration parameter are used by the driver, apart + from the MIV_WDOG base address. Hence, no additional configuration files are + required to use the driver. + + ============================================================================== + Theory of Operation + ============================================================================== + The Mi-V Watchdog driver functions are grouped into the following categories: + - Initialization and configuration + - Reading the current value and status of the watchdog timer + - Refreshing the watchdog timer value + - Support for enabling, disabling and clearing time-out and MVRP interrupts. + + -------------------------------- + Initialization and Configuration + -------------------------------- + The MIV_WDOG_init() function stores the base of MIV_WDT module in the MIV_ESS. + This base address is used by rest of the functions to access the Mi-V Watchdog + registers. Please make call this function before calling any other function + from this driver. + Note: The Mi-V Watchdog driver supports only one instance of MIV_WDT in the + hardware. + The Mi-V Watchdog driver provides the MIV_WDOG_configure() function to + configure the MIV_WDOG module with desired configuration values. It also + provides the MIV_WDOG_get_config() to read back the current configuration of + the MIV_WDOG. You can use this function to retrieve the current configurations + and then overwrite them with the application specific values, such as initial + watchdog timer value, Maximum Value (up to which) Refresh (is) Permitted, + watchdog time-out value, enable/disable forbidden region, enable/disable + MVRP interrupt and interrupt type. + + -------------------------------------------- + Reading the Watchdog Timer Value and Status + -------------------------------------------- + Mi-V Watchdog is a down counter. A refresh forbidden window can be created by + configuring the watchdog Maximum Value up to which Refresh is Permitted (MVRP). + When the current value of the watchdog timer is greater than the MVRP value, + refreshing the watchdog is forbidden. Attempting to refresh the watchdog timer + in the forbidden window will assert a timeout interrupt. The + MIV_WDOG_forbidden_status() function can be used to know whether the watchdog + timer is in forbidden window or has crossed it. By default, the forbidden + window is disabled. It can be enabled by providing an appropriate value as + parameter to the MIV_WDOG_configure() function. When the forbidden window is + disabled, any attempt to refresh the watchdog timer is ignored and the counter + keeps on down counting. + + The current value of the watchdog timer can be read using the + MIV_WDOG_current_value() function. This function can be called at any time. + + -------------------------------------------- + Refreshing the Watchdog Timer Value + -------------------------------------------- + The watchdog timer value is refreshed using the MIV_WDOG_reload() function. + The value reloaded into the watchdog timer down-counter is specified at the + configuration time with an appropriate value as parameter to the + MIV_WDOG_get_config() function. + + -------------------------------------------- + Interrupt Control + -------------------------------------------- + The Mi-V Watchdog generates two interrupts, The MVRP interrupt and + the timeout interrupt. + The MVRP interrupt is generated when the watchdog down-counter crosses the + Maximum Value up to which Refresh is Permitted (MVRP). Following functions to + control MVRP interrupt: + - MIV_WDOG_enable_mvrp_irq + - MIV_WDOG_disable_mvrp_irq + - MIV_WDOG_clear_mvrp_irq + + The timeout interrupt is generated when the watchdog down-counter crosses the + watchdog timeout value. The timeout value is a non-zero value and it can be + set to a maximum of MIV_WDOG_TRIGGER_MAX. The non-maskable interrupt is + generated when the watchdog crosses this timeout value, the down counter + keeps on down counting and a reset signal is generated when reaches zero. + Following functions to control timeout interrupt: + - MIV_WDOG_enable_timeout_irq + - MIV_WDOG_disable_timeout_irq + - MIV_WDOG_clear_timeout_irq + +*//*=========================================================================*/ + +#ifndef MIV_WATCHDOG_H_ +#define MIV_WATCHDOG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "miv_watchdog_regs.h" + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#else +#include "hal.h" +#endif + +/****************************************************************************//* + * The following constants can be used to configure the Mi-V Watchdog where a + * zero or non-zero value such as enable or disable is to be provided as a input + * parameter as shown below: + */ +#define MIV_WDOG_ENABLE 1u +#define MIV_WDOG_DISABLE 0u + +/***************************************************************************//** + The miv_wdog_config_t type for the watchdog Configuration structure. This + type is used as a parameter for the MIV_WDOG_configure() and the + MIV_WDOG_get_config() functions. + + Following are the values as part of this structure +| Parameter | Description | +|------------------|-----------------------------------------------------------| +| time_val | The value from which the watchdog timer counts down | +| mvrp_val | The Watchdog MVRP value | +| timeout_val | The watchdog timeout value | +| forbidden_en | Enable/disable the forbidden window | +| | When set, if a refresh occurs in the forbidden window, | +| | the watchdog timeout interrupt will be generated. | + +Time calculation example: + + time_val = 0xFFFFF0u + mvrp_val = 0x989680u + timeout_val = 0x3e8u + + A prescaler = 256 is used. + Considering clock = 50Mhz + + The MVRP interrupt will happen after + (0xFFFFF0 - 0x989680) * ( 1/(50MHz/256)) + mvrp interrupt will happen after 34 sec. after system reset + + (0xFFFFF0 - 0x3e8) * ( 1/(50MHz/256)) + timeout interrupt will happen after 85 sec. after system reset + */ +typedef struct miv_wdog_config +{ + uint32_t time_val; + uint32_t mvrp_val; + uint32_t timeout_val; + uint32_t forbidden_en; + uint32_t intr_type; +}miv_wdog_config_t; + +extern addr_t g_this_wdog; + +/***************************************************************************//* + Internal constants and types +*******************************************************************************/ + +/// @cond private +#define MIV_WDOG_TRIGGER_MAX 4095u +#define MIV_WDOG_TIMER_MAX 16777200u +/// @endcond + +/*-------------------------------------------------------------------------*//* +MIV_WDOG_REFRESH_KEY +===================== + +The MIV_WDOG_REFRESH_KEY macro holds the magic value which will cause a +reload of the watchdog's down counter when written to the watchdog's +WDOGREFRESH register. +*/ +#define MIV_WDOG_REFRESH_KEY (uint32_t)0xDEADC0DEU + +/*-------------------------------------------------------------------------*//* +MIV_WDOG_FORCE_RESET_KEY +===================== +The MIV_WDOG_FORCE_RESET_KEY macro holds the magic value which will force a +reset if the watchdog is already timeout. Writing any other value or writing +TRIGGER register at other times will trigger the watchdog NMI sequence +(i.e raise a timeout interrupt) + */ +#define MIV_WDOG_FORCE_RESET_KEY (uint32_t)0xDEADU + +/***************************************************************************//** + * The MIV_WDOG_init() is used to register the Mi-V Watchdog module base + * address to the driver. + * + * Note: User should call this function before calling any other Mi-V watchdog + * driver function. + * + * @param base_addr + * The base address of the Mi-V watchdog module. This address is used by + * rest of the watchdog driver functions to access the registers. + * + * @return + * This function does not return any value. + */ +void +MIV_WDOG_init +( + addr_t base_addr +); + +/***************************************************************************//** + * The MIV_WDOG_get_config() function returns the current configurations of the + * Mi-V Watchdog. The Mi-V Watchdog is pre-initialized by the flash + * bits at the design time. When used for the first time before calling the + * MIV_WDOG_configure() function, this function will return the default + * configurations as configured at the design time. + * + * @param config + * The config parameter is used to store the current configuration of the Mi-V + * Watchdog. + * + * Please see the description of miv_wdog_config_t for details. + * + * @return + * This function does not return any value. + * + * Example: + */ +void +MIV_WDOG_get_config +( + miv_wdog_config_t* config +); + +/***************************************************************************//** + * The MIV_WDOG_configure() function configures the watchdog module. The + * Watchdog module is pre-initialized by the flash bits at the design time to the + * default values. You can reconfigure the Watchdog module using + * MIV_WDOG_configure() function. + * + * Note that the MIV_WDOG_configure() function can be used only once, as it + * writes into the TIME register. After a write into the TIME register, the TIME, + * TRIGGER and MSVP register values are frozen and can't be altered again unless + * a system reset happens. + * + * Note also that the Mi-V Watchdog is not enabled at reset, calling this function + * will start the watchdog, it cannot then be disabled and must be refreshed + * periodically. + * + * @param config + * The config parameter is the input parameter in which the configurations to + * be applied to the watchdog module are provided by the application. + * Please see the description of miv_wdog_config_t for details. + * + * @return + * This function returns a zero value when executed successfully. A non-zero + * value is returned when the configuration values are out of bound. + * + * Example: + */ +uint8_t +MIV_WDOG_configure +( + const miv_wdog_config_t * config +); + +/***************************************************************************//** + * The MIV_WDOG_reload() function causes the watchdog to reload its down-counter + * timer with the load value configured through interrupt handler. This function + * must be called regularly to avoid a system reset or a watchdog interrupt. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_reload +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg(g_this_wdog, WDOGRFSH, MIV_WDOG_REFRESH_KEY); + } +} + +/***************************************************************************//** + * The MIV_WDOG_current_value() function returns the current value of the + * watchdog's down-counter. + * + * @param + * Void + * + * @return + * This function returns the current value of the watchdog’s down-counter as + * a 32-bit unsigned integer. + */ +static inline uint32_t +MIV_WDOG_current_value +( + void +) +{ + return (HAL_get_32bit_reg(g_this_wdog, WDOGRFSH)); +} + +/***************************************************************************//** + * The MIV_WDOG_forbidden_status() function returns the refresh status of the + * Mi-V Watchdog. + * + * @param + * Void + * + * @return + * This function returns the refresh status of the watchdog. A value of 1 + * indicates that watchdog's down-counter is within the forbidden window and + * that a reload should not be done. A value of 0 indicates that the watchdog's + * down counter is within the permitted window and that a reload is allowed. + */ +static inline uint32_t +MIV_WDOG_forbidden_status +( + void +) +{ + return (HAL_get_32bit_reg_field(g_this_wdog, WDOGSTAT_FORBIDDEN)); +} + +/***************************************************************************//** + * The MIV_WDOG_enable_mvrp_irq() function enables the MVRP interrupt. + * This interrupt is asserted when the timer countdown register leaves the + * maximum value up to which refresh is permitted (MVRP) window. + * + * @param + * Void + * + * @return + * This function does not return a value. + * + * Example: + */ +static inline void +MIV_WDOG_enable_mvrp_irq +( + void +) +{ + + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGCNTL_NEXT_INTENT_MSVP, 0x01u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_disable_mvrp_irq() function disables the generation of the + * MVRP interrupt. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_disable_mvrp_irq +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGCNTL_NEXT_INTENT_MSVP, 0x0u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_clear_timeout_irq() function clears the watchdog’s timeout + * interrupt which is connected to the MIV-RV32 interrupt. Calling + * MIV_WDOG_clear_timeout_irq() results in clearing the MIV-RV32 interrupt. + * Note: You must call the MIV_WDOG_clear_timeout_irq() function as part of your + * implementation of the interrupt handler in order to prevent the same + * interrupt event re-triggering a call to the timeout ISR. + * + * @param + * Void + * + * @return + * This function does not return any value. + * + */ +static inline void +MIV_WDOG_clear_timeout_irq +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_WDOG_TRIPPED, 0x01u); + /* + * Perform a second write to ensure that the first write completed before + * returning from this function. This is to account for posted writes across + * the AHB matrix. The second write ensures that the first write has + * completed and that the interrupt line has been de-asserted by the time + * the function returns. Omitting the second write may result in a delay + * in the de-assertion of the interrupt line going to the RISC-V and a + * retriggering of the interrupt. + */ + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_WDOG_TRIPPED, 0x01u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_clear_mvrp_irq() function clears the mvrp interrupt. + * + * Note: You must call the MIV_WDOG_clear_mvrp_irq() function as part of your + * implementation of the interrupt service routine (ISR) in order to + * prevent the same interrupt event re-triggering a call to the mvrp ISR. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_clear_mvrp_irq +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_MSVP_TRIPPED, 0x01u); + /* + * Perform a second write to ensure that the first write completed before + * returning from this function. This is to account for posted writes across + * the AHB matrix. The second write ensures that the first write has + * completed and that the interrupt line has been de-asserted by the time + * the function returns. Omitting the second write may result in a delay + * in the de-assertion of the interrupt line going to the RISC-V and a + * re-triggering of the interrupt. + */ + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_MSVP_TRIPPED, 0x01u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_timeout_occured() function reports the occurrence of a timeout + * event. + * + * @param + * Void + * + * @return + * A zero value indicates no watchdog timeout event occurred. A value of 1 + * indicates that a timeout event occurred. + */ +static inline uint32_t +MIV_WDOG_timeout_occured +( + void +) +{ + return (HAL_get_32bit_reg_field(g_this_wdog, WDOGSTAT_TRIGGERED)); +} + +/***************************************************************************//** + * The MIV_WDOG_force_reset() function is used to force an immediate reset + * if the watchdog has already triggered. Writing any value in this condition + * will result in watchdog timeout. + * The time out interrupt WDOG_IRQ will be set to high and watchdog timer + * countdown register updated with watchdog trigger timeout register value. + * If the Watchdog has timed out, a special 16-bit value needs to be written + * to the register to force a reset on CPU_RESETN, 0xDEAD + * Then the Watchdog countdown is reset/updated with the top Watchdog Runtime + * register value. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_force_reset +( + void +) +{ + if (WDOGSTAT_TRIGGERED_MASK == + HAL_get_32bit_reg_field(g_this_wdog, WDOGSTAT_TRIGGERED)) + + { + HAL_set_32bit_reg(g_this_wdog, WDOGFORCE, MIV_WDOG_FORCE_RESET_KEY); + } + + else + { + HAL_set_32bit_reg(g_this_wdog, WDOGFORCE, 0x0u); + } +} + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_WATCHDOG_H_ */ diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h new file mode 100644 index 0000000..2fca983 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h @@ -0,0 +1,122 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP watchdog module driver. This module is delivered as a part of Mi-V + * extended Sub-System(ESS) MIV_ESS. + */ + +#ifndef MIV_WDOG_REGISTERS +#define MIV_WDOG_REGISTERS 1u + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * Refresh register details + */ +#define WDOGRFSH_REG_OFFSET 0x00u + +/* Refresh register bits */ +#define WDOGRFSH_OFFSET 0x00u +#define WDOGRFSH_MASK 0xFFFFFFFFu +#define WDOGRFSH_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Control register details + */ +#define WDOGCNTL_REG_OFFSET 0x04u + +/* Control register next intent msvp bit */ +#define WDOGCNTL_NEXT_INTENT_MSVP_OFFSET 0x04u +#define WDOGCNTL_NEXT_INTENT_MSVP_MASK 0x01u +#define WDOGCNTL_NEXT_INTENT_MSVP_SHIFT 0u + +/* Control register next intent wdog bit */ +#define WDOGCNTL_NEXT_INTENT_WDOG_OFFSET 0x04u +#define WDOGCNTL_NEXT_INTENT_WDOG_MASK 0x02u +#define WDOGCNTL_NEXT_INTENT_WDOG_SHIFT 1u + +/* Control register next enforbidden bit */ +#define WDOGCNTL_NEXT_ENFORBIDDEN_OFFSET 0x04u +#define WDOGCNTL_NEXT_ENFORBIDDEN_MASK 0x10u +#define WDOGCNTL_NEXT_ENFORBIDDEN_SHIFT 4u + +/*------------------------------------------------------------------------------ + * Watchdog status register + */ +#define WDOGSTAT_REG_OFFSET 0x08u + +/* msvp_tripped bit */ +#define WDOGSTAT_MSVP_TRIPPED_OFFSET 0x08u +#define WDOGSTAT_MSVP_TRIPPED_MASK 0x01u +#define WDOGSTAT_MSVP_TRIPPED_SHIFT 0u + +/* WDOG Tripped bit */ +#define WDOGSTAT_WDOG_TRIPPED_OFFSET 0x08u +#define WDOGSTAT_WDOG_TRIPPED_MASK 0x02u +#define WDOGSTAT_WDOG_TRIPPED_SHIFT 1u + +/* Forbidden bit */ +#define WDOGSTAT_FORBIDDEN_OFFSET 0x08u +#define WDOGSTAT_FORBIDDEN_MASK 0x04u +#define WDOGSTAT_FORBIDDEN_SHIFT 2u + +/* Triggered bit */ +#define WDOGSTAT_TRIGGERED_OFFSET 0x08u +#define WDOGSTAT_TRIGGERED_MASK 0x08u +#define WDOGSTAT_TRIGGERED_SHIFT 3u + +/* wdoglocked bit */ +#define WDOGSTAT_WDOGLOCKED_OFFSET 0x08u +#define WDOGSTAT_WDOGLOCKED_MASK 0x10u +#define WDOGSTAT_WDOGLOCKED_SHIFT 4u + +/*------------------------------------------------------------------------------ + * Watchdog runtime register + */ +#define WDOGTIME_REG_OFFSET 0x0Cu + +/* wdogmsvp bit */ +#define WDOGTIME_WDOGVALUE_OFFSET 0x0Cu +#define WDOGTIME_WDOGVALUE_MASK 0xFFFFFFu +#define WDOGTIME_WDOGVALUE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Watchdog MVRP register + */ +#define WDOGMSVP_REG_OFFSET 0x10u + +/* wdogmsvp bit */ +#define WDOGMSVP_OFFSET 0x10u +#define WDOGMSVP_MASK 0xFFFFFFu +#define WDOGMSVP_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Watchdog Trigger Timeout register + */ +#define WDOGTRIG_REG_OFFSET 0x14u + +/* wdogmsvp bit */ +#define WDOGTRIG_WDOGRST_OFFSET 0x14u +#define WDOGTRIG_WDOGRST_MASK 0xFFFFFFu +#define WDOGTRIG_WDOGRST_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Watchdog Force Reset register details + */ +#define WDOGFORCE_REG_OFFSET 0x18u + +/* Refresh register bits */ +#define WDOGFORCE_OFFSET 0x18u +#define WDOGFORCE_MASK 0xFFFFFFFFu +#define WDOGFORCE_SHIFT 0u + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_WATCHDOG_REGS_H_ */ diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/hal/cpu_types.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/hal/cpu_types.h new file mode 100644 index 0000000..ef8ab20 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/hal/cpu_types.h @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file cpu_types.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Type definitions which can be commonly used by the fabric-ip drivers. + * + */ +#ifndef __CPU_TYPES_H +#define __CPU_TYPES_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned int size_t; + +/*------------------------------------------------------------------------------ + * addr_t: address type. + * Used to specify the address of peripherals present in the processor's memory + * map. + */ +typedef unsigned int addr_t; + +/*------------------------------------------------------------------------------ + * psr_t: processor state register. + * Used by HAL_disable_interrupts() and HAL_restore_interrupts() to store the + * processor's state between disabling and restoring interrupts. + */ +typedef unsigned int psr_t; + +#ifdef __cplusplus +} +#endif + +#endif /* CPU_TYPES_H */ + diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/hal/hal.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/hal/hal.h new file mode 100644 index 0000000..7eec17a --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/hal/hal.h @@ -0,0 +1,235 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file hal.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware abstraction layer functions for peripheral register accesses. + * + */ +#ifndef __HAL_H +#define __HAL_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include "cpu_types.h" +#include "hw_reg_access.h" +#include "hal_assert.h" +/***************************************************************************//** + * Enable all interrupts at the processor level. + */ +void HAL_enable_interrupts( void ); + +/***************************************************************************//** + * Disable all interrupts at the processor core level. + * Return the interrupts enable state before disabling occurred so that it can + * later be restored. + */ +psr_t HAL_disable_interrupts( void ); + +/***************************************************************************//** + * Restore the interrupts enable state at the processor core level. + * This function is normally passed the value returned from a previous call to + * HAL_disable_interrupts(). + */ +void HAL_restore_interrupts( psr_t saved_psr ); + +/***************************************************************************//** + */ +#define FIELD_OFFSET(FIELD_NAME) (FIELD_NAME##_OFFSET) +#define FIELD_SHIFT(FIELD_NAME) (FIELD_NAME##_SHIFT) +#define FIELD_MASK(FIELD_NAME) (FIELD_NAME##_MASK) + +/***************************************************************************//** + * The macro HAL_set_32bit_reg() allows writing a 32 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint32_t containing the value to write. + */ +#define HAL_set_32bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_32bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_32bit_reg() is used to read the value of a 32 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint32_t value. + */ +#define HAL_get_32bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_32bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)) )) + +/***************************************************************************//** + * The macro HAL_set_32bit_reg_field() is used to write a field within a + * 32 bits wide register. The field written can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * VALUE: A variable of type uint32_t containing the field value to write. + */ +#define HAL_set_32bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_32bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_32bit_reg_field() is used to read a register field from + * within a 32 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint32_t value. + */ +#define HAL_get_32bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_32bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +/***************************************************************************//** + * The macro HAL_set_16bit_reg() allows writing a 16 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint_fast16_t containing the value to write. + */ +#define HAL_set_16bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_16bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_16bit_reg() is used to read the value of a 16 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint16_t value. + */ +#define HAL_get_16bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_16bit_reg( (BASE_ADDR) + (REG_NAME##_REG_OFFSET) )) + +/***************************************************************************//** + * The macro HAL_set_16bit_reg_field() is used to write a field within a + * 16 bits wide register. The field written can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * VALUE: A variable of type uint16_t containing the field value to write. + */ +#define HAL_set_16bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_16bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_16bit_reg_field() is used to read a register field from + * within a 8 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint16_t value. + */ +#define HAL_get_16bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_16bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +/***************************************************************************//** + * The macro HAL_set_8bit_reg() allows writing a 8 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint_fast8_t containing the value to write. + */ +#define HAL_set_8bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_8bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_8bit_reg() is used to read the value of a 8 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint8_t value. + */ +#define HAL_get_8bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_8bit_reg( (BASE_ADDR) + (REG_NAME##_REG_OFFSET) )) + +/***************************************************************************//** + */ +#define HAL_set_8bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_8bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_8bit_reg_field() is used to read a register field from + * within a 8 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint8_t value. + */ +#define HAL_get_8bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_8bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +#ifdef __cplusplus +} +#endif + +#endif /*HAL_H*/ + diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/hal/hal_assert.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/hal/hal_assert.h new file mode 100644 index 0000000..1e18b54 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/hal/hal_assert.h @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hal_assert.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief HAL assert functions + */ +#ifndef __HAL_ASSERT_HEADER +#define __HAL_ASSERT_HEADER 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Disable assertions if we do not recognize the compiler. */ +#if defined ( __GNUC__ ) +#if defined(NDEBUG) +/***************************************************************************//** + * HAL_ASSERT() is defined out when the NDEBUG symbol is used. + ******************************************************************************/ +#define HAL_ASSERT(CHECK) + +#else + +/***************************************************************************//** + * Default behavior for HAL_ASSERT() macro: + *------------------------------------------------------------------------------ + The behavior is toolchain specific and project setting specific. + ******************************************************************************/ +#define HAL_ASSERT(CHECK)\ + do { \ + if (!(CHECK)) \ + { \ + __asm__ volatile ("ebreak"); \ + }\ + } while(0); + +#endif /* NDEBUG */ +#endif /*__GNUC__*/ + +#ifdef __cplusplus +} +#endif +#endif /* __HAL_ASSERT_HEADER */ + diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/hal/hal_irq.c b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/hal/hal_irq.c new file mode 100644 index 0000000..95a0775 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/hal/hal_irq.c @@ -0,0 +1,45 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hal_irq.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Legacy interrupt control functions for the Microchip driver library + * hardware abstraction layer. + * + */ +#include "hal.h" +#include "miv_rv32_hal/miv_rv32_hal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * + */ +void HAL_enable_interrupts(void) { + MRV_enable_interrupts(); +} + +/*------------------------------------------------------------------------------ + * + */ +psr_t HAL_disable_interrupts(void) { + psr_t psr; + psr = read_csr(mstatus); + MRV_disable_interrupts(); + return(psr); +} + +/*------------------------------------------------------------------------------ + * + */ +void HAL_restore_interrupts(psr_t saved_psr) { + write_csr(mstatus, saved_psr); +} + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/hal/hw_macros.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/hal/hw_macros.h new file mode 100644 index 0000000..189609c --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/hal/hw_macros.h @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hw_macros.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware registers access macros. + * + * THE MACROS DEFINED IN THIS FILE ARE DEPRECATED. DO NOT USE FOR NEW + * DEVELOPMENT. + * + * These macros are used to access peripheral registers. They allow access to + * 8, 16 and 32 bit wide registers. All accesses to peripheral registers should + * be done through these macros in order to ease porting across different + * processors/bus architectures. + * + * Some of these macros also allow access to a specific register field. + * + */ +#ifndef __HW_REGISTER_MACROS_H +#define __HW_REGISTER_MACROS_H 1 +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * 32 bits registers access: + */ +#define HW_get_uint32_reg(BASE_ADDR, REG_OFFSET) (*((uint32_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint32_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint32_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint32_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint32_t) \ + ( \ + (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint32_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint32_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 32 bits memory access: + */ +#define HW_get_uint32(BASE_ADDR) (*((uint32_t volatile *)(BASE_ADDR))) + +#define HW_set_uint32(BASE_ADDR, VALUE) (*((uint32_t volatile *)(BASE_ADDR)) = (VALUE)) + +/*------------------------------------------------------------------------------ + * 16 bits registers access: + */ +#define HW_get_uint16_reg(BASE_ADDR, REG_OFFSET) (*((uint16_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint16_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint16_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint16_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint16_t) \ + ( \ + (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint16_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint16_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 8 bits registers access: + */ +#define HW_get_uint8_reg(BASE_ADDR, REG_OFFSET) (*((uint8_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint8_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint8_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint8_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint8_t) \ + ( \ + (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint8_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint8_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 8 bits memory access: + */ +#define HW_get_uint8(BASE_ADDR) (*((uint8_t volatile *)(BASE_ADDR))) + +#define HW_set_uint8(BASE_ADDR, VALUE) (*((uint8_t volatile *)(BASE_ADDR)) = (VALUE)) + +#ifdef __cplusplus +extern "C" { +#endif + +#endif /* __HW_REGISTER_MACROS_H */ + diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/hal/hw_reg_access.S b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/hal/hw_reg_access.S new file mode 100644 index 0000000..dd29223 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/hal/hw_reg_access.S @@ -0,0 +1,215 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hw_reg_access.S + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware registers access functions. + * The implementation of these function is platform and toolchain specific. + * The functions declared here are implemented using assembler as part of the + * processor/toolchain specific HAL. This implementation is for the combination + * of the 32 bit RISC-V processors and GNU tool chain. + * + */ + +.section .text + .globl HW_set_32bit_reg + .globl HW_get_32bit_reg + .globl HW_set_32bit_reg_field + .globl HW_get_32bit_reg_field + .globl HW_set_16bit_reg + .globl HW_get_16bit_reg + .globl HW_set_16bit_reg_field + .globl HW_get_16bit_reg_field + .globl HW_set_8bit_reg + .globl HW_get_8bit_reg + .globl HW_set_8bit_reg_field + .globl HW_get_8bit_reg_field + + +/***************************************************************************//** + * HW_set_32bit_reg is used to write the content of a 32 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint32_t value + */ +HW_set_32bit_reg: + sw a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_32bit_reg is used to read the content of a 32 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + + * @return 32 bits value read from the peripheral register. + */ +HW_get_32bit_reg: + lw a0, 0(a0) + ret + +/***************************************************************************//** + * HW_set_32bit_reg_field is used to set the content of a field in a 32 bits + * wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint32_t mask + * a3: uint32_t value + */ +HW_set_32bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lw t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sw t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_32bit_reg_field is used to read the content of a field out of a + * 32 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint32_t mask + * + * @return 32 bits value containing the register field value specified + * as parameter. + */ +HW_get_32bit_reg_field: + lw a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +/***************************************************************************//** + * HW_set_16bit_reg is used to write the content of a 16 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint_fast16_t value + */ +HW_set_16bit_reg: + sh a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_16bit_reg is used to read the content of a 16 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + + * @return 16 bits value read from the peripheral register. + */ +HW_get_16bit_reg: + lh a0, (a0) + ret + +/***************************************************************************//** + * HW_set_16bit_reg_field is used to set the content of a field in a 16 bits + * wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast16_t mask + * a3: uint_fast16_t value + * @param value Value to be written in the specified field. + */ +HW_set_16bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lh t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sh t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_16bit_reg_field is used to read the content of a field from a + * 16 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast16_t mask + * + * @return 16 bits value containing the register field value specified + * as parameter. + */ +HW_get_16bit_reg_field: + lh a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +/***************************************************************************//** + * HW_set_8bit_reg is used to write the content of a 8 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint_fast8_t value + */ +HW_set_8bit_reg: + sb a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_8bit_reg is used to read the content of a 8 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + + * @return 8 bits value read from the peripheral register. + */ +HW_get_8bit_reg: + lb a0, 0(a0) + ret + +/***************************************************************************//** + * HW_set_8bit_reg_field is used to set the content of a field in a 8 bits + * wide peripheral register. + * + * a0: addr_t reg_addr, + * a1: int_fast8_t shift + * a2: uint_fast8_t mask + * a3: uint_fast8_t value + */ +HW_set_8bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lb t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sb t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_8bit_reg_field is used to read the content of a field from a + * 8 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast8_t mask + * + * @return 8 bits value containing the register field value specified + * as parameter. + */ +HW_get_8bit_reg_field: + lb a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +.end diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/hal/hw_reg_access.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/hal/hw_reg_access.h new file mode 100644 index 0000000..1a24309 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/hal/hw_reg_access.h @@ -0,0 +1,239 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hw_reg_access.S + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware registers access functions. + * The implementation of these function is platform and tool-chain specific. + * The functions declared here are implemented using assembler as part of the + * processor/tool-chain specific HAL. This implementation is for the combination + * of the 32 bit RISC-V processors and GNU tool chain. + * + */ +#ifndef __HW_REG_ACCESS +#define __HW_REG_ACCESS +#ifdef __cplusplus +extern "C" { +#endif + +#include "cpu_types.h" +/***************************************************************************//** + * HW_set_32bit_reg is used to write the content of a 32 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_32bit_reg +( + addr_t reg_addr, + uint32_t value +); + +/***************************************************************************//** + * HW_get_32bit_reg is used to read the content of a 32 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 32 bits value read from the peripheral register. + */ +uint32_t +HW_get_32bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_32bit_reg_field is used to set the content of a field in a 32 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void +HW_set_32bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint32_t mask, + uint32_t value +); + +/***************************************************************************//** + * HW_get_32bit_reg_field is used to read the content of a field out of a + * 32 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 32 bits value containing the register field value specified + * as parameter. + */ +uint32_t +HW_get_32bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint32_t mask +); + +/***************************************************************************//** + * HW_set_16bit_reg is used to write the content of a 16 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_16bit_reg +( + addr_t reg_addr, + uint_fast16_t value +); + +/***************************************************************************//** + * HW_get_16bit_reg is used to read the content of a 16 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 16 bits value read from the peripheral register. + */ +uint16_t +HW_get_16bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_16bit_reg_field is used to set the content of a field in a 16 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void HW_set_16bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast16_t mask, + uint_fast16_t value +); + +/***************************************************************************//** + * HW_get_16bit_reg_field is used to read the content of a field from a + * 16 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 16 bits value containing the register field value specified + * as parameter. + */ +uint16_t HW_get_16bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast16_t mask +); + +/***************************************************************************//** + * HW_set_8bit_reg is used to write the content of a 8 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_8bit_reg +( + addr_t reg_addr, + uint_fast8_t value +); + +/***************************************************************************//** + * HW_get_8bit_reg is used to read the content of a 8 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 8 bits value read from the peripheral register. + */ +uint8_t +HW_get_8bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_8bit_reg_field is used to set the content of a field in a 8 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void HW_set_8bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast8_t mask, + uint_fast8_t value +); + +/***************************************************************************//** + * HW_get_8bit_reg_field is used to read the content of a field from a + * 8 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 8 bits value containing the register field value specified + * as parameter. + */ +uint8_t HW_get_8bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast8_t mask +); + +#ifdef __cplusplus +} +#endif + +#endif /* __HW_REG_ACCESS */ + diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld new file mode 100644 index 0000000..474eb43 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld @@ -0,0 +1,154 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-execute-in-place.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * image executing from a one address space whereas the data, sdata and stack + * sections are placed in another address space. This could be used in cases such + * as: + * 1) When using MIV_RV32, the reset vector points to the LSRAM at address + * 0x80000000 and the data, sdata, bss and stack sections are placed in the + * TCM region. + * + * 2) Executing from a Non Volatile memory. The actual memory will depend on + * the FPGA platform. For exameple, it could be the eNVM on SmartFusion2, + * Igloo2 or on-board non-volatile memory which supports code execution. + * + * NOTE: Modify the memory section addresses and the sizes according to your + * Libero design. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + + +MEMORY +{ + rom (rx) : ORIGIN = 0x80000000, LENGTH = 16k + ram (rwx) : ORIGIN = 0x80004000, LENGTH = 16k +} + +STACK_SIZE = 1k; /* needs to be calculated for your application */ +HEAP_SIZE = 1k; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > rom + + .text : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.text.entry))) + . = ALIGN(0x10); + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } >rom + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } >ram AT>rom + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } >ram AT>rom + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram +} + diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv-rv32-ram.ld b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv-rv32-ram.ld new file mode 100644 index 0000000..53076a0 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv-rv32-ram.ld @@ -0,0 +1,150 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-ram.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * debug image executing in SRAM. + * + * This linker script assumes that a RAM is connected at on Mi-V soft processor + * memory space pointed by the reset vector address. + * + * NOTE : Modify the memory section address and the size according to your + * Libero design. + * For example: + * 1) If you want to download and step debug at a different RAM memory address in + * your design (For example TCM base address) than the one provided in this file. + * 2) The MIV_RV32, when used with MIV_ESS IP, provides ways to copy the executable + * HEX file from external Non-Volatile memory into the TCM at reset. In this + * case your executable must be linked to the TCM address. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +MEMORY +{ + ram (rwx) : ORIGIN = 0x80000000, LENGTH = 32k +} + +STACK_SIZE = 2k; /* needs to be calculated for your application */ +HEAP_SIZE = 1k; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > ram + + .text : ALIGN(0x10) + { + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } > ram + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } > ram + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } > ram + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram +} + diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv_rv32_assert.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv_rv32_assert.h new file mode 100644 index 0000000..b3912ed --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv_rv32_assert.h @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * MIV_RV32 HAL Embedded Software + * + */ +#ifndef MIV_RV32_ASSERT_HEADER +#define MIV_RV32_ASSERT_HEADER + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + * ASSERT() implementation. + ******************************************************************************/ +/* Disable assertions if we do not recognize the compiler. */ +#if defined ( __GNUC__ ) +#if defined(NDEBUG) +#define ASSERT(CHECK) +#else +#define ASSERT(CHECK)\ + do { \ + if (!(CHECK)) \ + { \ + __asm__ volatile ("ebreak"); \ + }\ + } while(0); + +#endif /* NDEBUG check */ +#endif /* compiler check */ + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_RV32_ASSERT_HEADER */ + diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv_rv32_entry.S b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv_rv32_entry.S new file mode 100644 index 0000000..0ea3172 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv_rv32_entry.S @@ -0,0 +1,590 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_entry.S + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor vectors, trap handling and startup code. + * + */ +#ifndef ENTRY_S +#define ENTRY_S + +#define A_EXTENSION_MASK 0x00000001u +#define MTVEC_MODE_BIT_MASK 0x00000003u +#define MTVEC_VECTORED_MODE_VAL 0x00000001u + +#define MTIMEH_ADDR 0x200BFFCu + + +#if __riscv_xlen == 64 +# define LREG ld +# define SREG sd +# define REGBYTES 8 +#else +# define LREG lw +# define SREG sw +# define REGBYTES 4 +#endif + +#if defined(MIV_FP_CONTEXT_SAVE) && defined(__riscv_flen) +#define SP_SHIFT_OFFSET 64 +#else +#define SP_SHIFT_OFFSET 32 +#endif + +.macro STORE_CONTEXT + addi sp, sp, -SP_SHIFT_OFFSET*REGBYTES + SREG x1, 0 * REGBYTES(sp) + SREG x1, 0 * REGBYTES(sp) + SREG x2, 1 * REGBYTES(sp) + SREG x3, 2 * REGBYTES(sp) + SREG x4, 3 * REGBYTES(sp) + SREG x5, 4 * REGBYTES(sp) + SREG x6, 5 * REGBYTES(sp) + SREG x7, 6 * REGBYTES(sp) + SREG x8, 7 * REGBYTES(sp) + SREG x9, 8 * REGBYTES(sp) + SREG x10, 9 * REGBYTES(sp) + SREG x11, 10 * REGBYTES(sp) + SREG x12, 11 * REGBYTES(sp) + SREG x13, 12 * REGBYTES(sp) + SREG x14, 13 * REGBYTES(sp) + SREG x15, 14 * REGBYTES(sp) + SREG x16, 15 * REGBYTES(sp) + SREG x17, 16 * REGBYTES(sp) + SREG x18, 17 * REGBYTES(sp) + SREG x19, 18 * REGBYTES(sp) + SREG x20, 19 * REGBYTES(sp) + SREG x21, 20 * REGBYTES(sp) + SREG x22, 21 * REGBYTES(sp) + SREG x23, 22 * REGBYTES(sp) + SREG x24, 23 * REGBYTES(sp) + SREG x25, 24 * REGBYTES(sp) + SREG x26, 25 * REGBYTES(sp) + SREG x27, 26 * REGBYTES(sp) + SREG x28, 27 * REGBYTES(sp) + SREG x29, 28 * REGBYTES(sp) + SREG x30, 29 * REGBYTES(sp) + SREG x31, 30 * REGBYTES(sp) + + #ifdef __riscv_flen + #ifdef MIV_FP_CONTEXT_SAVE + fsw f0, 31*REGBYTES(sp) + fsw f1, 32*REGBYTES(sp) + fsw f2, 33*REGBYTES(sp) + fsw f3, 34*REGBYTES(sp) + fsw f4, 35*REGBYTES(sp) + fsw f5, 36*REGBYTES(sp) + fsw f6, 37*REGBYTES(sp) + fsw f7, 38*REGBYTES(sp) + fsw f8, 39*REGBYTES(sp) + fsw f9, 40*REGBYTES(sp) + fsw f10, 41*REGBYTES(sp) + fsw f11, 42*REGBYTES(sp) + fsw f12, 43*REGBYTES(sp) + fsw f13, 44*REGBYTES(sp) + fsw f14, 45*REGBYTES(sp) + fsw f15, 46*REGBYTES(sp) + fsw f16, 47*REGBYTES(sp) + fsw f17, 48*REGBYTES(sp) + fsw f18, 49*REGBYTES(sp) + fsw f19, 50*REGBYTES(sp) + fsw f20, 51*REGBYTES(sp) + fsw f21, 52*REGBYTES(sp) + fsw f22, 53*REGBYTES(sp) + fsw f23, 54*REGBYTES(sp) + fsw f24, 55*REGBYTES(sp) + fsw f25, 56*REGBYTES(sp) + fsw f26, 57*REGBYTES(sp) + fsw f27, 58*REGBYTES(sp) + fsw f28, 59*REGBYTES(sp) + fsw f29, 60*REGBYTES(sp) + fsw f30, 61*REGBYTES(sp) + fsw f31, 62*REGBYTES(sp) + #endif /* __riscv_flen */ + #endif /* MIV_FP_CONTEXT_SAVE */ +.endm + + .section .entry, "ax" + .globl _start + +_start: + j handle_reset + +/* Some of the Mi-V soft IP cores support compressed 'C' extension. If the Mi-V + core in your design doesn't support 'C' extension and you enable 'C' extension + in firmware project compiler options, then it would result in a trap. For this + case, we are avoiding compressed instruction here so you can put a breakpoint + at the jump and you can at least look at mcause, mepc and get some hints + about the crash. */ +trap_entry: +.option push +.option norvc +j generic_trap_handler +.option pop + .word 0 + .word 0 + +sw_trap_entry: + j vector_sw_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + +tmr_trap_entry: + j vector_tmr_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + +ext_trap_entry: + j vector_ext_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + .word 0 + +#ifndef MIV_LEGACY_RV32 +MGEUI_trap_entry: + j vector_MGEUI_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MGECI_trap_entry: + j vector_MGECI_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + .word 0 + +#ifndef MIV_RV32_V3_0 +MSYS_MIE22_trap_entry: +#ifndef MIV_RV32_V3_0 + j vector_SUBSYSR_IRQHandler +#endif /*MIV_RV32_V3_0*/ +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE23_trap_entry: + j vector_SUBSYS_IRQHandler +#ifdef __riscv_compressed + .2byte 0 +#endif +#endif /*MIV_RV32_V3_0*/ + +MSYS_MIE24_trap_entry: + j vector_MSYS_EI0_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE25_trap_entry: + j vector_MSYS_EI1_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE26_trap_entry: + j vector_MSYS_EI2_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE27_trap_entry: + j vector_MSYS_EI3_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE28_trap_entry: + j vector_MSYS_EI4_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE29_trap_entry: + j vector_MSYS_EI5_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE30_trap_entry: +#ifndef MIV_RV32_V3_0 + j vector_MSYS_EI6_trap_handler +#else + j vector_SUBSYS_IRQHandler +#endif +#ifdef __riscv_compressed + .2byte 0 +#endif + +#ifndef MIV_RV32_V3_0 +MSYS_MIE31_trap_entry: + j vector_MSYS_EI7_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif +#endif /* MIV_RV32_V3_0 */ +#endif /* MIV_LEGACY_RV32 */ + +.align 4 +generic_trap_handler: + STORE_CONTEXT + csrr a0, mcause + csrr a1, mepc + jal handle_trap + j generic_restore + +vector_sw_trap_handler: + STORE_CONTEXT + jal handle_m_soft_interrupt + j generic_restore + +vector_tmr_trap_handler: + STORE_CONTEXT + jal handle_m_timer_interrupt + j generic_restore + +vector_ext_trap_handler: + STORE_CONTEXT +#ifdef MIV_LEGACY_RV32 + jal handle_m_ext_interrupt +#else + jal External_IRQHandler +#endif /* MIV_LEGACY_RV32 */ + j generic_restore + +#ifndef MIV_LEGACY_RV32 +vector_MGEUI_trap_handler: + STORE_CONTEXT + jal MGEUI_IRQHandler + j generic_restore + +vector_MGECI_trap_handler: + STORE_CONTEXT + jal MGECI_IRQHandler + j generic_restore + +vector_MSYS_EI0_trap_handler: + STORE_CONTEXT + jal MSYS_EI0_IRQHandler + j generic_restore + +vector_MSYS_EI1_trap_handler: + STORE_CONTEXT + jal MSYS_EI1_IRQHandler + j generic_restore + +vector_MSYS_EI2_trap_handler: + STORE_CONTEXT + jal MSYS_EI2_IRQHandler + j generic_restore + +vector_MSYS_EI3_trap_handler: + STORE_CONTEXT + jal MSYS_EI3_IRQHandler + j generic_restore + +vector_MSYS_EI4_trap_handler: + STORE_CONTEXT + jal MSYS_EI4_IRQHandler + j generic_restore + +vector_MSYS_EI5_trap_handler: + STORE_CONTEXT + jal MSYS_EI5_IRQHandler + j generic_restore + +vector_SUBSYS_IRQHandler: + STORE_CONTEXT + jal SUBSYS_IRQHandler + j generic_restore + +#ifndef MIV_RV32_V3_0 +vector_MSYS_EI6_trap_handler: + STORE_CONTEXT + jal MSYS_EI6_IRQHandler + j generic_restore + +vector_MSYS_EI7_trap_handler: + STORE_CONTEXT + jal MSYS_EI7_IRQHandler + j generic_restore + + +vector_SUBSYSR_IRQHandler: + STORE_CONTEXT + jal SUBSYSR_IRQHandler + j generic_restore + +#endif /*MIV_RV32_V3_0*/ +#endif /* MIV_LEGACY_RV32 */ + +generic_restore: + LREG x1, 0 * REGBYTES(sp) + LREG x2, 1 * REGBYTES(sp) + LREG x3, 2 * REGBYTES(sp) + LREG x4, 3 * REGBYTES(sp) + LREG x5, 4 * REGBYTES(sp) + LREG x6, 5 * REGBYTES(sp) + LREG x7, 6 * REGBYTES(sp) + LREG x8, 7 * REGBYTES(sp) + LREG x9, 8 * REGBYTES(sp) + LREG x10, 9 * REGBYTES(sp) + LREG x11, 10 * REGBYTES(sp) + LREG x12, 11 * REGBYTES(sp) + LREG x13, 12 * REGBYTES(sp) + LREG x14, 13 * REGBYTES(sp) + LREG x15, 14 * REGBYTES(sp) + LREG x16, 15 * REGBYTES(sp) + LREG x17, 16 * REGBYTES(sp) + LREG x18, 17 * REGBYTES(sp) + LREG x19, 18 * REGBYTES(sp) + LREG x20, 19 * REGBYTES(sp) + LREG x21, 20 * REGBYTES(sp) + LREG x22, 21 * REGBYTES(sp) + LREG x23, 22 * REGBYTES(sp) + LREG x24, 23 * REGBYTES(sp) + LREG x25, 24 * REGBYTES(sp) + LREG x26, 25 * REGBYTES(sp) + LREG x27, 26 * REGBYTES(sp) + LREG x28, 27 * REGBYTES(sp) + LREG x29, 28 * REGBYTES(sp) + LREG x30, 29 * REGBYTES(sp) + LREG x31, 30 * REGBYTES(sp) + + #ifdef __riscv_flen + #ifdef MIV_FP_CONTEXT_SAVE + flw f0, 0 * REGBYTES(sp) + flw f1, 1 * REGBYTES(sp) + flw f2, 2 * REGBYTES(sp) + flw f3, 3 * REGBYTES(sp) + flw f4, 4 * REGBYTES(sp) + flw f5, 5 * REGBYTES(sp) + flw f6, 6 * REGBYTES(sp) + flw f7, 7 * REGBYTES(sp) + flw f8, 8 * REGBYTES(sp) + flw f9, 9 * REGBYTES(sp) + flw f10, 10 * REGBYTES(sp) + flw f11, 11 * REGBYTES(sp) + flw f12, 12 * REGBYTES(sp) + flw f13, 13 * REGBYTES(sp) + flw f14, 14 * REGBYTES(sp) + flw f15, 15 * REGBYTES(sp) + flw f16, 16 * REGBYTES(sp) + flw f17, 17 * REGBYTES(sp) + flw f18, 18 * REGBYTES(sp) + flw f19, 19 * REGBYTES(sp) + flw f20, 20 * REGBYTES(sp) + flw f21, 21 * REGBYTES(sp) + flw f22, 22 * REGBYTES(sp) + flw f23, 23 * REGBYTES(sp) + flw f24, 24 * REGBYTES(sp) + flw f25, 25 * REGBYTES(sp) + flw f26, 26 * REGBYTES(sp) + flw f27, 27 * REGBYTES(sp) + flw f28, 28 * REGBYTES(sp) + flw f29, 29 * REGBYTES(sp) + flw f30, 30 * REGBYTES(sp) + flw f31, 31 * REGBYTES(sp) + #endif /* __riscv_flen */ + #endif /* MIV_FP_CONTEXT_SAVE */ + + addi sp, sp, SP_SHIFT_OFFSET*REGBYTES + mret + + .section .text, "ax" +handle_reset: +/* Ensure instructions are not relaxed, since gp is not yet set */ +.option push +.option norelax + +#ifndef MIV_RV32_V3_0 + csrwi mstatus, 0 + csrwi mie, 0 + la ra, _start + +/* Clearnig this to be on safer side as RTL doesnt seem to clear it on reset. */ +#ifndef MIV_LEGACY_RV32 + li t0, MTIMEH_ADDR + sw x0, 0(t0) +#endif + + csrr t0, misa + andi t0, t0, A_EXTENSION_MASK + bnez t0, ima_cores_setup /* Jump to IMA core handling */ + + +/* For MIV_RV32 cores the mtvec exception base address is fixed at Reset vector + address + 0x4. Check the mode bits. */ +/* In the MIV_RV32 v3.1, the MTVEC exception base address is WARL, and can be + configured by the user at runtime */ + + csrr t0, mtvec + andi t0, t0, MTVEC_MODE_BIT_MASK + li t1, MTVEC_VECTORED_MODE_VAL + bne t0, t1, ima_cores_setup /* Jump to IMA core handling */ + + /* When mode = 1 => this is vectored mode on MIV_RV32 core. + Verify that the trap_handler address matches the configuration in MTVEC */ + csrr t0, mtvec + andi t0, t0, 0xFFFFFFFC + la t1, trap_entry + bne t0, t1, vector_address_not_matching + j generic_reset_handling + +#else /* MIV_RV32_V3_0 */ + +/* Clearnig this to be on safer side as RTL doesnt seem to clear it on reset. */ +#ifndef MIV_LEGACY_RV32 + li t0, MTIMEH_ADDR + sw x0, 0(t0) +#endif + +/* In the MIV_RV32 v3.1, the MTVEC exception base address is WARL, and can be + configured by the user at runtime */ + csrr t0, mtvec + andi t0, t0, MTVEC_MODE_BIT_MASK + li t1, MTVEC_VECTORED_MODE_VAL + bne t0, t1, ima_cores_setup /* Jump to IMA core handling */ + +/* When mode = 1 => this is vectored mode on MIV_RV32 core. + Verify that the trap_handler address matches the configuration in MTVEC */ + csrr t0, mtvec + andi t0, t0, 0xFFFFFFFC + la t1, trap_entry + bne t0, t1, vector_address_not_matching + j generic_reset_handling +#endif /*MIV_RV32_V3_0*/ + +ima_cores_setup: + la t0, trap_entry + +#ifdef MIV_LEGACY_RV32_VECTORED_INTERRUPTS + addi t0, t0, 0x01 /* Set the mode bit for IMA cores. + For both MIV_RV32 v3.1 and v3.0 cores this is done by configurator. */ +#endif + csrw mtvec, t0 + +generic_reset_handling: +/* Copy sdata section first so that the gp is set and linker relaxation can be + used */ + la a4, __sdata_load + la a5, __sdata_start + la a6, __sdata_end + beq a4, a5, 1f /* Exit if source and dest are same */ + beq a5, a6, 1f /* Exit if section start and end addresses are same */ + call block_copy + +1: + /* initialize global pointer */ + la gp, __global_pointer$ + +.option pop + +/* Floating point support configuration */ +#ifdef __riscv_flen + csrr t0, mstatus + lui t1, 0xffffa + addi t1, t1, -1 + and t0, t0, t1 + lui t1, 0x4 + or t1, t0, t1 + csrw mstatus, t1 + + lui t0, 0x0 + fscsr t0 +#endif + call initializations + /* Initialize stack pointer */ + la sp, __stack_top + + /* Jump into C code */ + j _init + +/* Error: trap_entry is not at the expected address of reset_vector+mtvec offset + as configured in the MIV_RV32 core vectored mode */ +vector_address_not_matching: + ebreak + +initializations: +/* Initialize the .bss section */ + mv t0, ra /* Store ra for future use */ + la a5, __bss_start + la a6, __bss_end + beq a5, a6, 1f /* Section start and end address are the same */ + call zeroize_block + +1: +/* Initialize the .sbss section */ + la a5, __sbss_start + la a6, __sbss_end + beq a5, a6, 1f /* Section start and end address are the same */ + call zeroize_block + +/* Clear heap */ + la a5, __heap_start + la a6, __heap_end + beq a5, a6, 1f /* Section start and end address are the same */ + call zeroize_block + +1: +/* Copy data section */ + la a4, __data_load + la a5, __data_start + la a6, __data_end + beq a4, a5, 1f /* Exit early if source and dest are same */ + beq a5, a6, 1f /* Section start and end addresses are the same */ + call block_copy + +1: + mv ra, t0 /* Retrieve ra */ + ret + +zeroize_block: + bltu a6, a5, block_copy_error /* Error. End address is less than start */ + or a7, a6, a5 /* Check if start or end is unalined */ + andi a7, a7, 0x03u + bgtz a7, block_copy_error /* Unaligned addresses error*/ +zeroize_loop: + sw x0, 0(a5) + add a5, a5, __SIZEOF_POINTER__ + blt a5, a6, zeroize_loop + ret + +block_copy: + bltu a6, a5, block_copy_error /* Error. End address is less than start */ + or a7, a6, a5 /* Check if start or end is unalined */ + andi a7, a7, 0x03u + bgtz a7, block_copy_error /* Unaligned addresses error*/ +block_copy_loop: + lw a7, 0(a4) + sw a7, 0(a5) + addi a5, a5, 0x04 + addi a4, a4, 0x04 + blt a5, a6, block_copy_loop + j block_copy_exit + +block_copy_error: + j block_copy_error + +block_copy_exit: + ret + +#endif /*ENTRY_S*/ diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv_rv32_hal.c b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv_rv32_hal.c new file mode 100644 index 0000000..a112821 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv_rv32_hal.c @@ -0,0 +1,410 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_hal.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Implementation of Hardware Abstraction Layer for Mi-V soft processors + * + */ +#include +#include "miv_rv32_hal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SUCCESS 0U +#define ERROR 1U +#define MASK_32BIT 0xFFFFFFFFu + +/*------------------------------------------------------------------------------ + * Write in a sequence recommended by privileged spec to avoid spurious + * interrupts + + # New comparand is in a1:a0. + li t0, -1 + sw t0, mtimecmp # No smaller than old value. + sw a1, mtimecmp+4 # No smaller than new value. + sw a0, mtimecmp # New value. + */ +#ifndef MIV_RV32_EXT_TIMECMP +#define WRITE_MTIMECMP(value) MTIMECMPH = MASK_32BIT; \ + MTIMECMP = value & MASK_32BIT;\ + MTIMECMPH = (value >> 32u) & MASK_32BIT; +#else +#define WRITE_MTIMECMP(value) +#endif + +#ifndef MIV_RV32_EXT_TIMER +#define WRITE_MTIME(value) MTIME = value & MASK_32BIT;\ + MTIMEH = (value >> 32u) & MASK_32BIT; +#else +#define WRITE_MTIME(value) +#endif + +extern void Software_IRQHandler(void); + +#ifdef MIV_LEGACY_RV32 +#define MTIME_PRESCALER 100UL +/*------------------------------------------------------------------------------ + * + */ +uint8_t Invalid_IRQHandler(void); +uint8_t External_1_IRQHandler(void); +uint8_t External_2_IRQHandler(void); +uint8_t External_3_IRQHandler(void); +uint8_t External_4_IRQHandler(void); +uint8_t External_5_IRQHandler(void); +uint8_t External_6_IRQHandler(void); +uint8_t External_7_IRQHandler(void); +uint8_t External_8_IRQHandler(void); +uint8_t External_9_IRQHandler(void); +uint8_t External_10_IRQHandler(void); +uint8_t External_11_IRQHandler(void); +uint8_t External_12_IRQHandler(void); +uint8_t External_13_IRQHandler(void); +uint8_t External_14_IRQHandler(void); +uint8_t External_15_IRQHandler(void); +uint8_t External_16_IRQHandler(void); +uint8_t External_17_IRQHandler(void); +uint8_t External_18_IRQHandler(void); +uint8_t External_19_IRQHandler(void); +uint8_t External_20_IRQHandler(void); +uint8_t External_21_IRQHandler(void); +uint8_t External_22_IRQHandler(void); +uint8_t External_23_IRQHandler(void); +uint8_t External_24_IRQHandler(void); +uint8_t External_25_IRQHandler(void); +uint8_t External_26_IRQHandler(void); +uint8_t External_27_IRQHandler(void); +uint8_t External_28_IRQHandler(void); +uint8_t External_29_IRQHandler(void); +uint8_t External_30_IRQHandler(void); +uint8_t External_31_IRQHandler(void); + + +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for external interrupts. + */ +uint8_t (* const mrv_ext_irq_handler_table[32])(void) = +{ + + Invalid_IRQHandler, + External_1_IRQHandler, + External_2_IRQHandler, + External_3_IRQHandler, + External_4_IRQHandler, + External_5_IRQHandler, + External_6_IRQHandler, + External_7_IRQHandler, + External_8_IRQHandler, + External_9_IRQHandler, + External_10_IRQHandler, + External_11_IRQHandler, + External_12_IRQHandler, + External_13_IRQHandler, + External_14_IRQHandler, + External_15_IRQHandler, + External_16_IRQHandler, + External_17_IRQHandler, + External_18_IRQHandler, + External_19_IRQHandler, + External_20_IRQHandler, + External_21_IRQHandler, + External_22_IRQHandler, + External_23_IRQHandler, + External_24_IRQHandler, + External_25_IRQHandler, + External_26_IRQHandler, + External_27_IRQHandler, + External_28_IRQHandler, + External_29_IRQHandler, + External_30_IRQHandler, + External_31_IRQHandler +}; + +#else +/*------------------------------------------------------------------------------ + * Interrupt handlers as mapped into the MIE register of the MIV_RV32 + */ +extern void Reserved_IRQHandler(void); +extern void External_IRQHandler(void); +extern void MGEUI_IRQHandler(void); +extern void MGECI_IRQHandler(void); +extern void MSYS_EI0_IRQHandler(void); +extern void MSYS_EI1_IRQHandler(void); +extern void MSYS_EI2_IRQHandler(void); +extern void MSYS_EI3_IRQHandler(void); +extern void MSYS_EI4_IRQHandler(void); +extern void MSYS_EI5_IRQHandler(void); +extern void SUBSYS_IRQHandler(void); + +#ifndef MIV_RV32_V3_0 /*For MIV_RV32 v3.1*/ +extern void MSYS_EI6_IRQHandler(void); +extern void MSYS_EI7_IRQHandler(void); +extern void SUBSYSR_IRQHandler(void); // @suppress("Unused function declaration") +#endif /*MIV_RV32_V3_0*/ + +#endif /* MIV_LEGACY_RV32 */ + +/*------------------------------------------------------------------------------ + * Increment value for the mtimecmp register in order to achieve a system tick + * interrupt as specified through the MRV_systick_config() function. + */ +static uint64_t g_systick_increment = 0U; +static uint64_t g_systick_cmp_value = 0U; + +/*------------------------------------------------------------------------------ + * Configure the machine timer to generate an interrupt. + */ +uint32_t MRV_systick_config(uint64_t ticks) +{ + uint32_t ret_val = ERROR; + uint64_t remainder = ticks; + g_systick_increment = 0U; + g_systick_cmp_value = 0U; + + while (remainder >= MTIME_PRESCALER) + { + remainder -= MTIME_PRESCALER; + g_systick_increment++; + } + + g_systick_cmp_value = g_systick_increment + MRV_read_mtime(); + + if (g_systick_increment > 0U) + { + WRITE_MTIMECMP(g_systick_cmp_value); + set_csr(mie, MIP_MTIP); + MRV_enable_interrupts(); + ret_val = SUCCESS; + } + + return ret_val; +} + +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for machine timer interrupts. + */ +void handle_m_timer_interrupt(void) +{ + clear_csr(mie, MIP_MTIP); + + uint64_t mtime_at_irq = MRV_read_mtime(); + +#ifndef NDEBUG + static volatile uint32_t d_tick = 0u; +#endif + + while(g_systick_cmp_value < (mtime_at_irq + MTIME_DELTA)) { + g_systick_cmp_value = g_systick_cmp_value + g_systick_increment; + +#ifndef NDEBUG + d_tick += 1; +#endif + } +/***************************************************************************//** + /* + * Note: If d_tick > 1 it means, that a system timer interrupt has been + * missed. + * Please ensure that interrupt handlers are as short as possible to prevent + * them stopping other interrupts from being handled. For example, if a + * system timer interrupt occurs during a software interrupt, the system + * timer interrupt will not be handled until the software interrupt handling + * is complete. If the software interrupt handling time is more than one + * systick interval, it will result in d_tick > 1. + * If you are running the program using the debugger and halt the CPU at a + * breakpoint, MTIME will continue to increment and interrupts will be + * missed; resulting in d_tick > 1. + */ + + WRITE_MTIMECMP(g_systick_cmp_value); + + SysTick_Handler(); + + set_csr(mie, MIP_MTIP); +} + +void handle_m_soft_interrupt(void) +{ + Software_IRQHandler(); + MRV_clear_soft_irq(); +} +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for software interrupts. + */ +#ifdef MIV_LEGACY_RV32 +void handle_m_ext_interrupt(void) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; + uint8_t disable = EXT_IRQ_KEEP_ENABLED; + + if (0u !=int_num) + { + disable = mrv_ext_irq_handler_table[int_num](); + + PLIC->TARGET[hart_id].CLAIM_COMPLETE = int_num; + + if(EXT_IRQ_DISABLE == disable) + { + MRV_PLIC_disable_irq((IRQn_Type)int_num); + } + } +} +#else + +/*------------------------------------------------------------------------------ + * MSYS local interrupts table + */ +void (* const local_irq_handler_table[16])(void) = +{ +#ifndef MIV_RV32_V3_0 + MGEUI_IRQHandler, + MGECI_IRQHandler, + SUBSYS_IRQHandler, + SUBSYSR_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + MSYS_EI0_IRQHandler, + MSYS_EI1_IRQHandler, + MSYS_EI2_IRQHandler, + MSYS_EI3_IRQHandler, + MSYS_EI4_IRQHandler, + MSYS_EI5_IRQHandler, + MSYS_EI6_IRQHandler, + MSYS_EI7_IRQHandler +#else + MGEUI_IRQHandler, + MGECI_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + MSYS_EI0_IRQHandler, + MSYS_EI1_IRQHandler, + MSYS_EI2_IRQHandler, + MSYS_EI3_IRQHandler, + MSYS_EI4_IRQHandler, + MSYS_EI5_IRQHandler, + SUBSYS_IRQHandler, + Reserved_IRQHandler, +#endif +}; + +/*------------------------------------------------------------------------------ + * Jump to interrupt table containing local interrupts + */ +void handle_local_ei_interrupts(uint8_t irq_no) +{ + uint64_t mhart_id = read_csr(mhartid); + ASSERT(irq_no <= MIV_LOCAL_IRQ_MAX) + ASSERT(irq_no >= MIV_LOCAL_IRQ_MIN) + + uint8_t ei_no = (uint8_t)(irq_no - MIV_LOCAL_IRQ_MIN); + (*local_irq_handler_table[ei_no])(); +} +#endif /* MIV_LEGACY_RV32 */ + + +/*------------------------------------------------------------------------------ + * Trap handler. This function is invoked in the non-vectored mode. + */ +void handle_trap(uintptr_t mcause, uintptr_t mepc) +{ + uint64_t is_interrupt = mcause & MCAUSE_INT; + + if (is_interrupt) + { +#ifndef MIV_LEGACY_RV32 + if (((mcause & MCAUSE_CAUSE) >= MIV_LOCAL_IRQ_MIN) && ((mcause & MCAUSE_CAUSE) <= MIV_LOCAL_IRQ_MAX)) + { + handle_local_ei_interrupts((uint8_t)(mcause & MCAUSE_CAUSE)); + } + else if ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT) +#else + if ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT) +#endif + { +#ifndef MIV_LEGACY_RV32 + External_IRQHandler(); +#else + handle_m_ext_interrupt(); +#endif + } + else if ((mcause & MCAUSE_CAUSE) == IRQ_M_SOFT) + { + handle_m_soft_interrupt(); + } + else if ((mcause & MCAUSE_CAUSE) == IRQ_M_TIMER) + { + handle_m_timer_interrupt(); + } + } + else + { +#ifndef NDEBUG + /* + Arguments supplied to this function are mcause, mepc (exception PC) and + stack pointer. + Based on privileged-isa specification mcause values and meanings are: + + 0 Instruction address misaligned (mtval/mtval is the address) + 1 Instruction access fault (mtval/mtval is the address) + 2 Illegal instruction (mtval/mtval contains the + offending instruction opcode) + 3 Breakpoint + 4 Load address misaligned (mtval/mtval is the address) + 5 Load address fault (mtval/mtval is the address) + 6 Store/AMO address fault (mtval/mtval is the address) + 7 Store/AMO access fault (mtval/mtval is the address) + 8 Environment call from U-mode + 9 Environment call from S-mode + A Environment call from M-mode + B Instruction page fault + C Load page fault (mtval/mtval is the address) + E Store page fault (mtval/mtval is the address) + + # Please note: mtval is the newer name for register mbadaddr + # If you get a compile failure here, use the older name. + # At this point, both are supported in latest compiler, older compiler + # versions only support mbadaddr. + # See: https://github.com/riscv/riscv-gcc/issues/133 + */ + + /* interrupt pending */ + uintptr_t mip = read_csr(mip); + + /* additional info and meaning depends on mcause */ + uintptr_t mtval = read_csr(mtval); + + /* trap vector */ + uintptr_t mtvec = read_csr(mtvec); + + /* temporary, sometimes might hold temporary value of a0 */ + uintptr_t mscratch = read_csr(mscratch); + + /* status contains many smaller fields: */ + uintptr_t mstatus = read_csr(mstatus); + + /* PC value when the exception was taken*/ + uintptr_t mmepc = read_csr(mepc); + + /* breakpoint */ + __asm__("ebreak"); +#else + _exit(1 + mcause); +#endif /* NDEBUG */ + } +} + +#ifdef __cplusplus +} +#endif + diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv_rv32_hal.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv_rv32_hal.h new file mode 100644 index 0000000..9ce9ef6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv_rv32_hal.h @@ -0,0 +1,773 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_hal.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware Abstraction Layer functions for Mi-V soft processors + * + */ + +/*=========================================================================*//** + @mainpage MIV_RV32 Hardware Abstraction Layer + + ============================================================================== + Introduction + ============================================================================== + This document describes the Hardware Abstraction Layer (HAL) for the MIV_RV32 + Soft IP Core. This release of the HAL corresponds to the Soft IP core MIV_RV32 + v3.1 release. It also supports earlier versions of the MIV_RV32 as well as the + legacy RV32 IP cores. + The preprocessor macros provided with the MIV_RV32 HAL are used to customize + it to target the Soft Processor IP version being used in your project. + + The term "MIV_RV32" represents following two cores: + - MIV_RV32 v3.0 and later (the latest and greatest Mi-V soft processor) + - MIV_RV32IMC v2.1 (MIV_RV32 v3.0 is a drop in replacement for this core) + It is highly recommended to migrate your design to MIV_RV32 v3.1 + + The term, Legacy RV32 IP cores, represents following IP cores: + - MIV_RV32IMA_L1_AHB + - MIV_RV32IMA_L1_AXI + - MIV_RV32IMAF_L1_AHB + + These legacy RV32 IP cores are deprecated. It is highly recommended to migrate + your designs to MIV_RV32 v3.1 (and subsequent IP releases) for the latest + enhancements, bug fixes, and support. + + -------------------------------- + MIV_RV32 V3.1 + -------------------------------- + This is the latest release of the MIV_RV32 Soft IP core. For more details, + refer to the MIV_RV32 User [Guide](https://www.microchip.com/en-us/products/fpgas-and-plds/ip-core-tools/miv-rv32) + + The MIV_RV32 Core as well as this document use the terms defined below: + + -------------------------------- + - SUBSYS - Processor Subsystem for RISC-V + - OPSRV - Offload Processor Subsystem for RISC-V + - GPR - General Purpose Registers + - MGECIE - Machine GPR ECC Correctable Interrupt Enable + - MGEUIE - Machine GPR ECC Uncorrectable Interrupt Enable + - MTIE - Machine Timer Interrupt Enable + - MEIE - Machine External Interrupt Enable + - MSIE - Machine Software Interrupt Enable + - ISR - Interrupt Service Routine + + ============================================================================== + Customizing MIV_RV32 HAL + ============================================================================== + To use the HAL with older releases of MIV_RV32, preprocessor macros have been + provided. Using these macros, any of the IP version is targeted. + The HAL is used to target any of the mentioned platforms by adding the + following macros in the way : + Project Properties > C/C++ Build > Settings > Preprocessor in Assembler and + Compiler settings. + The table below shows the macros corresponding to the MIV Core being used in + your libero project. By default, the HAL targets v3.1 of the IP core and no + macros need to be set for this configutation. + + | Libero MI-V Soft IP Version | SoftConsole Macro | + |-----------------------------|-------------------| + | MIV_RV32 v3.1 | no macro required | + | MIV_RV32 v3.0 | MIV_CORE_V3_0 | + | Legacy RV32 Cores | MIV_LEGACY_RV32 | + + -------------------------------- + Interrupt Handling + -------------------------------- + The MIE Register is defined as a enum in the HAL, and the table below is used + as a reference when the vectored interrupts are enabled in the GUI core + configurator. + + The MIE register is a RISC-V Control and Status Register (CSR), which stands + for the Machine Interrupt Enable. This is used to enable the machine mode + interrupts in the MIV_RV32 hart. Refer to the RISC-V Priv spec for more details. + + The following table shows the trap entry addresses when an interrupt occurs and + the vectored interrupts are enabled in the GUI configurator. + + | MIE Register Bit | Interrupt Enable | Vector Address | + |-------------------|------------------|----------------| + | 31 | MSYS_IE7 | mtvec.BASE + 0x7C | + | 30 | MSYS_IE6 | mtvec.BASE + 0x78 | + | 29 | MSYS_IE5 | mtvec.BASE + 0x74 | + | 28 | MSYS_IE4 | mtvec.BASE + 0x70 | + | 27 | MSYS_IE3 | mtvec.BASE + 0x6C | + | 26 | MSYS_IE2 | mtvec.BASE + 0x68 | + | 25 | MSYS_IE1 | mtvec.BASE + 0x64 | + | 24 | MSYS_IE0 | mtvec.BASE + 0x60 | + | 23 | SUBSYS_EI | mtvec.BASE + 0x5C | + | 22 | SUBSYSR | mtvec.BASE + 0x58 | + | 17 | MGECIE | mtvec.BASE + 0x44 | + | 16 | MGEUIE | mtvec.BASE + 0x40 | + | 11 | MEIE | mtvec.BASE + 0x2C | + | 7 | MTIE | mtvec.BASE + 0x1C | + | 3 | MSIE | mtvec.BASE + 0x0C | + + + For changes in MIE register map, see the [MIE Register Map for MIV_RV32 v3.0] + (#mie-register-map-for-miv_rv32-v3.0) section. + + SUBSYSR is currently not being used by the core and is Reserved for future use. + + The mtvec.BASE field corresponds to the bits [31:2], where mtvec stands for + Machine Trap Vector, and all traps set the PC to the the value stored in the + mtvec.BASE field when in Non-Vectored mode. In this case, a generic trap + handler is as an interrupt service routine. + + When Vectored interrupts are enabled, use this formula to calculate the trap + address: (mtvec.BASE + 4*cause), where cause comes from the mcause CSR. The + mcause register is written with a code indicating the event that caused the trap. + For more details, see the RISC-V priv specification. + + The MIV_RV32 Soft IP core does not contain a Platfrom Level Interrup Controller + (PLIC). It is advised to use the PLIC contained within the MIV_ESS sub-system. + Connect the PLIC interrupt output of the MIV_ESS to the EXT_IRQ pin on the + MIV_RV32. + + The following table is the MIE register map for the MIV_RV32 Core V3.0. It only + highlights the differences between the V3.0 and V3.1 of the core. + + -------------------------------- + MIE Register Map for MIV_RV32 V3.0 + -------------------------------- + + | MIE Register Bit | Target Interrupt | Vector Address | + |-------------------|------------------|----------------| + | 31 | Not in use | top table | + | 30 | SUBSYS_EI | addr + 0x78 | + | 23 | Not in use | Not in use | + | 22 | Not in use | Not in use | + + Other interrupt bit postions like the MGEUIE and MSYS_IE5 to MSYS_IE0 remain + unchanged. + + -------------------------------- + Floating Point Interrupt Support + -------------------------------- + When an interrupt is taken and Floating Point instructions are used in the + ISR, the floating point register context must be saved to resume the application + correctly. To use this feature, enable the provided macro in the + Softconsole build settings. + This feature is turned off by default as it adds overhead which is not required + when the ISR does not used FP insturctions and saving the general purpose + register context is sufficient. + + | Macro Name | Definition | + |--------------------------|-------------------------------------------------| + | MIV_FP_CONTEXT_SAVE | Define to save the FP register file | + + + -------------------------------- + SUBSYS - SubSystem for RISC-V + -------------------------------- + SUBSYS stands for SubSystem for RISC-V. This was previously (MIV_RV32 v3.0) + known as OPSRV, which stands for "Offload Processor Subsystem + for RISC-V". See the earlier versions of the handbook for more details. + In the latest release of the MIV_RV32 IP core v3.1, OPSRV has been renamed to + SUBSYS. The MIV_RV32 HAL now uses SUBSYS instead of OPSRV. + + *//*=========================================================================*/ +#ifndef RISCV_HAL_H +#define RISCV_HAL_H + +#include "miv_rv32_regs.h" +#include "miv_rv32_plic.h" +#include "miv_rv32_assert.h" +#include "miv_rv32_subsys.h" + +#ifndef LEGACY_DIR_STRUCTURE +#include "fpga_design_config/fpga_design_config.h" +#else +#include "hw_platform.h" +#endif /*LEGACY_DIR_STRUCTURE*/ + +#ifdef __cplusplus +extern "C" { +#endif +/*-------------------------------------------------------------------------*//** + SUBSYS Backwards Compatibility + ======================================= + For application code using the older macro names and API functions, these macros + act as a compatibility layer and applications which use OPSRV API features work + due to these macro definitions. However, it is adviced to update your + application code to use the SUBSYS macros and API functions. + + | Macro Name | Now Called | + |-------------------------|--------------------------| + | OPSRV_TCM_ECC_CE_IRQ | SUBSYS_TCM_ECC_CE_IRQ | + | OPSRV_TCM_ECC_UCE_IRQ | SUBSYS_TCM_ECC_UCE_IRQ | + | OPSRV_AXI_WR_RESP_IRQ | SUBSYS_AXI_WR_RESP_IRQ | + | MRV32_MSYS_OPSRV_IRQn | MRV32_SUBSYS_IRQn | + | MRV32_opsrv_enable_irq | MRV32_subsys_enable_irq | + | MRV32_opsrv_disable_irq | MRV32_subsys_disable_irq | + | MRV32_opsrv_clear_irq | MRV32_subsys_clear_irq | + | OPSRV_IRQHandler | SUBSYS_IRQHandler | + */ + +/*-------------------------------------------------------------------------*//** + MTIME Timer Interrupt Constants + ======================================= + These values contain the register addresses for the registers used by the + machine timer interrupt + + MTIME_PRESCALER is not defined on the MIV_RV32IMC v2.0 and v2.1. By using this + definition the system crashes. For those core, use the following definition: + + #define MTIME_PRESCALER 100u + + MTIME and MTIMECMP + -------------------------------- + MIV_RV32 core offers flexibility in terms of generating MTIME and MTIMECMP + registers internal to the core or using external time reference. There four + possible combinations: + + - Internal MTIME and Internal MTIME IRQ enabled Generate the MTIME and MTIMECMP + registers internally. (The only combination available on legacy RV32 cores) + + - Internal MTIME enabled and Internal MTIME IRQ disabled Generate the MTIME + internally and have a timer interrupt input to the core as external pin. In + this case, 1 pin port will be available on MIV_RV32 for timer interrupt. + + - When the internal MTIME is disabled, and the Internal MTIME IRQ is enabled, the + system generates the time value externally and generates the mtimecmp and + interrupt internally (for example, a multiprocessor system with a shared time + between all cores). In this case, a 64-bit port is available on the MIV_RV32 + core as input. + + - Internal MTIME and Internal MTIME IRQ disabled Generate both the time and + timer interrupts externally. In this case a 64 bit port will be available on + the MIV_RV32 core as input, and a 1 pin port will be available for timer + interrupt. + + To handle all these combinations in the firmware, the following constants must + be defined in accordance with the configuration that you have made on your + MIV_RV32 core design. + + MIV_RV32_EXT_TIMER + -------------------------------- + When defined, it means that the MTIME register is not available internal to + the core. In this case, a 64 bit port will be available on the MIV_RV32 core as + input. When this macro is not defined, it means that the MTIME register is + available internally to the core. + + MIV_RV32_EXT_TIMECMP + -------------------------------- + When defined, it means the MTIMECMP register is not available internally to + the core and the Timer interrupt input to the core comes as an external pin. + When this macro is not defined it means the that MTIMECMP register exists + internal to the core and that the timer interrupt is generated internally. + +NOTE: All these macros must not be defined if you are using a MIV_RV32 core. + */ + +#define OPSRV_TCM_ECC_CE_IRQ SUBSYS_TCM_ECC_CE_IRQ +#define OPSRV_TCM_ECC_UCE_IRQ SUBSYS_TCM_ECC_UCE_IRQ +#define OPSRV_AXI_WR_RESP_IRQ SUBSYS_AXI_WR_RESP_IRQ +#define MRV32_MSYS_OPSRV_IRQn MRV32_SUBSYS_IRQn +#define MRV32_opsrv_enable_irq MRV32_subsys_enable_irq +#define MRV32_opsrv_disable_irq MRV32_subsys_disable_irq +#define MRV32_opsrv_clear_irq MRV32_subsys_clear_irq +#define OPSRV_IRQHandler SUBSYS_IRQHandler + +/*-------------------------------------------------------------------------*//** + External IRQ + ======================================= + Return value from External IRQ handler. This is used to disable the + External Interrupt. + + | Macro Name | Value | Description| + |-------------------|--------|----------------| + | EXT_IRQ_KEEP_ENABLED | 0 | Keep external interrupts enabled | + | EXT_IRQ_DISABLE | 1 | Disable external interrupts | + */ +#define EXT_IRQ_KEEP_ENABLED 0U +#define EXT_IRQ_DISABLE 1U + +#define MTIME_DELTA 5 +#ifdef MIV_LEGACY_RV32 +#define MSIP (*(uint32_t*)0x44000000UL) +#define MTIMECMP (*(uint32_t*)0x44004000UL) +#define MTIMECMPH (*(uint32_t*)0x44004004UL) +#define MTIME (*(uint32_t*)0x4400BFF8UL) +#define MTIMEH (*(uint32_t*)0x4400BFFCUL) + +/* To maintain backward compatibility with FreeRTOS config code */ +#define PRCI_BASE 0x44000000UL +#else /* MIV_LEGACY_RV32 */ + +/* To maintain backward compatibility with FreeRTOS config code */ +#define PRCI_BASE 0x02000000UL + +#ifndef MIV_RV32_EXT_TIMECMP +#define MTIMECMP (*(volatile uint32_t*)0x02004000UL) +#define MTIMECMPH (*(volatile uint32_t*)0x02004004UL) +#else +#define MTIMECMP (0u) +#define MTIMECMPH (0u) +#endif + +#define MTIME_PRESCALER (*(volatile uint32_t*)0x02005000UL) + +#ifndef MIV_RV32_EXT_TIMER +#define MTIME (*(volatile uint32_t*)0x0200BFF8UL) +#define MTIMEH (*(volatile uint32_t*)0x0200BFFCUL) + +/***************************************************************************//** + MIMPID Register + The MIMPID register is a RISC-V Control and Status Register In the v3.0 of + MIV_RV32, the value of `MIMPID = 0x000540AD`. In the v3.1 of MIV_RV32, the + value if `MIMPID = 0xE5010301` corresponding to (E)mbedded (5)ystem(01) core + version (03).(01) this terminology will be followed in the subsequent releases + of the core read the csr value and store it in a varible which may be used to + check the MIV_RV32 core version during runtime. + + Future releases of the core will increment the 03 and 01 as major and minor + releases respectively and the register can be read at runtime to find the + Soft IP core version. + + | Core Version | Register | Value | Notes | + |----------------|------------|---------|---------| + | MIV_RV32 V3.1 | mimpid | 0xE5010301 | implimentation ID | + | MIV_RV32 V3.0 | mimpid | 0x000540AD | implimentation ID | + */ +#define MIMPID read_csr(mimpid) + +/*Used as a mask to read and write to mte mtvec.BASE address*/ +#define MTVEC_BASE_ADDR_MASK 0xFFFFFFFC + +#else +#define MTIME (0u) +#define MTIMEH (0u) +#endif /*MIV_RV32_EXT_TIMER*/ + +/*-------------------------------------------------------------------------*//** + RISC-V Specification Interrupts + ======================================= + These definitions are provided for easy identification of the interrupt + in the MIE/MIP registers. + Apart from the standard software, timer, and external interrupts, the names + of the additional interrupts correspond to the names as used in the MIV_RV32 + handbook. Please refer the MIV_RV32 handbook for more details. + + All the interrups, provided by the MIV_RV32 core, follow the interrupt priority + order and register description as mentioned in the RISC-V spec. + + | Macro Name | Value | Description| + |-------------------|--------|----------------| + | MRV32_SOFT_IRQn | MIE_3_IRQn | Software interrupt enable | + | MRV32_TIMER_IRQn | MIE_7_IRQn | Timer interrupt enable | + | MRV32_EXT_IRQn | MIE_11_IRQn | External interrupt enable | + + */ +#define MRV32_SOFT_IRQn MIE_3_IRQn +#define MRV32_TIMER_IRQn MIE_7_IRQn +#define MRV32_EXT_IRQn MIE_11_IRQn + +/***************************************************************************//** + Interrupt numbers: + This enum represents the interrupt enable bits in the MIE register. + */ +enum +{ + MIE_0_IRQn = (0x01u), + MIE_1_IRQn = (0x01u<<1u), + MIE_2_IRQn = (0x01u<<2u), + MIE_3_IRQn = (0x01u<<3u), /*MSIE 0xC*/ + MIE_4_IRQn = (0x01u<<4u), + MIE_5_IRQn = (0x01u<<5u), + MIE_6_IRQn = (0x01u<<6u), + MIE_7_IRQn = (0x01u<<7u), /*MTIE 0x1C*/ + MIE_8_IRQn = (0x01u<<8u), + MIE_9_IRQn = (0x01u<<9u), + MIE_10_IRQn = (0x01u<<10u), + MIE_11_IRQn = (0x01u<<11u), /*MEIE 0x2C*/ + MIE_12_IRQn = (0x01u<<12u), + MIE_13_IRQn = (0x01u<<13u), + MIE_14_IRQn = (0x01u<<14u), + MIE_15_IRQn = (0x01u<<15u), + MIE_16_IRQn = (0x01u<<16u), /*MGEUIE ECC Uncorrectable 0x40*/ + MIE_17_IRQn = (0x01u<<17u), /*MGECIE ECC Correctable 0x44*/ + MIE_18_IRQn = (0x01u<<18u), + MIE_19_IRQn = (0x01u<<19u), + MIE_20_IRQn = (0x01u<<20u), + MIE_21_IRQn = (0x01u<<21u), + MIE_22_IRQn = (0x01u<<22u), /*SUBSYSR 0x58 (R)eserved*/ + MIE_23_IRQn = (0x01u<<23u), /*SUBSYS_IE 0x5C for MIV_RV32 v3.1*/ + MIE_24_IRQn = (0x01u<<24u), /*MSYS_IE0 0x60*/ + MIE_25_IRQn = (0x01u<<25u), /*MSYS_IE1 0x64*/ + MIE_26_IRQn = (0x01u<<26u), /*MSYS_IE2 0x68*/ + MIE_27_IRQn = (0x01u<<27u), /*MSYS_IE3 0x6C*/ + MIE_28_IRQn = (0x01u<<28u), /*MSYS_IE4 0x70*/ + MIE_29_IRQn = (0x01u<<29u), /*MSYS_IE5 0x74*/ + MIE_30_IRQn = (0x01u<<30u), /*MSYS_IE6 0x78, read comment below*/ + MIE_31_IRQn = (0x01u<<31u) /*MSYS_IE7 0x7C*/ +} MRV_LOCAL_IRQn_Type; + +#define MRV32_MGEUIE_IRQn MIE_16_IRQn +#define MRV32_MGECIE_IRQn MIE_17_IRQn +#define MRV32_MSYS_EIE0_IRQn MIE_24_IRQn +#define MRV32_MSYS_EIE1_IRQn MIE_25_IRQn +#define MRV32_MSYS_EIE2_IRQn MIE_26_IRQn +#define MRV32_MSYS_EIE3_IRQn MIE_27_IRQn +#define MRV32_MSYS_EIE4_IRQn MIE_28_IRQn +#define MRV32_MSYS_EIE5_IRQn MIE_29_IRQn +#ifndef MIV_RV32_V3_0 /*For MIV_RV32 v3.1*/ +#define MRV32_SUBSYSR_IRQn MIE_22_IRQn +#define MRV32_SUBSYS_IRQn MIE_23_IRQn +#define MRV32_MSYS_EIE6_IRQn MIE_30_IRQn +#define MRV32_MSYS_EIE7_IRQn MIE_31_IRQn +#else +#define MRV32_SUBSYS_IRQn MIE_30_IRQn +#endif /*MIV_RV32_V3_0*/ + +/*--------------------------------Public APIs---------------------------------*/ + +/***************************************************************************//** + The MRV32_clear_gpr_ecc_errors() function clears single bit ECC errors on the + GPRs. The ECC block does not write back corrected data to memory. Hence, when + ECC is enabled for the GPRs and if that data has a single bit error then the + data coming out of the ECC block is corrected and will not have the error, but + the data source will still have the error. Therefore, if data has a single bit + error, then the corrected data must be written back to prevent the single bit + error from becoming a double bit error. Clear the pending interrupt bit after + this using MRV32_mgeci_clear_irq() function to complete the ECC error handling. + + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline void MRV32_clear_gpr_ecc_errors(void) +{ + uint32_t temp; + + __asm__ __volatile__ ( + "sw x31, %0" + :"=m" (temp)); + + __asm__ volatile ( + "mv x31, x1;" + "mv x1, x31;" + + "mv x31, x2;" + "mv x2, x31;" + + "mv x31, x3;" + "mv x3, x31;" + + "mv x31, x4;" + "mv x4, x31;" + + "mv x31, x5;" + "mv x5, x31;" + + "mv x31, x6;" + "mv x6, x31;" + + "mv x31, x7;" + "mv x7, x31;" + + "mv x31, x8;" + "mv x8, x31;" + + "mv x31, x9;" + "mv x9, x31;" + + "mv x31, x10;" + "mv x10, x31;" + + "mv x31, x11;" + "mv x11, x31;" + + "mv x31, x12;" + "mv x12, x31;" + + "mv x31, x13;" + "mv x13, x31;" + + "mv x31, x14;" + "mv x14, x31;" + + "mv x31, x15;" + "mv x15, x31;" + + "mv x31, x16;" + "mv x16, x31;" + + "mv x31, x17;" + "mv x17, x31;" + + "mv x31, x18;" + "mv x18, x31;" + + "mv x31, x19;" + "mv x19, x31;" + + "mv x31, x20;" + "mv x20, x31;" + + "mv x31, x21;" + "mv x21, x31;" + + "mv x31, x22;" + "mv x22, x31;" + + "mv x31, x23;" + "mv x23, x31;" + + "mv x31, x24;" + "mv x24, x31;" + + "mv x31, x25;" + "mv x25, x31;" + + "mv x31, x26;" + "mv x26, x31;" + + "mv x31, x27;" + "mv x27, x31;" + + "mv x31, x28;" + "mv x28, x31;" + + "mv x31, x29;" + "mv x29, x31;" + + "mv x31, x30;" + "mv x30, x31;"); + + __asm__ __volatile__ ( + "lw x31, %0;" + : + :"m" (temp)); +} + + +/***************************************************************************//** + The MRV32_mgeui_clear_irq() function clears the GPR ECC Uncorrectable + Interrupt. MGEUI interrupt is available only when ECC is enabled in the MIV_RV32 + IP configurator. + + @return + This function does not return any value. + */ +static inline void MRV32_mgeui_clear_irq(void) +{ + clear_csr(mip, MRV32_MGEUIE_IRQn); +} + +/***************************************************************************//** + The MRV32_mgeci_clear_irq() function clears the GPR ECC Correctable Interrupt + MGECI interrupt is available only when ECC is enabled in the MIV_RV32 IP + configurator. + + @return + This function does not return any value. + */ +static inline void MRV32_mgeci_clear_irq(void) +{ + clear_csr(mip, MRV32_MGECIE_IRQn); +} + +/***************************************************************************//** + The MRV_enable_local_irq() function enables the local interrupts. It takes a + mask value as input. For each set bit in the mask value, the corresponding + interrupt bit in the MIE register is enabled. + + MRV_enable_local_irq( MRV32_SOFT_IRQn | MRV32_TIMER_IRQn | MRV32_EXT_IRQn | + MRV32_MSYS_EIE0_IRQn | + MRV32_MSYS_SUBSYS_IRQn); + */ +static inline void MRV_enable_local_irq(uint32_t mask) +{ + set_csr(mie, mask); +} + +/***************************************************************************//** + The MRV_disable_local_irq() function disables the local interrupts. It takes a + mask value as input. For each set bit in the mask value, the corresponding + interrupt bit in the MIE register is disabled. + + MRV_disable_local_irq( MRV32_SOFT_IRQn | MRV32_TIMER_IRQn | MRV32_EXT_IRQn | + MRV32_MSYS_EIE0_IRQn | + MRV32_MSYS_SUBSYS_IRQn); + */ +static inline void MRV_disable_local_irq(uint32_t mask) +{ + clear_csr(mie, mask); +} +#endif /* MIV_LEGACY_RV32 */ + +/***************************************************************************//** + The MRV_enable_interrupts() function enables all interrupts by setting the + machine mode interrupt enable bit in MSTATUS register. + + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline void MRV_enable_interrupts(void) +{ + set_csr(mstatus, MSTATUS_MIE); +} + +/***************************************************************************//** + The MRV_disable_interrupts() function disables all interrupts by clearing the + machine mode interrupt enable bit in MSTATUS register. + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline void MRV_disable_interrupts(void) +{ + clear_csr(mstatus, MSTATUS_MPIE); + clear_csr(mstatus, MSTATUS_MIE); +} + +/***************************************************************************//** + The MRV_read_mtvec_base() function reads the mtvec base value, which is the + addr used when an interrupt/trap occurs. In the mtvec register, [31:2] is the + BASE address. NOTE: The BASE address must be aligned on a 4B boundary. + + @param + The function does not take any parameters. + + @return + The function returns the value of the BASE field [31:2] as an unsigned 32-bit + value. + */ + +#ifndef MIV_LEGACY_RV32 +#ifndef MIV_RV32_v3_0 +static inline uint32_t MRV_read_mtvec_base (void) +{ + uint32_t mtvec_addr_base = read_csr(mtvec); + return mtvec_addr_base & MTVEC_BASE_ADDR_MASK; +} + +/***************************************************************************//** + The MRV_set_mtvec_base() function takes the mtvec_base address as a unsigned int + and writes the value into the BASE field [31:2] in the mtvec CSR, MODE[1:0] + is Read-only. BASE is 4B aligned, so the lowest 2 bits of mtvec_base are + ignored. + + @param mtvec_base + Any legal value is passed into the function, and it is used as the trap_entry + for interrupts. The PC jumps to this address provided when an interrupt occurs. + In case of vectored interrupts, the address value mentioned in the vector + table under the MIE Register Map is updated to the value passed to this + function parameter. + + @return + This function does not return any value. + */ +static inline void MRV_set_mtvec_base (uint32_t mtvec_base) +{ + mtvec_base = mtvec_base & MTVEC_BASE_ADDR_MASK; + write_csr(mtvec, mtvec_base); +} +#endif /*MIV_RV32_v3_0*/ +#endif /*MIV_LEGACY_RV32*/ + +/***************************************************************************//** + The MRV_read_mtime() function returns the current MTIME register value. + */ +static inline uint64_t MRV_read_mtime(void) +{ + volatile uint32_t hi = 0u; + volatile uint32_t lo = 0u; + + /* when mtime lower word is 0xFFFFFFFF, there will be rollover and + * returned value could be wrong. */ + do { + hi = MTIMEH; + lo = MTIME; + } while(hi != MTIMEH); + + return((((uint64_t)MTIMEH) << 32u) | lo); +} + +/***************************************************************************//** + The MRV_raise_soft_irq() function raises a synchronous software interrupt + by writing into the MSIP register. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV_raise_soft_irq(void) +{ + set_csr(mie, MIP_MSIP); /* Enable software interrupt bit */ + +#ifdef MIV_LEGACY_RV32 + /* You need to make sure that the global interrupt is enabled */ + MSIP = 0x01; /* raise soft interrupt */ +#else + /* Raise soft IRQ on MIV_RV32 processor */ + SUBSYS->soft_reg |= SUBSYS_SOFT_IRQ; +#endif +} + +/***************************************************************************//** + The MRV_clear_soft_irq() function clears a synchronous software interrupt + by clearing the MSIP register. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV_clear_soft_irq(void) +{ +#ifdef MIV_LEGACY_RV32 + MSIP = 0x00u; /* clear soft interrupt */ +#else + /* Clear soft IRQ on MIV_RV32 processor */ + SUBSYS->soft_reg &= ~SUBSYS_SOFT_IRQ; +#endif +} + +/***************************************************************************//** + System tick handler. This handler function gets called when the Machine + timer interrupt asserts. An implementation of this function must be provided + by the application to implement the application specific machine timer + interrupt handling. If application does not provide such implementation, the + weakly linked handler stub function implemented in riscv_hal_stubs.c gets + linked. + */ +void SysTick_Handler(void); + +/***************************************************************************//** + System timer tick configuration. + Configures the machine timer to generate a system tick interrupt at regular + intervals. Takes the number of system clock ticks between interrupts. + + Though this function can take any valid ticks value as parameter, we expect + that, for all practical purposes, a small tick value (to generate periodic + interrupts every few miliseconds) is passed. If you need to generate periodic + events in the range of seconds or more, you may use the SysTick_Handler() to + further count the number of interrupts and hence the larger time intervals. + + @param ticks + This is the number of ticks or clock cycles which are counted down from the + interrupt to be triggered. + + @return + Returns 0 if successful. + Returns 1 if the interrupt interval is not achieved. + */ +uint32_t MRV_systick_config(uint64_t ticks); + +#ifdef __cplusplus +} +#endif +#endif /* RISCV_HAL_H */ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv_rv32_hal_version.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv_rv32_hal_version.h new file mode 100644 index 0000000..4922bf2 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv_rv32_hal_version.h @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_hal_version.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware Abstraction Layer functions for Mi-V soft processors + * + */ + +#ifndef MIV_RV32_HAL_VERSION_H +#define MIV_RV32_HAL_VERSION_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MIV_RV32_HAL_VERSION_MAJOR 4 +#define MIV_RV32_HAL_VERSION_MINOR 2 +#define MIV_RV32_HAL_VERSION_PATCH 100 + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv_rv32_init.c b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv_rv32_init.c new file mode 100644 index 0000000..85f8aca --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv_rv32_init.c @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_init.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor memory section initializations and start-up code. + * + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern void main(void); + +void _init(void) +{ + /* This function is a placeholder for the case where some more hardware + * specific initializations are required before jumping into the application + * code. You can implement it here. */ + + /* Jump to the application code after all initializations are completed */ + main(); +} + +/* Function called after main() finishes */ +void +_fini(void) +{ +} + +#ifdef __cplusplus +} +#endif + diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv_rv32_plic.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv_rv32_plic.h new file mode 100644 index 0000000..3fd4103 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv_rv32_plic.h @@ -0,0 +1,214 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_plic.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V legacy RV32 soft processor PLIC access data structures and + * functions. + * Legacy RV32 soft processors are DEPRICATED. + * Migrate to MIV_RV32 v3.0 or later. + * + */ +#ifndef RISCV_PLIC_H +#define RISCV_PLIC_H + +#include +#include "miv_rv32_regs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================== + * Interrupt numbers: + */ +#ifdef MIV_LEGACY_RV32 +typedef enum +{ + MRV_NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + External_3_IRQn = 3, + External_4_IRQn = 4, + External_5_IRQn = 5, + External_6_IRQn = 6, + External_7_IRQn = 7, + External_8_IRQn = 8, + External_9_IRQn = 9, + External_10_IRQn = 10, + External_11_IRQn = 11, + External_12_IRQn = 12, + External_13_IRQn = 13, + External_14_IRQn = 14, + External_15_IRQn = 15, + External_16_IRQn = 16, + External_17_IRQn = 17, + External_18_IRQn = 18, + External_19_IRQn = 19, + External_20_IRQn = 20, + External_21_IRQn = 21, + External_22_IRQn = 22, + External_23_IRQn = 23, + External_24_IRQn = 24, + External_25_IRQn = 25, + External_26_IRQn = 26, + External_27_IRQn = 27, + External_28_IRQn = 28, + External_29_IRQn = 29, + External_30_IRQn = 30, + External_31_IRQn = 31 +} IRQn_Type; + +#define EXT_INTR_SOURCES 31 + +/*============================================================================== + * PLIC: Platform Level Interrupt Controller + */ +#define PLIC_BASE_ADDR 0x40000000UL + +typedef struct +{ + volatile uint32_t PRIORITY_THRESHOLD; + volatile uint32_t CLAIM_COMPLETE; + volatile uint32_t reserved[1022]; +} MRV_IRQ_Target_Type; + +typedef struct +{ + volatile uint32_t ENABLES[32]; +} MRV_Target_Enables_Type; + +typedef struct +{ + /*-------------------- Source Priority --------------------*/ + volatile uint32_t SOURCE_PRIORITY[1024]; + + /*-------------------- Pending array --------------------*/ + volatile const uint32_t PENDING_ARRAY[32]; + volatile uint32_t RESERVED1[992]; + + /*-------------------- Target enables --------------------*/ + volatile MRV_Target_Enables_Type TARGET_ENABLES[15808]; + + volatile uint32_t RESERVED2[16384]; + + /*--- Target Priority threshold and claim/complete---------*/ + MRV_IRQ_Target_Type TARGET[15872]; + +} PLIC_Type; + +#define PLIC ((PLIC_Type *)PLIC_BASE_ADDR) + +/*============================================================================== + * The function MRV_PLIC_init() initializes the PLIC controller and enables + * the global external interrupt bit. + */ +static inline void MRV_PLIC_init(void) +{ + uint32_t inc; + unsigned long hart_id = read_csr(mhartid); + + /* Disable all interrupts for the current hart. */ + for(inc = 0; inc < ((EXT_INTR_SOURCES + 32u) / 32u); ++inc) + { + PLIC->TARGET_ENABLES[hart_id].ENABLES[inc] = 0; + } + + /* Set priorities to zero. */ + for(inc = 0; inc < EXT_INTR_SOURCES; ++inc) + { + PLIC->SOURCE_PRIORITY[inc] = 0; + } + + /* Set the threshold to zero. */ + PLIC->TARGET[hart_id].PRIORITY_THRESHOLD = 0; + + /* Enable machine external interrupts. */ + set_csr(mie, MIP_MEIP); +} + +/*============================================================================== + * The function MRV_PLIC_enable_irq() enables the external interrupt for the + * interrupt number indicated by the parameter IRQn. + */ +static inline void MRV_PLIC_enable_irq(IRQn_Type IRQn) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t current = PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32]; + current |= (uint32_t)1 << (IRQn % 32); + PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32] = current; +} + +/*============================================================================== + * The function MRV_PLIC_disable_irq() disables the external interrupt for + * the interrupt number indicated by the parameter IRQn. + + * NOTE: + * This function can be used to disable the external interrupt from outside + * external interrupt handler function. + * This function MUST NOT be used from within the External Interrupt handler. + * If you wish to disable the external interrupt while the interrupt handler + * for that external interrupt is executing then you must use the return value + * EXT_IRQ_DISABLE to return from the extern interrupt handler. + */ +static inline void MRV_PLIC_disable_irq(IRQn_Type IRQn) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t current = PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32]; + + current &= ~((uint32_t)1 << (IRQn % 32)); + + PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32] = current; +} + +/*============================================================================== + * The function MRV_PLIC_set_priority() sets the priority for the external + * interrupt for the interrupt number indicated by the parameter IRQn. + */ +static inline void MRV_PLIC_set_priority(IRQn_Type IRQn, uint32_t priority) +{ + PLIC->SOURCE_PRIORITY[IRQn] = priority; +} + +/*============================================================================== + * The function MRV_PLIC_get_priority() returns the priority for the external + * interrupt for the interrupt number indicated by the parameter IRQn. + */ +static inline uint32_t MRV_PLIC_get_priority(IRQn_Type IRQn) +{ + return PLIC->SOURCE_PRIORITY[IRQn]; +} + +/***************************************************************************//** + * MRV_PLIC_clear_pending_irq(void) + * This is only called by the startup hart and only once + * Clears any pending interrupts as PLIC can be in unknown state on startup + */ +static inline void MRV_PLIC_clear_pending_irq(void) +{ + unsigned long hart_id = read_csr(mhartid); + volatile uint32_t int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; + volatile int32_t wait_possible_int; + + while (MRV_NoInterrupt_IRQn != int_num) + { + PLIC->TARGET[hart_id].CLAIM_COMPLETE = int_num; + wait_possible_int = 0xFU; + while (wait_possible_int) + { + wait_possible_int--; + } + + int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; + } +} + +#endif /* MIV_LEGACY_RV32 */ + +#ifdef __cplusplus +} +#endif + +#endif /* RISCV_PLIC_H */ diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv_rv32_regs.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv_rv32_regs.h new file mode 100644 index 0000000..07d58e7 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv_rv32_regs.h @@ -0,0 +1,520 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor register bit mask and shift constants encodings. + * + */ +#ifndef MIV_RV32_REGS_H +#define MIV_RV32_REGS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MSTATUS_UIE 0x00000001UL +#define MSTATUS_SIE 0x00000002UL +#define MSTATUS_HIE 0x00000004UL +#define MSTATUS_MIE 0x00000008UL +#define MSTATUS_UPIE 0x00000010UL +#define MSTATUS_SPIE 0x00000020UL +#define MSTATUS_HPIE 0x00000040UL +#define MSTATUS_MPIE 0x00000080UL +#define MSTATUS_SPP 0x00000100UL +#define MSTATUS_HPP 0x00000600UL +#define MSTATUS_MPP 0x00001800UL +#define MSTATUS_FS 0x00006000UL +#define MSTATUS_XS 0x00018000UL +#define MSTATUS_MPRV 0x00020000UL +#define MSTATUS_SUM 0x00040000UL +#define MSTATUS_MXR 0x00080000UL +#define MSTATUS_TVM 0x00100000UL +#define MSTATUS_TW 0x00200000UL +#define MSTATUS_TSR 0x00400000UL +#define MSTATUS_RES 0x7F800000UL +#define MSTATUS32_SD 0x80000000UL +#define MSTATUS64_SD 0x8000000000000000UL + +#define MCAUSE32_CAUSE 0x7FFFFFFFUL +#define MCAUSE64_CAUSE 0x7FFFFFFFFFFFFFFFUL +#define MCAUSE32_INT 0x80000000UL +#define MCAUSE64_INT 0x8000000000000000UL + +#define MIP_SSIP (1u << IRQ_S_SOFT) +#define MIP_HSIP (1u << IRQ_H_SOFT) +#define MIP_MSIP (1u << IRQ_M_SOFT) +#define MIP_STIP (1u << IRQ_S_TIMER) +#define MIP_HTIP (1u << IRQ_H_TIMER) +#define MIP_MTIP (1u << IRQ_M_TIMER) +#define MIP_SEIP (1u << IRQ_S_EXT) +#define MIP_HEIP (1u << IRQ_H_EXT) +#define MIP_MEIP (1u << IRQ_M_EXT) + +#define PRV_M 3U + +#define VM_MBARE 0U +#define VM_MBB 1U +#define VM_MBBID 2U +#define VM_SV32 8U +#define VM_SV39 9U +#define VM_SV48 10U + +#define IRQ_S_SOFT 1U +#define IRQ_H_SOFT 2U +#define IRQ_M_SOFT 3U +#define IRQ_S_TIMER 5U +#define IRQ_H_TIMER 6U +#define IRQ_M_TIMER 7U +#define IRQ_S_EXT 9U +#define IRQ_H_EXT 10U +#define IRQ_M_EXT 11U + +#define DEFAULT_RSTVEC 0x00001000 +#define DEFAULT_NMIVEC 0x00001004 +#define DEFAULT_MTVEC 0x00001010 +#define CONFIG_STRING_ADDR 0x0000100C +#define EXT_IO_BASE 0x40000000 +#define DRAM_BASE 0x80000000 + +#ifdef __riscv + +#if __riscv_xlen == 64 +# define MSTATUS_SD MSTATUS64_SD +# define SSTATUS_SD SSTATUS64_SD +# define MCAUSE_INT MCAUSE64_INT +# define MCAUSE_CAUSE MCAUSE64_CAUSE +# define RISCV_PGLEVEL_BITS 9 +#else +# define MSTATUS_SD MSTATUS32_SD +# define SSTATUS_SD SSTATUS32_SD +# define RISCV_PGLEVEL_BITS 10 +# define MCAUSE_INT MCAUSE32_INT +# define MCAUSE_CAUSE MCAUSE32_CAUSE +#endif + +#define RISCV_PGSHIFT 12U +#define RISCV_PGSIZE (1U << RISCV_PGSHIFT) + +#ifndef __ASSEMBLER__ + +#ifdef __GNUC__ + +#define read_csr(reg) ({ unsigned long __tmp; \ + __asm__ volatile ("csrr %0, " #reg : "=r"(__tmp)); \ + __tmp; }) + +#define write_csr(reg, val) ({ \ + __asm__ volatile ("csrw " #reg ", %0" :: "rK"(val)); }) + +#define swap_csr(reg, val) ({ unsigned long __tmp; \ + __asm__ volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "rK"(val)); \ + __tmp; }) + +#define set_csr(reg, bit) ({ unsigned long __tmp; \ + __asm__ volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ + __tmp; }) + +#define clear_csr(reg, bit) ({ unsigned long __tmp; \ + __asm__ volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ + __tmp; }) + +#ifdef __riscv_atomic + +#define MASK(nr) (1UL << nr) +#define MASK_NOT(nr) (~(1UL << nr)) + +/** + * atomic_read - read atomic variable + * @v: pointer of type int + * + * Atomically reads the value of @v. + */ +static inline int atomic_read(const int *v) +{ + return *((volatile int *)(v)); +} + +/** + * atomic_set - set atomic variable + * @v: pointer of type int + * @i: required value + * + * Atomically sets the value of @v to @i. + */ +static inline void atomic_set(int *v, int i) +{ + *v = i; +} + +/** + * atomic_add - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v. + */ +static inline void atomic_add(int i, int *v) +{ + __asm__ __volatile__ ( + "amoadd.w zero, %1, %0" + : "+A" (*v) + : "r" (i)); +} + +static inline int atomic_fetch_add(unsigned int mask, int *v) +{ + int out; + + __asm__ __volatile__ ( + "amoadd.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_sub - subtract integer from atomic variable + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v. + */ +static inline void atomic_sub(int i, int *v) +{ + atomic_add(-i, v); +} + +static inline int atomic_fetch_sub(unsigned int mask, int *v) +{ + int out; + + __asm__ __volatile__ ( + "amosub.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_add_return - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v and returns the result + */ +static inline int atomic_add_return(int i, int *v) +{ + register int c; + __asm__ __volatile__ ( + "amoadd.w %0, %2, %1" + : "=r" (c), "+A" (*v) + : "r" (i)); + return (c + i); +} + +/** + * atomic_sub_return - subtract integer from atomic variable + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v and returns the result + */ +static inline int atomic_sub_return(int i, int *v) +{ + return atomic_add_return(-i, v); +} + +/** + * atomic_inc - increment atomic variable + * @v: pointer of type int + * + * Atomically increments @v by 1. + */ +static inline void atomic_inc(int *v) +{ + atomic_add(1, v); +} + +/** + * atomic_dec - decrement atomic variable + * @v: pointer of type int + * + * Atomically decrements @v by 1. + */ +static inline void atomic_dec(int *v) +{ + atomic_add(-1, v); +} + +static inline int atomic_inc_return(int *v) +{ + return atomic_add_return(1, v); +} + +static inline int atomic_dec_return(int *v) +{ + return atomic_sub_return(1, v); +} + +/** + * atomic_sub_and_test - subtract value from variable and test result + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v and returns + * true if the result is zero, or false for all + * other cases. + */ +static inline int atomic_sub_and_test(int i, int *v) +{ + return (atomic_sub_return(i, v) == 0); +} + +/** + * atomic_inc_and_test - increment and test + * @v: pointer of type int + * + * Atomically increments @v by 1 + * and returns true if the result is zero, or false for all + * other cases. + */ +static inline int atomic_inc_and_test(int *v) +{ + return (atomic_inc_return(v) == 0); +} + +/** + * atomic_dec_and_test - decrement and test + * @v: pointer of type int + * + * Atomically decrements @v by 1 and + * returns true if the result is 0, or false for all other + * cases. + */ +static inline int atomic_dec_and_test(int *v) +{ + return (atomic_dec_return(v) == 0); +} + +/** + * atomic_add_negative - add and test if negative + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v and returns true + * if the result is negative, or false when + * result is greater than or equal to zero. + */ +static inline int atomic_add_negative(int i, int *v) +{ + return (atomic_add_return(i, v) < 0); +} + +static inline int atomic_xchg(int *v, int n) +{ + register int c; + __asm__ __volatile__ ( + "amoswap.w %0, %2, %1" + : "=r" (c), "+A" (*v) + : "r" (n)); + return c; +} + +/** + * atomic_and - Atomically clear bits in atomic variable + * @mask: Mask of the bits to be retained + * @v: pointer of type int + * + * Atomically retains the bits set in @mask from @v + */ +static inline void atomic_and(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoand.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_and(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoand.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_or - Atomically set bits in atomic variable + * @mask: Mask of the bits to be set + * @v: pointer of type int + * + * Atomically sets the bits set in @mask in @v + */ +static inline void atomic_or(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoor.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_or(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoor.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_xor - Atomically flips bits in atomic variable + * @mask: Mask of the bits to be flipped + * @v: pointer of type int + * + * Atomically flips the bits set in @mask in @v + */ +static inline void atomic_xor(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoxor.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_xor(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoxor.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * test_and_set_bit - Set a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_set_bit(int nr, volatile unsigned long *addr) +{ + unsigned long __res, __mask; + __mask = MASK(nr); + __asm__ __volatile__ ( \ + "amoor.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to clear + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_clear_bit(int nr, volatile unsigned long *addr) +{ + unsigned long __res, __mask; + __mask = MASK_NOT(nr); + __asm__ __volatile__ ( \ + "amoand.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * test_and_change_bit - Change a bit and return its old value + * @nr: Bit to change + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_change_bit(int nr, volatile unsigned long *addr) +{ + + unsigned long __res, __mask; + __mask = MASK(nr); + __asm__ __volatile__ ( \ + "amoxor.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * set_bit - Atomically set a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * This function is atomic and may not be reordered. + */ + +static inline void set_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOOR.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK(nr))); +} + +/** + * clear_bit - Clears a bit in memory + * @nr: Bit to clear + * @addr: Address to start counting from + * + * clear_bit() is atomic and may not be reordered. + */ +static inline void clear_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOAND.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK_NOT(nr))); +} + +/** + * change_bit - Toggle a bit in memory + * @nr: Bit to change + * @addr: Address to start counting from + * + * change_bit() is atomic and may not be reordered. + */ +static inline void change_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOXOR.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK(nr))); +} + +#endif /* __riscv_atomic */ + +#endif /* __GNUC__ */ + +#endif /* __ASSEMBLER__ */ + +#endif /* __riscv */ + +#ifdef __cplusplus +} +#endif + +#endif /* RISCV_REGS_H */ diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv_rv32_stubs.c b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv_rv32_stubs.c new file mode 100644 index 0000000..e26ecfc --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv_rv32_stubs.c @@ -0,0 +1,243 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_stubs.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Stubs for the Mi-V soft processor Interrupt handler. + * + * The functions below will only be linked with the application code if the user + * does not provide an implementation for these functions. These functions are + * defined with weak linking so that they can be overridden by a function with + * same prototype in the user's application code. + * + */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +__attribute__((weak)) void Software_IRQHandler(void) +{ + _exit(10); +} + +__attribute__((weak)) void SysTick_Handler(void) +{ + /* Default handler */ +} + +#ifdef MIV_LEGACY_RV32 +__attribute__((weak)) uint8_t Invalid_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_1_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_2_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_3_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_4_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_5_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_6_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_7_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_8_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_9_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_10_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_11_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_12_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_13_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_14_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_15_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_16_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_17_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_18_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_19_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_20_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_21_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_22_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_23_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_24_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_25_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_26_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_27_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_28_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_29_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_30_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_31_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +#else +__attribute__((weak)) void External_IRQHandler(void) +{ +} +__attribute__((weak)) void MGECI_IRQHandler(void) +{ +} +__attribute__((weak)) void MGEUI_IRQHandler(void) +{ +} +__attribute__((weak)) void SUBSYS_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI0_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI1_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI2_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI3_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI4_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI5_IRQHandler(void) +{ +} +__attribute__((weak)) void Reserved_IRQHandler(void) +{ + _exit(10); +} +#ifndef MIV_RV32_V3_0 /* For MIV_RV32 v3.0 */ +__attribute__((weak)) void MSYS_EI6_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI7_IRQHandler(void) +{ +} +__attribute__((weak)) void SUBSYSR_IRQHandler(void) +{ +} +#endif /* MIV_RV32_V3_0 */ +#endif /* MIV_LEGACY_RV32 */ + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv_rv32_subsys.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv_rv32_subsys.h new file mode 100644 index 0000000..509f13b --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv_rv32_subsys.h @@ -0,0 +1,293 @@ +/******************************************************************************* + * Copyright 2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_subsys.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor SUBSYS regsiter description and API fuctions. + * + */ +#ifndef MIV_RV32_SUBSYS_H +#define MIV_RV32_SUBSYS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef MIV_LEGACY_RV32 +#define MGEUI 16U +#define MGECI 17U +#define MSYS_EI0 24U +#define MSYS_EI1 25U +#define MSYS_EI2 26U +#define MSYS_EI3 27U +#define MSYS_EI4 28U +#define MSYS_EI5 29U + +#define MGEUI_MEIP (1u << MGEUI) +#define MGECI_MEIP (1u << MGECI) +#define MSYS_EI0IP (1u << MSYS_EI0) +#define MSYS_EI1IP (1u << MSYS_EI1) +#define MSYS_EI2IP (1u << MSYS_EI2) +#define MSYS_EI3IP (1u << MSYS_EI3) +#define MSYS_EI4IP (1u << MSYS_EI4) +#define MSYS_EI5IP (1u << MSYS_EI5) + +#define MIV_LOCAL_IRQ_MIN 16 +#ifndef MIV_RV32_V3_0 /*For MIV_RV32 v3.1*/ +#define SUBSYSR 22U +#define SUBSYS_EI 23U +#define MSYS_EI6 30U +#define MSYS_EI7 31U +#define MIV_SUBSYSR (1u << SUBSYSR) +#define MIV_SUBSYS (1u << SUBSYS_EI) +#define MSYS_EI6IP (1u << MSYS_EI6) +#define MSYS_EI7IP (1u << MSYS_EI7) +#define MIV_LOCAL_IRQ_MAX 31 + +#else /* MIV_RV32_V3_0 */ +#define MIV_LOCAL_IRQ_MAX 29 +#define SUBSYS_EI 30U +#define MIP_SUBSYS_REG (1u << SUBSYS_EI) + +#endif /* MIV_RV32_V3_0 */ +#endif /* MIV_LEGACY_RV32 */ + +#ifdef MIV_LEGACY_RV32 +#define MIV_LOCAL_IRQ_MAX 0U +#define MIV_LOCAL_IRQ_MIN 0U +#endif /* MIV_LEGACY_RV32 */ + +#ifdef __cplusplus +} +#endif + +/*-------------------------------------------------------------------------*//** + SUBSYS Register Configuration + ======================================= + For the SUBSYS registers configutation, the following definitions are used in + the SUBSUS API functions. For example, to raise soft interrupts, enable parity + checks, soft reset, and so on. + + | Configuration | Value | Description | + |--------------------------|-------|------------------------------------------------| + | SUBSYS_SOFT_REG_GRP_DED | 0x04 | Mask for the Core GPR DED Reset Register | + | SUBSYS_CFG_PARITY_CHECK | 0x01 | Use to set or clear the parity check on the TCM | + | SUBSYS_SOFT_RESET | 0x01 | Use the SUBSYS soft reset the MIV_RV32 IP core | + | SUBSYS_SOFT_IRQ | 0x02 | Use to raise a software interrupt through SUBSYS| + */ +/*Mask for the Core GPR DED Reset Register*/ +#define SUBSYS_SOFT_REG_GRP_DED 0x04U + +/*Use to set or clear the parity check on the TCM*/ +#define SUBSYS_CFG_PARITY_CHECK 0x01U + +/*Use the SUBSYS soft reset the MIV_RV32 IP core*/ +#define SUBSYS_SOFT_RESET 0x01U + +/*Use to raise a software interrupt through SUBSYS*/ +#define SUBSYS_SOFT_IRQ 0x02U + +/*-------------------------------------------------------------------------*//** + SUBSYS Interrupt Request Masks + ======================================= + The following values correspond to the bit value of the SUBSYS interrupt + enable and interrupt pending register. + + | Interrupt Mask | Value | Description | + |----------------------------|---------|-------------------------------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | TCM ECC controllable error irq enable | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | TCM ECC uncontrollable error irq enable | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | AXI write response error irq enable | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | Icache ECC Correctable error irq | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | Icache ECC Uncorrectable error irq | + | SUBSYS_BASE_ADDR | 0x6000u | Base address of the SUBSYS | + */ +/* TCM ECC correctable error irq enable mask value */ +#define SUBSYS_TCM_ECC_CE_IRQ 0x01u + +/* TCMECC uncorrectable error irq enable */ +#define SUBSYS_TCM_ECC_UCE_IRQ 0x02u + +/* AXI write response error irq enable */ +#define SUBSYS_AXI_WR_RESP_IRQ 0x10u + +/*Icache ECC Correctable error irq*/ +#define SUBSYS_ICACHE_ECC_CE_IRQ 0x40u + +/*Icache ECC Uncorrectable error irq*/ +#define SUBSYS_ICACHE_ECC_UCE_IRQ 0x80u + +/*Base address of the SUBSYS*/ +#define SUBSYS_BASE_ADDR 0x00006000UL + +/***************************************************************************//** + Subsys contains interrupt enable, interrupt pending and Subsys registers + which can be used to enable SUBSYS specific features such as ECC for vaious + memories. For more available features refer to the MIV_RV32 User Guide +*/ +typedef struct +{ + volatile uint32_t cfg; /*Parity is not supported by MIV_RV32 v3.1 and MIV_RV32 v3.0.100*/ + volatile uint32_t reserved0[3]; + volatile uint32_t irq_en; /*offset 0x10*/ + volatile uint32_t irq_pend; + volatile uint32_t reserved1[2]; + volatile uint32_t soft_reg; /*offset 0x20*/ +} SUBSYS_Type; + +#define SUBSYS ((SUBSYS_Type *)SUBSYS_BASE_ADDR) + +/***************************************************************************//** + The MRV32_subsys_enable_irq() function initializes the SUBSYS interrupts. It + takes the logical OR of the following defined IRQ masks as a parameter. + + @param irq_mask + | irq_mask | Value | + |------------------------|------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | + Use logical OR values of one or more interrupts to enable them in the SUBSYS + @return + This function does not return any value. + */ +static inline void MRV32_subsys_enable_irq(uint32_t irq_mask) +{ + SUBSYS->irq_en |= irq_mask; +} + +/***************************************************************************//** + The MRV32_subsys_disable_irq() function disables the SUBSYS interrupts. It + takes the logical OR of the following defined IRQ masks as a parameter. + + @param irq_mask + | irq_mask | Value | + |------------------------|------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | + Use logical OR values of one or more interrupts to disable them in the SUBSYS + @return + This function does not return any value. + */ +static inline void MRV32_subsys_disable_irq(uint32_t irq_mask) +{ + SUBSYS->irq_en &= ~irq_mask; +} + +/***************************************************************************//** + The MRV32_subsys_clear_irq() function clears the SUBSYS interrupts, which was + triggered. It takes the logical OR of the following defined IRQ masks as a + parameter. + @param irq_mask + | irq_mask | Value | + |------------------------|------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | + Use logical OR values of one or more interrupts to disable them in the SUBSYS + @return + This function does not return any value. + */ +static inline void MRV32_subsys_clear_irq(uint32_t irq_mask) +{ + SUBSYS->irq_pend |= irq_mask; +} + +/***************************************************************************//** + The MRV32_subsys_irq_cause() function returns the irq_pend register value which + is present in the SUBSYS. This is be used to check which irq_mask value + caused the SUBSYS interrupt to occur. + @param + This function does not take any parameters + + @return + This function returns the irq_pend regsiter value. +*/ +static inline uint32_t MRV32_subsys_irq_cause() +{ + return SUBSYS->irq_pend; +} + +/***************************************************************************//** + The MRV32_is_gpr_ded() function returns the core_gpr_ded_reset_reg bit value. + When ECC is enabled, the core_gpr_ded_reset_reg is set when the core was + reset due to GPR DED error. + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline uint32_t MRV32_is_gpr_ded(void) +{ + return((SUBSYS->soft_reg & SUBSYS_SOFT_REG_GRP_DED) >> 0x02u); +} + +/***************************************************************************//** + The MRV32_clear_gpr_ded() function must be used to clear the + core_gpr_ded_reset_reg bit. When ECC is enabled, the core_gpr_ded_reset_reg is + set when the core was previously reset due to GPR DED error. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV32_clear_gpr_ded(void) +{ + SUBSYS->soft_reg &= ~SUBSYS_SOFT_REG_GRP_DED; +} + +/***************************************************************************//** + The MRV32_enable_parity_check() function is used to enable parity check on + the TCM and it's interface transactions. This feature is not available on + MIV_RV32 v3.1 and MIV_RV32 v3.0.100 + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV32_enable_parity_check(void) +{ + SUBSYS->cfg |= SUBSYS_CFG_PARITY_CHECK; +} + +/***************************************************************************//** + The MRV32_disable_parity_check() function is used to disable parity check on + the TCM and it's interface transactions. + @param + This function does not take any parameters + + @return + This function does not return any value. + + */ +static inline void MRV32_disable_parity_check(void) +{ + SUBSYS->cfg &= ~SUBSYS_CFG_PARITY_CHECK; +} + +/***************************************************************************//** + The MRV32_cpu_soft_reset() function is used to cause a soft cpu reset on + the MIV_RV32 soft processor core. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV32_cpu_soft_reset(void) +{ + SUBSYS->soft_reg |= SUBSYS_SOFT_RESET; +} +#endif /* MIV_RV32_SUBSYS_H */ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv_rv32_syscall.c b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv_rv32_syscall.c new file mode 100644 index 0000000..bd2f881 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/miv_rv32_syscall.c @@ -0,0 +1,364 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_syscall.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Stubs for system calls. + * + */ +#include +#include +#include +#include +#include "miv_rv32_hal.h" + +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +#include + +#ifndef LEGACY_DIR_STRUCTURE +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" +#else +#include "core_uart_apb.h" +#endif + +#endif /*MSCC_STDIO_THRU_CORE_UART_APB*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + +/*------------------------------------------------------------------------------ + * CoreUARTapb instance data for the CoreUARTapb instance used for standard + * output. + */ +static UART_instance_t g_stdio_uart; + +/*============================================================================== + * Flag used to indicate if the UART driver needs to be initialized. + */ +static int g_stdio_uart_init_done = 0; + +/* + * Disable semihosting apis + */ +#pragma import(__use_no_semihosting_swi) + +/*============================================================================== + * sendchar() + */ +int sendchar(int ch) +{ + /*-------------------------------------------------------------------------- + * Initialize the UART driver if it is the first time this function is + * called. + */ + if ( !g_stdio_uart_init_done ) + { + /****************************************************************************** + * Baud value: + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + UART_init( &g_stdio_uart, + MSCC_STDIO_UART_BASE_ADDR, + ((SYS_CLK_FREQ/(16 * MSCC_STDIO_BAUD_VALUE))-1), + (DATA_8_BITS | NO_PARITY)); + + g_stdio_uart_init_done = 1; + } + + /*-------------------------------------------------------------------------- + * Output text to the UART. + */ + UART_send( &g_stdio_uart, (uint8_t *)&ch, 1 ); + + return (ch); +} + +/*============================================================================== + * getachar() + */ +int getachar(void) +{ + uint8_t rx_size; + uint8_t rx_byte; + + if ( !g_stdio_uart_init_done ) + { + /****************************************************************************** + * Baud value: + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + UART_init( &g_stdio_uart, + MSCC_STDIO_UART_BASE_ADDR, + ((SYS_CLK_FREQ/(16 * MSCC_STDIO_BAUD_VALUE))-1), + (DATA_8_BITS | NO_PARITY)); + + g_stdio_uart_init_done = 1; + } + + do + { + rx_size = UART_get_rx(&g_stdio_uart, &rx_byte, 1); + } while(0u == rx_size); + + return rx_byte; +} + +#endif /*MSCC_STDIO_THRU_CORE_UART_APB*/ + +#undef errno +static int errno; + +static char *__env[1] = { 0 }; +char **environ = __env; + +void write_hex(int fd, uint32_t hex) +{ + char towrite; + + write( fd , "0x", 2U ); + + for (uint32_t ii = 8U ; ii > 0U; ii--) + { + uint32_t jj = ii-1U; + uint8_t digit = ((hex & (0xFU << (jj*4U))) >> (jj*4U)); + towrite = digit < 0xAU ? (0x48U + digit) : (0x65U + (digit - 0xAU)); + write( fd, &towrite, 1U); + } +} + + +#ifdef GDB_TESTING +void __attribute__((optimize("O0"))) _exit(int code) +#else +void _exit(int code) +#endif +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + const char * message = "\nProgam has exited with code:"; + + write(STDERR_FILENO, message, strlen(message)); + write_hex(STDERR_FILENO, code); +#endif + + while (1){}; +} + +void *_sbrk(ptrdiff_t incr) +{ + extern char _end; + extern char _heap_end; + extern char __heap_start; + extern char __heap_end; + static char *curbrk = &_end; + void * ret = NULL; + + /* + * Did we allocated memory for the heap in the linker script? + * You need to set HEAP_SIZE to a non-zero value in your linker script if + * the following assertion fires. + */ + ASSERT(&__heap_end > &__heap_start); + + if (((curbrk + incr) < &_end) || ((curbrk + incr) > &_heap_end)) + { + errno = ENOMEM; + ret = ((char *) - 1); + } + else + { + curbrk += incr; + ret = curbrk - incr; + } + + /* + * Did we run out of heap? + * You need to increase the heap size in the linker script if the following + * assertion fires. + * */ + ASSERT(curbrk <= &__heap_end); + + return(ret); +} + +int _isatty(int fd) +{ + int ret = 0; + + if (fd <= 2) /* one of stdin, stdout, stderr */ + { + ret = 1; + } + else + { + errno = EBADF; + ret = 0; + } + + return(ret); +} + +static int stub(int err) +{ + errno = err; + return -1; +} + +int _open(const char* name, int flags, int mode) +{ + return stub(ENOENT); +} + +int _openat(int dirfd, const char* name, int flags, int mode) +{ + return stub(ENOENT); +} + +int _close(int fd) +{ + return stub(EBADF); +} + +int _execve(const char* name, char* const argv[], char* const env[]) +{ + return stub(ENOMEM); +} + +int _fork(void) +{ + return stub(EAGAIN); +} + +int _fstat(int fd, struct stat *st) +{ + int ret = 0; + + if (isatty(fd)) + { + st->st_mode = S_IFCHR; + ret = 0; + } + else + { + ret = stub(EBADF); + } + + return ret; +} + +int _getpid(void) +{ + return 1; +} + +int _kill(int pid, int sig) +{ + return stub(EINVAL); +} + +int _link(const char *old_name, const char *new_name) +{ + return stub(EMLINK); +} + +off_t _lseek(int fd, off_t ptr, int dir) +{ + off_t ret = 0; + if (_isatty(fd)) + { + ret = 0; + } + else + { + ret = stub(EBADF); + } + + return ret; +} + +ssize_t _read(int fd, void* ptr, size_t len) +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + + char* ptr1 = (char*)ptr; + + if (_isatty(fd)) + { + int count; + + for (count = 0; count < len; count++) + { + ptr1[count] = getachar(); + sendchar(ptr1[count]); + + /* Return partial buffer if we get EOL */ + if (('\r' == ptr1[count])||('\n' == ptr1[count])) + { + ptr1[count] = '\n'; + return count; + } + } + + return count; /* Filled the buffer */ + } +#endif + + return stub(EBADF); +} + +int _stat(const char* file, struct stat* st) +{ + return stub(EACCES); +} + +clock_t _times(struct tms* buf) +{ + return stub(EACCES); +} + +int _unlink(const char* name) +{ + return stub(ENOENT); +} + +int _wait(int* status) +{ + return stub(ECHILD); +} + +ssize_t _write(int fd, const void* ptr, size_t len) +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + int count_out; + char* ptr1 = (char*)ptr; + + /*-------------------------------------------------------------------------- + * Output text to the UART. + */ + count_out = 0; + while(len--) + { + sendchar(ptr1[count_out]); + count_out++; + } + + errno = 0; + return count_out; + +#else /* MSCC_STDIO_THRU_CORE_UART_APB */ + + return stub(EBADF); + +#endif /* MSCC_STDIO_THRU_CORE_UART_APB */ + +} + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/sample_fpga_design_config.h b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/sample_fpga_design_config.h new file mode 100644 index 0000000..a380d96 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-cryptography/src/platform/miv_rv32_hal/sample_fpga_design_config.h @@ -0,0 +1,167 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file sample_fpga_design_config.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Sample design configuration settings + * + */ + /*========================================================================*//** + @mainpage + Example file detailing how the fpga_design_config.h should be constructed + for the SoftConsole project targeted for Mi-V processors. + + @section intro_sec Introduction + The SoftConsole project targeted for Mi-V processors now have an improved + folder structure. Detailed description of the folder structure is available + at https://github.com/Mi-V-Soft-RISC-V/miv-rv32-documentation. + + The fpga_design_config.h must be stored as shown below + /boards//fpga_design_config.h + + Currently this file must be hand crafted when using the Mi-V Soft Processor. + In future, all the design and soft IP configurations will be automatically + generated from the Libero design description data. + + You can use this sample file as an example. + Rename this file from sample_fpga_design_config.h to fpga_design_config.h + and then customize it per your hardware design. + + @section Project configuration Instructions + 1. Change SYS_CLK_FREQ define to frequency of Mi-V Soft processor clock + 2 Add all the soft IP core BASE addresses + 3. Add the peripheral Core Interrupts to Mi-V Soft processor IRQ number + mappings + 4. Define MSCC_STDIO_UART_BASE_ADDR if you want a CoreUARTapb mapped to + STDIO + + **NOTE** + In the legacy folder structures, the file hw_config.h as was used at the + root of the project folder. This file is now depricated. + +*//*=========================================================================*/ + +#ifndef FPGA_DESIGN_CONFIG_H_ +#define FPGA_DESIGN_CONFIG_H_ + +/***************************************************************************//** + * Soft-processor clock definition + * This is the only clock brought over from the Mi-V Libero design. + */ +#ifndef SYS_CLK_FREQ +#define SYS_CLK_FREQ 50000000UL +#endif + +/***************************************************************************//** + * Peripheral base addresses. + * Format of define is: + * __BASE_ADDR + * The field is optional if there is only one instance of the core + * in the design + * MIV_ESS is an extended peripheral subsystem IP core with peripherals + * connections as defined below. + * The system can be further extended by attaching APB peripherals to the + * empty APB slots. + */ +#define MIV_ESS_PLIC_BASE_ADDR 0x70000000UL +#define COREUARTAPB0_BASE_ADDR 0x71000000UL +#define MIV_MTIMER_BASE_ADDR 0x72000000UL +#define MIV_ESS_APBSLOT3_BASE_ADDR 0x73000000UL +#define MIV_ESS_APBSLOT4_BASE_ADDR 0x74000000UL +#define COREGPIO_OUT_BASE_ADDR 0x75000000UL +#define CORESPI_BASE_ADDR 0x76000000UL +#define MIV_ESS_uDMA_BASE_ADDR 0x78000000UL +#define MIV_ESS_WDOG_BASE_ADDR 0x79000000UL +#define MIV_ESS_I2C_BASE_ADDR 0x7A000000UL +#define MIV_ESS_APBSLOTB_BASE_ADDR 0x7B000000UL +#define MIV_ESS_APBSLOTC_BASE_ADDR 0x7C000000UL +#define MIV_ESS_APBSLOTD_BASE_ADDR 0x7D000000UL +#define MIV_ESS_APBSLOTE_BASE_ADDR 0x7E000000UL +#define MIV_ESS_APBSLOTF_BASE_ADDR 0x7F000000UL + +/***************************************************************************//** + * Peripheral Interrupts are mapped to the corresponding Mi-V Soft processor + * interrupt in the Libero design. + * + * On the legacy RV32 cores, there can be up to 31 external interrupts (IRQ[30:0] + * pins). The legacy RV32 Soft processor external interrupts are defined in the + miv_rv32_plic.h + * + * These are of the form + * typedef enum +{ + NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + . + . + . + External_31_IRQn = 31 +} IRQn_Type; + + On the legacy RV32 processors, the PLIC identifies the interrupt and passes it + on to the processor core. The interrupt 0 is not used. The pin IRQ[0] should + map to External_1_IRQn likewise IRQ[30] should map to External_31_IRQn + +e.g + +#define TIMER0_IRQn External_30_IRQn +#define TIMER1_IRQn External_31_IRQn + + The MIV_RV32 soft processor has up to six optional system interrupts, MSYS_EI[n] + in addition to one EXT_IRQ. + The MIV_RV32 does not have an inbuilt PLIC and all the interrupts are directly + delivered to the processor core, hence unlike legacy RV32 cores, no interrupt + number mapping is necessary on MIV_RV32 core. + */ + +/**************************************************************************** + * Baud value to achieve a 115200 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ +#define BAUD_VALUE_115200 ((SYS_CLK_FREQ / (16 * 115200)) - 1) + +/****************************************************************************** + * Baud value to achieve a 57600 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + #define BAUD_VALUE_57600 ((SYS_CLK_FREQ / (16 * 57600)) - 1) + +/***************************************************************************//** + * Define MSCC_STDIO_THRU_CORE_UART_APB in the project settings if you want the + * standard IOs to be redirected to a terminal via UART. + */ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +/* + * A base address mapping for the STDIO printf/scanf mapping to CortUARTapb + * must be provided if it is being used + * + * e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR + */ +#define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB0_BASE_ADDR + +#ifndef MSCC_STDIO_UART_BASE_ADDR +#error MSCC_STDIO_UART_BASE_ADDR not defined- e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR +#endif + +#ifndef MSCC_STDIO_BAUD_VALUE +/* + * The MSCC_STDIO_BAUD_VALUE define should be set in your project's settings to + * specify the baud value used by the standard output CoreUARTapb instance for + * generating the UART's baud rate if you want a different baud rate from the + * default of 115200 baud + */ +#define MSCC_STDIO_BAUD_VALUE 115200 +#endif /*MSCC_STDIO_BAUD_VALUE*/ + +#endif /* end of MSCC_STDIO_THRU_CORE_UART_APB */ +/******************************************************************************* + * End of user edit section + */ +#endif /* FPGA_DESIGN_CONFIG_H_ */ diff --git a/applications/user-crypto/miv-rv32-rsa-services/.cproject b/applications/user-crypto/miv-rv32-rsa-services/.cproject new file mode 100644 index 0000000..1be698d --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/.cproject @@ -0,0 +1,333 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-rsa-services/.gitignore b/applications/user-crypto/miv-rv32-rsa-services/.gitignore new file mode 100644 index 0000000..f1b6b72 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/.gitignore @@ -0,0 +1,3 @@ +/.settings/ +/*miv-rv32-imc-debug*/ +/*miv-rv32-imc-release*/ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-rsa-services/.project b/applications/user-crypto/miv-rv32-rsa-services/.project new file mode 100644 index 0000000..67f932c --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/.project @@ -0,0 +1,26 @@ + + + miv-rv32-rsa-services + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/applications/user-crypto/miv-rv32-rsa-services/README.md b/applications/user-crypto/miv-rv32-rsa-services/README.md new file mode 100644 index 0000000..015d2d6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/README.md @@ -0,0 +1,160 @@ +PolarFire User Crypto RSA Services example +================================================================================ +This Example Project demonstrates the usage of the User Crypto hardware block for +the signature generation and verification using RSA service functions: + + - CALRSASignHash() is used to generate digital signature. + - CALRSAVerifyHash() is used to verify the digital signature. + +There are two different build configurations provided with this project which +configure this SoftConsole project for RISC-V IMC instruction extension. +The following configurations are provided with the example: + + - miv-rv32-imc-debug + - miv-rv32-imc-release + +Mi-V Soft Processor +-------------------------------------------------------------------------------- +This example uses Mi-V SoftProcessor MiV_RV32.The design is built for debugging +MiV_RV32 through the PolarFire FPGA programming JTAG port using a FlashPro5. +To achieve this the CoreJTAGDebug IP is used to connect to the JTAG port of the +MiV_RV32. + +All the platform/design specific definitions such as peripheral base addresses, +system clock frequency etc. are included in fpga_design_config.h. The +fpga_design_config.h is located at the root folder of this project. + +The Mi-V Soft Processor MiV_RV32 firmware projects needs the miv_rv32_hal and +the hal firmware(RISC-V HAL). + +The RISC-V HAL is available at GitHub [Mi-V-Soft-RISC-V](https://mi-v-ecosystem.github.io/redirects/platform). + +How to use this example +-------------------------------------------------------------------------------- +This example project is targeted at a MIV_RV32 design running on a PolarFire-Eval-Kit +connected via a USB-UART serial cable to a host PC running a terminal emulator +such as TeraTerm or Putty configured as follows: + + - 115200 baud + - 8 data bits + - 1 stop bit + - no parity + - no flow control. + +Run the example project using a debugger. The example project will display +instructions over the serial port. To execute the particular service, user has +to select the options as shown over the serial port. + +This program displays the return data from User Crypto processor for digital +signature generation and verification services. + +fpga_design_config (formerly known as hw_config.h) +-------------------------------------------------------------------------------- +The SoftConsole project targeted for Mi-V processors now use an improved +directory structure. The fpga_design_config.h must be stored as shown below + +` + /boards//fpga_design_config/fpga_design_config.h +` + +Currently, this file must be hand crafted when using the Mi-V Soft Processor. +In future, all the design and soft IP configurations will be automatically +generated from the Libero design description data. + +You can use the sample file provided with MIV_RV32 HAL as an example. Rename it +from sample_fpga_design_config.h to fpga_design_config.h and then customize it +per your hardware design such as SYS_CLK_FREQ, peripheral BASE addresses, +interrupt numbers, definition of MSCC_STDIO_UART_BASE_ADDR if you want a +CoreUARTapb mapped to STDIO, etc. + +### Generate digital signature + +Select 1 to generate digital signature for RSA public-key cryptography service. +This example project reads the message, hash type, RSA encoding, and private +key from UART terminal and calls the **CALRSASignHash()** function, The +**CALRSASignHash()** function performs signature generation for RSA public-key +cryptography on the hash produced using the RSA encoding type. After +successful completion, displays a success message along with the generated +signature or displays a failure message. + +### Verify digital signature: + +Select 2 to verify digital signature for RSA public-key cryptography service. +This example project reads the message, hash type, RSA encoding, public key, +and signature value from UART terminal and calls the **CALRSAVerifyHash()** +function. The CALRSAVerifyHash() function performs signature verification for +RSA public-key cryptography on the hash produced from message using the RSA +encoding type. After a successful completion, displays a success message +along with the generated signature or displays a failure message. + +### Configurations + +The CAL library needs a config_user.h containing the configuration data. +This application provides following settings as per CAL requirement + 1. A variable which provides the base address of the User Crypto hardware block + is defined in main.c + + `uint32_t g_user_crypto_base_addr = 0x62000000UL;` + + 2. A symbol INC_STDINT_H is defined in project preprocessor setting. + For more detail, please refer to caltypes.h file present in CAL folder. + +**NOTE**: + 1. If you try to enter data values other than 0 - 9, a - f, A - F, an error + message will be displayed on the serial terminal. + 2. You must enter all input data as whole bytes. If you enter the 128-bit key + {1230...0} as 0x12 0x3 and press return, this will be treated as + byte0 = 0x12, byte1 = 0x30, byte2-127 = 0x00. + +### Test script + +A test script is provided with this example which automatically enters the NIST +vectors and associated data to verify the functionality. You can use +RV32_RSA_services.ttl Tera Term Macro script present in project directory for +testing RSA Signature Services example project. + +**NOTE:** +1. Tera Term Macros don’t work with Windows 10 build 14393.0. You should update + to Windows 10 build 14393.0.105 or [later.](https://osdn.net/ticket/browse.php?group_id=1412&tid=36526) +2. Before running Tera Term Macro script, set language as English + (Setup->General->Language). Also setup transmit delay in (Setup->Serial port) + to 5msec/char and 5msec/line. +3. By default, Tera Term log will be stored in Tera Term installation Directory. + +## Target hardware + +This project was tested on PolarFire-Eval-Kit with CFG4 configuration of the +MIV_RV32 design available [here](https://github.com/Mi-V-Soft-RISC-V/PolarFire-Eval-Kit/tree/main/Libero_Projects) + +All the design specific definitions such as peripheral base addresses, system +clock frequency etc. are included in fpga_design_config.h. + +The firmware projects needs the HAL and the MIV_RV32 HAL firmware components. + +This example project can be used with another design using a different hardware +configurations. This can be achieved by overwriting the content of this example +project's "fpga_design_config.h" file with the correct data per your Libero design. + +### Booting the system + +Currently the example project is configured to use FlashPro debugger to execute +from LSRAM in both Debug and Release mode. + +In the release mode build configuration, following setting is used +`--change-section-lma *-0x80000000` under +Tool Settings > Cross RISCV GNU Create Flash Image > General > Other flags. + +This will allow you to attach the release mode executable as the memory +initialization client in Libero when you want to execute it from non-volatile memory. + +## Silicon revision dependencies + +This example is tested on PolarFire MPF300TS device. + +### CAL library src + +To obtain the CAL source code and a SoftConsole project to generate the CAL +library archive file (*.a) refer [SoftConsole Documentation](https://mi-v-ecosystem.github.io/SoftConsole-Documentation/SoftConsole-v2021.3/using_softconsole/other.html#crypto-application-library). +The CAL source code is bound by license agreement and it will be available as +part of the SoftConsole installation if the CAL specific license was agreed +while installing it. \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-rsa-services/miv-rv32-rsa-services hw Debug.launch b/applications/user-crypto/miv-rv32-rsa-services/miv-rv32-rsa-services hw Debug.launch new file mode 100644 index 0000000..fe7a5ff --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/miv-rv32-rsa-services hw Debug.launch @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/user-crypto/miv-rv32-rsa-services/miv-rv32-rsa-services hw attach.launch b/applications/user-crypto/miv-rv32-rsa-services/miv-rv32-rsa-services hw attach.launch new file mode 100644 index 0000000..16aa35f --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/miv-rv32-rsa-services hw attach.launch @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/user-crypto/miv-rv32-rsa-services/rsa_services.ttl b/applications/user-crypto/miv-rv32-rsa-services/rsa_services.ttl new file mode 100644 index 0000000..2e1d26a --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/rsa_services.ttl @@ -0,0 +1,155 @@ +; Tera Term Setting: +; 1. Before running Tera Term Macro script, you should set language as English +; and transmit delay in Serial port setup to 5msec/char and 5msec/line. +; 2. By default, Tera Term log will be stored in Tera Term installation Directory. + +changedir '.' +logopen "RSAservice.log" 0 0 0 1 + +settitle 'PolarFire SoC MSS User Crypto RSA service' + +setsync 1 + +;Clear screen +clearscreen 0 + +; Set baud rate to 115200 +setbaud 115200 + +; local echo off +setecho 0 + +;Press any key +send 13 +pause 2 + +; ------------------------------------------------------------------------------ +;RSA Sig Gen +; INPUT +; Msg = +; c43011f3ee88c9c9adcac8bf37221afa31769d347dec705e53aca98993e74606591867ccd2 +; 89ba1b4f19365f983e0c578346da76c5e2228a07e4fc9b3d4807163371a52b68b66873201d +; c7d6b56616ac2e4cb522120787df7f15a5e8763a54c179c635d65816bc19485de3eb35a520 +; 40591094fe0e6485a7e0c60e38e7c61551 + +; d = +; 0997634c477c1a039d44c810b2aaa3c7862b0b88d3708272e1e15f66fc9389709f8a11f3ea +; 6a5af7effa2d01c189c50f0d5bcbe3fa272e56cfc4a4e1d388a9dcd65df8628902556c8b6b +; b6a641709b5a35dd2622c73d4640bfa1359d0e76e1f219f8e33eb9bd0b59ec198eb2fccaae +; 0346bd8b401e12e3c67cb629569c185a2e0f35a2f741644c1cca5ebb139d77a89a2953fc5e +; 30048c0e619f07c8d21d1e56b8af07193d0fdf3f49cd49f2ef3138b5138862f1470bd2d16e +; 34a2b9e7777a6c8c8d4cb94b4e8b5d616cd5393753e7b0f31cc7da559ba8e98d888914e334 +; 773baf498ad88d9631eb5fe32e53a4145bf0ba548bf2b0a50c63f67b14e398a34b0d + +; n = +; cea80475324c1dc8347827818da58bac069d3419c614a6ea1ac6a3b510dcd72cc516954905 +; e9fef908d45e13006adf27d467a7d83c111d1a5df15ef293771aefb920032a5bb989f8e4f5 +; e1b05093d3f130f984c07a772a3683f4dc6fb28a96815b32123ccdd13954f19d5b8b24a103 +; e771a34c328755c65ed64e1924ffd04d30b2142cc262f6e0048fef6dbc652f21479ea1c4b1 +; d66d28f4d46ef7185e390cbfa2e02380582f3188bb94ebbf05d31487a09aff01fcbb4cd4bf +; d1f0a833b38c11813c84360bb53c7d4481031c40bad8713bb6b835cb08098ed15ba31ee4ba +; 728a8c8e10f7294e1b4163b7aee57277bfd881a6f9d43e02c6925aa3a043fb7fb78d + +; OUTPUT +; Generated Signature value = +; aa3a4e12eb87596c711c9a22bcabcb9dadffcabcecbd16228889e9bb457d5d22571a72f034 +; be4783384f43ce6fffc60534b8331cdd5d7c77f49180bfd194b5fd43a508c66d786c558876 +; 735894e6a9300952de792f747045e74d87fd50980230707a34a4df013ce050bbff0d6f5708 +; 85c9c7bf8dc499132caee071b41d81ff91b8ce21aa2f282cbf52389f239afe1490890be21f +; 9d808b3d70b97efd59c0b60e466088bb42714f212bc90db7e942ebcee60e7b107fff44fb35 +; 64ff07d6d02850215fd357d897c4d32bef8661689f2d84ff897637fb6d5568a7270e783426 +; b74b7037493e5155fd7cb3ddddfd36bd8a9c877d71d2a966057c08263d2939c84987 +; ------------------------------------------------------------------------------ +; RSA Signature Generation +; ------------------------------------------------------------------------------ + +; select signature generation +send '1' +pause 1 + +; select RSASSA-PKCS1-v1.5 +send '2' +pause 1 + +; select SHA-256 Algorithm +send '3' +pause 1 + +; Msg +send 'c43011f3ee88c9c9adcac8bf37221afa31769d347dec705e53aca98993e74606591867ccd2' +send '89ba1b4f19365f983e0c578346da76c5e2228a07e4fc9b3d4807163371a52b68b66873201d' +send 'c7d6b56616ac2e4cb522120787df7f15a5e8763a54c179c635d65816bc19485de3eb35a520' +send '40591094fe0e6485a7e0c60e38e7c61551' +pause 1 + +; d +send '0997634c477c1a039d44c810b2aaa3c7862b0b88d3708272e1e15f66fc9389709f8a11f3ea' +send '6a5af7effa2d01c189c50f0d5bcbe3fa272e56cfc4a4e1d388a9dcd65df8628902556c8b6b' +send 'b6a641709b5a35dd2622c73d4640bfa1359d0e76e1f219f8e33eb9bd0b59ec198eb2fccaae' +send '0346bd8b401e12e3c67cb629569c185a2e0f35a2f741644c1cca5ebb139d77a89a2953fc5e' +send '30048c0e619f07c8d21d1e56b8af07193d0fdf3f49cd49f2ef3138b5138862f1470bd2d16e' +send '34a2b9e7777a6c8c8d4cb94b4e8b5d616cd5393753e7b0f31cc7da559ba8e98d888914e334' +send '773baf498ad88d9631eb5fe32e53a4145bf0ba548bf2b0a50c63f67b14e398a34b0d' +pause 1 + +; n +send 'cea80475324c1dc8347827818da58bac069d3419c614a6ea1ac6a3b510dcd72cc516954905' +send 'e9fef908d45e13006adf27d467a7d83c111d1a5df15ef293771aefb920032a5bb989f8e4f5' +send 'e1b05093d3f130f984c07a772a3683f4dc6fb28a96815b32123ccdd13954f19d5b8b24a103' +send 'e771a34c328755c65ed64e1924ffd04d30b2142cc262f6e0048fef6dbc652f21479ea1c4b1' +send 'd66d28f4d46ef7185e390cbfa2e02380582f3188bb94ebbf05d31487a09aff01fcbb4cd4bf' +send 'd1f0a833b38c11813c84360bb53c7d4481031c40bad8713bb6b835cb08098ed15ba31ee4ba' +send '728a8c8e10f7294e1b4163b7aee57277bfd881a6f9d43e02c6925aa3a043fb7fb78d' +pause 10 + +timeout = 30 +wait +;; Send Dummy +send '3' +pause 1 +pause 10 + +;------------------------------------------------------------------------------- +; signature verification +;------------------------------------------------------------------------------- + +; select signature verification +send '2' +pause 1 + +; select RSASSA-PKCS1-v1.5 +send '2' +pause 1 + +; select SHA-256 Algorithm +send '3' +pause 1 + +; Msg +send 'c43011f3ee88c9c9adcac8bf37221afa31769d347dec705e53aca98993e74606591867ccd2' +send '89ba1b4f19365f983e0c578346da76c5e2228a07e4fc9b3d4807163371a52b68b66873201d' +send 'c7d6b56616ac2e4cb522120787df7f15a5e8763a54c179c635d65816bc19485de3eb35a520' +send '40591094fe0e6485a7e0c60e38e7c61551' +pause 1 + +; Public exponent value +send '00000000000000000000000000000000000000000000000000000000000000000000000000' +send '00000000000000000000000000000000000000000000000000000000000000000000000000' +send '00000000000000000000000000000000000000000000000000000000000000000000000000' +send '00000000000000000000000000000000000000000000000000000000000000000000000000' +send '00000000000000000000000000000000000000000000000000000000000000000000000000' +send '00000000000000000000000000000000000000000000000000000000000000000000000000' +send '00000000000000000000000000000000000000000000000000000000000000260445' +pause 1 + +; modulus n +send 'cea80475324c1dc8347827818da58bac069d3419c614a6ea1ac6a3b510dcd72cc516954905' +send 'e9fef908d45e13006adf27d467a7d83c111d1a5df15ef293771aefb920032a5bb989f8e4f5' +send 'e1b05093d3f130f984c07a772a3683f4dc6fb28a96815b32123ccdd13954f19d5b8b24a103' +send 'e771a34c328755c65ed64e1924ffd04d30b2142cc262f6e0048fef6dbc652f21479ea1c4b1' +send 'd66d28f4d46ef7185e390cbfa2e02380582f3188bb94ebbf05d31487a09aff01fcbb4cd4bf' +send 'd1f0a833b38c11813c84360bb53c7d4481031c40bad8713bb6b835cb08098ed15ba31ee4ba' +send '728a8c8e10f7294e1b4163b7aee57277bfd881a6f9d43e02c6925aa3a043fb7fb78d' +pause 4 + +logclose \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/application/helper.c b/applications/user-crypto/miv-rv32-rsa-services/src/application/helper.c new file mode 100644 index 0000000..3be82f2 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/application/helper.c @@ -0,0 +1,303 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file helper.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Helper function for PolarFire User Crypto- Cryptography service example. + * + */ +#include +#include +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" +#include "helper.h" + +static const uint8_t g_separator[] = +"\r\n\ +------------------------------------------------------------------------------"; +static const uint8_t hex_chars[16] = { '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + +/*============================================================================== + Function to clear local variable and array. + */ +static void clear_variable(uint8_t *p_var, uint16_t size) +{ + uint16_t inc; + + for(inc = 0; inc < size; inc++) + { + *p_var = 0x00; + p_var++; + } +} + +/*============================================================================== + Function to get the input data from user. + */ +uint16_t get_input_data +( + uint8_t* location, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +) +{ + uint16_t count = 0u; + + /* Clear the memory location. */ + clear_variable(location, size); + + /* Read data from UART terminal. */ + count = get_data_from_uart(location, size, msg, msg_size); + + return count; +} + +/*============================================================================== + Function to get the key from user. + */ +void get_key +( + uint8_t key_type, + uint8_t* location, + uint8_t size, + const uint8_t* msg, + uint8_t msg_size +) +{ + uint8_t status = 0u; + const uint8_t invalid_ms[] = "\r\n Invalid key type. "; + + if(status == VALID) + { + /* Read the 16 bytes of input data from UART terminal. */ + get_input_data(location, size, msg, msg_size); + } + else + { + UART_send(&g_uart, invalid_ms, sizeof( invalid_ms)); + } +} + +/*============================================================================== + Convert ASCII value to hex value. + */ +uint8_t convert_ascii_to_hex(uint8_t* dest, const uint8_t* src) +{ + uint8_t error_flag = 0u; + + if((*src >= '0') && (*src <= '9')) + { + *dest = (*src - '0'); + } + else if((*src >= 'a') && (*src <= 'f')) + { + *dest = (*src - 'a') + 10u; + } + else if((*src >= 'A') && (*src <= 'F')) + { + *dest = (*src - 'A') + 10u; + } + else if(*src != 0x00u) + { + UART_send(&g_uart, (const uint8_t *)"\r\n Invalid data.", sizeof("\r\n Invalid data.")); + error_flag = 1u; + } + return error_flag; +} + +/*============================================================================== + Validate the input hex value . + */ +uint8_t validate_input(uint8_t ascii_input) +{ + uint8_t valid_key = 0u; + + if(((ascii_input >= 'A') && (ascii_input <= 'F')) || \ + ((ascii_input >= 'a') && (ascii_input <= 'f')) || \ + ((ascii_input >= '0') && (ascii_input <= '9'))) + { + valid_key = 1u; + } + else + { + valid_key = 0u; + } + return valid_key; +} + +/*============================================================================== + Display content of buffer passed as parameter as hex values. + */ +void display_output +( + uint8_t* in_buffer, + uint32_t byte_length, + uint8_t reverse_buffer +) +{ + + uint32_t inc; + + + uint8_t byte = 0; + + UART_send(&g_uart, (const uint8_t*)" ", sizeof(" ")); + + + if(reverse_buffer == 0) + { + for(inc = 0; inc < byte_length; ++inc) + { + + + if((inc > 1u) &&(0u == (inc % 16u))) + { + UART_send(&g_uart, (const uint8_t*)"\r\n ", sizeof("\r\n ")); + } + + byte = in_buffer[inc]; + UART_send(&g_uart, &hex_chars[((byte & 0xF0) >> 4) ], 1); + UART_send(&g_uart, &hex_chars[(byte & 0x0F)], 1); + } + } + /* if reverse_byte is true */ + else + { + for(inc = byte_length ; inc > 0; inc -= 1) + { + if((inc < byte_length) &&(0u == (inc % 16u))) + { + UART_send(&g_uart, (const uint8_t*)"\r\n ", sizeof("\r\n ")); + } + + byte = in_buffer[inc - 1]; + UART_send(&g_uart, &hex_chars[((byte & 0xF0) >> 4) ], 1); + UART_send(&g_uart, &hex_chars[(byte & 0x0F)], 1); + } + } +} + +/*============================================================================== + Function to read data from UART terminal and stored it. + */ +uint16_t get_data_from_uart +( + uint8_t* src_ptr, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +) +{ + uint8_t complete = 0u; + uint8_t rx_buff[1]; + uint8_t rx_size = 0u; + uint16_t count = 0u; + uint16_t ret_size = 0u; + uint8_t first = 0u; + uint16_t src_ind = 0u; + uint8_t prev = 0; + uint8_t curr = 0; + uint8_t temp = 0; + uint8_t next_byte = 0; + uint16_t read_data_size = 0; + + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, msg, msg_size); + + if(size != 1) + { + read_data_size = size * 2; + } + else + { + read_data_size = size; + } + + /* Read the key size sent by user and store it. */ + count = 0u; + while(!complete) + { + rx_size = UART_get_rx(&g_uart, rx_buff, sizeof(rx_buff)); + if(rx_size > 0u) + { + /* Is it to terminate from the loop */ + if(ENTER == rx_buff[0]) + { + complete = 1u; + } + /* Is entered key valid */ + else if(validate_input(rx_buff[0]) != 1u) + { + UART_send(&g_uart, rx_buff, sizeof(rx_buff)); + UART_send(&g_uart, (const uint8_t *)"\r\n Invalid input.", + sizeof("\r\n Invalid input.")); + UART_send(&g_uart, msg, msg_size); + complete = 0u; + count = 0u; + first = 0u; + } + else + { + if(next_byte == 0) + { + convert_ascii_to_hex(&src_ptr[src_ind], &rx_buff[0]); + prev = src_ptr[src_ind]; + next_byte = 1; + } + else + { + convert_ascii_to_hex(&curr, &rx_buff[0]); + temp = ((prev << 4) & 0xF0); + src_ptr[src_ind] = (temp | curr); + next_byte = 0; + src_ind++; + } + + + /* Switching to next line after every 8 bytes */ + if(((count % 32u) == 0x00u) && (count > 0x00u) && (complete != 0x01u)) + { + UART_send(&g_uart, (const uint8_t *)"\n\r", sizeof("\n\r")); + first = 0u; + } + + if(first == 0u) + { + UART_send(&g_uart, (const uint8_t *)" ", sizeof(" ")); + first++; + } + UART_send(&g_uart, rx_buff, sizeof(rx_buff)); + count++; + if(read_data_size == count) + { + complete = 1u; + } + } + } + } + + if((count % 2) == 0) + { + ret_size = count / 2; + } + else + { + if(size != 1) + { + temp = src_ptr[src_ind]; + src_ptr[src_ind] = ((temp << 4) & 0xF0); + + ret_size = (count / 2) + 1; + } + else + { + ret_size = 1; + } + } + + return ret_size; +} + diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/application/helper.h b/applications/user-crypto/miv-rv32-rsa-services/src/application/helper.h new file mode 100644 index 0000000..0a2effe --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/application/helper.h @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file helper.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Helper function public API. + * + */ +#ifndef __HELPER_H_ +#define __HELPER_H_ 1 + +/****************************************************************************** + * Maximum buffer size. + *****************************************************************************/ +#define MAX_RX_DATA_SIZE 256 +#define MASTER_TX_BUFFER 10 +#define DATA_LENGTH_32_BYTES 32 + +/*============================================================================== + Macro + */ +#define VALID 0U +#define INVALID 1U +#define ENTER 13u + +/****************************************************************************** + * CoreUARTapb instance data. + *****************************************************************************/ +extern UART_instance_t g_uart; + +uint16_t get_input_data +( + uint8_t* location, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +); +void get_key +( + uint8_t key_type, + uint8_t* location, + uint8_t size, + const uint8_t* msg, + uint8_t msg_size +); +uint16_t get_data_from_uart +( + uint8_t* src_ptr, + uint16_t size, + const uint8_t* msg, + uint16_t msg_size +); +void display_output +( + uint8_t* in_buffer, + uint32_t byte_length, + uint8_t reverse_buffer +); +#endif /* __HELPER_H_ */ diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/application/main.c b/applications/user-crypto/miv-rv32-rsa-services/src/application/main.c new file mode 100644 index 0000000..25a4580 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/application/main.c @@ -0,0 +1,372 @@ + +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file main.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Application demonstrating the RSA cryptography service. Please see the + * Readme.md for more details. + * + */ +#include +#include "cal/calini.h" +#include "cal/calini.h" +#include "cal/utils.h" +#include "cal/pk.h" +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" +#include "fpga_design_config/fpga_design_config.h" +#include "miv_rv32_hal/miv_rv32_hal.h" +#include "helper.h" +/****************************************************************************** + * User Crypto base address. + *****************************************************************************/ +uint32_t g_user_crypto_base_addr = 0x62000000UL; + +/****************************************************************************** + * CoreUARTapb instance data. + *****************************************************************************/ +UART_instance_t g_uart; + +/*============================================================================== + Messages displayed over the UART. + */ + +const uint8_t g_greeting_msg[] = +"\r\n\r\n\ +******************************************************************************\r\n\ +******** PolarFire User Crypto RSA Signature Service Example Project *********\r\n\ +******************************************************************************\r\n\ + This example project demonstrates the use of the PolarFire SoC MSS User \r\n\ + Crypto RSA signature service. The following system service are demonstrated:\r\n\ + 1 - RSA signature generation.\r\n\ + 2 - RSA signature verification.\r\n"; + +const uint8_t g_select_operation_msg[] = +"\r\n\ +------------------------------------------------------------------------------\r\n\ + Select the Cryptographic operation to perform:\r\n\ + Press Key '1' to perform RSA signature generation \r\n\ + Press Key '2' to perform RSA signature verification \r\n\ +------------------------------------------------------------------------------\r\n"; + +/****************************************************************************** + * Instruction message. + *****************************************************************************/ +static const uint8_t g_separator[] = +"\r\n\ +------------------------------------------------------------------------------"; +const uint8_t siggen_select_msg[] = +"\r\n Selected RSA signature generation service. \r\n"; +const uint8_t sigver_select_msg[] = +"\r\n Selected RSA signature verification service. \r\n"; +const uint8_t rsa_encode_msg[] = + "\r\n Select RSA encoding/encryption block format: \r\n\ + Press Key '1' for No encoding/padding\r\n\ + Press Key '2' for RSASSA-PKCS1-v1.5\r\n\ + Press Key '3' for ANSI X9.31\r\n\ + Press Key '4' for RSASSA-PSS\r\n"; +const uint8_t hash_type_msg[] = + "\r\n Enter hash type: \r\n\ + Press Key '1' for SHA-1 Algorithm \r\n\ + Press Key '2' for SHA-224 Algorithm \r\n\ + Press Key '3' for SHA-256 Algorithm \r\n\ + Press Key '4' for SHA-384 Algorithm \r\n\ + Press Key '5' for SHA-512 Algorithm \r\n\ + Press Key '6' for SHA-512/224 Algorithm \r\n\ + Press Key '7' for SHA-512/256 Algorithm \r\n\ + Press Key '8' for MD5 Algorithm \r\n\ + Press Key '9' for Kasumi (3GPP) Algorithm \r\n\ + Press Key 'a' for SNOW (3GPP) Algorithm \r\n"; +const uint8_t msg[] = + "\r\n Enter message (max 32 word): \r\n"; +const uint8_t read_key_exp[] = + "\r\n Enter private key exponent value (max 64 word): \r\n"; +const uint8_t read_mod_value[] = + "\r\n Enter modulus N (max 64 word): \r\n"; +const uint8_t msg_success[] = + "\r\n RSA signature generation successful. \ + \r\n Generated Signature value:\r\n"; +const uint8_t msg_fail[] = + "\r\n RSA signature generation fail. \r\n"; +const uint8_t read_public_exp[] = + "\r\n Enter public exponent value (max 64 word): \r\n"; +const uint8_t read_sig_val[] = + "\r\n Enter signature value in words: \r\n"; +const uint8_t rsa_verify_success[] = + "\r\n RSA signature verification successful.\r\n"; +const uint8_t rsa_verify_fail[] = + "\r\n RSA signature verification fail. \r\n"; + +#define REVERSE_TRUE 1 +#define REVERSE_FALSE 0 +/*============================================================================== + Global Variables. + */ +uint32_t __attribute__ ((section (".crypto_data"))) sig_val[64] = {0x00}; +uint32_t __attribute__ ((section (".crypto_data"))) msg_g[32] = { 0x00 }; +uint32_t __attribute__ ((section (".crypto_data"))) d_g[64] = {0x00}; +uint32_t __attribute__ ((section (".crypto_data"))) n_g[64] = {0x00}; +uint32_t __attribute__ ((section (".crypto_data"))) nmu_g[65] = {0x00}; +uint32_t __attribute__ ((section (".crypto_data"))) e_g[64] = {0x00}; +uint32_t __attribute__ ((section (".crypto_data"))) e_len = 0x00; + +/*============================================================================== + Performs signature generation for RSA public-key cryptography. + */ +static void rsa_sign(void) +{ + SATR result; + uint8_t encode_type = 0; + uint8_t hash_type = 0; + uint16_t msg_len = 0; + uint16_t mod_len = 0; + + /* Read type of RSA encoding. */ + get_input_data((uint8_t*)&encode_type, sizeof(encode_type), rsa_encode_msg, + sizeof(rsa_encode_msg)); + encode_type -= 1; + + /* Read hash type. */ + get_input_data((uint8_t*)&hash_type, sizeof(hash_type), hash_type_msg, + sizeof(hash_type_msg)); + + /* Read message value. */ + msg_len = get_input_data((uint8_t*)&msg_g, sizeof(msg_g), msg, sizeof(msg)); + + /* Read private key exponent D. */ + get_input_data((uint8_t*)&d_g, sizeof(d_g), read_key_exp, + sizeof(read_key_exp)); + + /* Read module value N. */ + mod_len = get_input_data((uint8_t*)&n_g, sizeof(n_g), read_mod_value, + sizeof(read_mod_value)); + + /* Change the endianness of data received from UART terminal. */ + CALWordReverse((uint32_t*)&d_g, 64); + CALWordReverse((uint32_t*)&n_g, 64); + CALByteReverseWord((uint32_t*)&d_g, 64); + CALByteReverseWord((uint32_t*)&n_g, 64); + + result = CALPreCompute((uint32_t*)&n_g[0], &nmu_g[0], 64u); + if(SATR_SUCCESS == result) + { + CALPKTrfRes(SAT_TRUE); + } + else + { + UART_polled_tx_string(&g_uart, (uint8_t*)"\r\n N Mod value is not correct "); + } + + /* Performs signature generation for RSA public-key cryptography on the hash + produced from puiMsg using the RSA encoding type. */ + result = CALRSASignHash(encode_type, hash_type, &msg_g[0], &d_g[0], + &n_g[0], &nmu_g[0], msg_len, mod_len/4, + &sig_val[0], SAT_TRUE, 0); + + UART_send(&g_uart, g_separator, sizeof(g_separator)); + + /* Display the generated signature in hex format. */ + if(SATR_SUCCESS == result) + { + CALPKTrfRes(SAT_TRUE); + switch(result) + { + case SATR_SUCCESS: + + /* Display the generated signature in hex format. */ + UART_send(&g_uart, msg_success, sizeof(msg_success)); + display_output((uint8_t*)&sig_val[0],sizeof(sig_val),REVERSE_TRUE); + break; + case SATR_BADPARAM: + UART_polled_tx_string(&g_uart,(uint8_t*)"\r\n For PKCS encoding, padding length is less than 3\ + words.\r\n" ); + break; + } + } + else + { + /* RSA signature generation fail */ + UART_send(&g_uart, msg_fail, sizeof(msg_fail)); + } +} + +/*============================================================================== + Performs signature verification for RSA public-key cryptography. + */ +static void rsa_verify(void) +{ + SATR result; + uint8_t encode_type = 0; + uint8_t hash_type = 0; + uint16_t msg_len = 0; + uint16_t mod_len = 0; + uint16_t e_len = 0; + uint8_t opt = 0; + uint8_t rsa_flag = 0 ; + + /* Read type of RSA encoding. */ + get_input_data((uint8_t*)&encode_type, sizeof(encode_type), rsa_encode_msg, + sizeof(rsa_encode_msg)); + encode_type -= 1; + + /* Read hash type. */ + get_input_data((uint8_t*)&hash_type, sizeof(hash_type), hash_type_msg, + sizeof(hash_type_msg)); + + /* Read message value. */ + msg_len = get_input_data((uint8_t*)&msg_g, sizeof(msg_g), msg, sizeof(msg)); + + /* Read public exponent value E. */ + e_len = get_input_data((uint8_t*)&e_g, sizeof(e_g), read_public_exp, + sizeof(read_public_exp)); + + /* Read module value N */ + mod_len = get_input_data((uint8_t*)&n_g, sizeof(n_g), read_mod_value, + sizeof(read_mod_value)); + + /* check if all the value of sig_val is zero if not zero then user generated + * signature value */ + for ( int w_count = 0 ; w_count < 64 ; w_count ++) + { + if(sig_val[w_count] | 0x00000000 != 0) + { + rsa_flag = 1; + break ; + } + } + if( rsa_flag == 0){ + + /* Read signature value. i.e. puiS */ + get_input_data((uint8_t*)&sig_val, sizeof(sig_val), read_sig_val, + sizeof(read_sig_val)); + CALWordReverse((uint32_t*)&sig_val, 64); + } + + /* Change the endianness of data received from UART terminal. */ + CALWordReverse((uint32_t*)&e_g, 64); + CALWordReverse((uint32_t*)&n_g, 64); + CALByteReverseWord((uint32_t*)&e_g, 64); + CALByteReverseWord((uint32_t*)&n_g, 64); + + result = CALPreCompute((uint32_t*)&n_g[0], &nmu_g[0], 64u); + if(SATR_SUCCESS == result) + { + CALPKTrfRes(SAT_TRUE); + } + else + { + UART_polled_tx_string(&g_uart, (uint8_t*)"\r\n N Mod value is not correct "); + } + + /* Performs signature verification for RSA public-key cryptography on the + hash produced from puiMsg using the RSA encoding type. */ + result = CALRSAVerifyHash(encode_type, hash_type, &msg_g[0], &e_g[0], + e_len/4, &n_g[0], &nmu_g[0], msg_len, + mod_len/4, &sig_val[0], SAT_TRUE, 0); + + UART_send(&g_uart, g_separator, sizeof(g_separator)); + + /* Display the return status of RSA signature verification. */ + if(SATR_SUCCESS == result) + { + result = CALPKTrfRes(SAT_TRUE); + if(SATR_SUCCESS == result) + { + UART_send(&g_uart, rsa_verify_success, sizeof(rsa_verify_success)); + } + } + else + { + UART_send(&g_uart, rsa_verify_fail, sizeof(rsa_verify_fail)); + } +} + +/*============================================================================== + Display greeting message when application is started. + */ +static void display_greeting(void) +{ + UART_send(&g_uart, g_greeting_msg,sizeof(g_greeting_msg)); +} + +/*============================================================================== + Display the choice of cryptographic operation to perform. + */ +static void display_operation_choices(void) +{ + UART_send(&g_uart, g_select_operation_msg, sizeof(g_select_operation_msg)); +} + +/*============================================================================== + Display the Option to continue. + */ +static void display_option(void) +{ + uint8_t rx_size; + uint8_t rx_buff[1]; + + UART_send(&g_uart, g_separator, sizeof(g_separator)); + UART_send(&g_uart, (const uint8_t*)"\r\n Press any key to continue.\r\n", + sizeof("\r\n Press any key to continue.\r\n")); + do + { + rx_size = UART_get_rx(&g_uart, rx_buff, sizeof(rx_buff)); + } while(0u == rx_size); +} + +/*============================================================================== + * Perform RSA signature + */ +/* Main function */ +void main(void) +{ + uint8_t rx_buff[1]; + uint8_t rx_size = 0; + + /* UART initialization */ + UART_init(&g_uart, COREUARTAPB0_BASE_ADDR, BAUD_VALUE_115200, + (DATA_8_BITS | NO_PARITY)); + + /* Initializes the Athena Processor */ + CALIni(); + + /* Display greeting message. */ + display_greeting(); + + /* Select cryptographic operation to perform */ + display_operation_choices(); + + for(;;) + { + /* Read inputs from UART terminal. */ + rx_size = UART_get_rx(&g_uart, rx_buff, sizeof(rx_buff)); + if(rx_size > 0) + { + switch(rx_buff[0]) + { + case '1': + /* Performs signature generation for RSA */ + UART_send(&g_uart, siggen_select_msg, sizeof(siggen_select_msg)); + rsa_sign(); + display_option(); + display_operation_choices(); + break; + + case '2': + /* Performs signature verification for RSA*/ + UART_send(&g_uart, sigver_select_msg, sizeof(sigver_select_msg)); + rsa_verify(); + display_option(); + display_operation_choices(); + break; + + default: + break; + } + } + } + + return; +} diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h b/applications/user-crypto/miv-rv32-rsa-services/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h new file mode 100644 index 0000000..3fd1438 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/boards/polarfire-eval-kit/fpga_design_config/fpga_design_config.h @@ -0,0 +1,156 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file fpga_design_config.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Sample design configuration settings. + * + */ + /*========================================================================*//** + @mainpage + Example file detailing how the fpga_design_config.h should be constructed + for the SoftConsole project targeted for Mi-V processors. + + @section intro_sec Introduction + The SoftConsole project targeted for Mi-V processors now have an improved + folder structure. Detailed description of the folder structure is available + at https://github.com/Mi-V-Soft-RISC-V/miv-rv32-documentation. + + The fpga_design_config.h must be stored as shown below + /boards//fpga_design_config.h + + Currently this file must be hand crafted when using the Mi-V Soft Processor. + In future, all the design and soft IP configurations will be automatically + generated from the Libero design description data. + + You can use this sample file as an example. + Rename this file from sample_fpga_design_config.h to fpga_design_config.h + and then customize it per your hardware design. + + @section Project configuration Instructions + 1. Change SYS_CLK_FREQ define to frequency of Mi-V Soft processor clock + 2 Add all the soft IP core BASE addresses + 3. Add the peripheral Core Interrupts to Mi-V Soft processor IRQ number + mappings + 4. Define MSCC_STDIO_UART_BASE_ADDR if you want a CoreUARTapb mapped to + STDIO + + **NOTE** + In the legacy folder structures, the file hw_config.h as was used at the + root of the project folder. This file is now depricated. + +*//*=========================================================================*/ + +#ifndef FPGA_DESIGN_CONFIG_H_ +#define FPGA_DESIGN_CONFIG_H_ + +/***************************************************************************//** + * Soft-processor clock definition + * This is the only clock brought over from the Mi-V Libero design. + */ +#ifndef SYS_CLK_FREQ +#define SYS_CLK_FREQ 83000000UL +#endif + +/***************************************************************************//** + * Peripheral base addresses. + * Format of define is: + * __BASE_ADDR + * The field is optional if there is only one instance of the core + * in the design + * MIV_ESS is an extended peripheral subsystem IP core with peripherals + * connections as defined below. + * The system can be further extended by attaching APB peripherals to the + * empty APB slots. + */ +#define COREUARTAPB0_BASE_ADDR 0x70000000UL +#define COREGPIO_OUT_BASE_ADDR 0x70001000UL +#define CORESPI_BASE_ADDR 0x70002000UL +#define CORESYS_SERV_BASE_ADDR 0x70003000UL + +/***************************************************************************//** + * Peripheral Interrupts are mapped to the corresponding Mi-V Soft processor + * interrupt in the Libero design. + * + * On the legacy RV32 cores, there can be up to 31 external interrupts (IRQ[30:0] + * pins). The legacy RV32 Soft processor external interrupts are defined in the + miv_rv32_plic.h + * + * These are of the form + * typedef enum +{ + NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + . + . + . + External_31_IRQn = 31 +} IRQn_Type; + + On the legacy RV32 processors, the PLIC identifies the interrupt and passes it + on to the processor core. The interrupt 0 is not used. The pin IRQ[0] should + map to External_1_IRQn likewise IRQ[30] should map to External_31_IRQn + +e.g + +#define TIMER0_IRQn External_30_IRQn +#define TIMER1_IRQn External_31_IRQn + + The MIV_RV32 soft processor has up to six optional system interrupts, MSYS_EI[n] + in addition to one EXT_IRQ. + The MIV_RV32 does not have an inbuilt PLIC and all the interrupts are directly + delivered to the processor core, hence unlike legacy RV32 cores, no interrupt + number mapping is necessary on MIV_RV32 core. + */ + +/**************************************************************************** + * Baud value to achieve a 115200 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ +#define BAUD_VALUE_115200 ((SYS_CLK_FREQ / (16 * 115200)) - 1) + +/****************************************************************************** + * Baud value to achieve a 57600 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + #define BAUD_VALUE_57600 ((SYS_CLK_FREQ / (16 * 57600)) - 1) + +/***************************************************************************//** + * Define MSCC_STDIO_THRU_CORE_UART_APB in the project settings if you want the + * standard IOs to be redirected to a terminal via UART. + */ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +/* + * A base address mapping for the STDIO printf/scanf mapping to CortUARTapb + * must be provided if it is being used + * + * e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR + */ +#define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB0_BASE_ADDR + +#ifndef MSCC_STDIO_UART_BASE_ADDR +#error MSCC_STDIO_UART_BASE_ADDR not defined- e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR +#endif + +#ifndef MSCC_STDIO_BAUD_VALUE +/* + * The MSCC_STDIO_BAUD_VALUE define should be set in your project's settings to + * specify the baud value used by the standard output CoreUARTapb instance for + * generating the UART's baud rate if you want a different baud rate from the + * default of 115200 baud + */ +#define MSCC_STDIO_BAUD_VALUE 115200 +#endif /*MSCC_STDIO_BAUD_VALUE*/ + +#endif /* end of MSCC_STDIO_THRU_CORE_UART_APB */ +/******************************************************************************* + * End of user edit section + */ +#endif /* FPGA_DESIGN_CONFIG_H_ */ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld b/applications/user-crypto/miv-rv32-rsa-services/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld new file mode 100644 index 0000000..8541db6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/boards/polarfire-eval-kit/platform_config/linker/miv-rv32-ram.ld @@ -0,0 +1,160 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-ram.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * debug image executing in SRAM. + * + * This linker script assumes that a RAM is connected at on Mi-V soft processor + * memory space pointed by the reset vector address. + * + * NOTE : Modify the memory section address and the size according to your + * Libero design. + * For example: + * 1) If you want to download and step debug at a different RAM memory address in + * your design (For example TCM base address) than the one provided in this file. + * 2) The MIV_RV32, when used with MIV_ESS IP, provides ways to copy the executable + * HEX file from external Non-Volatile memory into the TCM at reset. In this + * case your executable must be linked to the TCM address. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +MEMORY +{ + ram (rwx) : ORIGIN = 0x80000000, LENGTH = 64k + crypto_ram (rw) : ORIGIN = 0x61000000, LENGTH = 32k +} + +RAM_START_ADDRESS = 0x80000000; /* Must be the same value MEMORY region ram ORIGIN above. */ +RAM_SIZE = 64k; /* Must be the same value MEMORY region ram LENGTH above. */ +STACK_SIZE = 2k; /* needs to be calculated for your application */ +HEAP_SIZE = 0k; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > ram + + .text : ALIGN(0x10) + { + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } > ram + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } > ram + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } > ram + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram + + . = 0x61000000; + .crypto_data : ALIGN(0x10) + { + . = ALIGN(0x10); + *(.crypto_data) + } > crypto_ram +} + diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/aesf5200.h b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/aesf5200.h new file mode 100644 index 0000000..889dddd --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/aesf5200.h @@ -0,0 +1,104 @@ +/* ------------------------------------------------------------------- + $Rev: 1293 $ $Date: 2017-07-27 14:09:14 -0400 (Thu, 27 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for F5200 AES function hardware implementation for + CAL. + ------------------------------------------------------------------- */ + +#ifndef AESF5200_H +#define AESF5200_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef AESF5200_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATR aesf5200aes (SATSYMTYPE eSymType, SATSYMMODE eMode, + void *pIV, SATBOOL bLoadIV, const void *pSrc, void *pDest, SATUINT32_t uiLen, + SATBOOL bDecrypt); + +extern SATR aesf5200aesk (SATSYMTYPE eSymType, const SATUINT32_t *puiKey); + +extern SATR aesf5200gcm (SATSYMTYPE eSymType, SATSYMMODE eMode, void *pIV, + const void *pSrc, void *pDest, SATUINT32_t uiEncLen, + const void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, SATUINT32_t uiMACLen, + SATBOOL bDecrypt); + +extern SATR aesf5200gcmdma(SATSYMTYPE eSymType, SATSYMMODE eMode, void *pIV, + const void *pSrc, void *pDest, SATUINT32_t uiEncLen, const void *pAuth, + SATUINT32_t uiAuthLen, void *pMAC, SATUINT32_t uiMACLen, SATBOOL bDecrypt, + SATUINT32_t uiDMAChConfig); + +extern SATR aesf5200kw(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR aesf5200kwp(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR aesf5200kr(SATSYMTYPE eSymType, SATSYMMODE eMode, + const SATUINT32_t *puiKey, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKrf, SATBOOL bDecrypt); + +extern SATR aesf5200dma(SATSYMTYPE eSymType, SATSYMMODE eMode, void *pIV, + SATBOOL bLoadIV, const void *pExtSrc, void *pExtDest, SATUINT32_t uiLen, + SATUINT32_t uiDMAChConfig, SATBOOL bDecrypt); + +extern SATR aesf5200krdma(SATSYMTYPE eSymType, SATSYMMODE eMode, + const SATUINT32_t *puiKey, void *pIV, SATBOOL bLoadIV, const void *pExtSrc, + void *pExtDest, SATUINT32_t uiLen, SATUINT32_t uiKrf, + SATUINT32_t uiDMAChConfig, SATBOOL bDecrypt); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/calcontext.h b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/calcontext.h new file mode 100644 index 0000000..fc408c2 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/calcontext.h @@ -0,0 +1,88 @@ +/* ------------------------------------------------------------------- + $Rev: 1298 $ $Date: 2017-08-04 13:04:19 -0400 (Fri, 04 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL context management functions. + ------------------------------------------------------------------- */ + +#ifndef CALCONTEXT_H +#define CALCONTEXT_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* Function resource handle. */ +/* ----- ------ ------- ---- */ +#define SATRES_DEFAULT (SATRESHANDLE)0U +#define SATRES_CALSW (SATRESHANDLE)1U + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ +typedef struct{ + SATUINT32_t uiBase; + SATRESCONTEXTPTR pContext; + }SATRESHANDLESTRUCT; + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALCONTEXT_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATRESCONTEXTPTR CALContextCurrent(const SATRESHANDLE hResource); + +extern SATR CALContextLoad(const SATRESHANDLE hResource, + const SATRESCONTEXTPTR pContext); + +extern SATR CALContextRemove(const SATRESHANDLE hResource); + +extern SATR CALContextUnload(const SATRESHANDLE hResource); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern void init_reshandles(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/calenum.h b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/calenum.h new file mode 100644 index 0000000..6281f3f --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/calenum.h @@ -0,0 +1,289 @@ +/* ------------------------------------------------------------------- + $Rev: 1566 $ $Date: 2018-09-14 11:04:30 -0400 (Fri, 14 Sep 2018) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + This file defines common types in the CAL. + + Most CAL types and constants are defined with the "SAT" prefix to + reduce the chance of name space collisions with other users. + ------------------------------------------------------------------- */ + +#ifndef CALENUM_H +#define CALENUM_H + +/* -------- */ +/* Includes */ +/* -------- */ + +/* CAL base types. */ +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ +/* NULL definitions. */ +#define SAT_NULL 0 + +/* Boolean definitions. */ +#define SAT_TRUE ((SATBOOL)1) +#define SAT_FALSE ((SATBOOL)0) + + +/* Major cipher key/SSP type. */ +/* ----- ------ ------- ----- */ +#define SATSSPTYPE_NULL (SATSSPTYPE)0 +#define SATSSPTYPE_SYMKEY (SATSSPTYPE)1 +#define SATSSPTYPE_ASYMKEY (SATSSPTYPE)2 +/* Special marker for end of list. */ +#define SATSSPTYPE_LAST (SATSSPTYPE)3 + + +/* Asymmetric Ciphers */ +/* ---------- ------- */ +#define SATASYMTYPE_NULL (SATASYMTYPE)0U +#define SATASYMTYPE_DSA_SIGN (SATASYMTYPE)1U +#define SATASYMTYPE_DSA_VERIFY (SATASYMTYPE)2U +#define SATASYMTYPE_RSA_ENCRYPT (SATASYMTYPE)3U +#define SATASYMTYPE_RSA_DECRYPT (SATASYMTYPE)4U +#define SATASYMTYPE_DH (SATASYMTYPE)5U +#define SATASYMTYPE_ECDSA_SIGN (SATASYMTYPE)6U +#define SATASYMTYPE_ECDSA_VERIFY (SATASYMTYPE)7U +#define SATASYMTYPE_ECDH (SATASYMTYPE)8U +#define SATASYMTYPE_RSA_SIGN (SATASYMTYPE)9U +#define SATASYMTYPE_RSA_VERIFY (SATASYMTYPE)10U +/* Special marker for end of list. */ +#define SATASYMTYPE_LAST (SATASYMTYPE)11U + + +/* Encoding Types */ +/* -------- ----- */ +#define SATRSAENCTYPE_NULL (SATRSAENCTYPE)0U +#define SATRSAENCTYPE_PKCS (SATRSAENCTYPE)1U +#define SATRSAENCTYPE_ANSI (SATRSAENCTYPE)2U +#define SATRSAENCTYPE_PSS (SATRSAENCTYPE)3U +/* Special marker for end of list. */ +#define SATRSAENCTYPE_LAST (SATRSAENCTYPE)4U + + +/* Symmetric Ciphers */ +/* --------- ------- */ + +/* Cipher Type. */ +#define SATSYMTYPE_NULL (SATSYMTYPE)0U +#define SATSYMTYPE_AES128 (SATSYMTYPE)1U +#define SATSYMTYPE_AES192 (SATSYMTYPE)2U +#define SATSYMTYPE_AES256 (SATSYMTYPE)3U +#define SATSYMTYPE_AESKS128 (SATSYMTYPE)4U +#define SATSYMTYPE_AESKS192 (SATSYMTYPE)5U +#define SATSYMTYPE_AESKS256 (SATSYMTYPE)6U +/* Special marker for end of list. */ +#define SATSYMTYPE_LAST (SATSYMTYPE)7U + +/* Names for common cipher key lengths, in bits. */ +#define SATSYMKEYSIZE_AES128 (SATSYMKEYSIZE)128U +#define SATSYMKEYSIZE_AES192 (SATSYMKEYSIZE)192U +#define SATSYMKEYSIZE_AES256 (SATSYMKEYSIZE)256U +#define SATSYMKEYSIZE_AESKS128 (SATSYMKEYSIZE)256U +#define SATSYMKEYSIZE_AESKS192 (SATSYMKEYSIZE)384U +#define SATSYMKEYSIZE_AESKS256 (SATSYMKEYSIZE)512U + +/* Cipher Mode. */ +#define SATSYMMODE_NULL (SATSYMMODE)0U +#define SATSYMMODE_ECB (SATSYMMODE)1U +#define SATSYMMODE_CBC (SATSYMMODE)2U +#define SATSYMMODE_CFB (SATSYMMODE)3U +#define SATSYMMODE_OFB (SATSYMMODE)4U +#define SATSYMMODE_CTR (SATSYMMODE)5U +#define SATSYMMODE_GCM (SATSYMMODE)6U +#define SATSYMMODE_GHASH (SATSYMMODE)8U +/* Special marker for end of list. */ +#define SATSYMMODE_LAST (SATSYMMODE)9U + + +/* Hashes */ +/* ------ */ +#define SATHASHTYPE_NULL (SATHASHTYPE)0U +#define SATHASHTYPE_SHA1 (SATHASHTYPE)1U +#define SATHASHTYPE_SHA224 (SATHASHTYPE)2U +#define SATHASHTYPE_SHA256 (SATHASHTYPE)3U +#define SATHASHTYPE_SHA384 (SATHASHTYPE)4U +#define SATHASHTYPE_SHA512 (SATHASHTYPE)5U +#define SATHASHTYPE_SHA512_224 (SATHASHTYPE)6U +#define SATHASHTYPE_SHA512_256 (SATHASHTYPE)7U +/* Special marker for end of list. */ +#define SATHASHTYPE_LAST (SATHASHTYPE)8U + +/* Hash sizes defined in bits */ +#define SATHASHSIZE_NULL (SATHASHSIZE)0U +#define SATHASHSIZE_SHA1 (SATHASHSIZE)160U +#define SATHASHSIZE_SHA224 (SATHASHSIZE)224U +#define SATHASHSIZE_SHA256 (SATHASHSIZE)256U +#define SATHASHSIZE_SHA384 (SATHASHSIZE)384U +#define SATHASHSIZE_SHA512 (SATHASHSIZE)512U +#define SATHASHSIZE_SHA512_224 (SATHASHSIZE)224U +#define SATHASHSIZE_SHA512_256 (SATHASHSIZE)256U + +#define SATHASHSIZE_HASH160 (SATHASHSIZE)160U +#define SATHASHSIZE_HASH192 (SATHASHSIZE)192U +#define SATHASHSIZE_HASH224 (SATHASHSIZE)224U +#define SATHASHSIZE_HASH256 (SATHASHSIZE)256U +#define SATHASHSIZE_HASH320 (SATHASHSIZE)320U +#define SATHASHSIZE_HASH384 (SATHASHSIZE)384U +#define SATHASHSIZE_HASH512 (SATHASHSIZE)512U +#define SATHASHSIZE_HASH521 (SATHASHSIZE)521U + + +/* Message Authentication Codes */ +/* ------- -------------- ----- */ + +/* Message Authentication Types */ +#define SATMACTYPE_NULL (SATMACTYPE)0U +#define SATMACTYPE_SHA1 (SATMACTYPE)1U +#define SATMACTYPE_SHA224 (SATMACTYPE)2U +#define SATMACTYPE_SHA256 (SATMACTYPE)3U +#define SATMACTYPE_SHA384 (SATMACTYPE)4U +#define SATMACTYPE_SHA512 (SATMACTYPE)5U +#define SATMACTYPE_SHA512_224 (SATMACTYPE)6U +#define SATMACTYPE_SHA512_256 (SATMACTYPE)7U +#define SATMACTYPE_AESCMAC128 (SATMACTYPE)10U +#define SATMACTYPE_AESCMAC192 (SATMACTYPE)11U +#define SATMACTYPE_AESCMAC256 (SATMACTYPE)12U +#define SATMACTYPE_AESGMAC (SATMACTYPE)13U +/* Special marker for end of list. */ +#define SATMACTYPE_LAST (SATMACTYPE)14U + + +/* Message Authentication Flags */ +#define SATMACFLAG_OP (SATMACTYPEFLAG)0U +#define SATMACFLAG_FIRSTPASS (SATMACTYPEFLAG)1U +#define SATMACFLAG_FINALPASS (SATMACTYPEFLAG)2U +#define SATMACFLAG_IKEYFINAL (SATMACTYPEFLAG)4U +#define SATMACFLAG_OKEYFINAL (SATMACTYPEFLAG)8U + + +/* Non-deterministic Random Bit Generator */ +/* ------- -------------- ----- */ + +/* NRBG register write enables */ +#define SATNRBGCONFIG_NONE 0x0 +#define SATNRBGCONFIG_RNG_CSR 0x1 +#define SATNRBGCONFIG_RNG_CNTLIM 0x2 +#define SATNRBGCONFIG_RNG_VOTIMER 0X4 +#define SATNRBGCONFIG_RNG_FMSK 0X8 + +/* RNG_CSR access defines */ +#define SATNRBGCONFIG_CSR_RODIS 0x0 +#define SATNRBGCONFIG_CSR_ROEN 0x1 +#define SATNRBGCONFIG_CSR_ROFATAL 0x2 +#define SATNRBGCONFIG_CSR_ROFATALCLR 0X4 + +/* RNG_FMSK mask values */ +#define SATNRBGCONFIG_FMSK_ROOSCF 0xFF +#define SATNRBGCONFIG_FMSK_MONOBITF 0x10000 +#define SATNRBGCONFIG_FMSK_POKERF 0x20000 +#define SATNRBGCONFIG_FMSK_RUNSF 0x40000 +#define SATNRBGCONFIG_FMSK_LRUNSF 0x80000 +#define SATNRBGCONFIG_FMSK_F1401 0xF0000 +#define SATNRBGCONFIG_FMSK_REPCNTF 0x100000 +#define SATNRBGCONFIG_FMSK_APROPF 0x200000 +#define SATNRBGCONFIG_FMSK_SP800 0x300000 + +/* RNG_ROHEALTH mask values */ +#define SATNRBGCONFIG_HLTH_ROOSCF 0x3FC0 +#define SATNRBGCONFIG_HLTH_APROPF 0x20 +#define SATNRBGCONFIG_HLTH_REPCNTF 0x10 +#define SATNRBGCONFIG_HLTH_LRUNSF 0x8 +#define SATNRBGCONFIG_HLTH_RUNSF 0x4 +#define SATNRBGCONFIG_HLTH_POKERF 0x2 +#define SATNRBGCONFIG_HLTH_MONOBITF 0x1 + + +/* Return Codes */ +/* ------ ----- */ +#define SATR_SUCCESS (SATR)0U +#define SATR_FAIL (SATR)1U +#define SATR_BADPARAM (SATR)2U +#define SATR_VERIFYFAIL (SATR)3U +#define SATR_KEYSFULL (SATR)4U +#define SATR_BUSY (SATR)5U +#define SATR_ROFATAL (SATR)6U +#define SATR_PARITYFLUSH (SATR)7U +#define SATR_SIGNFAIL (SATR)8U +#define SATR_VALIDATEFAIL (SATR)9U +#define SATR_PAF (SATR)10U +#define SATR_VALPARMX (SATR)11U +#define SATR_VALPARMY (SATR)12U +#define SATR_VALPARMB (SATR)13U +#define SATR_DCMPPARMX (SATR)14U +#define SATR_DCMPPARMB (SATR)15U +#define SATR_DCMPPARMP (SATR)16U +#define SATR_SIGNPARMD (SATR)17U +#define SATR_SIGNPARMK (SATR)18U +#define SATR_VERPARMR (SATR)19U +#define SATR_VERPARMS (SATR)20U +#define SATR_MSBICV1 (SATR)21U +#define SATR_MSBICV2 (SATR)22U +#define SATR_PADLEN (SATR)23U +#define SATR_LSB0PAD (SATR)24U +#define SATR_BADLEN (SATR)25U +#define SATR_BADHASHTYPE (SATR)26U +#define SATR_BADTYPE (SATR)27U +#define SATR_BADMODE (SATR)28U +#define SATR_BADCONTEXT (SATR)29U +#define SATR_BADHASHLEN (SATR)30U +#define SATR_BADMACTYPE (SATR)31U +#define SATR_BADMACLEN (SATR)32U +#define SATR_BADHANDLE (SATR)33U +#define SATR_FNP (SATR)34U +#define SATR_HFAULT (SATR)35U +#define SATR_NOPEND (SATR)36U +#define SATR_BADRSAENC (SATR)37U +#define SATR_BADMOD (SATR)38U +/* Special marker for end of list. */ +#define SATR_LAST (SATR)39U + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* See caltypes.h for type definitions associated with defines above. */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALENUM_C +#ifdef __cplusplus +extern "C" { +#endif + +/* NOTE: this header file does not have an associated C file. */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/calini.h b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/calini.h new file mode 100644 index 0000000..62461d1 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/calini.h @@ -0,0 +1,69 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL initialization + ------------------------------------------------------------------- */ + +#ifndef CALINI_H +#define CALINI_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALINI_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALIni(void); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/calpolicy.h b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/calpolicy.h new file mode 100644 index 0000000..2a43445 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/calpolicy.h @@ -0,0 +1,183 @@ +/* ------------------------------------------------------------------- + $Rev: 1293 $ $Date: 2017-07-27 14:09:14 -0400 (Thu, 27 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file defining CAL policy for endianess, HW/SW, etc. + ------------------------------------------------------------------- */ + +#ifndef CALPOLICY_H +#define CALPOLICY_H + +/* -------- */ +/* Includes */ +/* -------- */ + +/* The following include provides a custom configuration header file when + CALCONFIGH is defined +*/ +#ifdef CALCONFIGH +# include CALCONFIGH +#else +# error "CALCONFIGH not defined. CAL requires a custom configuration header \ +defined by CALCONFIGH. Review CAL README." +#endif + +/* ------- */ +/* Defines */ +/* ------- */ + +/* Context switching */ +#ifndef MAXRESHANDLES +# define MAXRESHANDLES 1 +#endif + +/* Little Endian (default) / Big Endian */ +#ifndef SAT_LITTLE_ENDIAN +# define SAT_LITTLE_ENDIAN 1 +#endif + +/* PK SW Point Validate Checking */ +#ifndef PKSWCHKVALPT +# define PKSWCHKVALPT 1 +#endif + +/* DMA */ +#ifndef USE_X52EXEC_DMA +# define USE_X52EXEC_DMA 0 +#endif + +/* SHA */ +#define MAXHASHLEN 512 +#define MAXHMACKEYLEN 512 + +/* RNG */ +#define NRBGSIMNUMRO 16 +#define ENTROPYMEMBLOCKS 7 +#define BUFMEMBLOCKS 3 +#ifndef RNXBLKLEN +#define RNXBLKLEN 32 +#endif +#ifndef RNXBLKOUTLEN +#define RNXBLKOUTLEN 4 +#endif + +#ifndef USENRBGSW +# define USENRBGSW 0 +#endif + +/* PK */ +#ifndef PKX0_BASE +# define PKX0_BASE 0xE0000000u +#endif + +#if USEPKSW +# ifndef MAXMODSIZE +# define MAXMODSIZE 8192 +# endif +# ifndef PKSWBUFSIZE +# define PKSWBUFSIZE 15*(MAXMODSIZE/32) +# endif +#else +# define USEPKSW 0 +#endif + +/* Set default values for X52 configuration defines. */ +#ifndef X52_CFG_OPT +# define X52_CFG_OPT 0 +#endif +#ifndef X52_LIR_LEN +# define X52_LIR_LEN 0x800 +#endif +#ifndef X52_BER_LEN +# define X52_BER_LEN 0x400 +#endif +#ifndef X52_MMR_LEN +# define X52_MMR_LEN 0x400 +#endif +#ifndef X52_TSR_LEN +# define X52_TSR_LEN 0x400 +#endif +#ifndef X52_FPR_LEN +# define X52_FPR_LEN 0x400 +#endif +#if X52_LIR_ROM_LEN>0 && X52_LIR_LEN>X52_LIR_ROM_LEN +# define PKX_OFFSET 2048 +#else +# define PKX_OFFSET 0 +#endif + +/* X52 Configuration Options */ +#define AESPKX (X52_CFG_OPT&0x00000001u) +#define AESPKXGCM (X52_CFG_OPT&0x00000008u) +#define AESPKXFASTKEY (X52_CFG_OPT&0x01000000u) +#define SHAPKXOPT1 (X52_CFG_OPT&0x00000020u) +#define SHAPKXOPT224 (X52_CFG_OPT&0x00000040u) +#define SHAPKXOPT256 (X52_CFG_OPT&0x00000080u) +#define SHAPKXOPT384 (X52_CFG_OPT&0x00000100u) +#define SHAPKXOPT512 (X52_CFG_OPT&0x00000200u) +#define SHAPKXOPT5124 (X52_CFG_OPT&0x00400000u) +#define SHAPKXOPT5126 (X52_CFG_OPT&0x00800000u) + +/* Define the maximum number of return values that may be handled using + CAL*TrfRes() function(s). +*/ +#define CAL_MAXTRFS 4 + +/* Volatile pointer operations */ +/* These access macros are designed so that they may be redefined by a + user compiling CAL. +*/ +#ifndef CALREAD32 +# define CALREAD32(ptr) ( *(ptr) ) +#endif +#ifndef CALWRITE32 +# define CALWRITE32(ptr, val) ( *(ptr)=val ) +#endif +#ifndef CALPOLL32 +# define CALPOLL32(ptr, val, mask) while ((*(ptr) & (mask)) != (val)); +#endif + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +#ifndef CALPOLICY_C +#ifdef __cplusplus +extern "C" { +#endif + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +/* NOTE: this header file does not have an associated C file. */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/caltypes.h b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/caltypes.h new file mode 100644 index 0000000..3b2fe0b --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/caltypes.h @@ -0,0 +1,328 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + This file defines common types in the CAL. + + Since support for the C99 stdint.h integer types is not universal, + these are defined herein and may require customization from compiler + to compiler, or use of the stdint.h header, if present (recommended). + + C99 supports 64-bit types; however, support in older compilers is + spotty. For those that do not support it, the macro NO64BITINT may be + defined by the user to prevent defintion of 64-bit types. This is + generally safe with CAL-PK and CAL-SYM; however, this is incompatible + with CAL-SW. + + Most CAL types and constants are defined with the "SAT" prefix to + reduce the chance of name space collisions with other users. + ------------------------------------------------------------------- */ + +#ifndef CALTYPES_H +#define CALTYPES_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* Base Types */ +/* ---- ----- */ + +/* The user may compile using stdint.h instead of the definitions below + by defining the macro INC_STDINT_H. */ +#ifdef INC_STDINT_H +#include +#endif + +/* Integer type abstraction layer. */ +#ifndef INC_STDINT_H + +typedef unsigned char uint8_t; +typedef signed char int8_t; + +typedef unsigned short uint16_t; +typedef signed short int16_t; + +typedef unsigned int uint32_t; +typedef int int32_t; + +/* stdint.h is a C99 feature, and C99 supports 64-bit ints, so this is + immune to the macro used to disable 64-bit int support. +*/ +typedef unsigned long long uint64_t; +typedef long long int64_t; + +typedef long uintptr_t; + +#endif + +/* Boolean type. */ +typedef uint8_t SATBOOL; + +/* Unsigned integer type */ +typedef uint8_t SATUINT8_t; +typedef uint16_t SATUINT16_t; +typedef uint32_t SATUINT32_t; +#ifdef INC_STDINT_H +typedef uint64_t SATUINT64_t; +#else +#ifndef NO64BITINT +typedef uint64_t SATUINT64_t; +#endif +#endif + +/* Integer type */ +typedef int8_t SATINT8_t; +typedef int16_t SATINT16_t; +typedef int32_t SATINT32_t; +#ifdef INC_STDINT_H +typedef int64_t SATINT64_t; +#else +#ifndef NO64BITINT +typedef int64_t SATINT64_t; +#endif +#endif + +typedef uintptr_t SATUINTPTR_t; + +/* Major cipher key/SSP type. */ +/* ----- ------ ------- ----- */ +typedef uint8_t SATSSPTYPE; +typedef SATSSPTYPE * SATSSPTYPEPTR; + + +/* Asymmetric Ciphers */ +/* ---------- ------- */ + +/* Cipher type. */ +typedef uint8_t SATASYMTYPE; +typedef SATASYMTYPE * SATASYMTYPEPTR; + +/* Cipher size type. */ +typedef uint16_t SATASYMSIZE; +typedef SATASYMSIZE * SATASYMSIZEPTR; + +/* Cipher encoding */ +typedef uint8_t SATRSAENCTYPE; +typedef SATRSAENCTYPE * SATRSAENCTYPEPTR; + +/* DSA public/private key. */ +typedef struct { + uint16_t ui16PLen; /* Length of modulus p. */ + uint16_t ui16QLen; /* Length of prime divisor q. */ + uint32_t *pui32P; /* Prime modulus p. */ + uint32_t *pui32Q; /* Prime divisor q. */ + uint32_t *pui32G; /* Generator g, length==p. */ + uint32_t *pui32X; /* Private key x, length==p. */ + uint32_t *pui32Y; /* Private key y, length==q. */ +} SATASYMDSADOMAIN; +typedef SATASYMDSADOMAIN * SATASYMDSADOMAINPTR; + + +/* Symmetric Ciphers */ +/* --------- ------- */ + +/* Cipher type. */ +typedef uint8_t SATSYMTYPE; +typedef SATSYMTYPE * SATSYMTYPEPTR; + +/* Cipher key size type (in bits). */ +typedef uint16_t SATSYMKEYSIZE; +typedef SATSYMKEYSIZE * SATSYMKEYSIZEPTR; + +/* Cipher mode type. */ +typedef uint8_t SATSYMMODE; +typedef SATSYMMODE * SATSYMMODEPTR; + +/* Cipher key object. */ +/* Other fields are only valid when sstCipher!=SATSYMTYPE_NULL. */ +typedef struct { + SATSYMTYPE sstCipher; + SATSYMKEYSIZE ssksKeyLen; + uint32_t *pui32Key; +} SATSYMKEY; +typedef SATSYMKEY * SATSYMKEYPTR; + + +/* Hashes */ +/* ------ */ + +/* Hash type. */ +typedef uint8_t SATHASHTYPE; +typedef SATHASHTYPE * SATHASHTYPEPTR; + +/* Hash size type (in bits). */ +typedef uint16_t SATHASHSIZE; +typedef SATHASHSIZE * SATHASHSIZEPTR; + + +/* Context switching. */ +/* ----- ------ ------- ----- */ + +typedef uint32_t SATRESHANDLE; +typedef SATRESHANDLE * SATRESHANDLEPTR; + +typedef struct { + SATHASHTYPE sshashtype; + uint32_t uiRunLen; + uint32_t uiHash[MAXHASHLEN/32]; /* holds intermed hash */ +} SHACTX; + +typedef struct { + SATHASHTYPE sshashtype; + uint32_t uiRunLen; + uint32_t uiKeyLen; + uint32_t uiHash[MAXHASHLEN/32]; /* holds intermed hash */ + uint32_t uiKey[MAXHMACKEYLEN/32]; /* holds intermed key */ +} SHAHMACCTX; + +typedef struct { + uint8_t uiContextType; + union{ + SHACTX ctxSHA; + SHAHMACCTX ctxMAC; + }CTXUNION; +} SATRESCONTEXT; +typedef SATRESCONTEXT * SATRESCONTEXTPTR; + + +/* Message Authentication Codes */ +/* ------- -------------- ----- */ + +/* MAC type. */ +typedef uint8_t SATMACTYPE; +typedef SATMACTYPE * SATMACTYPEPTR; +typedef uint8_t SATMACTYPEFLAG; + + +/* Random Number Generator */ +/* ------ ------ --------- */ +typedef union { + uint32_t u32[4]; + uint8_t u8[16]; +} uint128_t; + +typedef struct { + uint128_t ui128V; + uint128_t ui128K[2]; + uint32_t uiReseedCnt; + uint32_t uiReseedLim; + uint32_t uiEntropyFactor; + SATSYMKEYSIZE eStrength; + SATBOOL bTesting; + +} DRBGCTX; + +typedef DRBGCTX * DRBGCTXPTR; + + +/* Function Return Code */ +/* -------- ------ ---- */ +typedef uint16_t SATR ; +typedef SATR * SATRPTR ; + + +/* Transfer Results */ +/* -------- ------- */ +typedef struct { + SATUINT32_t uiLen; + volatile SATUINT32_t* vpuiSrc; + void* pDest; +} SATDATATRF; + +typedef struct { + SATUINT32_t uiResType; + SATUINT32_t uiNumDataTrf; + SATDATATRF dtrfArray[CAL_MAXTRFS]; +} SATRESULT; + + +/* EC Ultra Structs */ +/* -- ----- ------- */ +typedef uint32_t SATECTYPE; + +typedef struct { + SATUINT32_t uiLen; + SATUINT32_t* puiX; + SATUINT32_t* puiY; +} SATECPOINT; + +typedef struct { + SATUINT32_t uiLen; + SATUINT32_t* puiMod; + SATUINT32_t* puiMontPrecompute; + SATUINT32_t* puiRSqd; +} SATECMONTMOD; + +typedef struct { + SATUINT32_t uiCurveSize; + SATECTYPE eCurveType; + SATECPOINT* pBasePoint; + SATECMONTMOD* pModP; + SATECMONTMOD* pModN; + SATUINT32_t* puiA; + SATUINT32_t* puiB; +} SATECCURVE; + +typedef struct { + SATUINT32_t uiLen; + SATUINT32_t* puiSigR; + SATUINT32_t* puiSigS; + SATUINT32_t* puiSigX; + SATUINT32_t* puiSigY; +} SATECDSASIG; + +typedef struct { + SATHASHSIZE sHashLen; + SATUINT32_t* puiHash; +} SATHASH; + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef CALTYPES_C +#ifdef __cplusplus +extern "C" { +#endif + +/* NOTE: this header file does not have an associated C file. */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/config_user.h b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/config_user.h new file mode 100644 index 0000000..3728565 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/config_user.h @@ -0,0 +1,44 @@ +/* ------------------------------------------------------------------- + $Rev: 727 $ $Date: 2017-10-20 16:50:53 -0400 (Fri, 20 Oct 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + + User configuration file to include/exclude CAL components. + ------------------------------------------------------------------- */ + +#ifndef CALCONFIG_F5200_H +#define CALCONFIG_F5200_H + +#include "x52cfg_user.h" +#include + +extern uint32_t g_user_crypto_base_addr; + +#define SAT_LITTLE_ENDIAN 1 +#define PKX0_BASE (g_user_crypto_base_addr) +#define USEPKX 1 +#define USEAESPKX 1 +#define USESHAPKX 1 +#define USEDRBGPKX 1 +#define USENRBGPKX 1 +#define USECALCTX 1 + +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/drbg.h b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/drbg.h new file mode 100644 index 0000000..dba16f7 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/drbg.h @@ -0,0 +1,91 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for DRBG functions for CAL + ------------------------------------------------------------------- */ + +#ifndef DRBG_H +#define DRBG_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ +#define CALDRBGENTROPYFACTOR 2 + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef DRBG_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALDRBGInstantiate(const SATUINT32_t *puiNonce, + SATUINT32_t uiNonceLen, const SATUINT32_t *puiPzStr, + SATUINT32_t uiPzStrLen, SATSYMKEYSIZE eStrength, + SATUINT32_t uiEntropyFactor, SATUINT32_t uiReseedLim, SATBOOL bTesting); + +extern SATR CALDRBGReseed(const SATUINT32_t *puiAddIn, SATUINT32_t uiAddInLen); + +extern SATR CALDRBGGenerate(const SATUINT32_t *puiAddIn, SATUINT32_t uiAddInLen, + SATBOOL bPredResist, SATUINT32_t *puiOut, SATUINT32_t uiOutBlocks); + +extern SATR CALDRBGUninstantiate(void); + +extern SATR CALDRBGGetCtx(DRBGCTXPTR drbgCtxExt); + +extern SATR CALDRBGLoadCtx(DRBGCTXPTR drbgCtxExt); + +extern SATR CALDRBGGetbInst(void); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +extern SATR CALDrbgTrfRes(SATBOOL bBlock); + +extern void CALDrbgIni(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/drbgf5200.h b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/drbgf5200.h new file mode 100644 index 0000000..d7f6c4c --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/drbgf5200.h @@ -0,0 +1,120 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for F5200 DRBG function hardware implementations + in CAL. + ------------------------------------------------------------------- */ + +#ifndef DRBGF5200_H +#define DRBGF5200_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ +#define RNXEFACTOR (X52BER+2) +#define RNXIRLEN (X52BER+2) +#define RNXKEYORD (X52BER+3) +#define RNXRESPRED (X52BER+4) +#define RNXTESTSEL (X52BER+5) +#define RNXBADDIN (X52BER+6) +#define RNXPPSTR (X52BER+7) +#define RNXPCTX (X52BER+8) +#define RNXPRENT (X52BER+13) +#define RNXITMP3 (X52BER+20) +#define RNXPCTX2 (X52BER+22) +/* These use same locs as tb generator, but can change */ +#define RNXRDATA (X52BER_ENDIAN+0x24) +#define RNXAIDATAOFF 0x0062 +#define RNXAIDATA (X52BER_ENDIAN+RNXAIDATAOFF) +#define RNXCTXOFF 0x0094 +#define RNXCTX (X52FPR+RNXCTXOFF) +#define RNXCTXV (X52FPR_ENDIAN+RNXCTXOFF+6) +#define RNXCTXVMMR (X52MMR_ENDIAN+RNXCTXOFF+6) +#define RNXTESTENT (X52TSR_ENDIAN+8) + +#define RNXCTXWORDS 18 +#define RNXBLENLOC (RNXCTX+RNXCTXWORDS) +#define RNXBOUTLENLOC (RNXCTX+RNXCTXWORDS+1) + +#define RNXMAXTESTENT32 512 +#define CALDRBGMAXADDINLEN X52_BER_LEN-RNXAIDATAOFF-4 +#define CALDRBGMAXPSNONCELEN X52_BER_LEN-RNXAIDATAOFF-4 + + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef DRBGF5200_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATR drbgf5200Ini(void); + +extern SATR drbgf5200TrfRes(SATBOOL bBlock); + +extern SATR drbgf5200instantiate(const SATUINT32_t *puiNonce, + SATUINT32_t uiNonceLen, const SATUINT32_t *puiPzStr, SATUINT32_t uiPzStrLen, + SATSYMKEYSIZE eStrength, SATUINT32_t uiEntropyFactor, + SATUINT32_t uiReseedLim, SATBOOL bTesting); + +extern SATR drbgf5200reseed(const SATUINT32_t *puiAddIn, + SATUINT32_t uiAddInLen); + +extern SATR drbgf5200generate(const SATUINT32_t *puiAddIn, + SATUINT32_t uiAddInLen, SATBOOL bPredResist, SATUINT32_t uiReqLen, + SATUINT32_t *puiOut); + +extern SATR drbgf5200uninstantiate(void); + +extern SATR drbgf5200getctx(DRBGCTXPTR drbgCtxExt); + +extern SATR drbgf5200loadctx(DRBGCTXPTR drbgCtxExt); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/hash.h b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/hash.h new file mode 100644 index 0000000..f3fd6d4 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/hash.h @@ -0,0 +1,102 @@ +/* ------------------------------------------------------------------- + $Rev: 1293 $ $Date: 2017-07-27 14:09:14 -0400 (Thu, 27 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL hash functions. + ------------------------------------------------------------------- */ + +#ifndef HASH_H +#define HASH_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ +extern const SATHASHSIZE uiHashWordLen[SATHASHTYPE_LAST]; + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef HASH_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALHash(SATHASHTYPE eHashType, const void *pMsg, + SATUINT32_t uiMsgLen, void *pHash); + +extern SATR CALHashDMA(SATHASHTYPE eHashType, const void *pMsg, + SATUINT32_t uiMsgLen, void *pHash, SATUINT32_t uiDMAChConfig); + +extern SATR CALHashCtx(const SATRESHANDLE hResource, + const SATRESCONTEXTPTR pContext, const void *pMsg, SATUINT32_t uiMsgLen, + void *pHash, const SATBOOL bFinal); + +extern SATR CALHashCtxIni(const SATRESCONTEXTPTR pContext, + const SATHASHTYPE eHashType); + +extern SATR CALHashIni(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen); + +extern SATR CALHashWrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR CALHashRead(void *pHash); + +extern SATR CALKeyTree(SATBOOL bPathSizeSel, const SATUINT32_t* puiKey, + SATUINT8_t uiOpType, const SATUINT32_t* puiPath, SATUINT32_t* puiKeyOut); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATUINT32_t iGetHashLen(SATHASHTYPE eHashType); + +extern SATUINT32_t iGetBlockLen(SATHASHTYPE eHashType); + +extern SATR CALHashCtxLoad(const SATRESHANDLE hResource, + SATRESCONTEXTPTR const pContext, SATUINT32_t uiRunLen); + +extern SATUINT32_t iGetRunLen(SATRESCONTEXTPTR const pContext); + +extern SATR CALHashTypeIni(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/mac.h b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/mac.h new file mode 100644 index 0000000..acdc767 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/mac.h @@ -0,0 +1,95 @@ +/* ------------------------------------------------------------------- + $Rev: 1296 $ $Date: 2017-08-01 13:54:48 -0400 (Tue, 01 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL MAC functions. + ------------------------------------------------------------------- */ + +#ifndef MAC_H +#define MAC_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef MAC_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALMAC(SATMACTYPE eMACType, const SATUINT32_t *pKey, SATUINT32_t uiKeyLen, + const void *pMsg, SATUINT32_t uiMsgLen, void *pMAC); + +extern SATR CALMACDMA(SATMACTYPE eMACType, const SATUINT32_t *pKey, + SATUINT32_t uiKeyLen, const void *pMsg, SATUINT32_t uiMsgLen, + const void *pMAC, SATUINT32_t uiDMAChConfig); + +extern SATR CALMACIni(SATMACTYPE eMACType, const SATUINT32_t *pKey, + SATUINT32_t uiKeyLen, SATUINT32_t uiMsgLen); + +extern SATR CALMACCtx(const SATRESHANDLE hResource, + const SATRESCONTEXTPTR pContext, const void *pMsg, SATUINT32_t uiMsgLen, + void *pHash, const SATUINT8_t uiFlag); + +extern SATR CALMACCtxIni(const SATRESCONTEXTPTR pContext, const SATHASHTYPE eHashType, + const SATUINT32_t *pKey, SATUINT32_t uiKeyLen); + +extern SATR CALMACWrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR CALMACRead(void *pMAC); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATUINT32_t iGetMACKeyLen(SATMACTYPE eMACType); + +extern SATR CALMACCtxLoad(const SATRESHANDLE hResource, + SATRESCONTEXTPTR const pContext, SATUINT32_t uiRunLen); + +extern SATUINT32_t iGetMACRunLen(SATRESCONTEXTPTR const pContext); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/miv-rv32i-user-crypto-lib.a b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/miv-rv32i-user-crypto-lib.a new file mode 100644 index 0000000..5fda638 Binary files /dev/null and b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/miv-rv32i-user-crypto-lib.a differ diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/miv-rv32imc-user-crypto-lib.a b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/miv-rv32imc-user-crypto-lib.a new file mode 100644 index 0000000..ee7bcf4 Binary files /dev/null and b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/miv-rv32imc-user-crypto-lib.a differ diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/nrbg.h b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/nrbg.h new file mode 100644 index 0000000..d517065 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/nrbg.h @@ -0,0 +1,83 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for NRBG functions for CAL. + ------------------------------------------------------------------- */ + +#ifndef NRBG_H +#define NRBG_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef NRBG_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALNRBGSetTestEntropy(SATUINT32_t * puiEntropy, + SATUINT32_t uiEntLen32); + +extern SATR CALNRBGGetEntropy(SATUINT32_t * puiEntropy, SATUINT32_t uiEntLen32, + SATBOOL bTesting); + +extern SATR CALNRBGConfig(SATUINT32_t uiWriteEn, SATUINT32_t uiCSR, + SATUINT32_t uiCntLim, SATUINT32_t uiVoTimer, SATUINT32_t uiFMsk, + SATUINT32_t* puiStatus); + +extern SATUINT32_t CALNRBGHealthStatus(void); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATUINT32_t CALNRBGGetTestEntLen(void); + +extern SATR nrbgpkxgetentropy(SATUINT32_t * puiEntropy, + SATUINT32_t uiEntLen32); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/pk.h b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/pk.h new file mode 100644 index 0000000..5983d9a --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/pk.h @@ -0,0 +1,302 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for for CAL PK. + ------------------------------------------------------------------- */ + +#ifndef PK_H +#define PK_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef PK_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALPKTrfRes(SATBOOL bBlock); + +extern SATR CALDSASign(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALDSASignCM(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALDSASignHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, const SATUINT32_t* puiK, + const SATUINT32_t* puiX, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, SATUINT32_t uiN, + SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALDSASignHashCM(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, const SATUINT32_t* puiK, + const SATUINT32_t* puiX, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, SATUINT32_t uiN, + SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALDSAVerify(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiY, const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, + const SATUINT32_t* puiQMu, SATUINT32_t uiN, SATUINT32_t uiL); + +extern SATR CALDSAVerifyHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, const SATUINT32_t* puiY, + const SATUINT32_t* puiR, const SATUINT32_t* puiS, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALECDHC(const SATUINT32_t* puiS, const SATUINT32_t* puiWx, + const SATUINT32_t* puiWy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t* puiK, const SATUINT32_t* puiR, + const SATUINT32_t* puiRMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiZ); + +extern SATR CALECDSASign(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALECDSASignTwist(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALECDSASignCM(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALECDSASignTwistCM(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALECDSASignHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiK, const SATUINT32_t* puiD, const SATUINT32_t* puiB, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSASignHashCM(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiK, const SATUINT32_t* puiD, const SATUINT32_t* puiB, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSASignTwistHash(const SATUINT32_t* puiMsg, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSAVerify(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS,const + SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress); + +extern SATR CALECDSAVerifyTwist(const SATUINT32_t* puiHash, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALECDSAVerifyHash(const SATUINT32_t* puiMsg, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALECDSAVerifyTwistHash(const SATUINT32_t* puiMsg, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALECMult(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECMultCM(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t* puiN, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress, SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECMultTwist(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiLen, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECMultTwistCM(const SATUINT32_t* puiMul, + const SATUINT32_t* puiPx, const SATUINT32_t* puiPy, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiMod,const SATUINT32_t* puiMu, + const SATUINT32_t* puiN, SATUINT32_t uiLen, SATUINT32_t* puiRx, + SATUINT32_t* puiRy); + +extern SATR CALECMultAdd(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiB, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen, SATUINT32_t uiPtPCompress, SATUINT32_t uiPtQCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALECPtValidate(const SATUINT32_t* puiPx, const SATUINT32_t* puiPy, + const SATUINT32_t* puiB, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen); + +extern SATR CALECKeyPairGen(const SATUINT32_t* puiC, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + const SATUINT32_t* puiNM1, const SATUINT32_t* puiNM1Mu, const SATUINT32_t* puiB, + SATUINT32_t* puiD, SATUINT32_t* puiQx, SATUINT32_t* puiQy, SATUINT32_t uiLen); + +extern SATR CALExpo(const SATUINT32_t* puiBase, const SATUINT32_t* puiExpo, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALExpoCM(const SATUINT32_t* puiBase, const SATUINT32_t* puiExpo, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALMMult(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALMMultAdd(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiC, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALModRed(const SATUINT32_t* puiA, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiALen, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPreCompute(const SATUINT32_t* puiMod, SATUINT32_t* puiMu, + SATUINT32_t uiModLen); + +extern SATR CALRSACRT(const SATUINT32_t* puiCipher, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ,const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiLen, SATUINT32_t* puiPlain); + +extern SATR CALRSACRTCM(const SATUINT32_t* puiCipher, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t * puiE, const SATUINT32_t* puiP, + const SATUINT32_t* puiQ, const SATUINT32_t * puiN, + const SATUINT32_t * puiNMu, SATUINT32_t uiLen, SATUINT32_t uiELen, + SATUINT32_t* puiPlain); + +extern SATR CALRSACRTSign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + const SATUINT32_t* puiN, SATUINT32_t uiLen, SATUINT32_t* puiSig); + +extern SATR CALRSACRTSignCM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, const SATUINT32_t* puiQ, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSig); + +extern SATR CALRSACRTSignHash(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ,const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + const SATUINT32_t* puiN, SATUINT32_t uiMsgLen, SATUINT32_t uiModLen, + SATUINT32_t* puiSig, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALRSACRTSignHashCM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, const SATUINT32_t* puiQ, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, SATUINT32_t* puiSig, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALRSASign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiD, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, SATUINT32_t* puiSig); + +extern SATR CALRSASignHash(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiD, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, SATUINT32_t uiModLen, + SATUINT32_t* puiSig, SATBOOL bDMA, SATUINT32_t uiDMAChConfig); + +extern SATR CALRSAVerify(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, + const SATUINT32_t* puiSig); + +extern SATR CALRSAVerifyHash(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiMsg, const SATUINT32_t* puiE, SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, const SATUINT32_t* puiSig, SATBOOL bDMA, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPurge52(SATBOOL bVerify); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/pkx.h b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/pkx.h new file mode 100644 index 0000000..c23dda4 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/pkx.h @@ -0,0 +1,409 @@ +/* ------------------------------------------------------------------- + $Rev: 1298 $ $Date: 2017-08-04 13:04:19 -0400 (Fri, 04 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for for CAL PK. + ------------------------------------------------------------------- */ + +#ifndef PKX_H +#define PKX_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* X5200 Addressing */ +#define X52BER ((volatile SATUINT32_t *) (PKX0_BASE + 0x00000000u)) +#define X52MMR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00001000u)) +#define X52TSR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00002000u)) +#define X52FPR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00003000u)) +#define X52LIR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00004000u)) +#define X52CSR ((volatile SATUINT32_t *) (PKX0_BASE + 0x00007F80u)) +#define X52CSRMERRS ((volatile SATUINT32_t *) (PKX0_BASE + 0x00007F8Cu)) +#define X52CSRMERRT0 ((volatile SATUINT32_t *) (PKX0_BASE + 0x00007F94u)) + +#if SAT_LITTLE_ENDIAN +#define X52BER_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00008000u)) +#define X52MMR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00009000u)) +#define X52TSR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x0000A000u)) +#define X52FPR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x0000B000u)) +#define X52DMACONFIG_ENDIAN 0x8 +#else +#define X52BER_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00000000u)) +#define X52MMR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00001000u)) +#define X52TSR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00002000u)) +#define X52FPR_ENDIAN ((volatile SATUINT32_t *) (PKX0_BASE + 0x00003000u)) +#define X52DMACONFIG_ENDIAN 0x0 +#endif + +/* X5200 Macros */ +#define X52GO(x) (0x10 | ((x)<<8)) + +/* Counter Measures */ +#define RANDLEN 4 + +/* X5200 CSRMAIN bit field masks. */ +#define X52CSRMAINRST 1 +#define X52CSRMAINCCMPLT 2 +#define X52CSRMAINCMPLT 4 +#define X52CSRMAINBUSY 8 +#define X52CSRMAINGO 0x10 +#define X52CSRMAINPURGE 0x20 +#define X52CSRMAINECDIS 0x40 +#define X52CSRMAINALARM 0x80 +#define X52CSRMAINLIRA ((0xFFF) << 8) +#define X52CSRMERRSSEC ((0x2) << 24) +#define X52CSRMERRSA 0x1FFF + +/* Address pointers for ROM'd P-curve moduli */ +#define P192_MOD (&uiROMMods[0]) +#define P224_MOD (&uiROMMods[1]) +#define P256_MOD (&uiROMMods[2]) +#define P384_MOD (&uiROMMods[3]) +#define P521_MOD (&uiROMMods[4]) + +/* X5200 Addressing Flags */ +#define X52BYTEREVERSE_FLAG 1 +#define X52WORDREVERSE_FLAG 2 +#define X52BYTEREVERSE 0x00002000 +#define X52WORDREVERSE 0x00004000 +#define X52ADDRESSRANGE 0x2000 + +/* X5200 DMA channel configuration constants. */ +#define X52CCR_DEFAULT 0 /* BSIZE=auto, ESWP=none, PROT=user, INC=inc */ +#define X52CCR_BSIZEAUTO 0 /* BSIZE=auto */ +#define X52CCR_BSIZEBYTE 0x10 /* BSIZE=byte */ +#define X52CCR_BSIZEHWORD 0x20 /* BSIZE=half word */ +#define X52CCR_BSIZEWORD 0x30 /* BSIZE=word */ +#define X52CCR_ESWPNONE 0 /* ESWP=none */ +#define X52CCR_ESWPWORD 0x8 /* ESWP=swap bytes in word [0123]->[3210] */ +#define X52CCR_PROTUSER 0 /* PROT=user */ +#define X52CCR_PROTPRIV 0x2 /* PROT=priv */ +#define X52CCR_INCADDR 0 /* INC=inc */ +#define X52CCR_NOINCADDR 0x1 /* INC=non-inc */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef PKX_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern void CALPKXIni(void); + +extern void CALPKMem32Load(volatile SATUINT32_t * puiDst, + const SATUINT32_t * puiSrc, SATUINT32_t uiNum ); + +extern SATR CALPKXTrfRes(SATBOOL bBlock); + +extern SATR CALPKXPreCompute(const SATUINT32_t* puiMod, SATUINT32_t* puiMu, + SATUINT32_t uiModLen); + +extern SATR CALPKXExpo(const SATUINT32_t* puiBase, const SATUINT32_t* puiExpo, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALPKXExpoCM(const SATUINT32_t* puiBase, + const SATUINT32_t* puiExpo, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiExpLen, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPKXDSASign(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXDSASignCM(const SATUINT32_t* puiHash, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXDSASHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiG, + const SATUINT32_t* puiK, const SATUINT32_t* puiX, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATUINT32_t uiDMAChConfig, const SATBOOL bCM); + +extern SATR CALPKXDSAVerify(const SATUINT32_t *puiHash, + const SATUINT32_t *puiG, const SATUINT32_t *puiY, + const SATUINT32_t *puiSigR, const SATUINT32_t *puiSigS, + const SATUINT32_t *puiP, const SATUINT32_t *puiPMu, + const SATUINT32_t *puiQ, const SATUINT32_t *puiQMu, + SATUINT32_t uiN, SATUINT32_t uiL); + +extern SATR CALPKXDSAVHDMA(const SATUINT32_t *puiExtInput, SATHASHTYPE eHashType, + SATUINT32_t uiMsgLen, const SATUINT32_t *puiG, const SATUINT32_t *puiY, + const SATUINT32_t *puiSigR, const SATUINT32_t *puiSigS, + const SATUINT32_t *puiP, const SATUINT32_t *puiPMu, const SATUINT32_t *puiQ, + const SATUINT32_t *puiQMu, SATUINT32_t uiN, SATUINT32_t uiL, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXModRed(const SATUINT32_t* puiA, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiALen, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPKXMMult(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, SATUINT32_t uiModLen, + SATUINT32_t* puiResult); + +extern SATR CALPKXMMultAdd(const SATUINT32_t* puiA, const SATUINT32_t* puiB, + const SATUINT32_t* puiC, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiModLen, SATUINT32_t* puiResult); + +extern SATR CALPKXECMult(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECMultTwist(const SATUINT32_t* puiMul, + const SATUINT32_t* puiPx,const SATUINT32_t* puiPy, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen, SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECMultCM(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t * puiN, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress, SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECMultTwistCM(const SATUINT32_t* puiMul, + const SATUINT32_t* puiPx, const SATUINT32_t* puiPy, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + const SATUINT32_t * puiN, SATUINT32_t uiLen, SATUINT32_t* puiRx, + SATUINT32_t* puiRy); + +extern SATR CALPKXECMultAdd(const SATUINT32_t* puiMul, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiB, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + SATUINT32_t uiLen, SATUINT32_t uiPtPCompress, SATUINT32_t uiPtQCompress, + SATUINT32_t* puiRx, SATUINT32_t* puiRy); + +extern SATR CALPKXECDSASign(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASignTwist(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx,const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASignCM(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASignTwistCM(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSigR, + SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASH(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + const SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASHCM(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiK, + const SATUINT32_t* puiD, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + const SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, SATUINT32_t uiDMAChConfig, + const SATBOOL bCM); + +extern SATR CALPKXECDSASTwistH(const SATUINT32_t* puiHash, + const SATHASHTYPE eHashType, const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, + const SATUINT32_t* puiK, const SATUINT32_t* puiD, const SATUINT32_t* puiB, + const SATUINT32_t* puiZ, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, const SATUINT32_t uiLen, + SATUINT32_t* puiSigR, SATUINT32_t* puiSigS); + +extern SATR CALPKXECDSASTwistHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiK, const SATUINT32_t* puiD, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t* puiSigR, SATUINT32_t* puiSigS, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECDSAVerify(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVerifyTwist(const SATUINT32_t* puiHash, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVH(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB,const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, + const SATUINT32_t uiLen, const SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB,const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiLen, + SATUINT32_t uiPtCompress, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECDSAVTwistH(const SATUINT32_t* puiHash, const SATHASHTYPE eHashType, + const SATUINT32_t* puiGx, const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, + const SATUINT32_t* puiQy, const SATUINT32_t* puiSigR, + const SATUINT32_t* puiSigS, const SATUINT32_t* puiB, const SATUINT32_t* puiZ, + const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, const SATUINT32_t uiLen, SATUINT32_t uiPtCompress); + +extern SATR CALPKXECDSAVTwistHDMA(const SATUINT32_t* puiExtInput, + SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, const SATUINT32_t* puiGx, + const SATUINT32_t* puiGy, const SATUINT32_t* puiQx, const SATUINT32_t* puiQy, + const SATUINT32_t* puiSigR, const SATUINT32_t* puiSigS, + const SATUINT32_t* puiB, const SATUINT32_t* puiZ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECDHC(const SATUINT32_t* puiS, const SATUINT32_t* puiWx, + const SATUINT32_t* puiWy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, const SATUINT32_t* puiK, const SATUINT32_t* puiR, + const SATUINT32_t* puiRMu, SATUINT32_t uiLen, SATUINT32_t uiPtCompress, + SATUINT32_t* puiZ); + +extern SATR CALPKXRSACRT(const SATUINT32_t* puiCipher, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, const SATUINT32_t* puiPMu, + const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, SATUINT32_t uiLen, + SATUINT32_t* puiPlain); + +extern SATR CALPKXRSACRTCM(const SATUINT32_t* puiCipher, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, + const SATUINT32_t* puiDQ, const SATUINT32_t* puiE, + const SATUINT32_t* puiP, const SATUINT32_t* puiQ, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, const SATUINT32_t uiLen, const SATUINT32_t uiELen, + SATUINT32_t* puiPlain); + +extern SATR CALPKXRSACRTSign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiCipher, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, + const SATUINT32_t* puiQMu, const SATUINT32_t* puiN, SATUINT32_t uiLen, + SATUINT32_t* puiS); + +extern SATR CALPKXRSACRTSignCM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, + const SATUINT32_t* puiP, const SATUINT32_t* puiQ, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiLen, SATUINT32_t* puiSig); + +extern SATR CALPKXRSACRTSHDMA(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiQInv, + const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, const SATUINT32_t* puiP, + const SATUINT32_t* puiPMu, const SATUINT32_t* puiQ, const SATUINT32_t* puiQMu, + const SATUINT32_t* puiN, SATUINT32_t uiMsgLen, SATUINT32_t uiModLen, + SATUINT32_t* puiSig, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXRSACRTSHDMACM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiE, const SATUINT32_t uiELen, + const SATUINT32_t* puiQInv, const SATUINT32_t* puiDP, const SATUINT32_t* puiDQ, + const SATUINT32_t* puiP, const SATUINT32_t* puiQ, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, SATUINT32_t uiLen, + SATUINT32_t* puiSig, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXRSASign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiD, const SATUINT32_t* puiN, + const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, SATUINT32_t* puiSig); + +extern SATR CALPKXRSASHDMA(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiD, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, SATUINT32_t* puiSig, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXRSAVerify(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiHash, const SATUINT32_t* puiE, SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiModLen, + const SATUINT32_t* puiS); + +extern SATR CALPKXRSAVHDMA(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, + const SATUINT32_t* puiExtInput, const SATUINT32_t* puiE,SATUINT32_t uiExpLen, + const SATUINT32_t* puiN, const SATUINT32_t* puiNMu, SATUINT32_t uiMsgLen, + SATUINT32_t uiModLen, const SATUINT32_t* puiS, SATUINT32_t uiDMAChConfig); + +extern SATR CALPKXECPtValidate(const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiB, const SATUINT32_t* puiMod, + const SATUINT32_t* puiMu, SATUINT32_t uiLen); + +extern SATR CALPKXECKeyPairGen(const SATUINT32_t* puiC, const SATUINT32_t* puiPx, + const SATUINT32_t* puiPy, const SATUINT32_t* puiMod, const SATUINT32_t* puiMu, + const SATUINT32_t* puiNM1, const SATUINT32_t* puiNM1Mu, const SATUINT32_t* puiB, + SATUINT32_t* puiD, SATUINT32_t* puiQx, SATUINT32_t* puiQy, SATUINT32_t uiLen); + +extern SATR CALPKXPurge52(SATBOOL bVerify); + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ +extern SATRESULT SATResults; + +/* -------- ------ --------- */ +/* External Global Constants */ +/* -------- ------ --------- */ +extern const SATUINT32_t uiROMMods[]; + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/pkxlib.h b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/pkxlib.h new file mode 100644 index 0000000..fb4c0fc --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/pkxlib.h @@ -0,0 +1,95 @@ +/* ------------------------------------------------------------------- + $Rev: 1434 $ $Date: 2017-10-20 16:46:16 -0400 (Fri, 20 Oct 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for PKX-5200 Library. + ------------------------------------------------------------------- */ + +#ifndef PKXLIB_H +#define PKXLIB_H + +#include "caltypes.h" +#include "calpolicy.h" + +#define PKX_JMP_NONE (0xFFFFu + PKX_OFFSET) + +/* jump table entry points: starting PC value */ +#define PKX_JMP_RECIP_PRECOMPUTE (0x0000 + PKX_OFFSET) +#define PKX_JMP_MOD_EXP (0x0002 + PKX_OFFSET) +#define PKX_JMP_RSA_CRT (0x0004 + PKX_OFFSET) +#define PKX_JMP_EC_PTMUL (0x0006 + PKX_OFFSET) +#define PKX_JMP_EC_DSA_SIGN (0x0008 + PKX_OFFSET) +#define PKX_JMP_EC_DSA_VERIFY (0x000A + PKX_OFFSET) +#define PKX_JMP_DSA_SIGN (0x000C + PKX_OFFSET) +#define PKX_JMP_DSA_VERIFY (0x000E + PKX_OFFSET) +#define PKX_JMP_MOD_MULT (0x0010 + PKX_OFFSET) +#define PKX_JMP_MOD_RED (0x0012 + PKX_OFFSET) +#define PKX_JMP_EC_PTDECOMP (0x0014 + PKX_OFFSET) +#define PKX_JMP_EC_DHC (0x0016 + PKX_OFFSET) +#define PKX_JMP_MOD_MULT_ADD (0x0018 + PKX_OFFSET) +#define PKX_JMP_EC_PTMUL_ADD (0x001A + PKX_OFFSET) +#define PKX_JMP_EC_PTVALIDATE (0x001C + PKX_OFFSET) +#define PKX_JMP_F5200_SHA (0x001E + PKX_OFFSET) +#define PKX_JMP_F5200_AES (0x0020 + PKX_OFFSET) +#define PKX_JMP_F5200_AESK (0x0022 + PKX_OFFSET) +#define PKX_JMP_F5200_GCM (0x0024 + PKX_OFFSET) +#define PKX_JMP_F5200_GHA (0x0026 + PKX_OFFSET) +#define PKX_JMP_F5200_AESKW (0x0028 + PKX_OFFSET) +#define PKX_JMP_F5200_AESKWP (0x002A + PKX_OFFSET) +#define PKX_JMP_RNG_INSTANTIATE (0x002C + PKX_OFFSET) +#define PKX_JMP_RNG_RESEED (0x002E + PKX_OFFSET) +#define PKX_JMP_RNG_GENERATE (0x0030 + PKX_OFFSET) +#define PKX_JMP_RNG_UNINSTANTIATE (0x0032 + PKX_OFFSET) +#define PKX_JMP_RNG_GETENTROPY (0x0034 + PKX_OFFSET) +#define PKX_JMP_F5200_SHA_HMAC (0x0036 + PKX_OFFSET) +#define PKX_JMP_F5200_AES_DMA (0x0038 + PKX_OFFSET) +#define PKX_JMP_RNG_CTRLSTATUS (0x003A + PKX_OFFSET) +#define PKX_JMP_F5200_SHA_DMA (0x003C + PKX_OFFSET) +#define PKX_JMP_SHX_KEYTREE (0x003E + PKX_OFFSET) +#define PKX_JMP_PKX_DSA_DMA (0x0040 + PKX_OFFSET) +#define PKX_JMP_PKX_RSACRT_SIGN (0x0042 + PKX_OFFSET) +#define PKX_JMP_PKX_RSA_SIGN (0x0044 + PKX_OFFSET) +#define PKX_JMP_PKX_RSA_VERIFY (0x0046 + PKX_OFFSET) +#define PKX_JMP_PKX_EC_DSA_DMA (0x0048 + PKX_OFFSET) +#define PKX_JMP_F5200_AES_KEYROLL (0x004A + PKX_OFFSET) +#define PKX_JMP_EXPM (0x004C + PKX_OFFSET) +#define PKX_JMP_RSACRTM (0x004E + PKX_OFFSET) +#define PKX_JMP_EC_PTMULM (0x0050 + PKX_OFFSET) +#define PKX_JMP_DSA_SIGN_M (0x0052 + PKX_OFFSET) +#define PKX_JMP_EC_DSA_SIGN_M (0x0054 + PKX_OFFSET) +#define PKX_JMP_EC_KEYPAIRGEN (0x0056 + PKX_OFFSET) +#define PKX_JMP_RSACRTCM_SIGN (0x0058 + PKX_OFFSET) +#define PKX_JMP_F5200_GCM_NEW (0x005A + PKX_OFFSET) +/* PKX PKRev 2180 */ +/* PKX SHARev 2160 */ +/* PKX AESRev 2135 */ +/* Hex Checksum: 0xd0d79866 */ + +extern const SATUINT32_t uiPKX_Flags; +extern const SATUINT32_t uiPKX_BERWords; +extern const SATUINT32_t uiPKX_LIRWords; +extern const SATUINT32_t uiPKX_Rev; +extern const SATUINT32_t uiPKX_LibSize; +extern const SATUINT32_t uiPKX_LibChksum; +extern const SATUINT32_t uiPKX_Lib[]; +extern SATBOOL bMPF300TS_ES; + +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/shaf5200.h b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/shaf5200.h new file mode 100644 index 0000000..da598d1 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/shaf5200.h @@ -0,0 +1,101 @@ +/* ------------------------------------------------------------------- + $Rev: 1296 $ $Date: 2017-08-01 13:54:48 -0400 (Tue, 01 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for SHA function hardware implementation for CAL. + ------------------------------------------------------------------- */ + +#ifndef SHAF5200_H +#define SHAF5200_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ +#ifndef SHAF5200_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern SATR shapkxctx(SATRESCONTEXTPTR const pContext, const void *pBuffer, + SATUINT32_t uiBufLen,void *pHash, const SATBOOL bFinal); + +extern SATR shapkxhmacctx(SATRESCONTEXTPTR const pContext, const void *pBuffer, + SATUINT32_t uiBufLen, void *pHash, const SATUINT8_t uiFlag); + +extern SATR shapkxctxload(SATRESCONTEXTPTR const pContext); + +extern void shapkxctxunload(SATRESCONTEXTPTR const pContext); + +extern SATR shapkxini(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen); + +extern SATR shapkxhmacini(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, + const void *pKey, SATUINT32_t uiKeyLen); + +extern SATR shapkxwrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR shapkxhmacwrite(const void *pBuffer, SATUINT32_t uiBufLen); + +extern SATR shapkxread(void *pHash, SATUINT32_t uiRevFlag); + +extern SATR shapkxkeytree(SATBOOL bPathSizeSel, const SATUINT32_t* puiKey, + SATUINT8_t uiOpType, const SATUINT32_t* puiPath, SATUINT32_t* puiKeyOut); + +extern SATR shapkxdma(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen, + const void *pExtSrc, const void *pExtDest, SATUINT32_t uiDMAChConfig); + +extern SATR shapkxhmacdma(SATMACTYPE eMACType, const SATUINT32_t *pKey, + SATUINT32_t uiKeyLen, const void *pMsg, SATUINT32_t uiMsgLen, + const void *pMAC, SATUINT32_t uiDMAChConfig); + +extern SATR shapkxhashtypeini(void); + + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/sym.h b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/sym.h new file mode 100644 index 0000000..2e07faa --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/sym.h @@ -0,0 +1,129 @@ +/* ------------------------------------------------------------------- + $Rev: 1292 $ $Date: 2017-07-26 15:12:11 -0400 (Wed, 26 Jul 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for Symmetric Key Cryptography in CAL. + ------------------------------------------------------------------- */ + +#ifndef SYM_H +#define SYM_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "calpolicy.h" +#include "caltypes.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef SYM_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ +extern SATR CALSymTrfRes(SATBOOL bBlock); + +extern SATR CALSymEncrypt(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen); + +extern SATR CALSymDecrypt(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen); + +extern SATR CALSymEncryptDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymDecryptDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymEncryptKR(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF); + +extern SATR CALSymDecryptKR(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF); + +extern SATR CALSymEncryptKRDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymDecryptKRDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, + void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymEncAuth(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen); + +extern SATR CALSymDecVerify(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen); + +extern SATR CALSymKw(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR CALSymKwp(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, + const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, + SATBOOL bWrap); + +extern SATR CALSymEncAuthDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen, SATUINT32_t uiDMAChConfig); + +extern SATR CALSymDecVerifyDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, + SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, + SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, + SATUINT32_t uiMACLen, SATUINT32_t uiDMAChConfig); + + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/utils.h b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/utils.h new file mode 100644 index 0000000..91474f0 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/utils.h @@ -0,0 +1,93 @@ +/* ------------------------------------------------------------------- + $Rev: 1300 $ $Date: 2017-08-07 11:36:02 -0400 (Mon, 07 Aug 2017) $ + ------------------------------------------------------------------- */ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ + +/* ------------------------------------------------------------------- + Description: + C header file for CAL utility functions. + ------------------------------------------------------------------- */ + +#ifndef UTILS_H +#define UTILS_H + +/* -------- */ +/* Includes */ +/* -------- */ +#include "caltypes.h" +#include "calenum.h" + + +/* ------- */ +/* Defines */ +/* ------- */ + +/* ---- ----------- */ +/* Type Definitions */ +/* ---- ----------- */ + +/* -------- -------- ---------- */ +/* External Function Prototypes */ +/* -------- -------- ---------- */ + +#ifndef UTILS_C +#ifdef __cplusplus +extern "C" { +#endif + +/* Published API Functions */ +/* --------- --- --------- */ + +/* Unpublished Function Prototypes */ +/* ----------- -------- ---------- */ +extern void CALMemCopy(void *pDst, const void *pSrc, SATUINT32_t uiNum8); + +extern void CALMemClear( void * pLoc, SATUINT32_t uiNum ); + +extern void CALMemClear32( SATUINT32_t* puiLoc, SATUINT32_t uiLen32 ); + +extern SATBOOL CALMemCmp(const void *pA, const void *pB, SATUINT32_t uiNum); + +extern void CALVol32MemLoad(volatile SATUINT32_t * puiDst, const void * pSrc, + SATUINT32_t uiNum32); + +extern void CALVol32MemRead(void * pDst, volatile SATUINT32_t * puiSrc, + SATUINT32_t uiNum32); + +extern void CALByteReverse(SATUINT32_t* puiArray, SATINT32_t iNumberBytes); + +extern void CALByteReverseWord(SATUINT32_t* puiArray, SATINT32_t iNumberWords); + +extern void CALWordReverse(SATUINT32_t *puiArray, SATINT32_t iNumberWords); + +extern void vAppendNonzero(void *puiArray, SATUINT32_t uiLen, + SATUINT32_t uiBlockSize); + +extern void vAppendZero(void *puiArray, SATUINT32_t uiLen, + SATUINT32_t uiBlockSize); + +/* -------- ------ --------- */ +/* External Global Variables */ +/* -------- ------ --------- */ + +#ifdef __cplusplus +} +#endif +#endif +#endif + diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/x52cfg_user.h b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/x52cfg_user.h new file mode 100644 index 0000000..c8d8648 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/middleware/cal/x52cfg_user.h @@ -0,0 +1,72 @@ +/* ----------- MERCURY SYSTEMS INC IP PROTECTION HEADER ---------------- +* (c) Mercury Systems, Inc. 2020. All rights reserved. +* Mercury Proprietary Information +* +* +* This file, the information contained herein, and its documentation are +* proprietary to Mercury Systems, Inc. This file, the information contained +* herein, and its documentation may only be used, duplicated, or disclosed +* in accordance with the terms of a written license agreement between the +* receiving party and Mercury or the receiving party and an authorized +* licensee of Mercury. +* +* Each copy of this file shall include all copyrights, trademarks, service +* marks, and proprietary rights notices, if any. +* +* ------------ MERCURY SYSTEMS INC IP PROTECTION HEADER --------------*/ +/* X5200 configuration */ +/* $Date: 2015-07-23 14:30:19 -0400 (Thu, 23 Jul 2015) $ $Rev: 2093 $ */ +/* ------------------------------------------------------------------- + Options: + * LIR ROM size : 4096 + * LIR RAM size : 2048 + * BER size : 1024 + * MMR size : 1024 + * TSR size : 1024 + * FPR size : 1024 + * Single error correct, dual error detect (SECDED) memory parity + * DMA enabled + * FPGA multipliers disabled + * AES enabled + - Fast key schedule generation + - GCM/GHASH enabled + - AES countermeasures enabled + * RNG enabled + * External PRNG disabled + * SHA enabled + - Fast SHA enabled + - SHA-1 enabled + - SHA-224 enabled + - SHA-256 enabled + - SHA-384 enabled + - SHA-512 enabled + - SHA-512/224 enabled + - SHA-512/256 enabled + - SHA countermeasures enabled + * P-curves populated in FCR: + - P-192 populated + - P-224 populated + - P-256 populated + - P-384 populated + - P-521 populated + * Data memory scrambling enabled + + ------------------------------------------------------------------- */ + +#ifndef X52CFG_H +#define X52CFG_H + +#define X52_CFG_MODEL 0xf5200 +#define X52_CFG_DATE 0x15072720 +#define X52_CFG_REV 0x0000082e +#define X52_CFG_OPT 0x0fd87ff9 +#define X52_CFG_OPT2 0xc0000000 +#define X52_LIR_LEN 0x1800 +#define X52_LIR_ROM_LEN 0x1000 +#define X52_LIR_RAM_LEN 0x0800 +#define X52_BER_LEN 0x400 +#define X52_MMR_LEN 0x400 +#define X52_TSR_LEN 0x400 +#define X52_FPR_LEN 0x400 + +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/README.md b/applications/user-crypto/miv-rv32-rsa-services/src/platform/README.md new file mode 100644 index 0000000..f7f6030 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/README.md @@ -0,0 +1,27 @@ +# Mi-V soft processor platform source code + +## Repo organization + +``` + + | + |-- drivers + | |- fpga_ip + | | | CoreGPIO + | | | CoreSysServices_PF + | | | CoreUARTapb + | | + | |- off_chip + | | | . + | | | . + | | + |-- hal + | | + |-- miv_rv32_hal + + +``` + +The drivers published here are compatible with the improved SoftConsole project folder structure being used in the latest [example projects](https://github.com/Mi-V-Soft-RISC-V/miv-rv32-bare-metal-examples). +These drivers can also be used with the legacy folder structure (projects released via Firmware Catalog) by defining the **LEGACY_DIR_STRUCTURE** macro in the SoftConsole project settings. + diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c new file mode 100644 index 0000000..1a0073f --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c @@ -0,0 +1,533 @@ +/******************************************************************************* + * (c) Copyright 2008-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file core_gpio.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreGPIO bare metal driver implementation. + * + */ +#include "coregpio_regs.h" +#include "core_gpio.h" + +/*-------------------------------------------------------------------------*//** + * + */ +#define GPIO_INT_ENABLE_MASK (uint32_t)0x00000008UL +#define OUTPUT_BUFFER_ENABLE_MASK 0x00000004UL + + +#define NB_OF_GPIO 32 + +#define CLEAR_ALL_IRQ32 (uint32_t)0xFFFFFFFF +#define CLEAR_ALL_IRQ16 (uint16_t)0xFFFF +#define CLEAR_ALL_IRQ8 (uint8_t)0xFF + +/*-------------------------------------------------------------------------*//** + * GPIO_init() + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_init +( + gpio_instance_t * this_gpio, + addr_t base_addr, + gpio_apb_width_t bus_width +) +{ + uint8_t i = 0; + addr_t cfg_reg_addr = base_addr; + + this_gpio->base_addr = base_addr; + this_gpio->apb_bus_width = bus_width; + + /* Clear configuration. */ + for( i = 0, cfg_reg_addr = base_addr; i < NB_OF_GPIO; ++i ) + { + HW_set_8bit_reg( cfg_reg_addr, 0 ); + cfg_reg_addr += 4; + } + /* Clear any pending interrupts */ + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, CLEAR_ALL_IRQ32 ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, (uint16_t)CLEAR_ALL_IRQ16 ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, (uint16_t)CLEAR_ALL_IRQ16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, (uint8_t)CLEAR_ALL_IRQ8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, (uint8_t)CLEAR_ALL_IRQ8 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_config + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_config +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint32_t config +) +{ + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + uint32_t cfg_reg_addr = this_gpio->base_addr; + cfg_reg_addr += (port_id * 4); + HW_set_32bit_reg( cfg_reg_addr, config ); + + /* + * Verify that the configuration was correctly written. Failure to read + * back the expected value may indicate that the GPIO port was configured + * as part of the hardware flow and cannot be modified through software. + * It may also indicate that the base address passed as parameter to + * GPIO_init() was incorrect. + */ + HAL_ASSERT( HW_get_32bit_reg( cfg_reg_addr ) == config ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_set_outputs + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_set_outputs +( + gpio_instance_t * this_gpio, + uint32_t value +) +{ + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, GPIO_OUT, value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, GPIO_OUT0, (uint16_t)value ); + HAL_set_16bit_reg( this_gpio->base_addr, GPIO_OUT1, (uint16_t)(value >> 16) ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT0, (uint8_t)value ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT1, (uint8_t)(value >> 8) ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT2, (uint8_t)(value >> 16) ); + HAL_set_8bit_reg( this_gpio->base_addr, GPIO_OUT3, (uint8_t)(value >> 24) ); + break; + + default: + HAL_ASSERT(0); + break; + } + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( GPIO_get_outputs( this_gpio ) == value ); +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_inputs + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_inputs +( + gpio_instance_t * this_gpio +) +{ + uint32_t gpio_in = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + gpio_in = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_IN ); + break; + + case GPIO_APB_16_BITS_BUS: + gpio_in |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_IN0 ); + gpio_in |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_IN1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + gpio_in |= HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN0 ); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN1 ) << 8); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN2 ) << 16); + gpio_in |= (HAL_get_8bit_reg( this_gpio->base_addr, GPIO_IN3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return gpio_in; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_outputs + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_outputs +( + gpio_instance_t * this_gpio +) +{ + uint32_t gpio_out = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + gpio_out = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ); + break; + + case GPIO_APB_16_BITS_BUS: + gpio_out |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT0 ); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + gpio_out |= HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT0 ); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT1 ) << 8); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT2 ) << 16); + gpio_out |= (HAL_get_16bit_reg( this_gpio->base_addr, GPIO_OUT3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return gpio_out; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_set_output + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_set_output +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint8_t value +) +{ + HAL_ASSERT( port_id < NB_OF_GPIO ); + + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + { + uint32_t outputs_state; + + outputs_state = HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ); + if ( 0 == value ) + { + outputs_state &= ~(1 << port_id); + } + else + { + outputs_state |= 1 << port_id; + } + HAL_set_32bit_reg( this_gpio->base_addr, GPIO_OUT, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HAL_get_32bit_reg( this_gpio->base_addr, GPIO_OUT ) == outputs_state ); + } + break; + + case GPIO_APB_16_BITS_BUS: + { + uint16_t outputs_state; + uint32_t gpio_out_reg_addr = this_gpio->base_addr + GPIO_OUT_REG_OFFSET + ((port_id >> 4) * 4); + + outputs_state = HW_get_16bit_reg( gpio_out_reg_addr ); + if ( 0 == value ) + { + outputs_state &= ~(1 << (port_id & 0x0F)); + } + else + { + outputs_state |= 1 << (port_id & 0x0F); + } + HW_set_16bit_reg( gpio_out_reg_addr, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HW_get_16bit_reg( gpio_out_reg_addr ) == outputs_state ); + } + break; + + case GPIO_APB_8_BITS_BUS: + { + uint8_t outputs_state; + uint32_t gpio_out_reg_addr = this_gpio->base_addr + GPIO_OUT_REG_OFFSET + ((port_id >> 3) * 4); + + outputs_state = HW_get_8bit_reg( gpio_out_reg_addr ); + if ( 0 == value ) + { + outputs_state &= ~(1 << (port_id & 0x07)); + } + else + { + outputs_state |= 1 << (port_id & 0x07); + } + HW_set_8bit_reg( gpio_out_reg_addr, outputs_state ); + + /* + * Verify that the output register was correctly written. Failure to read back + * the expected value may indicate that some of the GPIOs may not exist due to + * the number of GPIOs selected in the CoreGPIO hardware flow configuration. + * It may also indicate that the base address or APB bus width passed as + * parameter to the GPIO_init() function do not match the hardware design. + */ + HAL_ASSERT( HW_get_8bit_reg( gpio_out_reg_addr ) == outputs_state ); + } + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_drive_inout + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_drive_inout +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + gpio_inout_state_t inout_state +) +{ + uint32_t config; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + switch( inout_state ) + { + case GPIO_DRIVE_HIGH: + /* Set output high */ + GPIO_set_output( this_gpio, port_id, 1 ); + + /* Enable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config |= OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + case GPIO_DRIVE_LOW: + /* Set output low */ + GPIO_set_output( this_gpio, port_id, 0 ); + + /* Enable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config |= OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + case GPIO_HIGH_Z: + /* Disable output buffer */ + cfg_reg_addr = this_gpio->base_addr + (port_id * 4); + config = HW_get_8bit_reg( cfg_reg_addr ); + config &= ~OUTPUT_BUFFER_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, config ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_enable_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_enable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t cfg_value; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + cfg_reg_addr += (port_id * 4); + cfg_value = HW_get_8bit_reg( cfg_reg_addr ); + cfg_value |= GPIO_INT_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, cfg_value ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_disable_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_disable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t cfg_value; + uint32_t cfg_reg_addr = this_gpio->base_addr; + + HAL_ASSERT( port_id < NB_OF_GPIO ); + + if ( port_id < NB_OF_GPIO ) + { + cfg_reg_addr += (port_id * 4); + cfg_value = HW_get_8bit_reg( cfg_reg_addr ); + cfg_value &= ~GPIO_INT_ENABLE_MASK; + HW_set_8bit_reg( cfg_reg_addr, cfg_value ); + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_clear_irq + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_clear_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +) +{ + uint32_t irq_clr_value = ((uint32_t)1) << ((uint32_t)port_id); + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, irq_clr_value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, irq_clr_value >> 16 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, irq_clr_value >> 24 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/*-------------------------------------------------------------------------*//** + * GPIO_get_irq_sources + * See "core_gpio.h" for details of how to use this function. + */ +uint32_t GPIO_get_irq_sources +( + gpio_instance_t * this_gpio +) +{ + uint32_t intr_src = 0; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + intr_src = HAL_get_32bit_reg( this_gpio->base_addr, IRQ ); + break; + + case GPIO_APB_16_BITS_BUS: + intr_src |= HAL_get_16bit_reg( this_gpio->base_addr, IRQ0 ); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ1 ) << 16); + break; + + case GPIO_APB_8_BITS_BUS: + intr_src |= HAL_get_16bit_reg( this_gpio->base_addr, IRQ0 ); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ1 ) << 8); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ2 ) << 16); + intr_src |= (HAL_get_16bit_reg( this_gpio->base_addr, IRQ3 ) << 24); + break; + + default: + HAL_ASSERT(0); + break; + } + + return intr_src; +} + +/*-------------------------------------------------------------------------*//** + * GPIO_clear_all_irq_sources + * See "core_gpio.h" for details of how to use this function. + */ +void GPIO_clear_all_irq_sources +( + gpio_instance_t * this_gpio, + uint32_t bitmask +) +{ + uint32_t irq_clr_value = bitmask; + + switch( this_gpio->apb_bus_width ) + { + case GPIO_APB_32_BITS_BUS: + HAL_set_32bit_reg( this_gpio->base_addr, IRQ, irq_clr_value ); + break; + + case GPIO_APB_16_BITS_BUS: + HAL_set_16bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_16bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 16 ); + break; + + case GPIO_APB_8_BITS_BUS: + HAL_set_8bit_reg( this_gpio->base_addr, IRQ0, irq_clr_value ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ1, irq_clr_value >> 8 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ2, irq_clr_value >> 16 ); + HAL_set_8bit_reg( this_gpio->base_addr, IRQ3, irq_clr_value >> 24 ); + break; + + default: + HAL_ASSERT(0); + break; + } +} diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h new file mode 100644 index 0000000..88ba178 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h @@ -0,0 +1,722 @@ +/******************************************************************************* + * (c) Copyright 2008-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file core_gpio.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreGPIO bare metal driver public API. + * + */ + +/*=========================================================================*//** + @mainpage CoreGPIO Bare Metal Driver. + + @section intro_sec Introduction + The CoreGPIO hardware IP includes up to 32 general-purpose input/output GPIOs. + This driver provides a set of functions for controlling the GPIOs as part of a + bare-metal system where no operating system is available. These drivers + can be adapted for use as part of an operating system, but the implementation + of the adaptation layer between this driver and the operating system's driver + model is outside the scope of this driver. + + @section driver_configuration Driver Configuration + The individual IOs of CoreGPIO can be configured either in the hardware flow + or as part of the software application through calls to the GPIO_config() + function. GPIOs configured as part of the hardware are fixed and cannot be + modified using a call to the GPI_config() function. + + @section theory_op Theory of Operation + The CoreGPIO driver uses the Actel Hardware Abstraction Layer (HAL) to access + hardware registers. You must ensure that the Actel HAL is included as part of + your software project. The Actel HAL is available through the Actel Firmware + Catalog. + + The CoreGPIO driver functions are logically grouped into the following groups: + - Initialization + - Configuration + - Reading and writing GPIO state + - Interrupt control + + The CoreGPIO driver is initialized through a call to the GPIO_init() function. + The GPIO_init() function must be called before any other GPIO driver functions + can be called. + + Each GPIO port is individually configured through a call to the + GPIO_config() function. Configuration includes deciding if a GPIO port is + going to be used as input, output, or both. GPIO ports configured as inputs + are further configured to generate interrupts based on the state of input. + Interrupts is either level- or edge-sensitive. + Note that a CoreGPIO hardware instance is generated as part of the hardware + flow with a fixed configuration for some or all of its IOs. + Attempting to modify the configuration of such a hardware-configured IO using + the GPIO_config() function has no effect. + + The state of the GPIO ports can be read and written using the following + functions: + - GPIO_get_inputs() + - GPIO_get_outputs() + - GPIO_set_outputs() + - GPIO_drive_inout() + + Interrupts generated by GPIO ports configured as inputs are controlled using + the following functions: + - GPIO_enable_irq() + - GPIO_disable_irq() + - GPIO_clear_irq() + - GPIO_get_irq_sources() + - GPIO_clear_all_irq_sources() + + *//*=========================================================================*/ +#ifndef CORE_GPIO_H_ +#define CORE_GPIO_H_ + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + The gpio_id_t enumeration is used to identify GPIOs as part of the + parameter to functions: + - GPIO_config(), + - GPIO_drive_inout(), + - GPIO_enable_int(), + - GPIO_disable_int(), + - GPIO_clear_int() + */ +typedef enum __gpio_id_t +{ + GPIO_0 = 0, + GPIO_1 = 1, + GPIO_2 = 2, + GPIO_3 = 3, + GPIO_4 = 4, + GPIO_5 = 5, + GPIO_6 = 6, + GPIO_7 = 7, + GPIO_8 = 8, + GPIO_9 = 9, + GPIO_10 = 10, + GPIO_11 = 11, + GPIO_12 = 12, + GPIO_13 = 13, + GPIO_14 = 14, + GPIO_15 = 15, + GPIO_16 = 16, + GPIO_17 = 17, + GPIO_18 = 18, + GPIO_19 = 19, + GPIO_20 = 20, + GPIO_21 = 21, + GPIO_22 = 22, + GPIO_23 = 23, + GPIO_24 = 24, + GPIO_25 = 25, + GPIO_26 = 26, + GPIO_27 = 27, + GPIO_28 = 28, + GPIO_29 = 29, + GPIO_30 = 30, + GPIO_31 = 31 +} gpio_id_t; + +/*-------------------------------------------------------------------------*//** + Possible width of the APB bus + */ +typedef enum __gpio_apb_width_t +{ + GPIO_APB_8_BITS_BUS = 0, + GPIO_APB_16_BITS_BUS = 1, + GPIO_APB_32_BITS_BUS = 2, + GPIO_APB_UNKNOWN_BUS_WIDTH = 3 +} gpio_apb_width_t; + +/*-------------------------------------------------------------------------*//** + Structure instance holding all data regarding the CoreGPIO + */ +typedef struct __gpio_instance_t +{ + addr_t base_addr; + gpio_apb_width_t apb_bus_width; +} gpio_instance_t; + +/*-------------------------------------------------------------------------*//** + GPIO ports definitions used to identify GPIOs as part of the parameter to + function GPIO_set_outputs(). + These definitions are also be used to identity GPIO through logical operations + on the return value of function GPIO_get_inputs(). + # GPIO_0_MASK + # GPIO_1_MASK + # GPIO_2_MASK + # GPIO_3_MASK + # GPIO_4_MASK + # GPIO_5_MASK + # GPIO_6_MASK + # GPIO_7_MASK + # GPIO_8_MASK + # GPIO_9_MASK + # GPIO_10_MASK + # GPIO_11_MASK + # GPIO_12_MASK + # GPIO_13_MASK + # GPIO_14_MASK + # GPIO_15_MASK + # GPIO_16_MASK + # GPIO_17_MASK + # GPIO_18_MASK + # GPIO_19_MASK + # GPIO_20_MASK + # GPIO_21_MASK + # GPIO_22_MASK + # GPIO_23_MASK + # GPIO_24_MASK + # GPIO_25_MASK + # GPIO_26_MASK + # GPIO_27_MASK + # GPIO_28_MASK + # GPIO_29_MASK + # GPIO_30_MASK + # GPIO_31_MASK + */ +#define GPIO_0_MASK 0x00000001UL +#define GPIO_1_MASK 0x00000002UL +#define GPIO_2_MASK 0x00000004UL +#define GPIO_3_MASK 0x00000008UL +#define GPIO_4_MASK 0x00000010UL +#define GPIO_5_MASK 0x00000020UL +#define GPIO_6_MASK 0x00000040UL +#define GPIO_7_MASK 0x00000080UL +#define GPIO_8_MASK 0x00000100UL +#define GPIO_9_MASK 0x00000200UL +#define GPIO_10_MASK 0x00000400UL +#define GPIO_11_MASK 0x00000800UL +#define GPIO_12_MASK 0x00001000UL +#define GPIO_13_MASK 0x00002000UL +#define GPIO_14_MASK 0x00004000UL +#define GPIO_15_MASK 0x00008000UL +#define GPIO_16_MASK 0x00010000UL +#define GPIO_17_MASK 0x00020000UL +#define GPIO_18_MASK 0x00040000UL +#define GPIO_19_MASK 0x00080000UL +#define GPIO_20_MASK 0x00100000UL +#define GPIO_21_MASK 0x00200000UL +#define GPIO_22_MASK 0x00400000UL +#define GPIO_23_MASK 0x00800000UL +#define GPIO_24_MASK 0x01000000UL +#define GPIO_25_MASK 0x02000000UL +#define GPIO_26_MASK 0x04000000UL +#define GPIO_27_MASK 0x08000000UL +#define GPIO_28_MASK 0x10000000UL +#define GPIO_29_MASK 0x20000000UL +#define GPIO_30_MASK 0x40000000UL +#define GPIO_31_MASK 0x80000000UL + +/*-------------------------------------------------------------------------*//** + * GPIO modes + * # GPIO_INPUT_MODE + * # GPIO_OUTPUT_MODE + * # GPIO_INOUT_MODE + */ +#define GPIO_INPUT_MODE 0x0000000002UL +#define GPIO_OUTPUT_MODE 0x0000000005UL +#define GPIO_INOUT_MODE 0x0000000003UL + +/*-------------------------------------------------------------------------*//** + * Possible GPIO inputs interrupt configurations. + * # GPIO_IRQ_LEVEL_HIGH + * # GPIO_IRQ_LEVEL_LOW + * # GPIO_IRQ_EDGE_POSITIVE + * # GPIO_IRQ_EDGE_NEGATIVE + * # GPIO_IRQ_EDGE_BOTH + */ +#define GPIO_IRQ_LEVEL_HIGH 0x0000000000UL +#define GPIO_IRQ_LEVEL_LOW 0x0000000020UL +#define GPIO_IRQ_EDGE_POSITIVE 0x0000000040UL +#define GPIO_IRQ_EDGE_NEGATIVE 0x0000000060UL +#define GPIO_IRQ_EDGE_BOTH 0x0000000080UL + +/*-------------------------------------------------------------------------*//** + * Possible states for GPIO configured as INOUT + */ +typedef enum gpio_inout_state +{ + GPIO_DRIVE_LOW = 0, + GPIO_DRIVE_HIGH, + GPIO_HIGH_Z +} gpio_inout_state_t; + +/*-------------------------------------------------------------------------*//** + The GPIO_init() function initializes a CoreGPIO hardware instance and the data + structure associated with the CoreGPIO hardware instance. + Note that a CoreGPIO hardware instance is generated with a fixed configuration + for some or all of its IOs as part of the hardware flow. + Attempting to modify the configuration of such a hardware-configured IO using + the GPIO_config() function has no effect. + + @param this_gpio + Pointer to the gpio_instance_t data structure instance holding all data + regarding the CoreGPIO hardware instance being initialized. A pointer to the + same data structure is used in subsequent calls to the CoreGPIO driver + functions in order to identify the CoreGPIO instance that must perform the + operation implemented by the called driver function. + + @param base_addr + The base_addr parameter is the base address in the memory map of the + processor for the registers of the GPIO instance being initialized. + + @param bus_width + The bus_width parameter informs the driver of the APB bus width selected + during the hardware flow configuration of the CoreGPIO hardware instance. It + indicates to the driver whether the CoreGPIO hardware registers are visible + as 8, 16, or 32-bits registers. Allowed values are: + - GPIO_APB_8_BITS_BUS + - GPIO_APB_16_BITS_BUS + - GPIO_APB_32_BITS_BUS + + @return + none. + + @example + @code + #define COREGPIO_BASE_ADDR 0xC2000000 + + gpio_instance_t g_gpio; + + void system_init( void ) + { + GPIO_init( &g_gpio, COREGPIO_BASE_ADDR, GPIO_APB_32_BITS_BUS ); + } + @endcode + */ +void GPIO_init +( + gpio_instance_t * this_gpio, + addr_t base_addr, + gpio_apb_width_t bus_width +); + +/*-------------------------------------------------------------------------*//** + The GPIO_config() function is used to configure an individual GPIO port. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO port to be configured. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @param config + The config parameter specifies the configuration to be applied to the GPIO + port identified by the first parameter. It is a logical OR of GPIO mode and + interrupt mode. The interrupt mode is only relevant if the GPIO is + configured as an input. + - Possible modes are: + - GPIO_INPUT_MODE, + - GPIO_OUTPUT_MODE, + - GPIO_INOUT_MODE. + - Possible interrupt modes are: + - GPIO_IRQ_LEVEL_HIGH, + - GPIO_IRQ_LEVEL_LOW, + - GPIO_IRQ_EDGE_POSITIVE, + - GPIO_IRQ_EDGE_NEGATIVE, + - GPIO_IRQ_EDGE_BOTH + + @return + none. + + @example + For example, the following call configures GPIO 4 as an input that generates + interrupts on a low-to-high transition of the input: + @code + GPIO_config( &g_gpio, GPIO_4, GPIO_INPUT_MODE | GPIO_IRQ_EDGE_POSITIVE ); + @endcode + */ +void GPIO_config +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint32_t config +); + +/*-------------------------------------------------------------------------*//** + The GPIO_set_outputs() function is used to set the state of the GPIO ports + configured as outputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param value + The value parameter specifies the state of the GPIO ports configured as + outputs. It is a bit mask of the form (GPIO_n_MASK | GPIO_m_MASK), where n + and m are numbers identifying GPIOs. + For example, (GPIO_0_MASK | GPIO_1_MASK | GPIO_2_MASK ) specifies that the + first, second, and third GPIO must be set high and all other outputs set + low. + + @return + none. + + @example + Set GPIO 0 and 8 outputs high and all other GPIO outputs low. + @code + GPIO_set_outputs( &g_gpio, GPIO_0_MASK | GPIO_8_MASK ); + @endcode + + @example + Set GPIO 2 and 4 outputs low without affecting the other GPIO outputs. + @code + uint32_t gpio_outputs; + gpio_outputs = GPIO_get_outputs( &g_gpio ); + gpio_outputs &= ~( GPIO_2_MASK | GPIO_4_MASK ); + GPIO_set_outputs( &g_gpio, gpio_outputs ); + @endcode + + @see GPIO_get_outputs() + */ +void GPIO_set_outputs +( + gpio_instance_t * this_gpio, + uint32_t value +); + +/*-------------------------------------------------------------------------*//** + The GPIO_set_output() function is used to set the state of a single GPIO port + configured as an output. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter specifies the GPIO port that has its output set by a + call to this function. + + @param value + The value parameter specifies the desired state for the GPIO output. A value + of 0 sets the output low, and a value of 1 sets the port high. + + @return + none. + */ +void GPIO_set_output +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + uint8_t value +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_inputs() function is used to read the state of all GPIOs + configured as inputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @return + This function returns a 32-bit unsigned integer, where each bit represents + the state of an input. The least significant bit represents the state of + GPIO 0, and the most significant bit represents the state of GPIO 31. + */ +uint32_t GPIO_get_inputs +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_outputs() function is used to read the current state of all + GPIO outputs. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @return + This function returns a 32-bit unsigned integer where each bit represents + the state of an output. The least significant bit represents the state + of GPIO 0, and the most significant bit represents the state of GPIO 31. + */ +uint32_t GPIO_get_outputs +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_drive_inout() function is used to set the output state of a + GPIO configured as INOUT. An INOUT GPIO is in one of three states: + - high + - low + - high impedance + + An INOUT output is typically be used where several devices drive the state of + a signal. The high and low states are equivalent to the high and low states of + a GPIO configured as an output. The high impedance state is used to prevent + the GPIO from driving the state of the output and therefore allow reading the + state of the GPIO as an input. + Note that the GPIO port you wish to use as INOUT through this function + must be configurable through software. Therefore, the GPIO ports used as INOUT + must not have a fixed configuration selected as part of the hardware flow. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO for which this function will + change the output state. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @param inout_state + The inout_state parameter specifies the state of the I/O identified by the + first parameter. Possible states are: + - GPIO_DRIVE_HIGH, + - GPIO_DRIVE_LOW, + - GPIO_HIGH_Z (high impedance) + + @return + none. + + @example + The call to GPIO_drive_inout() below will set the GPIO 7 output to + high impedance state. + @code + GPIO_drive_inout( &g_gpio, GPIO_7, GPIO_HIGH_Z ); + @endcode + */ +void GPIO_drive_inout +( + gpio_instance_t * this_gpio, + gpio_id_t port_id, + gpio_inout_state_t inout_state +); + +/*-------------------------------------------------------------------------*//** + The GPIO_enable_irq() function is used to enable an interrupt to be + generated based on the state of the input identified as a parameter. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO input that the call to + GPIO_enable_irq() enables to generate interrupts. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + @example + The call to GPIO_enable_irq() below allows GPIO 8 to generate interrupts. + + @code + GPIO_enable_irq( &g_gpio, GPIO_8 ); + @endcode + */ +void GPIO_enable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_disable_irq() function is used to disable interrupts from being + generated based on the state of the input specified as a parameter. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO input that the call to + GPIO_disable_irq() disables from generating interrupts. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + @example + The call to GPIO_disable_irq() below prevents GPIO 8 from generating + interrupts. + @code + GPIO_disable_irq( &g_gpio, GPIO_8 ); + @endcode + */ +void GPIO_disable_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_clear_irq() function is used to clear the interrupt generated by + the GPIO specified as a parameter. The GPIO_clear_irq() function must be + called as part of a GPIO interrupt service routine (ISR) in order to prevent + the same interrupt event from re-triggering a call to the GPIO ISR. + Note that interrupts may also need to be cleared in the processor's + interrupt controller. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param port_id + The port_id parameter identifies the GPIO input for which to clear the + interrupt. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the + first GPIO port and GPIO_31 the last one. + + @return + none. + + @example + The example below demonstrates the use of the GPIO_clear_irq() function as + part of the GPIO-9 interrupt service routine. + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + GPIO_clear_irq( &g_gpio, GPIO_9 ); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +void GPIO_clear_irq +( + gpio_instance_t * this_gpio, + gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The GPIO_get_irq_sources() function is used to identify the source of the + interrupt. i.e. to That is the GPIO input line, whose state change triggered + the interrupt. The GPIO_get_irq_sources() function must be called as part of + a GPIO interrupt service routine (ISR) in order to determine the interrupt + source. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @return + This function returns a 32-bit unsigned integer, where each bit represents + the pin number of a GPIO. + + @example + The example below demonstrates the use of the GPIO_get_irq_sources() + function as part of the GPIO-9 interrupt service routine. + + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + GPIO_clear_all_irq_sources(g_p_mygpio, GPIO_get_irq_sources(g_p_mygpio)); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +uint32_t GPIO_get_irq_sources +( + gpio_instance_t * this_gpio +); + +/*-------------------------------------------------------------------------*//** + The GPIO_clear_all_irq_sources() function is used to clear all the active + interrupts generated by the GPIO specified as a parameter. The + GPIO_clear_all_irq_sources() function must be called as part of a GPIO + interrupt service routine (ISR) in order to prevent the same interrupt event + from re-triggering a call to the GPIO ISR. + Note that interrupts may also need to be cleared in the processor's + interrupt controller. + + @param this_gpio + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. + + @param bitmask + This bitmask parameter is a 32-bit unsigned integer where each bit + represents the GPIO pin used to clear the interrupt bit register of the + corresponding GPIO bit. The least significant bit represents the status of + GPIO 0, and the most significant bit represents the status of GPIO 31. + + @return + none. + + @example + The example below demonstrates the use of the GPIO_clear_all_irq_sources() + function as part of the GPIO-9 interrupt service routine. + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + do_interrupt_processing(); + + GPIO_clear_all_irq_sources(g_p_mygpio, GPIO_get_irq_sources(g_p_mygpio)); + + NVIC_ClearPendingIRQ( GPIO9_IRQn ); + } + @endcode + */ +void GPIO_clear_all_irq_sources +( + gpio_instance_t * this_gpio, + uint32_t bitmask +); + +#ifdef __cplusplus +} +#endif + +#endif /* CORE_GPIO_H_ */ diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h new file mode 100644 index 0000000..41f5b7c --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h @@ -0,0 +1,45 @@ +/******************************************************************************* + * (c) Copyright 2008-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file coregpio_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreGPIO register definitions + * + */ + +#ifndef __CORE_GPIO_REGISTERS_H +#define __CORE_GPIO_REGISTERS_H 1 + +/*------------------------------------------------------------------------------ + * + */ +#define IRQ_REG_OFFSET 0x80 + +#define IRQ0_REG_OFFSET 0x80 +#define IRQ1_REG_OFFSET 0x84 +#define IRQ2_REG_OFFSET 0x88 +#define IRQ3_REG_OFFSET 0x8C + +/*------------------------------------------------------------------------------ + * + */ +#define GPIO_IN_REG_OFFSET 0x90 + +#define GPIO_IN0_REG_OFFSET 0x90 +#define GPIO_IN1_REG_OFFSET 0x94 +#define GPIO_IN2_REG_OFFSET 0x98 +#define GPIO_IN3_REG_OFFSET 0x9C + +/*------------------------------------------------------------------------------ + * + */ +#define GPIO_OUT_REG_OFFSET 0xA0 + +#define GPIO_OUT0_REG_OFFSET 0xA0 +#define GPIO_OUT1_REG_OFFSET 0xA4 +#define GPIO_OUT2_REG_OFFSET 0xA8 +#define GPIO_OUT3_REG_OFFSET 0xAC + +#endif /* __CORE_GPIO_REGISTERS_H */ diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c new file mode 100644 index 0000000..1fd3dd6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c @@ -0,0 +1,1495 @@ +/******************************************************************************* + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * CoreI2C software driver implementation. + * + */ + +#include "core_smbus_regs.h" +#include "core_i2c.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * I2C transaction direction. + */ +#define WRITE_DIR 0u +#define READ_DIR 1u + +/* -- TRANSACTIONS TYPES -- */ +#define NO_TRANSACTION 0u +#define MASTER_WRITE_TRANSACTION 1u +#define MASTER_READ_TRANSACTION 2u +#define MASTER_RANDOM_READ_TRANSACTION 3u +#define WRITE_SLAVE_TRANSACTION 4u +#define READ_SLAVE_TRANSACTION 5u + +/* -- SMBUS H/W STATES -- */ +/* -- MASTER STATES -- */ +#define ST_BUS_ERROR 0x00u /* Bus error during MST or selected slave modes */ +#define ST_I2C_IDLE 0xF8u /* No activity and no interrupt either... */ +#define ST_START 0x08u /* start condition sent */ +#define ST_RESTART 0x10u /* repeated start */ +#define ST_SLAW_ACK 0x18u /* SLA+W sent, ack received */ +#define ST_SLAW_NACK 0x20u /* SLA+W sent, nack received */ +#define ST_TX_DATA_ACK 0x28u /* Data sent, ACK'ed */ +#define ST_TX_DATA_NACK 0x30u /* Data sent, NACK'ed */ +#define ST_LOST_ARB 0x38u /* Master lost arbitration */ +#define ST_SLAR_ACK 0x40u /* SLA+R sent, ACK'ed */ +#define ST_SLAR_NACK 0x48u /* SLA+R sent, NACK'ed */ +#define ST_RX_DATA_ACK 0x50u /* Data received, ACK sent */ +#define ST_RX_DATA_NACK 0x58u /* Data received, NACK sent */ +#define ST_RESET_ACTIVATED 0xD0u /* Master reset is activated */ +#define ST_STOP_TRANSMIT 0xE0u /* Stop has been transmitted */ + +/* -- SLAVE STATES -- */ +#define ST_SLAVE_SLAW 0x60u /* SLA+W received */ +#define ST_SLAVE_SLAR_ACK 0xA8u /* SLA+R received, ACK returned */ +#define ST_SLV_LA 0x68u /* Slave lost arbitration */ +#define ST_GCA 0x70u /* GCA received */ +#define ST_GCA_LA 0x78u /* GCA lost arbitration */ +#define ST_RDATA 0x80u /* Data received */ +#define ST_SLA_NACK 0x88u /* Slave addressed, NACK returned */ +#define ST_GCA_ACK 0x90u /* Previously addresses with GCA, data ACKed */ +#define ST_GCA_NACK 0x98u /* GCA addressed, NACK returned */ +#define ST_RSTOP 0xA0u /* Stop received */ +#define ST_SLARW_LA 0xB0u /* Arbitration lost */ +#define ST_RACK 0xB8u /* Byte sent, ACK received */ +#define ST_SLAVE_RNACK 0xC0u /* Byte sent, NACK received */ +#define ST_FINAL 0xC8u /* Final byte sent, ACK received */ +#define ST_SLV_RST 0xD8u /* Slave reset state */ + + +/* I2C Channel base offset */ +#define CHANNEL_BASE_SHIFT 5u +#define CHANNEL_MASK 0x1E0u + +/* + * Maximum address offset length in slave write-read transactions. + * A maximum of two bytes will be interpreted as address offset within the slave + * tx buffer. + */ +#define MAX_OFFSET_LENGTH 2u + +/*------------------------------------------------------------------------------ + * I2C interrupts control functions implemented "i2c_interrupt.c". + * the implementation of these functions depend on the underlying hardware + * design and how the CoreI2C interrupt line is connected to the system's + * interrupt controller. + */ +void I2C_enable_irq( i2c_instance_t * this_i2c ); +void I2C_disable_irq( i2c_instance_t * this_i2c ); +static void enable_slave_if_required(i2c_instance_t * this_i2c); + +/*------------------------------------------------------------------------------ + * I2C_init() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_init +( + i2c_instance_t * this_i2c, + addr_t base_address, + uint8_t ser_address, + i2c_clock_divider_t ser_clock_speed +) +{ + psr_t saved_psr; + uint_fast16_t clock_speed = (uint_fast16_t)ser_clock_speed; + + /* + * We need to disable ints while doing this as there is no guarantee we + * have not been called already and the ISR is active. + */ + saved_psr = HAL_disable_interrupts(); + + /* + * Initialize all items of the this_i2c data structure to zero. This + * initializes all state variables to their init value. It relies on + * the fact that NO_TRANSACTION, I2C_SUCCESS and I2C_RELEASE_BUS all + * have an actual value of zero. + */ + memset(this_i2c, 0, sizeof(i2c_instance_t)); + + /* + * Set base address of I2C hardware used by this instance. + */ + this_i2c->base_address = base_address; + + /* + * Update Serial address of the device + */ + this_i2c->ser_address = ((uint_fast8_t)ser_address << 1u); + + /* + * Configure hardware. + */ + HAL_set_8bit_reg_field(this_i2c->base_address, ENS1, 0x00); /* Reset I2C hardware. */ + HAL_set_8bit_reg_field(this_i2c->base_address, ENS1, 0x01); /* set enable bit */ + HAL_set_8bit_reg_field(this_i2c->base_address, CR2, ( (clock_speed >> 2) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c->base_address, CR1, ( (clock_speed >> 1) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c->base_address, CR0, ( clock_speed & 0x01) ); + + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS, this_i2c->ser_address); + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, this_i2c->ser_address); + + /* + * Finally safe to enable interrupts. + */ + HAL_restore_interrupts( saved_psr ); +} +/*------------------------------------------------------------------------------ + * I2C_channel_init() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_channel_init +( + i2c_instance_t * this_i2c_channel, + i2c_instance_t * this_i2c, + i2c_channel_number_t channel_number, + i2c_clock_divider_t ser_clock_speed +) +{ + psr_t saved_psr; + uint_fast16_t clock_speed = (uint_fast16_t)ser_clock_speed; + + HAL_ASSERT(channel_number < I2C_MAX_CHANNELS); + HAL_ASSERT(I2C_CHANNEL_0 != channel_number); + + /* + * Cannot allow channel 0 in this function as we will trash the hardware + * base address and slave address. + */ + if ((channel_number < I2C_MAX_CHANNELS) && + (I2C_CHANNEL_0 != channel_number)) + { + /* + * We need to disable ints while doing this as the hardware should already + * be active at this stage. + */ + saved_psr = HAL_disable_interrupts(); + + /* + * Initialize channel data. + */ + memset(this_i2c_channel, 0, sizeof(i2c_instance_t)); + + this_i2c_channel->base_address = + ((this_i2c->base_address) & ~((addr_t)CHANNEL_MASK)) + | (((addr_t)channel_number) << CHANNEL_BASE_SHIFT); + + this_i2c_channel->ser_address = this_i2c->ser_address; + + HAL_set_8bit_reg_field(this_i2c_channel->base_address, ENS1, 0x00); /* Reset I2C channel hardware. */ + HAL_set_8bit_reg_field(this_i2c_channel->base_address, ENS1, 0x01); /* set enable bit */ + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR2, ( (clock_speed >> 2) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR1, ( (clock_speed >> 1) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR0, ( clock_speed & 0x01) ); + /* + * Finally safe to enable interrupts. + */ + HAL_restore_interrupts( saved_psr ); + } +} + +/*------------------------------------------------------------------------------ + * I2C_write() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_write +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * write_buffer, + uint16_t write_size, + uint8_t options +) +{ + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + saved_psr = HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_WRITE_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_WRITE_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + this_i2c->dir = WRITE_DIR; + this_i2c->master_tx_buffer = write_buffer; + this_i2c->master_tx_size = write_size; + this_i2c->master_tx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_read() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +) +{ + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + saved_psr = HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_READ_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_READ_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + + this_i2c->dir = READ_DIR; + + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_write_read() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_write_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * addr_offset, + uint16_t offset_size, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +) +{ + HAL_ASSERT(offset_size > 0u); + HAL_ASSERT(addr_offset != (uint8_t *)0); + HAL_ASSERT(read_size > 0u); + HAL_ASSERT(read_buffer != (uint8_t *)0); + + this_i2c->master_status = I2C_FAILED; + + if((read_size > 0u) && (offset_size > 0u)) + { + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + saved_psr = HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_RANDOM_READ_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_RANDOM_READ_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + + this_i2c->dir = WRITE_DIR; + + this_i2c->master_tx_buffer = addr_offset; + this_i2c->master_tx_size = offset_size; + this_i2c->master_tx_idx = 0u; + + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + + HAL_restore_interrupts( saved_psr ); + } +} + +/*------------------------------------------------------------------------------ + * I2C_get_status() + * See "core_i2c.h" for details of how to use this function. + */ +i2c_status_t I2C_get_status +( + i2c_instance_t * this_i2c +) +{ + i2c_status_t i2c_status ; + + i2c_status = this_i2c->master_status ; + + return i2c_status; +} + +/*------------------------------------------------------------------------------ + * I2C_wait_complete() + * See "core_i2c.h" for details of how to use this function. + */ +i2c_status_t I2C_wait_complete +( + i2c_instance_t * this_i2c, + uint32_t timeout_ms +) +{ + i2c_status_t i2c_status; + psr_t saved_psr; + /* + * Because we have no idea of what CPU we are supposed to be running on + * we need to guard this write to the timeout value to avoid ISR/user code + * interaction issues. Checking the status below should be fine as only a + * single byte should change in that. + */ + saved_psr = HAL_disable_interrupts(); + this_i2c->master_timeout_ms = timeout_ms; + HAL_restore_interrupts( saved_psr ); + + /* Run the loop until state returns I2C_FAILED or I2C_SUCESS*/ + do { + i2c_status = this_i2c->master_status; + } while(I2C_IN_PROGRESS == i2c_status); + return i2c_status; +} + +/*------------------------------------------------------------------------------ + * I2C_system_tick() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_system_tick +( + i2c_instance_t * this_i2c, + uint32_t ms_since_last_tick +) +{ + if(this_i2c->master_timeout_ms != I2C_NO_TIMEOUT) + { + if(this_i2c->master_timeout_ms > ms_since_last_tick) + { + this_i2c->master_timeout_ms -= ms_since_last_tick; + } + else + { + psr_t saved_psr; + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + /* + * Mark current transaction as having timed out. + */ + this_i2c->master_status = I2C_TIMED_OUT; + this_i2c->transaction = NO_TRANSACTION; + this_i2c->is_transaction_pending = 0; + + HAL_restore_interrupts( saved_psr ); + + /* + * Make sure we do not incorrectly signal a timeout for subsequent + * transactions. + */ + this_i2c->master_timeout_ms = I2C_NO_TIMEOUT; + } + } +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_tx_buffer() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_tx_buffer +( + i2c_instance_t * this_i2c, + const uint8_t * tx_buffer, + uint16_t tx_size +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + this_i2c->slave_tx_buffer = tx_buffer; + this_i2c->slave_tx_size = tx_size; + this_i2c->slave_tx_idx = 0u; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_rx_buffer() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_rx_buffer +( + i2c_instance_t * this_i2c, + uint8_t * rx_buffer, + uint16_t rx_size +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + this_i2c->slave_rx_buffer = rx_buffer; + this_i2c->slave_rx_size = rx_size; + this_i2c->slave_rx_idx = 0u; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_mem_offset_length() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_mem_offset_length +( + i2c_instance_t * this_i2c, + uint8_t offset_length +) +{ + HAL_ASSERT(offset_length <= MAX_OFFSET_LENGTH); + + /* + * Single byte update, should be interrupt safe + */ + if(offset_length > MAX_OFFSET_LENGTH) + { + this_i2c->slave_mem_offset_length = MAX_OFFSET_LENGTH; + } + else + { + this_i2c->slave_mem_offset_length = offset_length; + } +} + +/*------------------------------------------------------------------------------ + * I2C_register_write_handler() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_register_write_handler +( + i2c_instance_t * this_i2c, + i2c_slave_wr_handler_t handler +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + this_i2c->slave_write_handler = handler; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_enable_slave() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_enable_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register and slave mode flag without the I2C ISR interrupting + * us. + */ + saved_psr = HAL_disable_interrupts(); + + /* Set the Assert Acknowledge bit. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + /* Enable slave mode */ + this_i2c->is_slave_enabled = 1u; + + HAL_restore_interrupts( saved_psr ); + + /* Enable I2C IRQ*/ + I2C_enable_irq( this_i2c ); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_slave() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_disable_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + /* Reset the assert acknowledge bit. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + + /* Disable slave mode with IRQ blocked to make whole change atomic */ + this_i2c->is_slave_enabled = 0u; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * + */ +static void enable_slave_if_required +( + i2c_instance_t * this_i2c +) +{ + /* + * This function is only called from within the ISR and so does not need + * guarding on the register access. + */ + if( 0 != this_i2c->is_slave_enabled ) + { + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x01u ); + } +} +/*------------------------------------------------------------------------------ + * I2C_set_slave_second_addr() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_slave_second_addr +( + i2c_instance_t * this_i2c, + uint8_t second_slave_addr +) +{ + uint8_t second_slave_address; + + /* + This function does not support CoreI2C hardware configured with a fixed + second slave address. The current implementation of the ADDR1[0] register + bit makes it difficult for the driver to support both programmable and + fixed second slave address, so we choose to support programmable only. + With the programmable configuration, ADDR1[0] and ADDR0[0] both control + enable/disable of GCA recognition, as an effective OR of the 2 bit fields. + Therefore we set ADDR1[0] to 0 here, so that only ADDR0[0] controls GCA. + */ + second_slave_address = (uint8_t)((second_slave_addr << 1u) & (~SLAVE1_EN_MASK)); + + /* + * Single byte register write, should be interrupt safe + */ + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, second_slave_address); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_slave_second_addr() + * See "i2c.h" for details of how to use this function. + */ +void I2C_disable_slave_second_addr +( + i2c_instance_t * this_i2c +) +{ + /* + We are disabling the second slave address by setting the value of the 2nd + slave address to the primary slave address. The reason for using this method + of disabling 2nd slave address is that ADDRESS1[0] has different meaning + depending on hardware configuration. Its use would likely interfere with + the intended GCA setting. + */ + /* + * Single byte register write, should be interrupt safe + */ + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, this_i2c->ser_address); +} + +/*------------------------------------------------------------------------------ + * i2C_set_gca() + * See "i2c.h" for details of how to use this function. + */ + +void I2C_set_gca +( + i2c_instance_t * this_i2c +) +{ + /* + * This read modify write access should be interrupt safe as the address + * register is not written to in the ISR. + */ + /* accept GC addressing. */ + HAL_set_8bit_reg_field(this_i2c->base_address, GC, 0x01u); +} + +/*------------------------------------------------------------------------------ + * I2C_clear_gca() + * See "i2c.h" for details of how to use this function. + */ +void I2C_clear_gca +( + i2c_instance_t * this_i2c +) +{ + /* + * This read modify write access should be interrupt safe as the address + * register is not written to in the ISR. + */ + /* Clear GC addressing. */ + HAL_set_8bit_reg_field(this_i2c->base_address, GC, 0x00u); +} + +/*------------------------------------------------------------------------------ + * I2C_isr() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_isr +( + i2c_instance_t * this_i2c +) +{ + volatile uint8_t status; + uint8_t data; + uint8_t hold_bus; + uint8_t clear_irq = 1u; + + status = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + + switch( status ) + { + /************** MASTER TRANSMITTER / RECEIVER *******************/ + + case ST_START: /* start has been xmt'd */ + case ST_RESTART: /* repeated start has been xmt'd */ + HAL_set_8bit_reg_field( this_i2c->base_address, STA, 0x00u); + HAL_set_8bit_reg( this_i2c->base_address, DATA, this_i2c->target_addr); /* write call address */ + HAL_set_8bit_reg_field( this_i2c->base_address, DIR, this_i2c->dir); /* set direction bit */ + if(this_i2c->dir == WRITE_DIR) + { + this_i2c->master_tx_idx = 0u; + } + else + { + this_i2c->master_rx_idx = 0u; + } + + /* + * Clear the pending transaction. This condition will be true if the slave + * has acquired the bus to carry out pending master transaction which + * it had received during its slave transmission or reception mode. + */ + if(this_i2c->is_transaction_pending) + { + this_i2c->is_transaction_pending = 0u; + } + + /* + * Make sure to update proper transaction after master START + * or RESTART + */ + if(this_i2c->transaction != this_i2c->pending_transaction) + { + this_i2c->transaction = this_i2c->pending_transaction; + } + break; + + case ST_LOST_ARB: + /* Set start bit. Let's keep trying! Don't give up! */ + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + break; + + case ST_STOP_TRANSMIT: + /* Stop has been transmitted. Do nothing */ + break; + + /******************* MASTER TRANSMITTER *************************/ + case ST_SLAW_NACK: + /* SLA+W has been transmitted; not ACK has been received - let's stop. */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_FAILED; + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + case ST_SLAW_ACK: + case ST_TX_DATA_ACK: + /* data byte has been xmt'd with ACK, time to send stop bit or repeated start. */ + if (this_i2c->master_tx_idx < this_i2c->master_tx_size) + { + HAL_set_8bit_reg(this_i2c->base_address, DATA, (uint_fast8_t)this_i2c->master_tx_buffer[this_i2c->master_tx_idx++]); + } + else if ( this_i2c->transaction == MASTER_RANDOM_READ_TRANSACTION ) + { + /* We are finished sending the address offset part of a random read transaction. + * It is is time to send a restart in order to change direction. */ + this_i2c->dir = READ_DIR; + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + else /* done sending. let's stop */ + { + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + hold_bus = this_i2c->options & I2C_HOLD_BUS; + + /* Store the information of current I2C bus status in the bus_status*/ + this_i2c->bus_status = hold_bus; + if ( hold_bus == 0u ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); /*xmt stop condition */ + enable_slave_if_required(this_i2c); + } + else + { + I2C_disable_irq( this_i2c ); + clear_irq = 0u; + } + this_i2c->master_status = I2C_SUCCESS; + } + break; + + case ST_TX_DATA_NACK: + /* data byte SENT, ACK to be received + * In fact, this means we've received a NACK (This may not be + * obvious, but if we've rec'd an ACK then we would be in state + * 0x28!) hence, let's send a stop bit + */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u);/* xmt stop condition */ + this_i2c->master_status = I2C_FAILED; + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + /********************* MASTER (or slave?) RECEIVER *************************/ + + /* STATUS codes 08H, 10H, 38H are all covered in MTX mode */ + case ST_SLAR_ACK: /* SLA+R tx'ed. */ + /* Let's make sure we ACK the first data byte received (set AA bit in CTRL) unless + * the next byte is the last byte of the read transaction. + */ + if(this_i2c->master_rx_size > 1u) + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + } + else if(1u == this_i2c->master_rx_size) + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + else /* this_i2c->master_rx_size == 0u */ + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_SUCCESS; + this_i2c->transaction = NO_TRANSACTION; + } + break; + + case ST_SLAR_NACK: /* SLA+R tx'ed; let's release the bus (send a stop condition) */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_FAILED; + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + case ST_RX_DATA_ACK: /* Data byte received, ACK returned */ + /* First, get the data */ + this_i2c->master_rx_buffer[this_i2c->master_rx_idx++] = HAL_get_8bit_reg(this_i2c->base_address, DATA); + if( this_i2c->master_rx_idx >= (this_i2c->master_rx_size - 1u)) + { + /* If we're at the second last byte, let's set AA to 0 so + * we return a NACK at the last byte. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + break; + + case ST_RX_DATA_NACK: /* Data byte received, NACK returned */ + /* Get the data, then send a stop condition */ + this_i2c->master_rx_buffer[this_i2c->master_rx_idx] = HAL_get_8bit_reg(this_i2c->base_address, DATA); + + hold_bus = this_i2c->options & I2C_HOLD_BUS; + + /* Store the information of current I2C bus status in the bus_status*/ + this_i2c->bus_status = hold_bus; + if ( hold_bus == 0u ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); /*xmt stop condition */ + + /* Bus is released, now we can start listening to bus, if it is slave */ + enable_slave_if_required(this_i2c); + } + else + { + I2C_disable_irq( this_i2c ); + clear_irq = 0u; + } + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + this_i2c->master_status = I2C_SUCCESS; + break; + + /******************** SLAVE RECEIVER **************************/ + case ST_GCA_NACK: /* NACK after, GCA addressing */ + case ST_SLA_NACK: /* Re-enable AA (assert ack) bit for future transmissions */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + this_i2c->transaction = NO_TRANSACTION; + this_i2c->slave_status = I2C_SUCCESS; + + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + break; + + case ST_GCA_LA: /* Arbitr. lost (GCA rec'd) */ + case ST_SLV_LA: /* Arbitr. lost (SLA rec'd) */ + /* + * We lost arbitration and either the GCE or our address was the + * one received so pend the master operation we were starting. + */ + this_i2c->is_transaction_pending = 1u; + /* Fall through to normal ST processing as we are now in slave mode */ + + case ST_GCA: /* General call address received, ACK returned */ + case ST_SLAVE_SLAW: /* SLA+W received, ACK returned */ + this_i2c->transaction = WRITE_SLAVE_TRANSACTION; + this_i2c->slave_rx_idx = 0u; + this_i2c->random_read_addr = 0u; + /* + * If Start Bit is set clear it, but store that information since it is because of + * pending transaction + */ + if(HAL_get_8bit_reg_field(this_i2c->base_address, STA)) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + this_i2c->is_transaction_pending = 1u; + } + this_i2c->slave_status = I2C_IN_PROGRESS; +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + /* Fall through to put address as first byte in payload buffer */ +#else + /* Only break from this case if the slave address must NOT be included at the + * beginning of the received write data. */ + break; +#endif + case ST_GCA_ACK: /* DATA received; ACK sent after GCA */ + case ST_RDATA: /* DATA received; must clear DATA register */ + if((this_i2c->slave_rx_buffer != (uint8_t *)0) + && (this_i2c->slave_rx_idx < this_i2c->slave_rx_size)) + { + data = HAL_get_8bit_reg(this_i2c->base_address, DATA); + this_i2c->slave_rx_buffer[this_i2c->slave_rx_idx++] = data; + +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + if((ST_RDATA == status) || (ST_GCA_ACK == status)) + { + /* Ignore the slave address byte in the random read address + computation in the case where INCLUDE_SLA_IN_RX_PAYLOAD + is defined. */ +#endif + this_i2c->random_read_addr = (this_i2c->random_read_addr << 8) + data; +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + } +#endif + } + + if(this_i2c->slave_rx_idx >= this_i2c->slave_rx_size) + { + /* Rx buffer is full. NACK next received byte. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + break; + + case ST_RSTOP: + /* STOP or repeated START occurred. */ + /* We cannot be sure if the transaction has actually completed as + * this hardware state reports that either a STOP or repeated START + * condition has occurred. We assume that this is a repeated START + * if the transaction was a write from the master to this point.*/ + if ( this_i2c->transaction == WRITE_SLAVE_TRANSACTION ) + { + if ( this_i2c->slave_rx_idx == this_i2c->slave_mem_offset_length ) + { + this_i2c->slave_tx_idx = this_i2c->random_read_addr; + } + /* Call the slave's write transaction handler if it exists. */ + if ( this_i2c->slave_write_handler != 0u ) + { + i2c_slave_handler_ret_t h_ret; + h_ret = this_i2c->slave_write_handler( this_i2c, this_i2c->slave_rx_buffer, (uint16_t)this_i2c->slave_rx_idx ); + if ( I2C_REENABLE_SLAVE_RX == h_ret ) + { + /* There is a small risk that the write handler could + * call I2C_disable_slave() but return + * I2C_REENABLE_SLAVE_RX in error so we only enable + * ACKs if still in slave mode. */ + enable_slave_if_required(this_i2c); + } + else + { + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x0u ); + /* Clear slave mode flag as well otherwise in mixed + * master/slave applications, the AA bit will get set by + * subsequent master operations. */ + this_i2c->is_slave_enabled = 0u; + } + } + else + { + /* Re-enable address acknowledge in case we were ready to nack the next received byte. */ + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x01u ); + } + } + else /* A stop or repeated start outside a write/read operation */ + { + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * See if we need to re-enable acknowledgement as some error conditions, such + * as a master prematurely ending a transfer, can see us get here with AA set + * to 0 which will disable slave operation if we are not careful. + */ + enable_slave_if_required(this_i2c); + } + + /* Mark any previous master write transaction as complete. */ + this_i2c->slave_status = I2C_SUCCESS; + + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + + break; + + case ST_SLV_RST: /* SMBUS ONLY: timeout state. must clear interrupt */ + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction. + */ + this_i2c->transaction = NO_TRANSACTION; + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * Clear status to I2C_FAILED only if there was an operation in progress. + */ + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->slave_status = I2C_FAILED; + } + + enable_slave_if_required(this_i2c); /* Make sure AA is set correctly */ + + break; + + /****************** SLAVE TRANSMITTER **************************/ + case ST_SLAVE_SLAR_ACK: /* SLA+R received, ACK returned */ + case ST_SLARW_LA: /* Arbitration lost, and: */ + case ST_RACK: /* Data tx'ed, ACK received */ + if ( status == ST_SLAVE_SLAR_ACK ) + { + this_i2c->transaction = READ_SLAVE_TRANSACTION; + this_i2c->random_read_addr = 0u; + this_i2c->slave_status = I2C_IN_PROGRESS; + /* If Start Bit is set clear it, but store that information since it is because of + * pending transaction + */ + if(HAL_get_8bit_reg_field(this_i2c->base_address, STA)) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + this_i2c->is_transaction_pending = 1u; + } + } + if (this_i2c->slave_tx_idx >= this_i2c->slave_tx_size) + { + /* Ensure 0xFF is returned to the master when the slave specifies + * an empty transmit buffer. */ + HAL_set_8bit_reg(this_i2c->base_address, DATA, 0xFFu); + } + else + { + /* Load the data the data byte to be sent to the master. */ + HAL_set_8bit_reg(this_i2c->base_address, DATA, (uint_fast8_t)this_i2c->slave_tx_buffer[this_i2c->slave_tx_idx++]); + } + /* Determine if this is the last data byte to send to the master. */ + if (this_i2c->slave_tx_idx >= this_i2c->slave_tx_size) /* last byte? */ + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + /* Next read transaction will result in slave's transmit buffer + * being sent from the first byte. */ + this_i2c->slave_tx_idx = 0u; + } + break; + + case ST_SLAVE_RNACK: /* Data byte has been transmitted; not-ACK has been received. */ + case ST_FINAL: /* Last Data byte tx'ed, ACK received */ + /* We assume that the transaction will be stopped by the master. + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. */ + this_i2c->slave_tx_idx = 0u; + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + /* Mark previous state as complete */ + this_i2c->slave_status = I2C_SUCCESS; + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + + break; + + /* Master Reset has been activated Wait 35 ms for interrupt to be set, + * clear interrupt and proceed to 0xF8 state. */ + case ST_RESET_ACTIVATED: + case ST_BUS_ERROR: /* Bus error during MST or selected slave modes */ + default: + /* Some undefined state has encountered. Clear Start bit to make + * sure, next good transaction happen */ + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction. + */ + this_i2c->transaction = NO_TRANSACTION; + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * Clear statuses to I2C_FAILED only if there was an operation in progress. + */ + if(I2C_IN_PROGRESS == this_i2c->master_status) + { + this_i2c->master_status = I2C_FAILED; + } + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->slave_status = I2C_FAILED; + } + + break; + } + + if ( clear_irq ) + { + /* clear interrupt. */ + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + /* Read the status register to ensure the last I2C registers write took place + * in a system built around a bus making use of posted writes. */ + status = HAL_get_8bit_reg( this_i2c->base_address, STATUS); +} + +/*------------------------------------------------------------------------------ + * I2C_smbus_init() + * See "i2c.h" for details of how to use this function. + */ + +/* + * SMBSUS_NO = 1 + * SMBALERT_NO = 1 + * SMBus enable = 1 + */ +#define INIT_AND_ENABLE_SMBUS 0x54u +void I2C_smbus_init +( + i2c_instance_t * this_i2c +) +{ + /* + * Single byte register write, should be interrupt safe + */ + /* Enable SMBUS */ + HAL_set_8bit_reg(this_i2c->base_address, SMBUS, INIT_AND_ENABLE_SMBUS); +} + +/*------------------------------------------------------------------------------ + * I2C_enable_smbus_irq() + * See "i2c.h" for details of how to use this function. + */ +void I2C_enable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + if ( irq_type & I2C_SMBALERT_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_IE, 0x01u); + } + if ( irq_type & I2C_SMBSUS_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_IE, 0x01u); + } + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_smbus_irq() + * See "i2c.h" for details of how to use this function. + */ +void I2C_disable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + if ( irq_type & I2C_SMBALERT_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_IE, 0x00u); + } + if (irq_type & I2C_SMBSUS_IRQ ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_IE, 0x00u); + } + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_suspend_smbus_slave() + * See "i2c.h" for details of how to use this function. + */ +void I2C_suspend_smbus_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_NO_CONTROL, 0x00u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_resume_smbus_slave() + * See "i2c.h" for details of how to use this function. + */ +void I2C_resume_smbus_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_NO_CONTROL, 0x01u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_reset_smbus() + * See "i2c.h" for details of how to use this function. + */ +void I2C_reset_smbus +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + HAL_set_8bit_reg_field(this_i2c->base_address, SMBUS_MST_RESET, 0x01u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_smbus_alert() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_smbus_alert +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_NO_CONTROL, 0x00u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_clear_smbus_alert() + * See "i2c.h" for details of how to use this function. + */ +void I2C_clear_smbus_alert +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_NO_CONTROL, 0x01u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_get_irq_status() + * See "i2c.h" for details of how to use this function. + */ +uint8_t I2C_get_irq_status +( + i2c_instance_t * this_i2c +) +{ + uint8_t status ; + uint8_t irq_type = I2C_NO_IRQ ; + + status = HAL_get_8bit_reg(this_i2c->base_address, SMBUS); + + if( status & (uint8_t)SMBALERT_NI_STATUS_MASK ) + { + irq_type |= I2C_SMBALERT_IRQ ; + } + + if( status & (uint8_t)SMBSUS_NI_STATUS_MASK ) + { + irq_type |= I2C_SMBSUS_IRQ ; + } + + status = HAL_get_8bit_reg(this_i2c->base_address, CONTROL); + + if( status & (uint8_t)SI_MASK ) + { + irq_type |= I2C_INTR_IRQ ; + } + return(irq_type); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_addr2() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_user_data +( + i2c_instance_t * this_i2c, + void * p_user_data +) +{ + this_i2c->p_user_data = p_user_data ; +} + +/*------------------------------------------------------------------------------ + * I2C_get_user_data() + * See "i2c.h" for details of how to use this function. + */ +void * I2C_get_user_data +( + i2c_instance_t * this_i2c +) +{ + return( this_i2c->p_user_data); +} + +#ifdef __cplusplus +} +#endif + diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h new file mode 100644 index 0000000..3891ce0 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h @@ -0,0 +1,2306 @@ +/***************************************************************************//** + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * CoreI2C software driver Application Programming Interface. + * This file contains defines and function declarations allowing to interface + * with the CoreI2C software driver. + * + */ +/*=========================================================================*//** + @mainpage CoreI2C Bare Metal Driver. + The CoreI2C bare metal software driver supports I2C master and slave + operations. + + ============================================================================== + Introduction + ============================================================================== + The CoreI2C driver provides a set of functions for controlling the Microchip + CoreI2C hardware IP. The driver supports up to 16 separate I2C channels per + CoreI2C instance, with common slave address settings shared between channels + on a device. + + Optional features of the CoreI2C allow it to operate with I2C based protocols + such as System Management Bus (SMBus), Power Management Bus (PMBus), and + Intelligent Platform Management Interface (IPMI). This driver provides support + for these features when enabled in the CoreI2C IP. + + The major features provided by CoreI2C driver: + - Provides support to configuring the I2C channels of each CoreI2C peripheral device. + - I2C master operations. + - I2C slave operations. + - SMBus related operations. + + This driver is used as part of a bare metal system where no operating + system is available. The driver gets adapted as a part of an operating system, + but the implementation of the adaptation layer between the driver and the operating + system's driver model is outside the scope of this driver. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + Your application software should configure the CoreI2C driver through + calls to the I2C_init() function for each CoreI2C instance in the + hardware design. The configuration parameters include the CoreI2C hardware + instance base address and other runtime parameters, such as the I2C serial + clock frequency and the I2C device address. + + Once channel 0 of a CoreI2C peripheral has been initialized by I2C_init(), + any additional channels present should be configured by calling + I2C_channel_init() for each of the remaining channels. + + Apart from the CoreI2C hardware instance base address, no CoreI2C hardware configuration + parameters are used by the driver. Hence, no additional configuration files are required + to use the driver. + + -------------------------------- + Interrupt Control + -------------------------------- + The CoreI2C driver has to enable and disable the generation of interrupts by + CoreI2C at various times when it is operating. This enabling and disabling of + interrupts must be done through the system’s interrupt controller. For that + reason, the method of controlling the CoreI2C interrupt is system specific + and it is necessary to customize the I2C_enable_irq() and I2C_disable_irq() + functions. These functions are available in the i2c_interrupt.c file. + The default implementation calls HAL_ASSERT(0) to indicate to the application + developer that a suitable implementations for these functions must be provided. + + The implementation of the I2C_enable_irq() function should permit interrupts + generated by a CoreI2C instance to interrupt the processor. The implementation + of the I2C_disable_irq() function should prevent interrupts generated by a + CoreI2C instance from interrupting the processor. See the provided example + projects for a working implementation of these functions. + + The I2C_register_write_handler() function registers a write handler + function with the CoreI2C driver that calls on completion of an I2C write + transaction by the CoreI2C slave. It is your responsibility to create and + register the implementation of this handler function that processes or + trigger the processing of the received data. + + The SMBSUS and SMBALERT interrupts are related to the SMBus interface and are + enabled and disabled through I2C_enable_smbus_irq() and + I2C_disable_smbus_irq() respectively. It is your responsibility to create + interrupt handler functions in your application to get the desired response + for the SMBus interrupts. + + Note: You must include the path to any application header files that are + included in the i2c_interrupt.c file, as an include path in your + project's compiler settings. The details of how to do this will depend + on your development software. + + -------------------------------- + SMBus Logic Options + -------------------------------- + SMBus related APIs does not have any effect if the "Generate SMBus Logic" + is not enabled in the CoreI2C hardware configuration. Following are API's + that does not give the desired results if SMBus Logic is disabled. + + - I2C_smbus_init() + - I2C_reset_smbus() + - I2C_enable_smbus_irq() + - I2C_disable_smbus_irq() + - I2C_suspend_smbus_slave() + - I2C_resume_smbus_slave() + - I2C_set_smsbus_alert() + - I2C_clear_smsbus_alert() + - I2C_get_irq_status() + + -------------------------------- + Fixed Baud Rate Values + -------------------------------- + The serial clock frequency parameter passed to the I2C_init() and + I2C_channel_init() functions may not have any effect if fixed values were + selected for Baud rate in the hardware configuration of CoreI2C. When fixed + values are selected for these baud rates, the driver cannot overwrite + the fixed values. + + ----------------------------------- + Fixed Slave Address Options Values + ----------------------------------- + The primary slave address parameter passed to the I2C_init() function and + secondary address value passed to the I2C_set_slave_second_addr() function, + may not have the desired effect if fixed values were selected for the slave 0 + address and slave 1 address respectively. Proper operation of this version of + the driver requires the slave addresses to be programmable. + + ============================================================================== + Theory of Operation + ============================================================================== + The CoreI2C software driver is designed to allow the control of multiple + instances of CoreI2C with one or more I2C channels. Each channel in an + instance of CoreI2C in the hardware design is associated with a single + instance of the i2c_instance_t structure in the software. You must allocate + memory for one unique i2c_instance_t structure instance for each channel of + each CoreI2C hardware instance. The contents of these data structures are + initialised by calling I2C_init() and if necessary I2C_channel_init(). + A pointer to the structure is passed to the subsequent driver functions in order + to identify the CoreI2C hardware instance and channel to perform the + requested operation. + + Note: Do not attempt to directly manipulate the contents of i2c_instance_t + structures. These structures are only intended to be modified by the driver + functions. + + The CoreI2C driver functions are grouped into the following categories: + - Initialization and configuration functions + - Interrupt control + - I2C slave addressing functions + - I2C master operations functions to handle write, read, and write-read + transactions + - I2C slave operations functions to handle write, read, and write-read + transactions + - Mixed master-slave operations + - SMBus interface configuration and control + + -------------------------------- + Initialization and Configuration + -------------------------------- + The CoreI2C device is first initialized by calling the I2C_init() + function. Since each CoreI2C peripheral supports up to 16 channels, an + additional function, I2C_channel_init(), is required to initialize the + remaining channels with their own data structures. + + I2C_init() function initializes channel 0 of a CoreI2C and the i2c_instance_t + for channel 0 acts as the basis for further channel initialization as the + hardware base address and I2C serial address are same across all the channels. + Ensure to call I2C_init() function before calling any other I2C driver function + calls. The I2C_init() call for each CoreI2C takes the I2C serial address assigned + to the I2C and the serial clock divider to generate its I2C clock as configuration + parameters. + + I2C_channel_init() function takes as input parameters a pointer to the CoreI2C + i2c_instance_t which has been initialized by calling the I2C_init() and a pointer + to a separate i2c_instance_t which represents this new channel. Another input + parameter which is required by this function is serial clock divider which generates + its I2C clock. + + -------------------------------- + Interrupt Control + -------------------------------- + The CoreI2C driver is interrupt driven and it uses each channels INT + interrupt to drive the state machine which is at the heart of the driver. + The application is responsible for providing the link between the interrupt + generating hardware and the CoreI2C interrupt handler and must ensure that + the I2C_isr() function is called with the correct i2c_instance_t structure + pointer for the CoreI2C channel initiating the interrupt. + + The driver enables and disables the generation of INT interrupts by CoreI2C + at various times when it is operating through the user supplied + I2C_enable_irq() and I2C_disable_irq() functions. + + The I2C_register_write_handler() function is used to register a write + handler function with the CoreI2C driver which is called on completion + of an I2C write transaction by the CoreI2C slave. It is the user + applications responsibility to create and register the implementation of + this handler function that processes or triggers the processing of the + received data. + + The other two interrupt sources in the CoreI2C are related to SMBus + operation and are enabled and disabled through I2C_enable_smbus_irq() and + I2C_disable_smbus_irq() respectively. Due to the application specific + nature of the response to SMBus interrupts, you must design interrupt + handler functions in the application to get the desired behaviour for + SMBus related interrupts. + + If enabled, the SMBA_INT signal from the CoreI2C is asserted if an + SMBALERT condition is signalled on the SMBALERT_NI input for the channel. + + If enabled, the SMBS_INT signal from the CoreI2C is asserted if an + SMBSUSPEND condition is signalled on the SMBSUS_NI input for the channel. + + ## I2C Slave Addressing Functions + A CoreI2C peripheral responds to the following three slave addresses: + - Slave address 0 - This is the primary slave address that accesses + a CoreI2C channel when it acts as a slave in + I2C transactions. You must configure the primary slave + address using I2C_init(). + + - Slave address 1 - This is the secondary slave address which might be + required in certain application specific scenarios. + The secondary slave address is configured by + I2C_set_slave_second_addr() and is disabled by + I2C_disable_slave_second_addr(). + + - General call address - A CoreI2C slave can be configured to respond to + a broadcast command by a master transmitting the + general call address of 0x00. Use the I2C_set_gca() + function to enable the slave to respond to the general + call address. If the CoreI2C slave is not required to + respond to the general call address, disable this + address by calling I2C_clear_gca(). + + Note: All channels on a CoreI2C instance share the same slave address logic. + This means that they cannot have separate slave addresses and rely on + the separate physical I2C bus connections to distinguish them. + + -------------------------------- + Transaction Types + -------------------------------- + The I2C driver is designed to handle three types of I2C transaction: + - Write transactions + - Read transactions + - Write-read transactions + + ## Write Transaction + The master I2C device initiates a write transaction by sending a START bit + as soon as the bus becomes free. The START bit is followed by the 7-bit + serial address of the target slave device followed by the read/write bit + indicating the direction of the transaction. The slave acknowledges the + receipt of it's address with an acknowledge bit. The master sends data one + byte at a time to the slave, which must acknowledge the receipt of each byte + for the next byte to be sent. The master sends a STOP bit to complete the + transaction. The slave can abort the transaction by replying with a + non-acknowledge bit instead of an acknowledge bit. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ## Read Transaction + The master I2C device initiates a read transaction by sending a START bit + as soon as the bus becomes free. The START bit is followed by the 7-bit + serial address of the target slave device followed by the read/write bit + indicating the direction of the transaction. The slave acknowledges the + receipt of it's slave address with an acknowledge bit. The slave sends + data one byte at a time to the master, which must acknowledge the receipt of + each byte for the next byte to be sent. The master sends a non-acknowledge + bit following the last byte it wishes to read followed by a STOP bit. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ## Write-Read Transaction + The write-read transaction is a combination of a write transaction + immediately followed by a read transaction. There is no STOP bit in between + the write and read phases of a write-read transaction. A repeated START + bit is sent between the write and read phases. + + Whilst the write handler is being executed, the slave holds the clock line + low to stretch the clock until the response is ready. + + The write-read transaction is typically used to send a command or offset + in the write transaction specifying the logical data to be transferred + during the read phase. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ## Master Operations + The application can use the I2C_write(), I2C_read(), and I2C_write_read() + functions to initiate an I2C bus transaction. The application can then wait + for the transaction to complete using the I2C_wait_complete() function + or poll the status of the I2C transaction using the I2C_get_status() + function until it returns a value different from I2C_IN_PROGRESS. The + I2C_system_tick() function is used to set a time base for the + I2C_wait_complete() function's time out delay. + + ## Slave Operations + To configure the I2C driver to operate as an I2C slave requires the use + of the following functions: + - I2C_set_slave_tx_buffer() + - I2C_set_slave_rx_buffer() + - I2C_set_slave_mem_offset_length() + - I2C_register_write_handler() + - I2C_enable_slave() + + Use of all functions is not required if the slave I2C does not need to support + all types of I2C read transactions. The subsequent sections list the functions + that must be used to support each transaction type. + + ## Responding to Read Transactions + The following functions are used to configure the CoreI2C driver to + respond to I2C read transactions: + • I2C_set_slave_tx_buffer() + • I2C_enable_slave() + + The I2C_set_slave_tx_buffer() function specifies the data buffer that + is transmitted when the I2C slave is the target of an I2C read + transaction. It is then up to the application to manage the content of + that buffer to control the data that will be transmitted to the I2C + master as a result of the read transaction. + + The I2C_enable_slave() function enables the I2C hardware instance + to respond to the I2C transactions. It must be called after the I2C driver + has been configured to respond to the required transaction types. + + ## Responding to Write Transactions + The following functions are used to configure the I2C driver to respond + to I2C write transactions: + • I2C_set_slave_rx_buffer() + • I2C_register_write_handler() + • I2C_enable_slave() + + The I2C_set_slave_rx_buffer() function specifies the data buffer that + stored the data received by the I2C slave when it targets an I2C write + transaction. + + The I2C_register_write_handler() function specifies the handler function + that must be called on completion of the I2C write transaction. It is this + handler function that processes or triggers the processing of the received + data. + + The I2C_enable_slave() function enables the I2C hardware instance + to respond to I2C transactions. It must be called after the I2C driver + has been configured to respond to the required transaction types. + + ## Responding to Write-Read Transactions + The following functions are used to configure the CoreI2C driver to + respond to write-read transactions: + - I2C_set_slave_mem_offset_length() + - I2C_set_slave_tx_buffer() + - I2C_set_slave_rx_buffer() + - I2C_register_write_handler() + - I2C_enable_slave() + + The I2C_set_slave_mem_offset_length() function specifies the number of + bytes expected by the I2C slave during the write phase of the write-read + transaction. + + The I2C_set_slave_tx_buffer() function specifies the data that is + transmitted to the I2C master during the read phase of the write-read + transaction. The value received by the I2C slave during the write phase of + the transaction will be used as an index into the transmit buffer + specified by this function. It decides which part of the transmit buffer + will be transmitted to the I2C master as part of the read phase of the + write-read transaction. + + The I2C_set_slave_rx_buffer() function specifies the data buffer that + stores the data received by the I2C slave during the write phase of + the write-read transaction. This buffer must be large enough to accommodate + the number of bytes specified through the I2C_set_slave_mem_offset_length() + function. + + The I2C_register_write_handler() function can optionally be used to + specify a handler function that is called on completion of the write phase + of the I2C write-read transaction. If a handler function is registered, it + is responsible for processing the received data in the slave receive + buffer and populating the slave transmit buffer with the data that will be + transmitted to the I2C master as part of the read phase of the write-read + transaction. + + The I2C_enable_slave() function enables the CoreI2C hardware instance to + respond to the I2C transactions. It must be called after configuring the + CoreI2C driver to respond to the required transaction types. + + ## Mixed Master-Slave Operations + The CoreI2C device supports mixed master and slave operations. If the + CoreI2C slave has a transaction in progress and your application attempts to + begin a master mode transaction, the CoreI2C driver queues the master mode + transaction until the bus is released and the CoreI2C can switch to master + mode and acquire the bus. The CoreI2C master then starts the previously + queued master transaction. + + ## SMBus Control + The CoreI2C driver enables the CoreI2C peripheral’s SMBus functionality + using the I2C_smbus_init() function. + + The I2C_suspend_smbus_slave() function is used with a master mode CoreI2C + to force slave devices on the SMBus to enter their Power-Down/Suspend mode. + The I2C_resume_smbus_slave() function is used to end the suspend operation + on the SMBus. + + The I2C_reset_smbus() function is used with a master mode CoreI2C to force + all devices on the SMBus to reset their SMBUs interface. + + The I2C_set_smsbus_alert() function is used by a slave mode CoreI2C to + force communication with the SMBus master. Once communications with the + master is initiated, the I2C_clear_smsbus_alert() function clears the alert + condition. + + The I2C_enable_smbus_irq() and I2C_disable_smbus_irq() functions are used to + enable and disable the SMBSUS and SMBALERT SMBus interrupts. + + *//*=========================================================================*/ + +#ifndef CORE_I2C_H_ +#define CORE_I2C_H_ + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#include "hal_assert.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + I2C_RELEASE_BUS + ======================================= + The I2C_RELEASE_BUS constant is used to specify the options parameter to + functions I2C_read(), I2C_write() and I2C_write_read() to indicate + that a STOP bit must be generated at the end of the I2C transaction to release + the bus. + */ +#define I2C_RELEASE_BUS 0x00u + +/*-------------------------------------------------------------------------*//** + I2C_HOLD_BUS + ======================================= + The I2C_HOLD_BUS constant specify the options parameter to functions I2C_read(), + I2C_write(), and I2C_write_read() to indicate that a STOP bit must not be + generated at the end of the I2C transaction in order to retain the bus ownership. + This causes the next transaction to begin with a repeated START bit and no STOP + bit between the transactions. + */ +#define I2C_HOLD_BUS 0x01u + +/*-------------------------------------------------------------------------*//** + Interrupt Identifier Number + ======================================= + The following constants specify the interrupt identifier number which is + solely used by the driver API. This has nothing to do with hardware interrupt + line. I2C_INTR_IRQ is the primary interrupt signal which drives the state machine + of the CoreI2C driver. The I2C_SMBALERT_IRQ and I2C_SMBSUS_IRQ are used by + SMBus interrupt enable and disable functions. These IRQ numbers are also used + by I2C_get_irq_status(). + + | Constant | Description | + |--------------------|--------------------------------------------------------| + | I2C_NO_IRQ | No interrupt | + | I2C_SMBALERT_IRQ | Used by SMBus interrupt enable functions | + | I2C_SMBSUS_IRQ | Used by SMBus interrupt disable functions | + | I2C_INTR_IRQ | Primary interrupt signal which drives the state machine| + + */ +#define I2C_NO_IRQ 0x00u +#define I2C_SMBALERT_IRQ 0x01u +#define I2C_SMBSUS_IRQ 0x02u +#define I2C_INTR_IRQ 0x04u + +/*-------------------------------------------------------------------------*//** + I2C_NO_TIMEOUT + ======================================= + The I2C_wait_complete() function uses I2C_NO_TIMEOUT constant as a parameter + to indicate that the wait for completion of the transaction should not time out. + */ +#define I2C_NO_TIMEOUT 0u + +/***************************************************************************//** + The i2c_channel_number_t type is used to specify the channel number of a + CoreI2C instance. + */ +typedef enum i2c_channel_number { + I2C_CHANNEL_0 = 0u, + I2C_CHANNEL_1, + I2C_CHANNEL_2, + I2C_CHANNEL_3, + I2C_CHANNEL_4, + I2C_CHANNEL_5, + I2C_CHANNEL_6, + I2C_CHANNEL_7, + I2C_CHANNEL_8, + I2C_CHANNEL_9, + I2C_CHANNEL_10, + I2C_CHANNEL_11, + I2C_CHANNEL_12, + I2C_CHANNEL_13, + I2C_CHANNEL_14, + I2C_CHANNEL_15, + I2C_MAX_CHANNELS = 16u +} i2c_channel_number_t; + +/***************************************************************************//** + The i2c_clock_divider_t type specifies the divider to be applied + to the I2C PCLK or BCLK signal in order to generate the I2C clock. + The I2C_BCLK_DIV_8 value selects a clock frequency based on division of BCLK, + all other values select a clock frequency based on division of PCLK. + */ +typedef enum i2c_clock_divider { + I2C_PCLK_DIV_256 = 0u, + I2C_PCLK_DIV_224, + I2C_PCLK_DIV_192, + I2C_PCLK_DIV_160, + I2C_PCLK_DIV_960, + I2C_PCLK_DIV_120, + I2C_PCLK_DIV_60, + I2C_BCLK_DIV_8 +} i2c_clock_divider_t; + +/***************************************************************************//** + The i2c_status_t type is used to report the status of I2C transactions. + */ +typedef enum i2c_status +{ + I2C_SUCCESS = 0u, + I2C_IN_PROGRESS, + I2C_FAILED, + I2C_TIMED_OUT +} i2c_status_t; + +/***************************************************************************//** + The i2c_slave_handler_ret_t type is used by slave write handler functions + to indicate whether or not the received data buffer should be released. + */ +typedef enum i2c_slave_handler_ret { + I2C_REENABLE_SLAVE_RX = 0u, + I2C_PAUSE_SLAVE_RX = 1u +} i2c_slave_handler_ret_t; + +/***************************************************************************//** + This structure identifies various CoreI2C hardware instances in the system + and the I2C channels within them. The application software should declare + one instance of this structure for each channel of each instance of CoreI2C + in your system. I2C_init() and I2C_channel_init() functions initialize this + structure depending on whether it is channel 0 or one of the additional + channels, respectively. A pointer to an initialized instance of the + structure should be passed as the first parameter to the CoreI2C driver + functions, to identify which CoreI2C hardware instance and channel should + perform the requested operation. + + The contents of this data structure should not be modified or used outside of + the CoreI2C driver. Software using the CoreI2C driver should only need to + create one single instance of this data structure for each channel of each + CoreI2C hardware instance in the system then pass a pointer to these data + structures with each call to the CoreI2C driver in order to identify which + CoreI2C hardware instance to use. + */ +typedef struct i2c_instance i2c_instance_t ; +/***************************************************************************//* + Slave write handler functions prototype +/***************************************************************************//** + This defines the function prototype that must be followed by I2C slave write + handler functions. These functions are registered with the CoreI2C driver + through the I2C_register_write_handler() function. + + Declaring and Implementing Slave Write Handler Functions: + + Slave write handler functions should follow the following prototype: + @code + i2c_slave_handler_ret_t write_handler + ( + i2c_instance_t *instance, uint8_t * data, uint16_t size + ); + @endcode + + The instance parameter is a pointer to the i2c_instance_t for which this + slave write handler has been declared. + + The data parameter is a pointer to a buffer (received data buffer) holding + the data written to the I2C slave. + + Define the INCLUDE_SLA_IN_RX_PAYLOAD macro for the driver to insert the + actual address used to access the slave as the first byte in the buffer. + This allows the applications to tailor their response based on the actual + address used to access the slave (primary address, secondary address, or GCA). + + The size parameter is the number of bytes held in the received data buffer. + Handler functions must return one of the following values: + - I2C_REENABLE_SLAVE_RX + - I2C_PAUSE_SLAVE_RX + + If the handler function returns I2C_REENABLE_SLAVE_RX, the driver releases + the received data buffer and allows further I2C write transactions to the + I2C slave. + + If the handler function returns I2C_PAUSE_SLAVE_RX, the I2C slave responds + to subsequent write requests with a non-acknowledge bit (NACK), until the + received data buffer content gets processed by some other part of the + software application. + + Call the I2C_enable_slave() after returning the I2C_PAUSE_SLAVE_RX to release + the received data buffer in order to store the data received by the subsequent + I2C write transactions. + */ +typedef i2c_slave_handler_ret_t (*i2c_slave_wr_handler_t)(i2c_instance_t *instance, uint8_t *, uint16_t ); + +/***************************************************************************//** + This structure is used to identify the various CoreI2C hardware instances in + your system and the I2C channels within them. Your application software should + declare one instance of this structure for each channel of each instance of + CoreI2C in your system. The functions I2C_init() and I2C_channel_init() + initialize this structure depending on whether it is channel 0 or one of the + additional channels respectively. A pointer to an initialized instance of the + structure should be passed as the first parameter to the CoreI2C driver + functions, to identify which CoreI2C hardware instance and channel should + perform the requested operation. + + The contents of this data structure should not be modified or used outside of + the CoreI2C driver. Software using the CoreI2C driver should only need to + create one single instance of this data structure for each channel of each + CoreI2C hardware instance in the system then pass a pointer to these data + structures with each call to the CoreI2C driver in order to identify the + CoreI2C hardware instance it wishes to use. + */ +struct i2c_instance +{ + addr_t base_address; + uint_fast8_t ser_address; + + /* Transmit related info:*/ + uint_fast8_t target_addr; + + /* Current transaction type (WRITE, READ, RANDOM_READ)*/ + uint8_t transaction; + + uint_fast16_t random_read_addr; + + uint8_t options; + + /* Master TX INFO: */ + const uint8_t * master_tx_buffer; + uint_fast16_t master_tx_size; + uint_fast16_t master_tx_idx; + uint_fast8_t dir; + + /* Master RX INFO: */ + uint8_t * master_rx_buffer; + uint_fast16_t master_rx_size; + uint_fast16_t master_rx_idx; + + /* Master Status */ + volatile i2c_status_t master_status; + uint32_t master_timeout_ms; + + /* Slave TX INFO */ + const uint8_t * slave_tx_buffer; + uint_fast16_t slave_tx_size; + uint_fast16_t slave_tx_idx; + + /* Slave RX INFO */ + uint8_t * slave_rx_buffer; + uint_fast16_t slave_rx_size; + uint_fast16_t slave_rx_idx; + /* Slave Status */ + volatile i2c_status_t slave_status; + + /* Slave data: */ + uint_fast8_t slave_mem_offset_length; + i2c_slave_wr_handler_t slave_write_handler; + uint8_t is_slave_enabled; + + /* user specific data */ + void *p_user_data ; + + /* I2C bus status */ + uint8_t bus_status; + + /* Is transaction pending flag */ + uint8_t is_transaction_pending; + + /* I2C Pending transaction */ + uint8_t pending_transaction; +}; + +/*------------------------Public Function-------------------------------------*/ + +/***************************************************************************//** + The I2C_init() function configures channel 0 of a CoreI2C instance. It sets + the base hardware address which is used to locate the CoreI2C instance + in memory and also used internally by I2C_channel_init() to calculate the + register addresses for any additional channels. The slave serial address set + is shared by all channels on a CoreI2C instance. + + If only one channel is configured in a CoreI2C, the address of the + i2c_instance_t used in I2C_Init() will also be used in subsequent calls to the + CoreI2C driver functions. If more than one channel is configured in the + CoreI2C, I2C_channel_init() will be called after I2C_init(), which initializes + the i2c_instance_t data structure for a specific channel. + + @param this_i2c + Pointer to the i2c_instance_t data structure that holds all the data + related to channel 0 of the CoreI2C instance is initialized. A pointer + to this structure is used in all subsequent calls to the CoreI2C driver + functions which operates on channel 0 of this CoreI2C instance. + + @param base_address + Base address in the processor's memory map of the registers of the CoreI2C + instance being initialized. + + @param ser_address + This parameter sets the primary I2C serial address (SLAVE0 address) for the + CoreI2C to initialize. It is the principal I2C bus address to which the + CoreI2C instance will respond. CoreI2C can operate in master mode or slave + mode and the serial address is significant only in the case of I2C slave + mode. In master mode, CoreI2C does not require a serial address and the + value of this parameter is not important. If you do not intend to use the + CoreI2C device in slave mode, then provide any dummy slave address value + to this parameter. However, in systems where the CoreI2C is expected to + switch from master mode to slave mode, it is advisable to initialize the + CoreI2C device with a valid serial slave address. Call the I2C_init() + function whenever it is required to change the primary slave address as + there is no separate function to set the primary slave address of the + I2C device. The serial address initialized through this function is + basically the primary slave address or slave address0. + I2C_set_slave_second_addr() is used to set the secondary slave address + or slave address 1. + Note : ser_address parameter does not have any affect if fixed slave + address is enabled in CoreI2C hardware design. CoreI2C will + be always addressed with the hardware configured fixed slave + address. + Note : ser_address parameter will not have any affect if the CoreI2C + instance is only used in master mode. + + @param ser_clock_speed + This parameter sets the I2C serial clock frequency. It selects the divider + that generates the serial clock from the APB PCLK or from the BCLK. + It can be one of the following: + - I2C_PCLK_DIV_256 + - I2C_PCLK_DIV_224 + - I2C_PCLK_DIV_192 + - I2C_PCLK_DIV_160 + - I2C_PCLK_DIV_960 + - I2C_PCLK_DIV_120 + - I2C_PCLK_DIV_60 + - I2C_BCLK_DIV_8 + Note: serial_clock_speed value does not have any affect if the fixed baud + rate is enabled in CoreI2C hardware instance configuration dialogue + window. The fixed baud rate divider value overrides the value passed + as parameter in this function. + Note: serial_clock_speed value is not critical for devices that only operate + as slaves and can be set to any of the above values. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void system_init( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + } + @endcode + */ +void I2C_init +( + i2c_instance_t * this_i2c, + addr_t base_address, + uint8_t ser_address, + i2c_clock_divider_t ser_clock_speed +); + +/***************************************************************************//** + The I2C_channel_init() function initializes and configures hardware and data + structures of one of the additional channels of a CoreI2C instance. + I2C_init() must be called before calling this function to set the CoreI2C + instance hardware base address and I2C serial address. I2C_channel_init() also + initializes I2C serial clock divider to set the serial clock baud rate. + The pointer to data structure i2c_instance_t used for a particular channel + is used as an input parameter to subsequent CoreI2C driver functions + which operate on this channel. + + @param this_i2c_channel + Pointer to the i2c_instance_t data structure that holds all data related to + the CoreI2C channel gets initialized. A pointer to the same data structure + is used in subsequent calls to the CoreI2C driver functions in order to + identify the CoreI2C channel instance that should perform the operation + implemented by the called driver function. + + @param this_i2c + This is a pointer to an i2c_instance_t structure, previously initialized by + I2C_init(). It holds information regarding the hardware base address and + I2C serial address for the CoreI2C containing the channel to be + initialized. This information is required by I2C_channel_init() to + initialize the i2c_instance_t structure pointed by this_i2c_channel as + all channels in a CoreI2C instance share the same base address and serial + address. It is very important that the i2c_instance_t structure pointed + by this_i2c must be previously initialized by calling I2C_init(). + + @param channel_number + This parameter of type i2c_channel_number_t identifies the channel to be + initialized. + + @param ser_clock_speed + This parameter sets the I2C serial clock frequency. It selects the divider + that is used to generate the serial clock from the APB PCLK or from + the BCLK. It can be one of the following: + - I2C_PCLK_DIV_256 + - I2C_PCLK_DIV_224 + - I2C_PCLK_DIV_192 + - I2C_PCLK_DIV_160 + - I2C_PCLK_DIV_960 + - I2C_PCLK_DIV_120 + - I2C_PCLK_DIV_60 + - I2C_BCLK_DIV_8 + Note: serial_clock_speed value does not have any affect if the fixed baud + rate is enabled in CoreI2C hardware instance configuration dialogue + window. The fixed baud rate divider value will supersede the value + passed as parameter in this function. + Note: ser_clock_speed value is not critical for devices that only operate + as slaves and can be set to any of the above values. + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_SER_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + i2c_instance_t g_i2c_channel_1_inst; + + uint8_t tx_buffer[DATA_LENGTH]; + uint8_t write_length = DATA_LENGTH; + + void system_init( void ) + { + uint8_t target_slave_addr = 0x12; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize CoreI2C channel 1 with different clock speed + I2C_channel_init( &g_i2c_channel_1_inst, &g_i2c_inst, I2C_CHANNEL_1, + I2C_PCLK_DIV_224 ); + + // Write data to Channel 1 of CoreI2C instance. + I2C_write( &g_i2c_channel_1_inst, target_slave_addr, tx_buffer, + write_length, I2C_RELEASE_BUS ); + } + @endcode + +*/ +void I2C_channel_init +( + i2c_instance_t * this_i2c_channel, + i2c_instance_t * this_i2c, + i2c_channel_number_t channel_number, + i2c_clock_divider_t ser_clock_speed +); + +/***************************************************************************//** + The I2C_isr function is the CoreI2C interrupt service routine. User must + call this function from their application level CoreI2C interrupt handler + function. This function runs the I2C state machine based on previous and + current status. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREINTERRUPT_BASE_ADDR 0xCC000000u + #define COREI2C_SER_ADDR 0x10u + #define I2C_IRQ_NB 2u + + i2c_instance_t g_i2c_inst; + + void core_i2c_isr( void ) + { + I2C_isr( &g_i2c_inst ); + } + + void main( void ) + { + CIC_init( COREINTERRUPT_BASE_ADDR ); + NVIC_init(); + CIC_set_irq_handler( I2C_IRQ_NB, core_i2c_isr ); + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + NVIC_enable_interrupt( NVIC_IRQ_0 ); + } + @endcode + */ +void I2C_isr +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//* + #Master Specific Functions + + The following functions are only used within an I2C master's implementation. +/***************************************************************************//** + This function initiates an I2C master write transaction. This function returns + immediately after initiating the transaction. The content of the write buffer + passed as parameter should not be modified until the write transaction + completes. It also means that the memory allocated for the write buffer should + not be freed or should not go out of scope before the write completes. You can + check for the write transaction completion using the I2C_status() function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr + This parameter specifies the serial address of the target I2C device. + + @param write_buffer + This parameter is a pointer to a buffer holding the data to be written to + the target I2C device. Do not to release the memory used by this buffer + before the write transaction completes. For example, it is not appropriate + to return from a function allocating this buffer as an auto array variable + before the write transaction completes as this would result in the buffer's + memory being de-allocated from the stack when the function returns. This + memory could then be subsequently reused and modified causing unexpected + data to be written to the target I2C device. + + @param write_size + Number of bytes held in the write_buffer to be written to the target I2C + device. + + @param options + The options parameter is used to indicate if the I2C bus should be released + on completion of the write transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the write transaction causing the bus to be released for other I2C + devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the write + transaction, preventing other I2C devices from initiating a bus transaction. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t tx_buffer[DATA_LENGTH]; + uint8_t write_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Write data to Channel 0 of CoreI2C instance. + I2C_write( &g_i2c_inst, target_slave_addr, tx_buffer, write_length, + I2C_RELEASE_BUS ); + + // Wait for completion and record the outcome + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_write +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * write_buffer, + uint16_t write_size, + uint8_t options +); + +/***************************************************************************//** + This function initiates an I2C master read transaction. This function returns + immediately after initiating the transaction. + The contents of the read buffer passed as parameter should not be modified + until the read transaction completes. It also means that the memory allocated + for the read buffer should not be freed or should not go out of scope before + the read completes. You can check for the read transaction completion using + the I2C_status() function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr + This parameter specifies the serial address of the target I2C device. + + @param read_buffer + This is a pointer to a buffer where the data received from the target device + gets stored. Do not to release the memory used by this buffer before the read + transaction completes. For example, it is not appropriate to return from a + function allocating this buffer as an auto array variable before the read + transaction completes as this would result in the buffer's memory being + de-allocated from the stack when the function returns. This memory could + then be subsequently reallocated resulting in the read transaction + corrupting the newly allocated memory. + + @param read_size + This parameter specifies the number of bytes to read from the target device. + This size must not exceed the size of the read_buffer buffer. + + @param options + The options parameter is used to indicate if the I2C bus should be released + on completion of the read transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the read transaction causing the bus to be released for other I2C + devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the read transaction, + preventing other I2C devices from initiating a bus transaction. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t rx_buffer[DATA_LENGTH]; + uint8_t read_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Read data from target slave Channel 0 of CoreI2C instance. + I2C_read( &g_i2c_inst, target_slave_addr, rx_buffer, read_length, + I2C_RELEASE_BUS ); + + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +); + +/***************************************************************************//** + This function initiates an I2C write-read transaction where data is first + written to the target device before issuing a restart condition and changing + the direction of the I2C transaction in order to read from the target device. + + The same warnings about buffer allocation in I2C_write() and I2C_read() + applies to this function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr + This parameter specifies the serial address of the target I2C device. + + @param addr_offset + This parameter is a pointer to the buffer containing the data that is sent + to the slave during the write phase of the write-read transaction. This + data is typically used to specify an address offset specifying to the I2C + slave device what data it must return during the read phase of the + write-read transaction. + + @param offset_size + This parameter specifies the number of offset bytes to be written during the + write phase of the write-read transaction. This is typically the size of the + buffer pointed by the addr_offset parameter. + + @param read_buffer + This parameter is a pointer to the buffer where the data read from the I2C + slave will be stored. + + @param read_size + This parameter specifies the number of bytes to read from the target I2C + slave device. This size must not exceed the size of the buffer pointed by + the read_buffer parameter. + + @param options + The options parameter is used to indicate if the I2C bus should be released + on completion of the write-read transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the write-read transaction causing the bus to be released for other + I2C devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the write-read + transaction, preventing other I2C devices from initiating a bus transaction. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define TX_LENGTH 16u + #define RX_LENGTH 8u + + i2c_instance_t g_i2c_inst; + uint8_t rx_buffer[RX_LENGTH]; + uint8_t read_length = RX_LENGTH; + uint8_t tx_buffer[TX_LENGTH]; + uint8_t write_length = TX_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + I2C_write_read( &g_i2c_inst, target_slave_addr, tx_buffer, write_length, + rx_buffer, read_length, I2C_RELEASE_BUS ); + + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_write_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * addr_offset, + uint16_t offset_size, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +); + +/***************************************************************************//** + This function indicates the current state of a CoreI2C channel. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + The return value indicates the current state of a CoreI2C channel or the + outcome of the previous transaction if no transaction is in progress. + Following are the return values are: + - I2C_SUCCESS + The last I2C transaction has completed successfully. + - I2C_IN_PROGRESS + There is an I2C transaction in progress. + - I2C_FAILED + The last I2C transaction failed. + - I2C_TIMED_OUT + The request has failed to complete in the allotted time. + + @example + @code + i2c_instance_t g_i2c_inst; + + while( I2C_IN_PROGRESS == I2C_get_status( &g_i2c_inst ) ) + { + // Do something useful while waiting for I2C operation to complete + our_i2c_busy_task(); + } + + if( I2C_SUCCESS != I2C_get_status( &g_i2c_inst ) ) + { + // Something went wrong... + our_i2c_error_recovery( &g_i2c_inst ); + } + @endcode + */ +i2c_status_t I2C_get_status +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + This function waits for the current I2C transaction to complete. The return + value indicates whether the last I2C transaction was successful or not. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + @param timeout_ms + The timeout_ms parameter specifies the delay within which the current I2C + transaction should complete. The time out delay is given in + milliseconds. I2C_wait_complete() will return I2C_TIMED_OUT if the current + transaction has not completed after the time out delay has expired. This + parameter can be set to I2C_NO_TIMEOUT to indicate that I2C_wait_complete() + must not time out. + + @return + The return value indicates the outcome of the last I2C transaction. It can + be one of the following: + - I2C_SUCCESS + The last I2C transaction has completed successfully. + - I2C_FAILED + The last I2C transaction failed. + - I2C_TIMED_OUT + The last transaction failed to complete within the time out delay given + as second parameter. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t rx_buffer[DATA_LENGTH]; + uint8_t read_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Read data from Channel 0 of CoreI2C instance. + I2C_read( &g_i2c_inst, target_slave_addr, rx_buffer, read_length, + I2C_RELEASE_BUS ); + + // Wait for completion and record the outcome + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +i2c_status_t I2C_wait_complete +( + i2c_instance_t * this_i2c, + uint32_t timeout_ms +); + +/***************************************************************************//** + This function is used to control the expiration of the time out delay + specified as a parameter to the I2C_wait_complete() function. It must be + called from the interrupt service routine of a periodic interrupt source such + as the SysTick timer interrupt. It takes the period of the interrupt + source as its ms_since_last_tick parameter and uses it as the time base for + the I2C_wait_complete() function's time out delay. + + Note: This function does not need to be called if the I2C_wait_complete() + function is called with a timeout_ms value of I2C_NO_TIMEOUT. + + Note: If this function is not called then the I2C_wait_complete() function + will behave as if its timeout_ms was specified as I2C_NO_TIMEOUT and it + will not time out. + + Note: If this function is being called from an interrupt handler (for example, + SysTick) it is important that the calling interrupt have a lower priority + than the CoreI2C interrupt(s) to ensure any updates to the shared data are + protected. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + @param ms_since_last_tick + The ms_since_last_tick parameter specifies the number of milliseconds that + elapsed since the last call to I2C_system_tick(). This parameter would + typically be a constant specifying the interrupt rate of a timer used to + generate system ticks. + + @return None. + + @example + The following example shows how the I2C_system_tick() function. I2C_system_tick() + is called for each I2C channel from the SysTick timer interrupt service routine. + The following example shows how the SysTick is configured to generate an interrupt + in every 10 milliseconds. + @code + #define SYSTICK_INTERVAL_MS 10 + + void SysTick_Handler(void) + { + I2C_system_tick(&g_core_i2c0, SYSTICK_INTERVAL_MS); + I2C_system_tick(&g_core_i2c2, SYSTICK_INTERVAL_MS); + } + @endcode + */ +void I2C_system_tick +( + i2c_instance_t * this_i2c, + uint32_t ms_since_last_tick +); + +/***************************************************************************//* + #Slave Specific Functions + + The following functions are only used within the implementation of an I2C slave device. + +/***************************************************************************//** + This function specifies the memory buffer holding the data that will be sent + to the I2C master when this CoreI2C channel is the target of an I2C read or + write-read transaction. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param tx_buffer + This parameter is a pointer to the memory buffer holding the data to be + returned to the I2C master when this CoreI2C channel is the target of an + I2C read or write-read transaction. + + @param tx_size + Size of the transmit buffer pointed by the tx_buffer parameter. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Specify the transmit buffer containing the data that will be + // returned to the master during read and write-read transactions. + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + } + @endcode + */ +void I2C_set_slave_tx_buffer +( + i2c_instance_t * this_i2c, + const uint8_t * tx_buffer, + uint16_t tx_size +); + +/***************************************************************************//** + This function specifies the memory buffer that is used by the CoreI2C channel + to receive data when it is a slave. This buffer is the memory where data gets + stored when the CoreI2C channel is the target of an I2C master write + transaction (that is, when it is the slave). + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param rx_buffer + This parameter is a pointer to the memory buffer allocated by the caller + software to be used as a slave receive buffer. + + @param rx_size + Size of the slave receive buffer. This is the amount of memory allocated + to the buffer pointed by rx_buffer. + Note: Indirectly, this buffer size specifies the maximum I2C write + transaction length this CoreI2C channel targets. This is because + this CoreI2C channel responds to further received bytes with + a non-acknowledge bit (NACK) as soon as its receive buffer is + full. This causes the write transaction to fail. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_RX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_rx_buffer[SLAVE_RX_BUFFER_SIZE]; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Specify the buffer used to store the data written by the I2C master. + I2C_set_slave_rx_buffer( &g_i2c_inst, g_slave_rx_buffer, + sizeof(g_slave_rx_buffer) ); + } + @endcode + */ +void I2C_set_slave_rx_buffer +( + i2c_instance_t * this_i2c, + uint8_t * rx_buffer, + uint16_t rx_size +); + +/***************************************************************************//** + This function is used as part of the configuration of a CoreI2C channel to + operate as a slave supporting write-read transactions. It specifies the + number of bytes expected as part of the write phase of a write-read + transaction. The bytes received during the write phase of a write-read + transaction will be interpreted as an offset into the slave's transmit buffer. + This allows random access into the I2C slave transmit buffer from a remote + I2C master. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param offset_length + The offset_length parameter configures the number of bytes to be interpreted + by the CoreI2C slave as a memory offset value during the write phase of + write-read transactions. The maximum value for the offset_length parameter + is two. The value of offset_length has the following effect on the + interpretation of the received data. + • If offset_length is 0, the offset into the transmit buffer is fixed at 0. + • If offset_length is 1, a single byte of received data is interpreted as an + unsigned 8-bit offset value in the range 0 to 255. + • If offset_length is 2, 2 bytes of received data are interpreted as an + unsigned 16-bit offset value in the range 0 to 65535. The first byte + received in this case provides the high order bits of the offset and + the second byte provides the low order bits. + If the number of bytes received does not match the non 0 value of + offset_length, the transmit buffer offset is set to 0. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + I2C_set_slave_mem_offset_length( &g_i2c_inst, 1 ); + } + @endcode + */ +void I2C_set_slave_mem_offset_length +( + i2c_instance_t * this_i2c, + uint8_t offset_length +); + +/***************************************************************************//** + Register the function that is called to process the data written to this + CoreI2C channel when it is the slave in an I2C write transaction. + + Note: If a write handler is registered, it is called on completion of the + write phase of a write-read transaction and responsible for processing + the received data in the slave receive buffer and populating the slave + transmit buffer with the data that is transmitted to the I2C master + as part of the read phase of the write-read transaction. If a write + handler is not registered, the write data of a write-read transaction is + interpreted as an offset into the slave’s transmit buffer and handled by + the driver. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param handler + Pointer to the function that processes the I2C write request. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + // local function prototype + void slave_write_handler + ( + i2c_instance_t * this_i2c, + uint8_t * p_rx_data, + uint16_t rx_size + ); + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + I2C_set_slave_mem_offset_length( &g_i2c_inst, 1 ); + I2C_register_write_handler( &g_i2c_inst, slave_write_handler ); + } + @endcode +*/ +void I2C_register_write_handler +( + i2c_instance_t * this_i2c, + i2c_slave_wr_handler_t handler +); + +/***************************************************************************//** + This function enables slave mode operation for a CoreI2C channel. It enables + the CoreI2C slave to receive data when it is the target of an I2C read, write, + or write-read transaction. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + // Enable I2C slave + I2C_enable_slave( &g_i2c_inst ); + @endcode + */ +void I2C_enable_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + This function disables the slave mode operation for a CoreI2C channel. It stops + the CoreI2C slave that acknowledges the I2C read, write, or write-read + transactions targeted at it. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + // Disable I2C slave + I2C_disable_slave( &g_i2c_inst ); + @endcode + */ +void I2C_disable_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_slave_second_addr() function sets the secondary slave address for + a CoreI2C slave device. This is an additional slave address required in certain + applications, for example, to enable fail-safe operation in a system. As the + CoreI2C device supports 7-bit addressing, the highest value assigned to second + slave address is 127 (0x7F). + + Note: This function does not support CoreI2C hardware configured with a fixed + second slave address. The current implementation of the ADDR1[0] register + bit makes it difficult for the driver to support both programmable and + fixed second slave address, so we choose to support programmable only. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param second_slave_addr + The second_slave_addr parameter is the secondary slave address of the I2C + device. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SECOND_SLAVE_ADDR 0x20u + + i2c_instance_t g_i2c_inst; + void main( void ) + { + // Initialize the CoreI2C driver with its base address, primary I2C + // serial address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_second_addr( &g_i2c_inst, SECOND_SLAVE_ADDR ); + } + @endcode + */ +void I2C_set_slave_second_addr +( + i2c_instance_t * this_i2c, + uint8_t second_slave_addr +); + +/***************************************************************************//** + The I2C_disable_slave_second_addr() function disables the secondary slave + address of the CoreI2C slave device. + + Note: This version of the driver only supports CoreI2C hardware configured + with a programmable second slave address. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + i2c_instance_t g_i2c_inst; + I2C_disable_slave_second_addr( &g_i2c_inst); + @endcode + */ +void I2C_disable_slave_second_addr +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_gca() function is used to set the general call acknowledgement bit + of a CoreI2C slave device. This allows all channels of the CoreI2C slave + device to respond to a general call or broadcast message from an I2C master. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + i2c_instance_t g_i2c_inst; + + // Enable recognition of the General Call Address + I2C_set_gca( &g_i2c_inst ); + @endcode + */ +void I2C_set_gca +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_clear_gca() function is used to clear the general call acknowledgement + bit of a CoreI2C slave device. This will stop all channels of the I2C slave + device responding to any general call or broadcast message from the master. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + i2c_instance_t g_i2c_inst; + + // Disable recognition of the General Call Address + I2C_clear_gca( &g_i2c_inst ); + @endcode + */ + +void I2C_clear_gca +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//* + #I2C SMBUS Specific APIs + +/***************************************************************************//** + The I2C_smbus_init() function enables SMBus timeouts and status logic for a + CoreI2C channel. + + Note: This and any of the other SMBus related functionality will only have an + effect if the CoreI2C was instantiated with the Generate SMBus Logic + option checked. + + Note: If the CoreI2C was instantiated with the Generate IPMI Logic option + checked this function then enables the IPMI 3mS SCL low timeout but + none of the other SMBus functions will have any effect. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void system_init( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst); + } + @endcode + */ +void I2C_smbus_init +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_enable_smbus_irq() function is used to enable the CoreI2C channel’s + SMBSUS and SMBALERT SMBus interrupts. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param irq_type + The irq_type specify the SMBUS interrupt(s) which will be enabled. + The two possible interrupts are: + - I2C_SMBALERT_IRQ + - I2C_SMBSUS_IRQ + To enable both interrupts in one call, use I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ. + + @return + None + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both I2C_SMBALERT_IRQ & I2C_SMBSUS_IRQ interrupts + I2C_enable_smbus_irq( &g_i2c_inst, + (uint8_t)(I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ) ); + } + @endcode + */ +void I2C_enable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +); + +/***************************************************************************//** + The I2C_disable_smbus_irq() function disable the CoreI2C channel’s SMBSUS and + SMBALERT SMBus interrupts. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param irq_type + The irq_type specifies the SMBUS interrupt(s) which are disabled. + The two possible interrupts are: + • I2C_SMBALERT_IRQ + • I2C_SMBSUS_IRQ + To disable both ints in one call, use I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both SMBALERT & SMBSUS interrupts + I2C_enable_smbus_irq( &g_i2c_inst, + (uint8_t)(I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ)); + + ... + + // Disable the SMBALERT interrupt + I2C_disable_smbus_irq( &g_i2c_inst, I2C_SMBALERT_IRQ ); + } + @endcode + */ +void I2C_disable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +); + +/***************************************************************************//** + The I2C_suspend_smbus_slave() function forces any SMBUS slave devices + connected to a CoreI2C channel into Power-Down or Suspend mode by asserting + the channel's SMBSUS signal. The CoreI2C channel is the SMBus master in this + case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // suspend SMBus slaves + I2C_suspend_smbus_slave( &g_i2c_inst ); + + ... + + // Re-enable SMBus slaves + I2C_resume_smbus_slave( &g_i2c_inst ); + } + @endcode + */ +void I2C_suspend_smbus_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_resume_smbus_slave() function de-asserts the CoreI2C channel's SMBSUS + signal to take any connected slave devices out of the Suspend mode. The CoreI2C + channel is the SMBus master in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // suspend SMBus slaves + I2C_suspend_smbus_slave( &g_i2c_inst ); + + ... + + // Re-enable SMBus slaves + I2C_resume_smbus_slave( &g_i2c_inst ); + } + @endcode + */ +void I2C_resume_smbus_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_reset_smbus() function resets the CoreI2C channel's SMBus connection + by forcing SCLK low for 35 mS. The reset that automatically cleares after 35 ms + gets elapsed. The CoreI2C channel is the SMBus master in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Make sure the SMBus channel is in a known state by resetting it + I2C_reset_smbus( &g_i2c_inst ); + } + @endcode + */ +void I2C_reset_smbus +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_smbus_alert() function is used to force master communication with + an I2C slave device by asserting the CoreI2C channel's SMBALERT signal. The + CoreI2C channel is the SMBus slave in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Get the SMBus masters attention + I2C_set_smbus_alert( &g_i2c_inst ); + + ... + + // Once we are happy, drop the alert + I2C_clear_smbus_alert( &g_i2c_inst ); + } + @endcode + */ +void I2C_set_smbus_alert +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_clear_smbus_alert() function is used to de-assert the CoreI2C channel's + SMBALERT signal once a slave device gets a response from the master. The + CoreI2C channel is the SMBus slave in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Get the SMBus masters attention + I2C_set_smbus_alert( &g_i2c_inst ); + + ... + + // Once we are happy, drop the alert + I2C_clear_smbus_alert( &g_i2c_inst ); + } + @endcode + */ +void I2C_clear_smbus_alert +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_get_irq_status function returns information about which interrupts are + currently pending in a CoreI2C channel. + The interrupts supported by CoreI2C are: + • SMBUSALERT + • SMBSUS + • INTR + + The macros I2C_NO_IRQ, I2C_SMBALERT_IRQ, I2C_SMBSUS_IRQ, and I2C_INTR_IRQ are + provided to use with this function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + This function returns the status of the CoreI2C channel's interrupts as a + single byte bitmap where a bit is set to indicate a pending interrupt. + The following are the bit positions associated with each interrupt type: + Bit 0 - SMBUS_ALERT_IRQ + Bit 1 - SMBSUS_IRQ + Bit 2 - INTR_IRQ + It returns 0, if there are no pending interrupts. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + uint8_t irq_to_enable = I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ; + uint8_t pending_irq = 0u; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both I2C_SMBALERT_IRQ & I2C_SMBSUS_IRQ irq + I2C_enable_smbus_irq( &g_i2c_inst, irq_to_enable ); + + // Get I2C IRQ type + pending_irq = I2C_get_irq_status( &g_i2c_inst ); + + // Let's assume, in system, INTR and SMBALERT IRQ is pending. + // So pending_irq will return status of both the IRQs + + if( pending_irq & I2C_SMBALERT_IRQ ) + { + // if true, it means SMBALERT_IRQ is there in pending IRQ list + } + if( pending_irq & I2C_INTR_IRQ ) + { + // if true, it means I2C_INTR_IRQ is there in pending IRQ list + } + } + @endcode + */ +uint8_t I2C_get_irq_status +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_user_data() function allows the association of a block of application + specific data with a CoreI2C channel. The composition of the data block is an + application matter and the driver simply provides the means for the application + to set and retrieve the pointer. For example, this is used to provide additional + channel specific information to the slave write handler. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param p_user_data + The p_user_data parameter is a pointer to the user specific data block for + this channel. It is defined as void * as the driver does not know the actual + type of data being pointed to and simply stores the pointer for later + retrieval by the application. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + app_data_t channel_xdata; + + void main( void ) + { + app_data_t *p_xdata; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Store location of user data in instance structure + I2C_set_user_data( &g_i2c_inst, (void *)&channel_xdata ); + + ... + + // Retrieve location of user data and do some work on it + p_xdata = (app_data_t *)I2C_get_user_data( &g_i2c_inst ); + if( NULL != p_xdata ) + { + p_xdata->foo = 123; + } + } + @endcode + */ +void I2C_set_user_data +( + i2c_instance_t * this_i2c, + void * p_user_data +); + +/***************************************************************************//** + The I2C_get_user_data() function is used to allows the retrieval of the address + of a block of application specific data associated with a CoreI2C channel. + The composition of the data block is an application matter and the driver + simply provides the means for the application to set and retrieve the pointer. + For example, this is used to provide additional channel specific information + to the slave write handler. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + This function returns a pointer to the user specific data block for this + channel. It is defined as void * as the driver does not know the actual type + of data being pointed. If no user data has been registered for this channel + a NULL pointer is returned. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + app_data_t channel_xdata; + + void main( void ) + { + app_data_t *p_xdata; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Store location of user data in instance structure + I2C_set_user_data( &g_i2c_inst, (void *)&channel_xdata ); + + ... + + // Retrieve location of user data and do some work on it + p_xdata = (app_data_t *)I2C_get_user_data( &g_i2c_inst ); + if( NULL != p_xdata ) + { + p_xdata->foo = 123; + } + } + @endcode + */ +void * I2C_get_user_data +( + i2c_instance_t * this_i2c +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h new file mode 100644 index 0000000..b1d872d --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h @@ -0,0 +1,190 @@ +/******************************************************************************* + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + */ + +#ifndef __CORE_SMBUS_REGISTERS +#define __CORE_SMBUS_REGISTERS 1 + +/*------------------------------------------------------------------------------ + * CONTROL register details + */ +#define CONTROL_REG_OFFSET 0x00u + +/* + * CR0 bits. + */ +#define CR0_OFFSET 0x00u +#define CR0_MASK 0x01u +#define CR0_SHIFT 0u + +/* + * CR1 bits. + */ +#define CR1_OFFSET 0x00u +#define CR1_MASK 0x02u +#define CR1_SHIFT 1u + +/* + * AA bits. + */ +#define AA_OFFSET 0x00u +#define AA_MASK 0x04u +#define AA_SHIFT 2u + +/* + * SI bits. + */ +#define SI_OFFSET 0x00u +#define SI_MASK 0x08u +#define SI_SHIFT 3u + +/* + * STO bits. + */ +#define STO_OFFSET 0x00u +#define STO_MASK 0x10u +#define STO_SHIFT 4u + +/* + * STA bits. + */ +#define STA_OFFSET 0x00u +#define STA_MASK 0x20u +#define STA_SHIFT 5u + +/* + * ENS1 bits. + */ +#define ENS1_OFFSET 0x00u +#define ENS1_MASK 0x40u +#define ENS1_SHIFT 6u + +/* + * CR2 bits. + */ +#define CR2_OFFSET 0x00u +#define CR2_MASK 0x80u +#define CR2_SHIFT 7u + +/*------------------------------------------------------------------------------ + * STATUS register details + */ +#define STATUS_REG_OFFSET 0x04u + +/*------------------------------------------------------------------------------ + * DATA register details + */ +#define DATA_REG_OFFSET 0x08u + +/* + * TARGET_ADDR bits. + */ +#define TARGET_ADDR_OFFSET 0x08u +#define TARGET_ADDR_MASK 0xFEu +#define TARGET_ADDR_SHIFT 1u + +/* + * DIR bit. + */ +#define DIR_OFFSET 0x08u +#define DIR_MASK 0x01u +#define DIR_SHIFT 0u + + +/*------------------------------------------------------------------------------ + * ADDRESS register details + */ +#define ADDRESS_REG_OFFSET 0x0Cu + +/* + * GC bits. + */ +#define GC_OFFSET 0x0Cu +#define GC_MASK 0x01u +#define GC_SHIFT 0u + +/* + * ADR bits. + */ +#define OWN_SLAVE_ADDR_OFFSET 0x0Cu +#define OWN_SLAVE_ADDR_MASK 0xFEu +#define OWN_SLAVE_ADDR_SHIFT 1u + +/*------------------------------------------------------------------------------ + * SMBUS register details + */ +#define SMBUS_REG_OFFSET 0x10u + +/* + * SMBALERT_IE bits. + */ +#define SMBALERT_IE_OFFSET 0x10u +#define SMBALERT_IE_MASK 0x01u +#define SMBALERT_IE_SHIFT 0u + +/* + * SMBSUS_IE bits. + */ +#define SMBSUS_IE_OFFSET 0x10u +#define SMBSUS_IE_MASK 0x02u +#define SMBSUS_IE_SHIFT 1u + +/* + * SMB_IPMI_EN bits. + */ +#define SMB_IPMI_EN_OFFSET 0x10u +#define SMB_IPMI_EN_MASK 0x04u +#define SMB_IPMI_EN_SHIFT 2u + +/* + * SMBALERT_NI_STATUS bits. + */ +#define SMBALERT_NI_STATUS_OFFSET 0x10u +#define SMBALERT_NI_STATUS_MASK 0x08u +#define SMBALERT_NI_STATUS_SHIFT 3u + +/* + * SMBALERT_NO_CONTROL bits. + */ +#define SMBALERT_NO_CONTROL_OFFSET 0x10u +#define SMBALERT_NO_CONTROL_MASK 0x10u +#define SMBALERT_NO_CONTROL_SHIFT 4u + +/* + * SMBSUS_NI_STATUS bits. + */ +#define SMBSUS_NI_STATUS_OFFSET 0x10u +#define SMBSUS_NI_STATUS_MASK 0x20u +#define SMBSUS_NI_STATUS_SHIFT 5u + +/* + * SMBSUS_NO_CONTROL bits. + */ +#define SMBSUS_NO_CONTROL_OFFSET 0x10u +#define SMBSUS_NO_CONTROL_MASK 0x40u +#define SMBSUS_NO_CONTROL_SHIFT 6u + +/* + * SMBUS_MST_RESET bits. + */ +#define SMBUS_MST_RESET_OFFSET 0x10u +#define SMBUS_MST_RESET_MASK 0x80u +#define SMBUS_MST_RESET_SHIFT 7u + +/*------------------------------------------------------------------------------ + * SLAVE ADDRESS 1 register details + */ + +#define ADDRESS1_REG_OFFSET 0x1Cu + +/* + * SLAVE1_EN bit of Slave Address 1 . + */ +#define SLAVE1_EN_OFFSET 0x1Cu +#define SLAVE1_EN_MASK 0x01u +#define SLAVE1_EN_SHIFT 0u + +#endif /* __CORE_SMBUS_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c new file mode 100644 index 0000000..12e352d --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * CoreI2C driver interrupt control. + * + */ +#include "core_i2c.h" + +/*------------------------------------------------------------------------------ + * This function must be modified to enable interrupts generated from the + * CoreI2C instance identified as parameter. + */ +void I2C_enable_irq( i2c_instance_t * this_i2c ) +{ + HAL_ASSERT(0) +} + +/*------------------------------------------------------------------------------ + * This function must be modified to disable interrupts generated from the + * CoreI2C instance identified as parameter. + */ +void I2C_disable_irq( i2c_instance_t * this_i2c ) +{ + HAL_ASSERT(0) +} diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.c b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.c new file mode 100644 index 0000000..2e11750 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.c @@ -0,0 +1,1345 @@ +/***************************************************************************//** + * Copyright 2013-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * CoreSPI bare metal driver implementation for CoreSPI. + * + * This Core SPI driver provides functions for implementing SPI master or + * SPI slave operations with the CoreSPI version 4.2.xxx It is not compatible + * with CoreSPI version 3.0.xxx. + * + * @file core_spi.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreSPI software configuration + * + */ + +#include "core_spi.h" +#include "corespi_regs.h" +#include + +/******************************************************************************* + * Null parameters with appropriate type definitions + */ +#define NULL_ADDR ( ( addr_t ) 0u ) +#define NULL_INSTANCE ( ( spi_instance_t * ) 0u ) +#define NULL_BUFF ( ( uint8_t * ) 0u ) +#define NULL_FRAME_HANDLER ( ( spi_frame_rx_handler_t ) 0u ) +#define NULL_BLOCK_HANDLER ( ( spi_block_rx_handler_t ) 0u ) +#define NULL_SLAVE_TX_UPDATE_HANDLER ( ( spi_slave_frame_tx_handler_t ) 0u ) +#define NULL_SLAVE_CMD_HANDLER NULL_BLOCK_HANDLER + +#define SPI_ALL_INTS (0xFFu) /* For clearing all active interrupts */ + +/******************************************************************************* + * Possible states for different register bit fields + */ + +#define DISABLE 0u +#define ENABLE 1u + + +/******************************************************************************* + * Function return values + */ +enum { + FAILURE = 0u, + SUCCESS = 1u +}; + +/******************************************************************************* + * Local function declarations + */ +static void fill_slave_tx_fifo( spi_instance_t * this_spi ); +static void read_slave_rx_fifo( spi_instance_t * this_spi ); +static void recover_from_rx_overflow( const spi_instance_t * this_spi ); + +/******************************************************************************* + * SPI_init() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_init +( + spi_instance_t * this_spi, + addr_t base_addr, + uint16_t fifo_depth +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( NULL_ADDR != base_addr ); + HAL_ASSERT( SPI_MAX_FIFO_DEPTH >= fifo_depth ); + HAL_ASSERT( SPI_MIN_FIFO_DEPTH <= fifo_depth ); + + if( ( NULL_INSTANCE != this_spi ) && ( base_addr != NULL_ADDR ) ) + { + /* + * Initialize all transmit / receive buffers and handlers + * + * Relies on the fact that byte filling with 0x00 will equate + * to 0 for any non byte sized items too. + */ + + /* First fill struct with 0s */ + memset( this_spi, 0, sizeof(spi_instance_t) ); + + /* Configure CoreSPI instance attributes */ + this_spi->base_addr = (addr_t)base_addr; + + /* Store FIFO depth or fall back to minimum if out of range */ + if( ( SPI_MAX_FIFO_DEPTH >= fifo_depth ) && ( SPI_MIN_FIFO_DEPTH <= fifo_depth ) ) + { + this_spi->fifo_depth = fifo_depth; + } + else + { + this_spi->fifo_depth = SPI_MIN_FIFO_DEPTH; + } + /* Make sure the CoreSPI is disabled while we configure it */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Ensure all slaves are deselected */ + HAL_set_8bit_reg( this_spi->base_addr, SSEL, 0u ); + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Ensure RXAVAIL, TXRFM, SSEND and CMDINT are disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, 0u ); + /* + * Enable the CoreSPI in the reset default of master mode + * with TXUNDERRUN, RXOVFLOW and TXDONE interrupts disabled. + * The driver does not currently use interrupts in master mode. + */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL1, ENABLE | CTRL1_MASTER_MASK ); + } +} + +/***************************************************************************//** + * SPI_configure_slave_mode() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_configure_slave_mode +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Don't yet know what slave transfer mode will be used */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_NONE; + + /* Make sure the CoreSPI is disabled while we configure it */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Ensure RXAVAIL, TXRFM, SSEND and CMDINT are disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, 0u ); + /* + * Enable the CoreSPI in slave mode with TXUNDERRUN, RXOVFLOW and TXDONE + * interrupts disabled. The appropriate interrupts will be enabled later + * on when the transfer mode is configured. + */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL1, ENABLE ); + } +} + +/***************************************************************************//** + * SPI_configure_master_mode() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_configure_master_mode +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Disable the CoreSPI for a little while, while we configure the CoreSPI */ + HAL_set_8bit_reg_field(this_spi->base_addr, CTRL1_ENABLE, DISABLE); + + /* Reset slave transfer mode to unknown in case it has been set previously */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_NONE; + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Ensure RXAVAIL, TXRFM, SSEND and CMDINT are disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, 0u ); + + /* Enable the CoreSPI in master mode with TXUNDERRUN, RXOVFLOW and TXDONE interrupts disabled */ + HAL_set_8bit_reg( this_spi->base_addr, CTRL1, ENABLE | CTRL1_MASTER_MASK ); + } +} + +/***************************************************************************//** + * SPI_set_slave_select() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +) +{ + spi_slave_t temp = (spi_slave_t)(0x00u) ; + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( SPI_MAX_NB_OF_SLAVES > slave ); + + if( ( NULL_INSTANCE != this_spi ) && ( SPI_MAX_NB_OF_SLAVES > slave ) ) + { + /* This function is only intended to be used with an SPI master */ + if( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW ) ) + { + recover_from_rx_overflow( this_spi ); + } + /* Set the correct slave select bit */ + temp = (spi_slave_t)( HAL_get_8bit_reg( this_spi->base_addr, SSEL ) | ((uint32_t)1u << (uint32_t)slave) ); + HAL_set_8bit_reg( this_spi->base_addr, SSEL, (uint_fast8_t)temp ); + } + } +} + +/***************************************************************************//** + * SPI_clear_slave_select() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_clear_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +) +{ + spi_slave_t temp = (spi_slave_t) (0x00u) ; + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( SPI_MAX_NB_OF_SLAVES > slave ); + + if( ( NULL_INSTANCE != this_spi ) && ( SPI_MAX_NB_OF_SLAVES > slave ) ) + { + /* This function is only intended to be used with an SPI master. */ + if( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW) ) + { + recover_from_rx_overflow( this_spi ); + } + /* Clear the correct slave select bit */ + temp = (spi_slave_t)( HAL_get_8bit_reg( this_spi->base_addr, SSEL ) & ~((uint32_t)1u << (uint32_t)slave) ); + HAL_set_8bit_reg( this_spi->base_addr, SSEL, (uint_fast8_t)temp ) ; + } + } +} + +/***************************************************************************//** + * SPI_transfer_frame() + * See "core_spi.h" for details of how to use this function. + */ +uint32_t SPI_transfer_frame +( + spi_instance_t * this_spi, + uint32_t tx_bits +) +{ + volatile uint32_t rx_data = 0u; /* Ensure consistent return value if in slave mode */ + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI master. */ + if( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Flush the receive and transmit FIFOs by resetting both */ + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK); + + /* Send frame. */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, tx_bits ); + + /* Wait for frame Tx to complete. */ + while ( ENABLE != HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_DONE ) ) + { + ; + } + + /* Read received frame. */ + rx_data = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + } + } + + /* Finally, return the frame we received from the slave or 0 */ + return( rx_data ); +} + + +/***************************************************************************//** + * SPI_transfer_block() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_transfer_block +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_buffer, + uint16_t rx_byte_size +) +{ + uint32_t transfer_size = 0U; /* Total number of bytes to transfer. */ + uint16_t transfer_idx = 0U; /* Number of bytes transferred so far */ + uint16_t tx_idx = 0u; /* Number of valid data bytes sent */ + uint16_t rx_idx = 0u; /* Number of valid response bytes received */ + uint16_t transit = 0U; /* Number of bytes "in flight" to avoid FIFO errors */ + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI master. */ + if( ( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) && + /* Check for empty transfer as well */ + ( 0u != ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) ) ) + { + /* + * tansfer_size is one less than the real amount as we have to write + * the last frame separately to trigger the slave deselect in case + * the SPS option is in place. + */ + transfer_size = ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) - 1u; + /* Flush the receive and transmit FIFOs */ + HAL_set_8bit_reg(this_spi->base_addr, CMD, (uint32_t)(CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK )); + + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW) ) + { + recover_from_rx_overflow( this_spi ); + } + + /* Disable the Core SPI for a little bit, while we load the TX FIFO */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + while( ( tx_idx < transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out 0s to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + } + ++transit; + ++tx_idx; + } + + /* If room left to put last frame in before the off, then do it */ + if( ( tx_idx == transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data, not expecting any reply this time */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out last 0 to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + } + + ++transit; + ++tx_idx; + } + + /* FIFO is all loaded up so enable Core SPI to start transfer */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + + /* Perform the remainder of the transfer by sending a byte every time a byte + * has been received. This should ensure that no Rx overflow can happen in + * case of an interrupt occurring during this function. + * + * We break the transfer down into stages to minimise the processing in + * each loop as the SPI interface is very demanding at higher clock rates. + * This works well with FIFOs but might be less efficient if there is only + * a single frame buffer. + * + * First stage transfers remaining command bytes (if any). + * At this stage anything in the RX FIFO can be discarded as it is + * not part of a valid response. + */ + while( tx_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + /* Send another byte. */ + if( tx_idx == transfer_size ) /* Last frame is special... */ + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Read and discard. */ + HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now, we are writing dummy bytes to push through the response from + * the slave but we still have to keep discarding any read data that + * corresponds with one of our command bytes. + */ + while( transfer_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + if( tx_idx < transfer_size ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Read and discard. */ + HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now we are now only sending dummy data to push through the + * valid response data which we store in the response buffer. + */ + while( tx_idx < transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received byte. */ + rx_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* If we still need to send the last frame */ + while( tx_idx == transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received byte. */ + rx_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* + * Finally, we are now finished sending data and are only reading + * valid response data which we store in the response buffer. + */ + while( transfer_idx <= transfer_size ) + { + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received byte. */ + rx_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + } + } + } + } +} + +/***************************************************************************//** + * SPI_transfer_block_store_all_resp() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_transfer_block_store_all_resp +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_data_buffer, + uint16_t rx_byte_size, + uint8_t * cmd_response_buffer +) +{ + uint32_t transfer_size = 0U; /* Total number of bytes to transfer. */ + uint16_t transfer_idx = 0U; /* Number of bytes transferred so far */ + uint16_t tx_idx = 0u; /* Number of valid data bytes sent */ + uint16_t rx_idx = 0u; /* Number of valid response bytes received */ + uint16_t transit = 0U; /* Number of bytes "in flight" to avoid FIFO errors */ + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI master. */ + if( ( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) && + /* Check for empty transfer as well */ + ( 0u != ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) ) ) + { + /* + * tansfer_size is one less than the real amount as we have to write + * the last frame separately to trigger the slave deselect in case + * the SPS option is in place. + */ + transfer_size = ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) - 1u; + /* Flush the receive and transmit FIFOs */ + HAL_set_8bit_reg(this_spi->base_addr, CMD, (uint32_t)(CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK )); + + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW) ) + { + recover_from_rx_overflow( this_spi ); + } + + /* Disable the Core SPI for a little bit, while we load the TX FIFO */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + while( ( tx_idx < transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out 0s to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + } + ++transit; + ++tx_idx; + } + + /* If room left to put last frame in before the off, then do it */ + if( ( tx_idx == transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data, not expecting any reply this time */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out last 0 to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + } + + ++transit; + ++tx_idx; + } + + /* FIFO is all loaded up so enable Core SPI to start transfer */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + + /* Perform the remainder of the transfer by sending a byte every time a byte + * has been received. This should ensure that no Rx overflow can happen in + * case of an interrupt occurring during this function. + * + * We break the transfer down into stages to minimise the processing in + * each loop as the SPI interface is very demanding at higher clock rates. + * This works well with FIFOs but might be less efficient if there is only + * a single frame buffer. + * + * First stage transfers remaining command bytes (if any). + * At this stage anything in the RX FIFO can be discarded as it is + * not part of a valid response. + */ + while( tx_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + /* Send another byte. */ + if( tx_idx == transfer_size ) /* Last frame is special... */ + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received command byte. */ + cmd_response_buffer[transfer_idx] = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now, we are writing dummy bytes to push through the response from + * the slave, which we store in the command response buffer. + */ + while( transfer_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + if( tx_idx < transfer_size ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received command byte. */ + cmd_response_buffer[transfer_idx] = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now we are now only sending dummy data to push through the + * valid response data which we store in the data response buffer. + */ + while( tx_idx < transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received data byte. */ + rx_data_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* If we still need to send the last frame */ + while( tx_idx == transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received data byte. */ + rx_data_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* + * Finally, we are now finished sending data and are only reading + * valid response data which we store in the data response buffer. + */ + while( transfer_idx <= transfer_size ) + { + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received data byte. */ + rx_data_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + } + } + } + } +} +/***************************************************************************//** + * SPI_set_frame_rx_handler() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_frame_rx_handler +( + spi_instance_t * this_spi, + spi_frame_rx_handler_t rx_handler +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if(NULL_INSTANCE != this_spi) + { + /* This function is only intended to be used with an SPI slave. */ + if(DISABLE == HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER)) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Disable SSEND and CMD interrupts as we are not doing block transfers */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTSSEND, DISABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + + /* Disable block Rx handler as they are mutually exclusive. */ + this_spi->block_rx_handler = 0U; + + /* Keep a copy of the pointer to the Rx handler function. */ + this_spi->frame_rx_handler = rx_handler; + + if( SPI_SLAVE_XFER_FRAME != this_spi->slave_xfer_mode ) + { + /* + * Either just coming from init or were previously in block mode + * so no tx frame handler is set at this point in time... + * + * Don't allow TXDONE interrupts. + */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXDONE, DISABLE ); + } + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK); + + /* Enable Rx and FIFO error interrupts */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTRXOVFLOW, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXURUN, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTRXDATA, ENABLE ); + + /* Make sure correct mode is selected */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_FRAME; + + /* Finally re-enable the CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } + } +} + +/***************************************************************************//** + * SPI_set_slave_tx_frame() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_slave_tx_frame +( + spi_instance_t * this_spi, + uint32_t frame_value, + spi_slave_frame_tx_handler_t slave_tx_frame_handler +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI slave. */ + if( DISABLE == HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Disable SSEND and CMD interrupts as we are not doing block transfers */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTSSEND, DISABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + + if( SPI_SLAVE_XFER_FRAME != this_spi->slave_xfer_mode ) + { + /* + * Either just coming from init or were previously in block mode + * so no rx frame handler is set at this point in time... + * + * Don't allow RXDATA interrupts. + */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTRXDATA, DISABLE ); + } + + /* Disable slave block tx buffer as it is mutually exclusive with frame + * level handling. */ + this_spi->slave_tx_buffer = NULL_BUFF; + this_spi->slave_tx_size = 0U; + this_spi->slave_tx_idx = 0U; + + /* Flush the receive and transmit FIFOs*/ + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK); + + /* Assign the slave frame update handler - NULL_SLAVE_TX_UPDATE_HANDLER for none */ + this_spi->slave_tx_frame_handler = slave_tx_frame_handler; + + /* Keep a copy of the slave Tx frame value. */ + this_spi->slave_tx_frame = frame_value; + + /* Load one frame into Tx data register. */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, this_spi->slave_tx_frame ); + + /* Enable Tx Done interrupt in order to reload the slave Tx frame after each + * time it has been sent. */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXDONE, ENABLE ); + + /* Make sure correct mode is selected */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_FRAME; + + /* Ready to go so enable CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } + } +} + +/***************************************************************************//** + * SPI_set_slave_block_buffers() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_slave_block_buffers +( + spi_instance_t * this_spi, + const uint8_t * tx_buffer, + uint32_t tx_buff_size, + uint8_t * rx_buffer, + uint32_t rx_buff_size, + spi_block_rx_handler_t block_rx_handler +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI slave. */ + if( DISABLE == HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Make sure correct mode is selected */ + this_spi->slave_xfer_mode = SPI_SLAVE_XFER_BLOCK; + /* + * No command handler should be setup at this stage so fake this + * to ensure 0 padding works. + */ + this_spi->cmd_done = 1u; + + /* Disable frame handlers as they are mutually exclusive with block Rx handler. */ + this_spi->frame_rx_handler = NULL_FRAME_HANDLER; + this_spi->slave_tx_frame_handler = NULL_SLAVE_TX_UPDATE_HANDLER; + + /* Keep a copy of the pointer to the block Rx handler function. */ + this_spi->block_rx_handler = block_rx_handler; + + /* Assign slave receive buffer */ + this_spi->slave_rx_buffer = rx_buffer; + this_spi->slave_rx_size = rx_buff_size; + this_spi->slave_rx_idx = 0U; + + /* Assign slave transmit buffer*/ + this_spi->slave_tx_buffer = tx_buffer; + this_spi->slave_tx_size = tx_buff_size; + this_spi->slave_tx_idx = 0U; + + /* Flush the receive and transmit FIFOs */ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Preload the transmit FIFO. */ + while( !(HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_TXFULL)) && + ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->slave_tx_buffer[this_spi->slave_tx_idx] ); + ++this_spi->slave_tx_idx; + } + /* + * Disable TXDATA interrupt as we will look after transmission in rx handling + * because we know that once we have read a frame it is safe to send another one. + */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTTXDATA, DISABLE ); + + /* Enable Rx, FIFO error and SSEND interrupts */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTRXOVFLOW, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_INTTXURUN, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTRXDATA, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTSSEND, ENABLE ); + + /* Disable command handler until it is set explicitly */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + + /* Now enable the CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } + } +} + +/***************************************************************************//** + * SPI_set_cmd_handler() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_cmd_handler +( + spi_instance_t * this_spi, + spi_block_rx_handler_t cmd_handler, + uint32_t cmd_size +) +{ + uint32_t ctrl2 = 0u; + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( NULL_SLAVE_CMD_HANDLER != cmd_handler ); + HAL_ASSERT( 0u < cmd_size ); + + if( ( NULL_INSTANCE != this_spi ) && ( 0u < cmd_size ) && + ( NULL_SLAVE_CMD_HANDLER != cmd_handler ) ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + /* + * Note we don't flush the FIFOs as this has been done already when + * block mode was configured. + * + * Clear this flag so zero padding is disabled until command response + * has been taken care of. + */ + this_spi->cmd_done = 0u; + + /* Assign user handler for Command received interrupt */ + this_spi->cmd_handler = cmd_handler; + + /* Configure the command size and Enable Command received interrupt */ + ctrl2 = HAL_get_8bit_reg( this_spi->base_addr, CTRL2 ); + + /* First clear the count field then insert count and int enables */ + ctrl2 &= ~(uint32_t)CTRL2_CMDSIZE_MASK; + ctrl2 |= (uint32_t)((cmd_size & CTRL2_CMDSIZE_MASK) | CTRL2_INTCMD_MASK | CTRL2_INTRXDATA_MASK); + HAL_set_8bit_reg( this_spi->base_addr, CTRL2, ctrl2 ); + + /* Now enable the CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } +} + +/***************************************************************************//** + * SPI_set_cmd_response() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_set_cmd_response +( + spi_instance_t * this_spi, + const uint8_t * resp_tx_buffer, + uint32_t resp_buff_size +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + HAL_ASSERT( NULL_BUFF != resp_tx_buffer ); + HAL_ASSERT( 0u < resp_buff_size ); + + if( ( NULL_INSTANCE != this_spi ) && ( 0u < resp_buff_size ) && + ( NULL_BUFF != resp_tx_buffer ) ) + { + this_spi->resp_tx_buffer = resp_tx_buffer; + this_spi->resp_buff_size = resp_buff_size; + this_spi->resp_buff_tx_idx = 0u; + + fill_slave_tx_fifo(this_spi); + } +} + + +/***************************************************************************//** + * SPI_enable() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_enable +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + } +} + + +/***************************************************************************//** + * SPI_disable() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_disable +( + spi_instance_t * this_spi +) +{ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* Disable the Core SPI while we configure */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + } +} + + +/***************************************************************************//** + * SPI interrupt service routine. + */ +void SPI_isr +( + spi_instance_t * this_spi +) +{ + uint32_t rx_frame; + int32_t guard; + +/* + * The assert and the NULL check here can be commented out to reduce the interrupt + * latency once you are sure the interrupt vector code is correct. + */ + HAL_ASSERT( NULL_INSTANCE != this_spi ); + if( NULL_INSTANCE != this_spi ) + { + /* Handle receive. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_RXDATA ) ) + { + /* + * Service receive data according to transfer mode in operation. + * + * We check block mode first as this is most likely to have back to back + * transfers with multiple bytes. + * + * Note the order of the checks here will effect interrupt latency and + * for critical timing the mode you are using most often should probably be + * be the first checked. + */ + if( SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode ) /* Block handling mode. */ + { + while( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Read irrespective to clear the RX IRQ */ + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + if( this_spi->slave_rx_idx < this_spi->slave_rx_size ) + { + this_spi->slave_rx_buffer[this_spi->slave_rx_idx] = (uint8_t)rx_frame; + } + ++this_spi->slave_rx_idx; + } + /* + * Now handle updating of tx FIFO to keep the data flowing. + * First see if there is anything in slave_tx_buffer to send. + */ + while( ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) + && ( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->slave_tx_buffer[this_spi->slave_tx_idx] ); + ++this_spi->slave_tx_idx; + } + /* + * Next see if there is anything in resp_tx_buffer to send. + */ + if( this_spi->slave_tx_idx >= this_spi->slave_tx_size ) + { + while( ( this_spi->resp_buff_tx_idx < this_spi->resp_buff_size ) + && ( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->resp_tx_buffer[this_spi->resp_buff_tx_idx] ); + ++this_spi->resp_buff_tx_idx; + } + } + /* + * Lastly, see if we are ready to pad with 0s . + */ + if( this_spi->cmd_done && ( this_spi->slave_tx_idx >= this_spi->slave_tx_size ) && + ( this_spi->resp_buff_tx_idx >= this_spi->resp_buff_size ) ) + { + guard = 1 + ((int32_t)this_spi->fifo_depth / 4); + while( ( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) + && ( 0 != guard ) ) + { + /* + * Pad TX FIFO with 0s for consistent behaviour if the master + * tries to transfer more than we expected. + */ + HAL_set_32bit_reg(this_spi->base_addr, TXDATA, 0x00u); + /* + * We use the guard count to cover the event that we are never + * seeing the TX FIFO full because the data is being pulled + * out as fast as we can stuff it in. In this case we never spend + * more than our allocated time spinning here. + */ + guard--; + } + } + } + else if( SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode ) /* Single frame handling mode. */ + { + while( 0u == HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + if( NULL_FRAME_HANDLER != this_spi->frame_rx_handler ) + { + this_spi->frame_rx_handler( rx_frame ); + } + } + } + else /* Slave transfer mode not set up so discard anything in RX FIFO */ + { + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_RXFIFORST_MASK ); + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_RXDATA, ENABLE ); + } + + /* Handle transmit. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_TXDONE ) ) + { + /* + * Note, the driver only currently uses the txdone interrupt when + * in frame transmit mode. In block mode all TX handling is done by the + * receive interrupt handling code as we know that for every frame received + * a frame must be placed in the TX FIFO. + */ + if( SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode ) + { + /* Execute the user callback to update the slave_tx_frame */ + if( NULL_SLAVE_TX_UPDATE_HANDLER != this_spi->slave_tx_frame_handler ) + { + this_spi->slave_tx_frame_handler ( this_spi ); + } + + /* Reload slave tx frame into Tx data register. */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, this_spi->slave_tx_frame ); + } + else if( SPI_SLAVE_XFER_BLOCK != this_spi->slave_xfer_mode ) + { + /* Slave transfer mode not set up so discard anything in TX FIFO */ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK ); + } + else + { + /* Nothing to do, no slave mode configured */ + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_TXDONE, ENABLE ); + } + + + /* Handle receive overflow. */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, INTMASK_RXOVERFLOW)) + { + HAL_set_8bit_reg(this_spi->base_addr, CMD, CMD_RXFIFORST_MASK); + HAL_set_8bit_reg_field(this_spi->base_addr, INTCLR_RXOVERFLOW, ENABLE); + } + + /* Handle transmit under run. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_TXUNDERRUN ) ) + { + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK ); + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_TXUNDERRUN, ENABLE ); + } + + /* Handle command interrupt. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_CMDINT ) ) + { + read_slave_rx_fifo( this_spi ); + + /* + * Call the command handler if one exists. + */ + if( NULL_SLAVE_CMD_HANDLER != this_spi->cmd_handler ) + { + this_spi->cmd_handler( this_spi->slave_rx_buffer, this_spi->slave_rx_idx ); + } + this_spi->cmd_done = 1u; + /* Disable command interrupt until slave select becomes de-asserted to avoid retriggering. */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, DISABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_CMDINT, ENABLE ); + } + + /* Handle slave select becoming de-asserted. */ + if( ENABLE == HAL_get_8bit_reg_field( this_spi->base_addr, INTMASK_SSEND) ) + { + /* Only supposed to do all this if transferring blocks... */ + if(SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode) + { + uint32_t rx_size; + + /* Empty any remaining bytes in RX FIFO */ + read_slave_rx_fifo( this_spi ); + rx_size = this_spi->slave_rx_idx; + /* + * Re-enable command interrupt if required. + * Must be done before re loading FIFO to ensure stale response + * data is not pushed into the FIFO. + */ + if(NULL_SLAVE_CMD_HANDLER != this_spi->cmd_handler) + { + this_spi->cmd_done = 0u; + this_spi->resp_tx_buffer = 0u; + this_spi->resp_buff_size = 0u; + this_spi->resp_buff_tx_idx = 0u; + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_CMDINT, ENABLE ); + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL2_INTCMD, ENABLE ); + } + /* + * Reset the transmit index to 0 to restart transmit at the start of the + * transmit buffer in the next transaction. This also requires flushing + * the Tx FIFO and refilling it with the start of Tx data buffer. + */ + this_spi->slave_tx_idx = 0u; + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + fill_slave_tx_fifo( this_spi ); + + /* Prepare to receive next packet. */ + this_spi->slave_rx_idx = 0u; + /* + * Call the receive handler if one exists. + */ + if( NULL_BLOCK_HANDLER != this_spi->block_rx_handler ) + { + this_spi->block_rx_handler( this_spi->slave_rx_buffer, rx_size ); + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_RXDATA, ENABLE ); + } + + HAL_set_8bit_reg_field( this_spi->base_addr, INTCLR_SSEND, ENABLE ); + } + } +} + +/******************************************************************************* + * Local function definitions + */ + +/***************************************************************************//** + * Fill the transmit FIFO (used for slave block transfers). + */ +static void fill_slave_tx_fifo +( + spi_instance_t * this_spi +) +{ + /* First see if slave_tx_buffer needs transmitting */ + while( ( this_spi->slave_tx_idx < this_spi->slave_tx_size ) && + !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->slave_tx_buffer[this_spi->slave_tx_idx] ); + ++this_spi->slave_tx_idx; + } + + /* Then see if it is safe to look at putting resp_tx_buffer in FIFO? */ + if( this_spi->slave_tx_idx >= this_spi->slave_tx_size ) + { + while( ( this_spi->resp_buff_tx_idx < this_spi->resp_buff_size ) && + !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_TXFULL ) ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)this_spi->resp_tx_buffer[this_spi->resp_buff_tx_idx] ); + ++this_spi->resp_buff_tx_idx; + } + } +} + +/***************************************************************************//** + * + */ +static void read_slave_rx_fifo +( + spi_instance_t * this_spi +) +{ + uint32_t rx_frame; + + if( SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode ) /* Block handling mode. */ + { + while( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); /* Read irresepective to clear the RX IRQ */ + if( this_spi->slave_rx_idx < this_spi->slave_rx_size ) + { + this_spi->slave_rx_buffer[this_spi->slave_rx_idx] = (uint8_t)rx_frame; + } + ++this_spi->slave_rx_idx; + } + } + else if( SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode ) /* Frame handling mode */ + { + while( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Single frame handling mode. */ + rx_frame = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + if( NULL_FRAME_HANDLER != this_spi->frame_rx_handler ) + { + this_spi->frame_rx_handler( rx_frame ); + } + } + } + else /* Slave transfer mode not set up so discard anything in RX FIFO */ + { + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_RXFIFORST_MASK ); + } +} + +/***************************************************************************//** + * This function is to recover the CoreSPI from receiver overflow. + * It temporarily disables the CoreSPI from interacting with external world, flushes + * the transmit and receiver FIFOs, clears all interrupts and then re-enables + * the CoreSPI instance referred by this_spi parameter. + */ +static void recover_from_rx_overflow +( + const spi_instance_t * this_spi +) +{ + /* Disable CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + /* Reset TX and RX FIFOs */ + HAL_set_8bit_reg( this_spi->base_addr, CMD, CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK ); + + /* Clear all interrupts */ + HAL_set_8bit_reg( this_spi->base_addr, INTCLR, SPI_ALL_INTS ); + + /* Enable CoreSPI */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); +} + + diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.h b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.h new file mode 100644 index 0000000..c6873f7 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreSPI/core_spi.h @@ -0,0 +1,1324 @@ +/***************************************************************************//** + * Copyright 2013-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Core SPI bare metal software driver public API. + * + * This Core SPI driver provides functions for implementing SPI master or + * SPI slave operations with the CoreSPI version 4.2.xxx It is not compatible + * with CoreSPI version 3.0.xxx. + * + * The Core SPI driver supports two classes of data transfer operation: + * SPI frame operation or SPI block transfer operations. + * + * Frame operations allow transferring individual SPI frames from 4 to 32-bits + * in length. Block operations allow transferring blocks of data organized as + * 8-bit frames. + * + * @file core_spi.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreSPI prototypes + * + */ + +/*=========================================================================*//** + @mainpage Core SPI Bare Metal Driver. + + ============================================================================== + Introduction + ============================================================================== + CoreSPI is an IP component that implements a full-duplex, synchronous, and + configurable serial peripheral interface (SPI) with frame sizes from 4 to 32 + bits and bus interface sizes of 8-, 16-, or 32-bit. Each CoreSPI instance + communicates with up to eight slave devices. + + This driver provides a set of functions for controlling CoreSPI as part of + the bare metal system where no operating system is available. These drivers + can be adapted to be used as a part of an operating system, but the + implementation of the adaptation layer between driver and the operating + system's driver model is outside the scope of this User's Guide. + + ============================================================================== + Driver Configuration + ============================================================================== + Your application software should configure the CoreSPI driver through calls + to the SPI_init() function for each CoreSPI instance in the hardware design. + This function configures a default set of parameters that include a CoreSPI + hardware instance base address and the depth of the FIFOs for this instance. + + The CoreSPI instance is configured at the time of instantiation in hardware + design for APB width, frame size, FIFO depth, serial clock speed, serial + clock polarity, serial clock phase, and slave select state parameters. + + CoreSPI can communicate with up to eight different slave devices that match + the CoreSPI configuration at the time of hardware instantiation. + + The functions SPI_configure_slave_mode() and SPI_configure_master_mode() are + used to configure the CoreSPI instance as a master or slave as required by + the application. + + When CoreSPI wishes to communicate with a specific slave device, call + the SPI_set_slave_select() function with the slave number as an argument. + This function selects the slave device. A previously selected slave gets + unselected by calling the SPI_clear_slave_select() function. + + ============================================================================== + Theory of Operation + ============================================================================== + The CoreSPI driver functions are grouped into the following categories: + • Initialization + • Configuration for either master or slave operations + • SPI master frame transfer control + • SPI master block transfer control + • SPI slave frame transfer control + • SPI slave block transfer control + + Frame transfers allow CoreSPI to write or read up to 32-bits of data in a + single SPI transaction. For example, a frame transfer of 12-bits might be used + to read the result of an ADC conversion from a SPI analog to digital converter. + + Block transfers allow CoreSPI to write and/or read a number of bytes in a single + SPI transaction. With the driver as is, block transfer transactions allow data + transfers in multiples of 8-bits (8, 16, 24, 32, 40,...) and the CoreSPI instance + has to be configured for 8-bit frames. For other frame sizes, the + SPI_transfer_block() code can act as a template for developing a frame block + transfer function. + Block transfers are typically used with byte oriented devices like SPI + FLASH devices. + + Note: The CoreSPI instance in the hardware design must be configured for + the frame size required by the application; configuration by driver is + not possible. + + -------------------------------- + Initialization + -------------------------------- + The CoreSPI driver is initialized through a call to the SPI_init() function. + The SPI_init() function takes a pointer to the global CoreSPI instance data + structure of type spi_instance_t and the base address of the CoreSPI instance + as defined by the hardware design. The CoreSPI instance global data structure + is used by the driver to store state information for each CoreSPI instance. + A pointer to these data structures is also used as the first parameter to + any of the driver functions to identify which CoreSPI will be used by the + called function. It is the responsibility of the application programmer to + create and maintain these global CoreSPI instance data structures. Any call + to a CoreSPI driver function should be of the form SPI_function_name + ( &g_core_spi0, ... ). + The SPI_init() function resets the transmit and receives FIFOs of CoreSPI + instance being initialized. + The SPI_init() function must be called before any other CoreSPI driver + functions can be called. + + ---------------------------------------------------- + Configuration + ---------------------------------------------------- + A CoreSPI instance can operate either as a master or as a slave SPI device. + There are two distinct functions for configuring a CoreSPI instance for + master or slave operations. + + ## Master Configuration + The SPI_configure_master_mode() function configures the specified CoreSPI + block for operations as an SPI master. This function must be called once + before the CoreSPI block communicates with an SPI slave device. + + ## Slave Configuration + The SPI_configure_slave_mode() function configures the specified CoreSPI + block for operations as a SPI slave. This function must be called after + calling the SPI_init() to configure the CoreSPI instance referred by this_spi + parameter to operate in the slave mode. + + ------------------------------------- + SPI Master Frame Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI master frame transfers: + • SPI_set_slave_select() + • SPI_transfer_frame() + • SPI_clear_slave_select() + + The master must first select the target slave or slaves to be addressed by + calling the SPI_set_slave_select() function. This causes the relevant select + line(s) to become asserted while data is clocked out onto the SPI data line. + + A function call is then made to SPI_transfer_frame() specifying the value + of the data frame to be sent and returning the value read. + + After the transfer is complete, use the SPI_clear_slave_select() function + to prevent this slave select line from being asserted during subsequent SPI + transactions. A call to this function is required only if the master is + communicating with multiple slave devices. + + ------------------------------------- + SPI Master Block Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI master block transfers: + • SPI_set_slave_select() + • SPI_transfer_block() + • SPI_clear_slave_select() + + The master must first select the target slave or slaves by calling + SPI_set_slave_select(). This causes the relevant slave select line(s) to + become asserted while data is clocked out onto the SPI data line. + Alternatively, a general purpose input/output (GPIO) can be used to control + the state of the target slave device's chip select signal. + + A call is then made to the SPI_transfer_block() function. The parameters of + this function specify the following: + • The number of bytes to be transmitted + • A pointer to the buffer containing the data to be transmitted + • The number of bytes to be received + • A pointer to the buffer where the received data gets stored + + The number of bytes to be transmitted can be set to zero to indicate that the + transfer is purely a block read transfer. The number of bytes to be received + can be set to zero to specify that the transfer is purely a block write + transfer. + + Block mode transfers as implemented by the driver are effectively half duplex + as we do not store the values received from the slave device whilst we are + transmitting. If full duplex operation is required, the driver + SPI_transfer_block() function can serve as a starting point for implementing + full duplex block transfers. + + The SPI_clear_slave_select() function can be used after the transfer is + complete to prevent this slave select line from being asserted during + subsequent SPI transactions. A call to this function is only required if + the master is communicating with multiple slave devices. + + ------------------------------------- + SPI Slave Frame Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI slave frame transfers: + • SPI_set_frame_rx_handler() + • SPI_set_slave_tx_frame() + + The SPI_set_frame_rx_handler() function specifies the receive handler + function that is called when a frame of data has been received by the + SPI when it is configured as a slave. The receive handler function specified + through this call processes the frame data written over the SPI bus to the + SPI slave by the remote SPI master. The receive handler function must be + implemented as part of the application. It is only required if the SPI slave + is the target of SPI frame write transactions. + + The SPI_set_slave_tx_frame() function specifies the frame data that is + returned to the SPI master. The frame data specified through this function + is the value that will be read over the SPI bus by the remote SPI master, + when it initiates a transaction. Call the SPI_set_slave_tx_frame() function + only if the SPI slave is the target of SPI read transactions. That is, if + data is meant to be read over CoreSPI. + + If both frame handlers are required, call the SPI_set_frame_rx_handler() + first, otherwise the initial TX frame gets discarded when SPI_set_frame_rx_handler() + clears the FIFOs as part of its initialization. + + ------------------------------------- + SPI Slave Block Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI slave block transfers: + • SPI_set_slave_block_buffers() + • SPI_set_cmd_handler() + • SPI_set_cmd_response() + + The SPI_set_slave_block_buffers() function is used to configure an SPI slave + for block transfer operations. It specifies the following: + • The buffer containing the data that will be returned to the remote SPI + master + • The buffer where data received from the remote SPI master will be + stored + • The optional handler function that will be called after the receive + buffer is filled + + The SPI_set_cmd_handler() function specifies a command handler function that + is called by the driver once a specific number of frames have been + received after the SPI chip select signal becomes active. The number of + bytes making up the command part of the transaction is specified as part of + the parameters to the SPI_set_cmd_handler() function. The command handler + function is implemented as a part of the application making use of the SPI + driver and typically calls the SPI_set_cmd_response() function. + + The SPI_set_cmd_response() function specifies the data that gets returned + to the master. Typically, the SPI_set_slave_block_buffers() function is + called as a part of the system initialisation to specify the data sent to + the master while the command bytes are being received. The transmit buffer + specified through calling the SPI_set_slave_block_buffers() function would + also typically include one or more bytes allowing the turn around time + for the command handler function to execute and call the + SPI_set_cmd_response() function. + + *//*=========================================================================*/ +#ifndef CORE_SPI_H_ +#define CORE_SPI_H_ + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#include "hal_assert.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + SPI FIFO Depth + ======================================= + SPI_MAX_FIFO_DEPTH & SPI_MIN_FIFO_DEPTH constants define the maximum and minimum + FIFO depths allowed for the CoreSPI instance. User need to inform the driver of + the FIFO depth for each CoreSPI instance to ensure that the FIFOs are managed correctly. + + | Constant | Description | + |--------------------|----------------------------------------------------| + | SPI_MAX_FIFO_DEPTH | Maximum FIFO depth allowed for the CoreSPI instance| + | SPI_MIN_FIFO_DEPTH | Minimum FIFO depth allowed for the CoreSPI instance| + + */ +#define SPI_MAX_FIFO_DEPTH 32u +#define SPI_MIN_FIFO_DEPTH 1u + +/***************************************************************************//** + Instances of this structure are used to identify the specific CoreSPI hardware + instances. A pointer to an instance of the spi_instance_t structure is passed + as the first parameter to the CoreSPI driver functions to identify which SPI + performs the requested operation. + */ +typedef struct spi_instance spi_instance_t; + +/***************************************************************************//** + This function pointer type is to assign a callback function for TX interrupt + when slave wants to send the next updated frame. + + Declaring and Implementing Slave Frame Transmit Handler Functions: + Slave transmit frame update handler functions should follow the following + prototype: + void slave_tx_frame_update_handler ( spi_instance_t * this_spi ); + The actual name of the transmit handler is unimportant. You can use any name + of your choice for the frame update handler. + + A common handler function may be used when multiple CoreSPI instances are + configured as slave, as the particular slave device currently requiring + service is indicated by the function parameter. + */ +typedef void (*spi_slave_frame_tx_handler_t)( spi_instance_t * this_spi ); + +/***************************************************************************//** + This defines the function prototype that must be followed by the SPI slave + frame receive handler functions. These functions are registered with the SPI + driver through the SPI_set_frame_rx_handler() function. + + Declaring and Implementing the Slave Frame Receive Handler Functions: + The Slave frame receive handler functions should follow the following + prototype: + void slave_frame_receive_handler(uint32_t rx_frame); + The actual name of the receive handler is unimportant. You can use any name + of your choice for the receive frame handler. The rx_frame parameter contains + the value of the received frame. + + Separate handler functions are required for each slave instance as there is + no indication of the slave requiring service passed to the handler. + + */ +typedef void (*spi_frame_rx_handler_t)( uint32_t rx_frame ); + +/***************************************************************************//** + This defines the function prototype that must be followed by SPI slave + block receive handler functions. These functions are registered with the + SPI driver through the SPI_set_slave_block_buffers() function. + + Declaring and Implementing Slave Block Receive Handler Functions: + Slave block receive handler functions should follow the following prototype: + void spi_block_rx_handler ( uint8_t * rx_buff, uint16_t rx_size ); + The actual name of the receive handler is unimportant. You can use any name + of your choice for the receive frame handler. The rx_buff parameter contains + a pointer to the start of the received block. The rx_size parameter contains + the number of bytes of the received block. + + Separate handler functions are required for each slave instance as there is + no indication of the slave requiring service passed to the handler. + + */ +typedef void (*spi_block_rx_handler_t)( uint8_t * rx_buff, uint32_t rx_size ); + +/***************************************************************************//** + This enumeration is used to select a specific SPI slave device (0 to 7). It is + used as a parameter to the SPI_configure_master_mode(), SPI_set_slave_select(), + and SPI_clear_slave_select() functions. + */ +typedef enum __spi_slave_t +{ + SPI_SLAVE_0 = 0, + SPI_SLAVE_1 = 1, + SPI_SLAVE_2 = 2, + SPI_SLAVE_3 = 3, + SPI_SLAVE_4 = 4, + SPI_SLAVE_5 = 5, + SPI_SLAVE_6 = 6, + SPI_SLAVE_7 = 7, + SPI_MAX_NB_OF_SLAVES = 8 +} spi_slave_t; + +/***************************************************************************//** + This enumeration is used to indicate the current slave mode transfer type so + that we are not relying on buffer comparisons to dictate the logic of the driver. + */ +typedef enum __spi_sxfer_mode_t +{ + SPI_SLAVE_XFER_NONE = 0, /* Not configured yet */ + SPI_SLAVE_XFER_BLOCK = 1, /* Block transfers, with SSEND delimiting end of block */ + SPI_SLAVE_XFER_FRAME = 2 /* Single frame transfers */ +} spi_sxfer_mode_t; + +/***************************************************************************//** + There is one instance of this structure for each of the core SPIs. Instances + of this structure are used to identify a specific SPI. A pointer to an + instance of the spi_instance_t structure is passed as the first parameter to + SPI driver functions to identify which SPI should perform the requested operation. + */ +struct spi_instance{ + + /* Base address in the processor's memory map for the + registers of the CoreSPI instance being initialized */ + addr_t base_addr; /* Base address of SPI hardware instance */ + + uint32_t rx_frame; /* received data */ + + /* Internal transmit state: */ + const uint8_t * slave_tx_buffer; /* Pointer to slave transmit buffer */ + uint32_t slave_tx_size; /* Size of slave transmit buffer */ + uint32_t slave_tx_idx; /* Current index into slave transmit buffer */ + + /* Slave command response buffer: */ + const uint8_t * resp_tx_buffer; + uint32_t resp_buff_size; + uint32_t resp_buff_tx_idx; + spi_block_rx_handler_t cmd_handler; + uint32_t cmd_done; /* Flag which indicates response has been set up and + it is safe to pad with 0s once the response is sent */ + + /* Internal receive state: */ + uint8_t * slave_rx_buffer; /* Pointer to buffer where data received by a slave will be stored */ + uint32_t slave_rx_size; /* Slave receive buffer size */ + uint32_t slave_rx_idx; /* Current index into slave receive buffer */ + + /* Slave received frame handler: */ + spi_frame_rx_handler_t frame_rx_handler; /* Pointer to function that will be called when a frame + is received when the SPI block is configured as slave */ + /* Slave transmitted frame handler: */ + uint32_t slave_tx_frame; /* Value of the data frame that will be transmitted + when the SPI block is configured as slave */ + spi_slave_frame_tx_handler_t slave_tx_frame_handler; /* Callback function pointer to update slave_tx_frame */ + + /* Slave block rx handler: */ + spi_block_rx_handler_t block_rx_handler; /* Pointer to the function that will be called when a data block has been received */ + + /* Per instance specific hardware information that the driver needs to know */ + uint16_t fifo_depth; /* Depth of RX and TX FIFOs in frames */ + + /* How we are expecting to deal with slave transfers */ + spi_sxfer_mode_t slave_xfer_mode; /* Current slave mode transfer configuration */ +}; + +/*------------------------Public Function-------------------------------------*/ + +/***************************************************************************//** + The SPI_init() function initializes the hardware and data structures of a + CoreSPI instance referenced by this_spi parameter. This function must be + called for each CoreSPI instance with a unique this_spi and base_addr + parameter combination. The SPI_init() function must be called before any + other CoreSPI driver functions are called. + + After calling the SPI_init() the CoreSPI is configured as a master, + all interrupt sources will be masked and all the slaves are deselected. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to be initialized. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @param base_addr + The base_addr parameter is the base address in the processor's memory map for + the registers of the CoreSPI instance being initialized. It is assumed that + any non NULL value passed in here points to a valid instance of a CoreSPI as + the driver has no way of verifying this. Failure to pass in a valid address + can result in system instability. + + @param fifo_depth + The fifo_depth parameter specifies the number of frames in the receive + and transmit FIFOs of the CoreSPI instance being initialized. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + @endcode + */ +void SPI_init +( + spi_instance_t * this_spi, + addr_t base_addr, + uint16_t fifo_depth +); + +/***************************************************************************//** + The SPI_configure_slave_mode() function is used when a CoreSPI instance is + to be configured as a SPI slave. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to be configured. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + + int main(void) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_slave_mode ( &g _spi0 ); + } + @endcode + */ +void SPI_configure_slave_mode +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_configure_master_mode() function is used when a CoreSPI instance is + to be configured as a SPI master. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to be configured. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + + int main(void) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_master_mode ( &g _spi0 ); + } + @endcode + */ +void SPI_configure_master_mode +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_set_slave_select() function is used by a CoreSPI master to select a + specific slave. This function causes the relevant slave select signal to be + asserted while data is clocked out onto the SPI data line. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param slave + The slave parameter is one of the spi_slave_t enumerated constants + identifying a slave. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + const uint32_t master_tx_frame = 0x0100A0E1; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0 ); + SPI_transfer_frame( &g_spi0, master_tx_frame ); + SPI_clear_slave_select( &g_spi0, SPI_SLAVE_0 ); + + @endcode + */ +void SPI_set_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +); + +/***************************************************************************//** + The SPI_clear_slave_select() function is used by a CoreSPI master to + deselect a specific slave. This function causes the relevant slave select + signal to be de-asserted. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param slave + The slave parameter is one of the spi_slave_t enumerated constants + identifying a slave. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0; + const uint32_t master_tx_frame = 0x0100A0E1; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0 ); + SPI_transfer_frame( &g_spi0, master_tx_frame ); + SPI_clear_slave_select( &g_spi0, SPI_SLAVE_0 ); + @endcode + */ +void SPI_clear_slave_select +( + spi_instance_t * this_spi, + spi_slave_t slave +); + +/***************************************************************************//** + The SPI_transfer_frame() function is used by a SPI master to transmit and + receive a single frame of the size that has been configured at the time of + CoreSPI hardware instantiation. This function is typically used for + transactions with a SPI slave where the number of transmit and receive bits + are not divisible by 8 or where full duplex exchange of frames is required. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param tx_bits + The tx_bits parameter is a 32-bit word containing the value that will be + transmitted. If the frame size configured for the CoreSPI is less than 32-bits, + the upper bits will be ignored. + Note: The bit length of the value to be transmitted to the slave is + set when the CoreSPI is instantiated in the hardware design. + + @return + This function returns a 32-bit word containing the value that is received + from the slave. If the frame size configured for the CoreSPI in question is + less that 32-bits, the upper bits will be 0. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + const uint32_t master_tx_frame = 0x0100A0E1; + uint32_t master_rx; + + SPI_init(&g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ); + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0 ); + master_rx = SPI_transfer_frame( &g_spi0, master_tx_frame ); + SPI_clear_slave_select( &g_spi0, SPI_SLAVE_0 ); + @endcode + */ +uint32_t SPI_transfer_frame +( + spi_instance_t * this_spi, + uint32_t tx_bits +); + +/***************************************************************************//** + The SPI_transfer_block() function is used by the SPI master to transmit and + receive blocks of data organized as a specified number of 8-bit frames. It + can be used for the following: + • Writing a data block to a slave + • Reading a data block from a slave + • Sending a command to a slave followed by reading the outcome of + the command in a single SPI transaction. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param cmd_buffer + The cmd_buffer parameter is a pointer to the buffer that contains the data + sent by the master from the beginning of the transfer. This pointer can be + null (0) if the master does not need to send a command before reading data. + + @param cmd_byte_size + The cmd_byte_size parameter specifies the number of bytes in cmd_buffer that + will be sent. A value ‘0’ indicates that no data needs to be sent to the slave. + + @param rx_buffer + The rx_buffer parameter is a pointer to the buffer that stores the data received + from the slave after sending the command. This pointer can be null (0) if the + master does not receive any data from the slave. + + @param rx_byte_size + The rx_byte_size parameter specifies the number of bytes received from + the slave and stored in the rx_buffer. A value ‘0’ indicates that no data is + to be read from the slave. + + @return + This function does not return any value. + + @example + @code + Polled write transfer example + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + + uint8_t master_tx_buffer[MASTER_TX_BUFFER] = + { + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A + }; + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0) ; + SPI_transfer_block + ( + &g_spi0, + master_tx_buffer, + sizeof(master_tx_buffer), + 0, + 0 + ); + SPI_clear_slave_select(&g_spi0, SPI_SLAVE_0 ); + @endcode + */ +void SPI_transfer_block +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_buffer, + uint16_t rx_byte_size +); + +/***************************************************************************//** + The SPI_transfer_block_store_all_resp() function is used by the SPI master + to transmit and receive blocks of data organized as a specified number + of 8-bit frames. It can be used for the following: + • Writing a data block to a slave + • Reading a data block from a slave + • Sending a command to a slave followed by reading the outcome of + the command in a single SPI transaction + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param cmd_buffer + The cmd_buffer parameter is a pointer to the buffer that contains the data sent by + the master from the beginning of the transfer. This pointer can be null (0) + if the master does not need to send a command before reading data. + + @param cmd_byte_size + The cmd_byte_size parameter specifies the number of bytes contained in + cmd_buffer that will be sent. A value ‘0’ indicates that no data needs + to be sent to the slave. + + @param rx_data_buffer + The rx_data_buffer parameter is a pointer to the buffer that stores the data received + from the slave after sending the command. This pointer can be null (0) if the + master does not receive any data from the slave. + + @param rx_byte_size + The rx_byte_size parameter specifies the number of bytes received from + the slave and stores in the rx_buffer. A value ‘0’ indicates that no data is + to be read from the slave. + + @param cmd_response_buffer + The cmd_response_buffer parameter is a pointer to the buffer which stores the + command response from the slave, while the master is transmitting the number + of bytes indicated by cmd_byte_size parameter. + + @return + This function does not return any value. + + @example + @code + Polled write transfer example + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + + uint8_t master_tx_buffer[MASTER_TX_BUFFER] = + { + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A + }; + + uint8_t cmd_rx_buffer[CMD_RX_BUFFER]={0}; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0) ; + SPI_transfer_block_store_all_resp + ( + &g_spi0, + master_tx_buffer, + sizeof(master_tx_buffer), + 0, + 0, + cmd_response_buffer + ); + SPI_clear_slave_select(&g_spi0, SPI_SLAVE_0 ); + @endcode + */ +void SPI_transfer_block_store_all_resp +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_data_buffer, + uint16_t rx_byte_size, + uint8_t * cmd_response_buffer +); + +/***************************************************************************//** + The SPI_set_frame_rx_handler() function is used by the SPI slaves to specify + the receive handler function that is called by the SPI driver interrupt + handler when a frame of data is received by the SPI slave. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param rx_handler + The rx_handler parameter is a pointer to the frame receive handler that must + be called when a frame is received by the CoreSPI slave. Passing in a NULL + pointer disables the receive handler but does enable the receive interrupt to + ensure the RX FIFO is empty each time a frame is received. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + uint32_t g_slave_rx_frame = 0; + spi_instance_t g_spi0; + + void slave_frame_handler(uint32_t rx_frame) + { + g_slave_rx_frame = rx_frame; + } + int setup_slave( void ) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_slave_mode( &g_spi0 ); + SPI_set_frame_rx_handler( &g_spi0, slave_frame_handler ); + } + @endcode + */ +void SPI_set_frame_rx_handler +( + spi_instance_t * this_spi, + spi_frame_rx_handler_t rx_handler +); + +/***************************************************************************//** + The SPI_set_slave_tx_frame() function is used by the SPI slaves to specify + the frame that gets transmitted when a transaction is initiated by the SPI + master. This function allows you to assign a slave_tx_frame_handler function, + which will be executed upon transmit interrupt when the SPI is in slave mode. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param frame_value + The frame_value parameter contains the value of the frame to be sent to the + master. + Note: The bit length of the value to be transmitted to the master is + set when the CoreSPI is instantiated in the hardware design. + + @param slave_tx_frame_handler + The slave_tx_frame_handler function pointer is executed upon occurrence of + transmit interrupt when CoreSPI is operating in slave mode. This parameter + is optional and if set to NULL it is assumed that the frame value is static or + updated asynchronously. + + @return + This function does not return any value. + + @example + @code + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + const uint32_t slave_tx_frame[2] = { 0x0110F761, 0x0110F671 }; + uint32_t master_rx; + uint32_t slave_frame_idx = 0 ; + + slave_frame_update( spi_instance_t * this_spi ) + { + this_spi->slave_tx_frame = slave_tx_frame[slave_frame_idx++]; + if( slave_frame_idx > 2 ) + slave_frame_idx = 0; + } + main() + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 1 ); + SPI_configure_master_mode( &g_spi0 ) ; + SPI_set_slave_tx_frame( &g_spi0, slave_tx_frame[slave_frame_idx++], + &slave_frame_update ); + } + @endcode + */ +void SPI_set_slave_tx_frame +( + spi_instance_t * this_spi, + uint32_t frame_value, + spi_slave_frame_tx_handler_t slave_tx_frame_handler +); + +/***************************************************************************//** + The SPI_set_slave_block_buffers() function is used to configure an SPI slave + for block transfer operations. It specifies one or more of the following: + • The data that is transmitted when accessed by a master. + • The buffer where the data received from a master is stored. + • The handler function that must be called after the receive buffer has + been filled. + • The number of bytes that must be received from the master before calling + the recieve handler function. + These parameters allow the following use cases: + • Slave performing an action after receiving a block of data from a + master containing a command. This action is performed by the + receive handler based on the content of the receive data buffer. + • Slave returning a block of data to the master. The type of information + is always the same but the actual values change over time. For example, + returning the voltage of a predefined set of analog inputs. + • Slave returning data based on a command contained in the first part of + the SPI transaction. For example, reading the voltage of the analog + input specified by the first data byte by the master. This is achieved + by using the SPI_set_slave_block_buffers() function in conjunction with + functions SPI_set_cmd_handler() and SPI_set_cmd_response(). + + See the SPI_set_cmd_handler() function description for details of + this use case. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param tx_buffer + The tx_buffer parameter is a pointer to a buffer containing the data that + will be sent to the master. This parameter can be set to ‘0’ if the SPI + slave is not intended to be the target of SPI read transactions. + + @param tx_buff_size + The tx_buff_size parameter specifies the number of bytes that are + transmitted by the SPI slave. It is the number of bytes contained in the + tx_buffer. This parameter can be set to ‘0’ if the SPI slave is not + intended to be the target of SPI read transactions. The driver returns 0s + to the master if there is no buffer specified or the master reads beyond the + end of the buffer. + Note: If SPI_transfer_block() is used to read from this slave and there is + no command handler involved, the buffer size here must be at least the + combined length of the command and response specified by the master. + On receiving this data, the master discards the data bytes equal to + command length bytes from the start of the received buffer. + + @param rx_buffer + The rx_buffer parameter is a pointer to the buffer where data received + from the master is stored. This parameter can be set to ‘0’ if the + SPI slave is not intended to be the target of SPI write or write-read + transactions. + + @param rx_buff_size + The rx_buff_size parameter specifies the size of the receive buffer. It is + also the number of bytes that must be received before the receive handler + is called, if a receive handler is specified using the block_rx_handler + parameter. Any bytes received in excess of the size specified by the + rx_buff_size parameter are discarded. This parameter can be set to ‘0’ + if the SPI slave is not intended to be the target of SPI write or + write-read transactions. + + @param block_rx_handler + The block_rx_handler parameter is a pointer to a function that is called + when receive buffer has been filled or the slave select has been de-asserted. + This parameter can be set to ‘0’ if the SPI slave is not intended to be the + target of SPI write or write-read transactions. + + @return + This function does not return any value. + + @example + @code + Slave Performing Operation Based on Master Command: + In this example the SPI slave is configured to receive 10 bytes of data + or command from the SPI slave, and process the data received from the master. + + #define SPI0_BASE_ADDR 0xC2000000 + + uint32_t nb_of_rx_handler_calls = 0; + spi_instance_t g_spi0; + + void spi1_block_rx_handler_b + ( + uint8_t * rx_buff, + uint16_t rx_size + ) + { + ++nb_of_rx_handler_calls; + } + + void setup_slave( void ) + { + uint8_t slave_rx_buffer[10] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_slave_mode( &g_spi0 ); + + SPI_set_slave_block_buffers + ( + &g_spi0, + 0, + 0, + slave_rx_buffer, + sizeof( master_tx_buffer ), + spi1_block_rx_handler_b + ); + } + @endcode + */ +void SPI_set_slave_block_buffers +( + spi_instance_t * this_spi, + const uint8_t * tx_buffer, + uint32_t tx_buff_size, + uint8_t * rx_buffer, + uint32_t rx_buff_size, + spi_block_rx_handler_t block_rx_handler +); + +/***************************************************************************//** + The SPI_isr() function is the top level interrupt handler function for the + CoreSPI driver. You must call SPI_isr() from the system level + (CoreInterrupt and NVIC level) interrupt handler assigned to the interrupt + triggered by the CoreSPI SPIINT signal. Your system level interrupt handler + must also clear the system level interrupt triggered by the CoreSPI SPIINT + signal before returning, to prevent a re-assertion of the same interrupt. + + This function supports all types of interrupt triggered by CoreSPI. It is not + a complete interrupt handler by itself; rather, it is a top level wrapper that + abstracts CoreSPI command interrupt and slave mode transmit interrupt handling + by calling lower level handler functions specific to each type of CoreSPI + interrupt. You must create the lower level handler functions to suit your + application and register them with the driver through calling the + SPI_set_cmd_handler(), SPI_set_cmd_response(), and SPI_set_slave_tx_frame() + functions. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + + @example + @code + + Example of configuring a CoreInterrupt connected to the Fabric Interrupt on a + SmartFusion device to handle CoreSPI interrupt. + + #define #define SPI1_INT_IRQ_NB 0 + spi_instance_t g_spi0; + + Void CIC_irq1_handler(void) + { + SPI_isr( &g_spi0 ); + } + + void Fabric_IRQHandler( void ) + { + // Call the CoreInterrupt driver ISR to determine the source of the + // interrupt and call the relevant ISR registered to it. + CIC_irq_handler(); + + // Clear NVIC interrupt status to allow further interrupts + NVIC_ClearPendingIRQ( Fabric_IRQn ); + } + + main() + { + ... + + CIC_init( CIC_BASE_ADDR ); + + // Install handler for SPI IRQ + CIC_set_irq_handler( SPI0_INT_IRQ_NB, CIC_irq1_handler ); + + NVIC_ClearPendingIRQ( Fabric_IRQn ); + NVIC_EnableIRQ( Fabric_IRQn ); + + CIC_enable_irq( SPI1_INT_IRQ_NB ); + + ... + } + @endcode + */ +void SPI_isr +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_set_cmd_handler() function specifies a command handler function that + will be called when the number of bytes received reaches the command size + specified as cmd_size parameter. + + This function is used by the SPI slaves performing block transfers. Its + purpose is to allow an SPI slave to decide the data that will be returned to + the master while an SPI transaction is taking place. Typically, one or more + command bytes are sent by the master to request some specific data. The slave + interprets the command byte(s) while one or more turn-around bytes are + transmitted. The slave adjusts its transmit data buffer based on the command + during the turn around time. + + The following table provides an example of the use of this function where the + SPI slave returns data bytes D0 to D6 based on the value of a command. The + 3 bytes long command is made up of a command opcode byte followed by an + address byte followed by a size byte. The cmd_handler() function specified + through an earlier call to SPI_set_cmd_handler() is called by the CoreSPI + driver once the third byte is received. The cmd_handler() function + interprets the command bytes and calls SPI_set_cmd_response() to set the SPI + slave's response transmit buffer with the data to be transmitted after the + turnaround bytes (T0 to T3). The number of turnaround bytes must be + sufficient to give enough time for the cmd_handler() to execute. The number + of turnaround bytes is specified by the protocol used on top of the SPI + transport layer so that master and slave agree on the number of turn around + bytes. + +|Timestamp| SPI Transaction | Bytes | Comments | +|---------|-------------|----------------------|---------------| +| t0|COMMAND|C A S |C - command opcode byte, A - address byte, S - size byte| +|t1| TURN-AROUND|T0 T1 |cmd_handler() called here (T0 to T3 are TURN-AROUND bytes)| +|t2|TURN-AROUND|T2 T3|SPI_set_cmd_response() called here by implementation of cmd_handler() +|| | |to set the data that will be transmitted by the SPI slave.| +|t3| DATA | D0 D1 D2 D3 D4 D5 D6 |Data transmition (SPI slave return data bytes)| + + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure identifying + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @param cmd_handler + The cmd_handler parameter is a pointer to a function with the prototype: + void cmd_handler(uint8_t * rx_buff, uint32_t rx_size); + It specifies the function that will be called when the number of bytes + specified by the cmd_size parameter has been received. + + @param cmd_size + The cmd_size parameter specifies the number of bytes that must be received + before calling the command handler function specified by the cmd_handler. + The CoreSPI supports cmd_size values in the range 1 to 7. + + @return + This function does not return any value. + + @example + @code + The following example demonstrates how to configure CoreSPI to implement + the protocol given as an example above. The configure_slave() function + configures CoreSPI. It sets receive and transmit buffers. The transmit + buffer specified through the call to SPI_set_slave_block_buffers() function + specifies the data that will be returned to the master in bytes between + t0 and t3. These bytes will be sent to the master while the master transmits + the command and dummy bytes. The spi_slave_cmd_handler() function will be + called by the driver at time t1 after the 3 command bytes have been received. + The spi_block_rx_handler() function will be called by the driver at time t4, + when the transaction completes and the slave select signal becomes + de-asserted. + + #define SPI0_BASE_ADDR 0xC2000000 + #define COMMAND_SIZE 3 + #define NB_OF_DUMMY_BYTES 4 + #define MAX_TRANSACTION_SIZE 16 + + spi_instance_t g_spi0; + uint8_t slave_tx_buffer[COMMAND_SIZE + NB_OF_DUMMY_BYTES]; + uint8_t slave_rx_buffer[MAX_TRANSACTION_SIZE]; + + void configure_slave( void ) + { + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + SPI_configure_slave_mode( &g_spi0 ); + SPI_set_slave_block_buffers + ( + &g_spi0, + slave_tx_buffer, + COMMAND_SIZE + NB_OF_DUMMY_BYTES, + slave_rx_buffer, + sizeof(slave_rx_buffer), + spi_block_rx_handler + ); + + SPI_set_cmd_handler + ( + &g_spi0, + spi_slave_cmd_handler, + COMMAND_SIZE + ); + } + + void spi_slave_cmd_handler + ( + uint8_t * rx_buff, + uint32_t rx_size + ) + { + uint8_t command; + uint8_t address; + uint8_t size; + uint8_t * p_response; + uint32_t response_size; + + command = rx_buff[0]; + address = rx_buff[1]; + size = rx_buff[2]; + + p_response = get_response_data( command, address, size, &response_size ); + SPI_set_cmd_response( &g_spi0, p_response, response_size ); + } + + void spi_block_rx_handler + ( + uint8_t * rx_buff, + uint32_t rx_size + ) + { + process_rx_data( rx_buff, rx_size ); + } + @endcode + */ +void SPI_set_cmd_handler +( + spi_instance_t * this_spi, + spi_block_rx_handler_t cmd_handler, + uint32_t cmd_size +); + +/***************************************************************************//** + The SPI_set_cmd_response() function specifies the data that will be returned + to the master. See the description of SPI_set_cmd_handler() for details. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param resp_tx_buffer + The resp_tx_buffer parameter is a pointer to the buffer containing the data + that must be returned to the host in the data phase of an SPI transaction. + + @param resp_buff_size + The resp_buff_size parameter specifies the size of the buffer pointed by the + resp_tx_buffer parameter. + + @return + This function does not return any value. + */ +void SPI_set_cmd_response +( + spi_instance_t * this_spi, + const uint8_t * resp_tx_buffer, + uint32_t resp_buff_size +); + +/***************************************************************************//** + The SPI_enable() function enables the CoreSPI and allows it to respond to the external + signals. It is usually called to re-enable a CoreSPI instance which has been + disabled previously via by calling the SPI_disable() as the normal state of a CoreSPI + after enabling the initialization. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + */ +void SPI_enable +( + spi_instance_t * this_spi +); + +/***************************************************************************//** + The SPI_disable() function disables the CoreSPI and stops responding to the + external signals. + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + the g_core_spi global data structure defined within the application code. + + @return + This function does not return any value. + */ +void SPI_disable +( + spi_instance_t * this_spi +); + +#ifdef __cplusplus +} +#endif + +#endif /* CORE_SPI_H_*/ diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreSPI/corespi_regs.h b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreSPI/corespi_regs.h new file mode 100644 index 0000000..a3e5b2a --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreSPI/corespi_regs.h @@ -0,0 +1,270 @@ +/***************************************************************************//** + * Copyright 2011-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file corespi_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreSPI memory map + * + */ + +#ifndef CORESPI_REGS_H_ +#define CORESPI_REGS_H_ + +/******************************************************************************* + * Control register 1: + *------------------------------------------------------------------------------ + */ +#define CTRL1_REG_OFFSET 0x00u + +#define CTRL1_ENABLE_OFFSET 0x00u +#define CTRL1_ENABLE_MASK 0x01u +#define CTRL1_ENABLE_SHIFT 0x00 + +#define CTRL1_MASTER_OFFSET 0x00u +#define CTRL1_MASTER_MASK 0x02u +#define CTRL1_MASTER_SHIFT 0x01 + +#define CTRL1_INTRXDATA_OFFSET 0x00u +#define CTRL1_INTRXDATA_MASK 0x04u +#define CTRL1_INTRXDATA_SHIFT 0x02 + +#define CTRL1_INTTXDONE_OFFSET 0x00u +#define CTRL1_INTTXDONE_MASK 0x08u +#define CTRL1_INTTXDONE_SHIFT 0x03 + +#define CTRL1_INTRXOVFLOW_OFFSET 0x00u +#define CTRL1_INTRXOVFLOW_MASK 0x10u +#define CTRL1_INTRXOVFLOW_SHIFT 0x04 + +#define CTRL1_INTTXURUN_OFFSET 0x00u +#define CTRL1_INTTXURUN_MASK 0x20u +#define CTRL1_INTTXURUN_SHIFT 0x05 + +#define CTRL1_FRAMEURUN_OFFSET 0x00u +#define CTRL1_FRAMEURUN_MASK 0x40u +#define CTRL1_FRAMEURUN_SHIFT 0x06 + +#define CTRL1_OENOFF_OFFSET 0x00u +#define CTRL1_OENOFF_MASK 0x80u +#define CTRL1_OENOFF_SHIFT 0x07 + +/******************************************************************************* + * Interrupt clear register: + *------------------------------------------------------------------------------ + */ +#define INTCLR_REG_OFFSET 0x04u + +#define INTCLR_TXDONE_OFFSET 0x04u +#define INTCLR_TXDONE_MASK 0x01u +#define INTCLR_TXDONE_SHIFT 0x00 + +#define INTCLR_RXDONE_OFFSET 0x04u +#define INTCLR_RXDONE_MASK 0x02u +#define INTCLR_RXDONE_SHIFT 0x01 + +#define INTCLR_RXOVERFLOW_OFFSET 0x04u +#define INTCLR_RXOVERFLOW_MASK 0x04u +#define INTCLR_RXOVERFLOW_SHIFT 0x02 + +#define INTCLR_TXUNDERRUN_OFFSET 0x04u +#define INTCLR_TXUNDERRUN_MASK 0x08u +#define INTCLR_TXUNDERRUN_SHIFT 0x03 + +#define INTCLR_CMDINT_OFFSET 0x04u +#define INTCLR_CMDINT_MASK 0x10u +#define INTCLR_CMDINT_SHIFT 0x04 + +#define INTCLR_SSEND_OFFSET 0x04u +#define INTCLR_SSEND_MASK 0x20u +#define INTCLR_SSEND_SHIFT 0x05 + +#define INTCLR_RXDATA_OFFSET 0x04u +#define INTCLR_RXDATA_MASK 0x40u +#define INTCLR_RXDATA_SHIFT 0x06 + +#define INTCLR_TXDATA_OFFSET 0x04u +#define INTCLR_TXDATA_MASK 0x80u +#define INTCLR_TXDATA_SHIFT 0x07 + +/******************************************************************************* + * Receive data register: + *------------------------------------------------------------------------------ + */ +#define RXDATA_REG_OFFSET 0x08u + +/******************************************************************************* + * Transmit data register: + *------------------------------------------------------------------------------ + */ +#define TXDATA_REG_OFFSET 0x0Cu + +/******************************************************************************* + * Masked interrupt status register: + *------------------------------------------------------------------------------ + */ +#define INTMASK_REG_OFFSET 0x10u + +#define INTMASK_TXDONE_OFFSET 0x10u +#define INTMASK_TXDONE_MASK 0x01u +#define INTMASK_TXDONE_SHIFT 0x00 + +#define INTMASK_RXDONE_OFFSET 0x10u +#define INTMASK_RXDONE_MASK 0x02u +#define INTMASK_RXDONE_SHIFT 0x01 + +#define INTMASK_RXOVERFLOW_OFFSET 0x10u +#define INTMASK_RXOVERFLOW_MASK 0x04u +#define INTMASK_RXOVERFLOW_SHIFT 0x02 + +#define INTMASK_TXUNDERRUN_OFFSET 0x10u +#define INTMASK_TXUNDERRUN_MASK 0x08u +#define INTMASK_TXUNDERRUN_SHIFT 0x03 + +#define INTMASK_CMDINT_OFFSET 0x10u +#define INTMASK_CMDINT_MASK 0x10u +#define INTMASK_CMDINT_SHIFT 0x04 + +#define INTMASK_SSEND_OFFSET 0x10u +#define INTMASK_SSEND_MASK 0x20u +#define INTMASK_SSEND_SHIFT 0x05 + +#define INTMASK_RXDATA_OFFSET 0x10u +#define INTMASK_RXDATA_MASK 0x40u +#define INTMASK_RXDATA_SHIFT 0x06 + +#define INTMASK_TXDATA_OFFSET 0x10u +#define INTMASK_TXDATA_MASK 0x80u +#define INTMASK_TXDATA_SHIFT 0x07 + +/******************************************************************************* + * Raw interrupt status register: + *------------------------------------------------------------------------------ + */ +#define INTRAW_REG_OFFSET 0x14u + +#define INTRAW_TXDONE_OFFSET 0x14u +#define INTRAW_TXDONE_MASK 0x01u +#define INTRAW_TXDONE_SHIFT 0x00 + +#define INTRAW_RXDONE_OFFSET 0x14u +#define INTRAW_RXDONE_MASK 0x02u +#define INTRAW_RXDONE_SHIFT 0x01 + +#define INTRAW_RXOVERFLOW_OFFSET 0x14u +#define INTRAW_RXOVERFLOW_MASK 0x04u +#define INTRAW_RXOVERFLOW_SHIFT 0x02 + +#define INTRAW_TXUNDERRUN_OFFSET 0x14u +#define INTRAW_TXUNDERRUN_MASK 0x08u +#define INTRAW_TXUNDERRUN_SHIFT 0x03 + +#define INTRAW_CMDINT_OFFSET 0x14u +#define INTRAW_CMDINT_MASK 0x10u +#define INTRAW_CMDINT_SHIFT 0x04 + +#define INTRAW_SSEND_OFFSET 0x14u +#define INTRAW_SSEND_MASK 0x20u +#define INTRAW_SSEND_SHIFT 0x05 + +#define INTRAW_RXDATA_OFFSET 0x14u +#define INTRAW_RXDATA_MASK 0x40u +#define INTRAW_RXDATA_SHIFT 0x06 + +#define INTRAW_TXDATA_OFFSET 0x14u +#define INTRAW_TXDATA_MASK 0x80u +#define INTRAW_TXDATA_SHIFT 0x07 + +/******************************************************************************* + * Control register 2: + *------------------------------------------------------------------------------ + */ +#define CTRL2_REG_OFFSET 0x18u + +#define CTRL2_CMDSIZE_OFFSET 0x18u +#define CTRL2_CMDSIZE_MASK 0x07u +#define CTRL2_CMDSIZE_SHIFT 0x00 + +#define CTRL2_INTCMD_OFFSET 0x18u +#define CTRL2_INTCMD_MASK 0x10u +#define CTRL2_INTCMD_SHIFT 0x04 + +#define CTRL2_INTSSEND_OFFSET 0x18u +#define CTRL2_INTSSEND_MASK 0x20u +#define CTRL2_INTSSEND_SHIFT 0x05 + +#define CTRL2_INTRXDATA_OFFSET 0x18u +#define CTRL2_INTRXDATA_MASK 0x40u +#define CTRL2_INTRXDATA_SHIFT 0x06 + +#define CTRL2_INTTXDATA_OFFSET 0x18u +#define CTRL2_INTTXDATA_MASK 0x80u +#define CTRL2_INTTXDATA_SHIFT 0x07 + +/******************************************************************************* + * Command register: + *------------------------------------------------------------------------------ + */ +#define CMD_REG_OFFSET 0x1Cu + +#define CMD_RXFIFORST_OFFSET 0x1Cu +#define CMD_RXFIFORST_MASK 0x01u +#define CMD_RXFIFORST_SHIFT 0x00 + +#define CMD_TXFIFORST_OFFSET 0x1Cu +#define CMD_TXFIFORST_MASK 0x02u +#define CMD_TXFIFORST_SHIFT 0x01 + +/******************************************************************************* + * Status register: + *------------------------------------------------------------------------------ + */ +#define STATUS_REG_OFFSET 0x20u + +#define STATUS_FIRSTFRAME_OFFSET 0x20u +#define STATUS_FIRSTFRAME_MASK 0x01u +#define STATUS_FIRSTFRAME_SHIFT 0x00 + +#define STATUS_DONE_OFFSET 0x20u +#define STATUS_DONE_MASK 0x02u +#define STATUS_DONE_SHIFT 0x01 + +#define STATUS_RXEMPTY_OFFSET 0x20u +#define STATUS_RXEMPTY_MASK 0x04u +#define STATUS_RXEMPTY_SHIFT 0x02 + +#define STATUS_TXFULL_OFFSET 0x20u +#define STATUS_TXFULL_MASK 0x08u +#define STATUS_TXFULL_SHIFT 0x03 + +#define STATUS_RXOVFLOW_OFFSET 0x20u +#define STATUS_RXOVFLOW_MASK 0x10u +#define STATUS_RXOVFLOW_SHIFT 0x04 + +#define STATUS_TXUNDERRUN_OFFSET 0x20u +#define STATUS_TXUNDERRUN_MASK 0x20u +#define STATUS_TXUNDERRUN_SHIFT 0x05 + +#define STATUS_SSEL_OFFSET 0x20u +#define STATUS_SSEL_MASK 0x40u +#define STATUS_SSEL_SHIFT 0x06 + +#define STATUS_ACTIVE_OFFSET 0x20u +#define STATUS_ACTIVE_MASK 0x80u +#define STATUS_ACTIVE_SHIFT 0x07 + +/******************************************************************************* + * Slave select register: + *------------------------------------------------------------------------------ + */ +#define SSEL_REG_OFFSET 0x24u + +/******************************************************************************* + * Transmit data last register: + *------------------------------------------------------------------------------ + */ +#define TXLAST_REG_OFFSET 0x28u + + +#endif /*CORESPI_REGS_H_*/ diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.c b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.c new file mode 100644 index 0000000..b8adaed --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.c @@ -0,0 +1,889 @@ +/******************************************************************************* + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * PF_System_Services driver implementation. See file "core_syservices_pf.h" for + * description of the functions implemented in this file. + * + */ + +#include "core_sysservices_pf.h" +#include "coresysservicespf_regs.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define NULL_BUFFER (( uint8_t* ) 0) + +static uint8_t execute_ss_command +( + uint8_t cmd_opcode, + const uint8_t* cmd_data, + uint16_t cmd_data_size, + const uint8_t* p_response, + uint16_t response_size, + uint16_t mb_offset, + uint16_t response_offset +); + +uint32_t g_css_pf_base_addr = 0u; + +/***************************************************************************//** + * SYS_init() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +void +SYS_init +( + uint32_t base_addr +) +{ + g_css_pf_base_addr = base_addr; +} + +/***************************************************************************//** + * SYS_get_serial_number() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_serial_number +( + const uint8_t * p_serial_number, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if (p_serial_number == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(SERIAL_NUMBER_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_serial_number, + SERIAL_NUMBER_RESP_LEN, + mb_offset, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_get_user_code() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_user_code +( + const uint8_t * p_user_code, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_user_code == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(USERCODE_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_user_code, + USERCODE_RESP_LEN, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_get_design_info() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_design_info +( + const uint8_t * p_design_info, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_design_info == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(DESIGN_INFO_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_design_info, + DESIGN_INFO_RESP_LEN, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_get_device_certificate() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t +SYS_get_device_certificate +( + const uint8_t * p_device_certificate, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_device_certificate == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(DEVICE_CERTIFICATE_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_device_certificate, + DEVICE_CERTIFICATE_RESP_LEN, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_read_digest() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_read_digest +( + const uint8_t * p_digest, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_digest == NULL_BUFFER) + { + return status; + } + +#ifndef CORESYSSERVICES_MPFS + status = execute_ss_command(READ_DIGEST_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_digest, + READ_DIGEST_RESP_LEN, + mb_offset, + 0u); +#else + status = execute_ss_command(READ_DIGEST_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_digest, + READ_DIGEST_MPFS_RESP_LEN, + mb_offset, + 0u); +#endif + return status; + +} + +/***************************************************************************//** + * SYS_query_security() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_query_security +( + uint8_t * p_security_locks, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint8_t idx = 0u; + + if(p_security_locks == NULL_BUFFER) + { + return status; + } + +#ifndef CORESYSSERVICES_MPFS + uint8_t buf[12] = {0}; + /* Actual QUERY_SECURITY_RESP_LEN is 9 or 33 but PF_System_Services core + * needs number of words instead of number of bytes to be written to or read + * from MailBox */ + status = execute_ss_command(QUERY_SECURITY_REQUEST_CMD, + NULL_BUFFER, + 0u, + buf, + (QUERY_SECURITY_RESP_LEN + 3u), + mb_offset, + 0u); + + for (idx = 0u; idx < 9u; idx++) + { + *(p_security_locks+idx) = buf[idx]; + } + +#else + uint8_t buf[36] = {0}; + + status = execute_ss_command(QUERY_SECURITY_REQUEST_CMD, + NULL_BUFFER, + 0u, + buf, + (QUERY_SECURITY_MPFS_RESP_LEN + 3u), + mb_offset, + 0u); + + for (idx = 0u; idx < 33u; idx++) + { + *(p_security_locks+idx) = buf[idx]; + } + +#endif + + return status; +} + +/***************************************************************************//** + * SYS_read_debug_info() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_read_debug_info +( + const uint8_t * p_debug_info, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_debug_info == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(READ_DEBUG_INFO_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_debug_info, + READ_DEBUG_INFO_RESP_LEN, + mb_offset, + 0u); + return status; +} + +#ifdef CORESYSSERVICES_MPFS +/***************************************************************************//** + * SYS_read_envm_parameter() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_read_envm_parameter +( + uint8_t * p_envm_param, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if(p_envm_param == NULL_BUFFER) + { + return status; + } + + status = execute_ss_command(READ_ENVM_PARAM_REQUEST_CMD, + NULL_BUFFER, + 0, + p_envm_param, + READ_ENVM_PARAM_RESP_LEN, + mb_offset, + 0); + return status; +} + +#endif + +/***************************************************************************//** + * SYS_puf_emulation_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_puf_emulation_service +( + const uint8_t * p_challenge, + uint8_t op_type, + uint8_t* p_response, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint8_t mb_format[20] = {0x00}; + uint8_t index = 0u; + + if((p_response == NULL_BUFFER) || (p_challenge == NULL_BUFFER)) + { + return status; + } + + /* Frame the data required for mailbox */ + mb_format[index] = op_type; + + for (index = 4u; index < 20u; index++) + { + mb_format[index] = p_challenge[index - 4u]; + } + + status = execute_ss_command(PUF_EMULATION_SERVICE_REQUEST_CMD, + mb_format, + PUF_EMULATION_SERVICE_CMD_LEN, + p_response, + PUF_EMULATION_SERVICE_RESP_LEN, + mb_offset, + 5u); /* mentioning offset to number of words instead of bytes */ + + return status; +} + +/***************************************************************************//** + * SYS_digital_signature_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_digital_signature_service +( + const uint8_t* p_hash, + uint8_t format, + uint8_t* p_response, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if((p_hash == NULL_BUFFER) || (p_response == NULL_BUFFER)) + { + return status; + } + + if (format == DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD) + { + status = execute_ss_command(DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD, + p_hash, + DIGITAL_SIGNATURE_HASH_LEN, + p_response, + DIGITAL_SIGNATURE_RAW_FORMAT_RESP_SIZE, + mb_offset, + 12u); /* mentioning offset to number of words instead of bytes */ + } + else + { + status = execute_ss_command(DIGITAL_SIGNATURE_DER_FORMAT_REQUEST_CMD, + p_hash, + DIGITAL_SIGNATURE_HASH_LEN, + p_response, + DIGITAL_SIGNATURE_DER_FORMAT_RESP_SIZE, + mb_offset, + 12u); /* mentioning offset to number of words instead of bytes */ + } + + return status; +} + +/***************************************************************************//** + * SYS_secure_nvm_write() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_secure_nvm_write +( + uint8_t format, + uint8_t snvm_module, + const uint8_t* p_data, + const uint8_t* p_user_key, + uint16_t mb_offset +) +{ + uint8_t frame[256] = {0x00}; + uint8_t* p_frame = &frame[0]; + uint16_t index = 0u; + uint8_t status = SYS_PARAM_ERR; + + HAL_ASSERT(!(NULL_BUFFER == p_data)); + HAL_ASSERT(!(snvm_module >= 221u)); + if (format != SNVM_NON_AUTHEN_TEXT_REQUEST_CMD) + { + HAL_ASSERT(!(NULL_BUFFER == p_user_key)); + } + + if ((p_data == NULL_BUFFER) || (snvm_module >= 221)) + { + return status; + } + + if ((format != SNVM_NON_AUTHEN_TEXT_REQUEST_CMD) + && (p_user_key == NULL_BUFFER)) + { + return status; + } + + if ((format != SNVM_NON_AUTHEN_TEXT_REQUEST_CMD) + && (format != SNVM_AUTHEN_TEXT_REQUEST_CMD) + && (format != SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD)) + { + return status; + } + + *p_frame = snvm_module; /* SNVMADDR - SNVM module */ + + p_frame += 4u; /* Next 3 bytes RESERVED - For alignment */ + + /* Copy user key and send the command/data to mailbox. */ + if ((format == SNVM_AUTHEN_TEXT_REQUEST_CMD) || + (format == SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD)) + { + /* Copy user data */ + for (index = 0u; index < (AUTHENTICATED_TEXT_DATA_LEN - USER_SECRET_KEY_LEN - 4u); index++) + { + *p_frame = p_data[index]; + p_frame++; + } + + /* Copy user key */ + for (index = 0u; index < USER_SECRET_KEY_LEN; index++) + { + *p_frame = p_user_key[index]; + p_frame++; + } + + status = execute_ss_command(format, + &frame[0], + AUTHENTICATED_TEXT_DATA_LEN, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + } + else + { + /* Copy user data */ + for (index = 0u; index < (NON_AUTHENTICATED_TEXT_DATA_LEN - 4u); index++) + { + *(p_frame+index) = p_data[index]; + } + + status = execute_ss_command(format, + &frame[0], + NON_AUTHENTICATED_TEXT_DATA_LEN, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + } + + return status; +} + +/***************************************************************************//** + * SYS_secure_nvm_read() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_secure_nvm_read +( + uint8_t snvm_module, + const uint8_t* p_user_key, + uint8_t* p_admin, + uint8_t* p_data, + uint16_t data_len, + uint16_t mb_offset +) +{ + /* Frame the message. */ + uint8_t frame[16] = {0x00u}; + uint8_t* p_frame = &frame[0u]; + uint8_t status = SYS_PARAM_ERR; + uint8_t response[256] = {0x00u}; + uint16_t index = 0u; + + HAL_ASSERT(!(NULL_BUFFER == p_data)); + HAL_ASSERT(!(NULL_BUFFER == p_admin)); + HAL_ASSERT(!(snvm_module > 221u)); + + HAL_ASSERT(data_len == 236u || data_len == 252u); + + if((p_data == NULL_BUFFER) || + (snvm_module >= 221) || + (p_admin == NULL_BUFFER)) + { + return status; + } + + *p_frame = snvm_module; /* SNVMADDR - SNVM module */ + + p_frame += 4u; /* RESERVED - For alignment */ + + /* Copy user key */ + if (236u == data_len) + { + HAL_ASSERT(p_user_key != NULL_BUFFER); + + if(p_user_key == NULL_BUFFER) + { + return status; + } + + for (index = 0u; index < 12u; index++) + { + *p_frame = p_user_key[index]; + p_frame++; + } + } + else + { + p_frame += 12u; + } + + status = execute_ss_command(SNVM_READ_REQUEST_CMD, + &frame[0], + 16u, + response, + (data_len + 4u), + mb_offset, + 4u); /* mentioning offset to number of words instead of bytes */ + + if (SYS_SUCCESS == status) + { + for (index = 0u; index < 4u; index++) + { + *(p_admin+index) = (uint32_t)response[index]; + } + + + /* Copy data into user buffer. */ + for (index = 4u; index < (data_len + 4u); index++) + { + *(p_data + (index - 4u)) = response[index]; + } + } + else + { + ; + } + + return status; +} + +/***************************************************************************//** + * SYS_nonce_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_nonce_service +( + const uint8_t * p_nonce, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + + if((p_nonce == NULL_BUFFER)) + { + return status; + } + + status = execute_ss_command(NONCE_SERVICE_REQUEST_CMD, + NULL_BUFFER, + 0u, + p_nonce, + NONCE_SERVICE_RESP_LEN, + mb_offset, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_bitstream_authenticate_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_bitstream_authenticate_service +( + uint32_t spi_flash_address, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint32_t l_spi_flash_address = spi_flash_address; + status = execute_ss_command(BITSTREAM_AUTHENTICATE_CMD, + (uint8_t* )&l_spi_flash_address, + 4u, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_IAP_image_authenticate_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_IAP_image_authenticate_service +( + uint8_t spi_idx +) +{ + uint8_t status = SYS_PARAM_ERR; + + HAL_ASSERT(!(spi_idx == 1u)); + + if (spi_idx == 1u) + { + return status; + } + + status = execute_ss_command(IAP_BITSTREAM_AUTHENTICATE_CMD, + NULL_BUFFER, + 0u, + NULL_BUFFER, + 0u, + spi_idx, + 0u); + + return status; +} + +/***************************************************************************//** + * SYS_digest_check_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_digest_check_service +( + uint32_t options, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint32_t l_options = options; + + status = execute_ss_command(DIGEST_CHECK_CMD, + (uint8_t* )&l_options, + 4u, + NULL_BUFFER, + 0u, + mb_offset, + 0u); + return status; +} + +/***************************************************************************//** + * SYS_iap_service() + * See "core_sysservices_pf.h" for details of how to use this function. + */ +uint8_t SYS_iap_service +( + uint8_t iap_cmd, + uint32_t spiaddr, + uint16_t mb_offset +) +{ + uint8_t status = SYS_PARAM_ERR; + uint16_t l_mb_offset = 0u; + uint16_t cmd_data_size = 0u; + uint8_t* cmd_data = NULL_BUFFER; + bool invalid_param = false; + + if (((IAP_PROGRAM_BY_SPIIDX_CMD == iap_cmd) + || (IAP_VERIFY_BY_SPIIDX_CMD == iap_cmd)) + && (1u == spiaddr)) + { + invalid_param = true; + HAL_ASSERT(!invalid_param); + } + + if (!invalid_param) + { + switch(iap_cmd) + { + case IAP_PROGRAM_BY_SPIIDX_CMD: + case IAP_VERIFY_BY_SPIIDX_CMD: + /*In SPI_IDX based program and verify commands, + * Mailbox is not Required. Instead of mailbox offset + * SPI_IDX is passed as parameter.*/ + l_mb_offset = (uint16_t)(0xFFu & spiaddr); + break; + + case IAP_PROGRAM_BY_SPIADDR_CMD: + case IAP_VERIFY_BY_SPIADDR_CMD: + /*In SPI_ADDR based program and verify commands, + * Mailbox is Required*/ + l_mb_offset = mb_offset; + /*command data size is four bytes holding the + * SPI Address in it.*/ + cmd_data_size = 4u; + cmd_data = (uint8_t*)&spiaddr; + break; + + case IAP_AUTOUPDATE_CMD: + /*In auto update command Mailbox is not Required*/ + l_mb_offset = 0u; + break; + + default: + l_mb_offset = 0u; + + } + + status = execute_ss_command( + (uint8_t)iap_cmd, + cmd_data, + cmd_data_size, + NULL_BUFFER, + 0, + (uint16_t)l_mb_offset, + 0); + } + + return status; +} + +/***************************************************************************//** + Internal functions. +*/ +/* +This function executes the SS command. If Mailbox input data is required by the +it will first load it from cmd_data into the Mailbox. If the service requires +the response data to be read from mailbox, it will do so and store it in p_response. +*/ +static uint8_t execute_ss_command +( + uint8_t cmd_opcode, + const uint8_t* cmd_data, + uint16_t cmd_data_size, + const uint8_t* p_response, + uint16_t response_size, + uint16_t mb_offset, + uint16_t response_offset +) +{ + /* Pointer used during Writing to Mailbox memory. */ + uint32_t status = 0u; + uint16_t idx = 0u; + uint16_t ss_command = 0u; + uint32_t* word_buf; + uint16_t timeout_count = SS_TIMEOUT_COUNT; + + /* making sure that the system controller is not executing any service i.e. + SS_USER_BUSY is gone 0 */ + + while (1u == HAL_get_32bit_reg_field(g_css_pf_base_addr, SS_USER_BUSY)) + { + --timeout_count; + + if (timeout_count == 0) + { + return SS_USER_BUSY_TIMEOUT; + } + } + + /* Form the SS command: bit 0to6 is the opcode, bit 7to15 is the Mailbox offset + For some services this field has another meaning + (e.g. for IAP bitstream auth. it means spi_idx) */ + ss_command = ((mb_offset << 7u) | (cmd_opcode & 0x7Fu)); + + /* Load the command register with the SS request command code*/ + HAL_set_32bit_reg(g_css_pf_base_addr, SS_CMD, ss_command); + + if (cmd_data_size > 0u) + { + HAL_ASSERT(!(NULL_BUFFER == cmd_data)); + HAL_ASSERT(!(cmd_data_size % 4u)); + + /* Load the MBX_WCNT register with number of words */ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_WCNT, (cmd_data_size/4u)); + + /* Load the MBX_WADDR register with offset of input data (write to Mailbox) + For all the services this offset remains either 0 or Not applicable + for the services in which no Mailbox write is required.*/ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_WADDR, (0x00u + mb_offset)); + + } + + if (response_size > 0u) + { + HAL_ASSERT(!(NULL_BUFFER == p_response)); + HAL_ASSERT(!(response_size % 4u)); + + /* + Load the MBX_RWCNT register with number of words to be read from Mailbox + */ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_RCNT, (response_size/4u)); + + /* + Load the MBX_RADRDESC register with offset address within the mailbox + format for that particular service. + It will be 0 for the services where there is no output data from G5CONTROL + is expected. + This function assumes that this value is pre-calculated by service specific + functions as this value is fixed for each service. + */ + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_RADDR, (response_offset + mb_offset)); + } + + /*Set the request bit in SYS_SERV_REQ register to start the service*/ + HAL_set_32bit_reg_field(g_css_pf_base_addr, SS_REQ_REQ, 0x01u); + + if (cmd_data_size > 0u) + { + word_buf = (uint32_t*)cmd_data; + + /* Write the user data into mail box. */ + for (idx = 0u; idx < (cmd_data_size/4u); idx++) + { + HAL_set_32bit_reg( g_css_pf_base_addr, MBX_WDATA, word_buf[idx]); + } + } + + timeout_count = SS_TIMEOUT_COUNT; + if (response_size > 0u) + { + word_buf = (uint32_t*)p_response; + + for (idx = 0u; idx < (response_size/4u); idx++) + { + while (0u == HAL_get_32bit_reg_field(g_css_pf_base_addr, + SS_USER_RDVLD)) + { + --timeout_count; + + if (timeout_count == 0) + { + return SS_USER_RDVLD_TIMEOUT; + } + } + word_buf[idx] = HAL_get_32bit_reg(g_css_pf_base_addr, MBX_RDATA); + } + } + + timeout_count = SS_TIMEOUT_COUNT; + /* make sure that service is complete i.e. SS_USER_BUSY is gone 0 */ + while (1u == HAL_get_32bit_reg_field(g_css_pf_base_addr, SS_USER_BUSY)) + { + --timeout_count; + + if (timeout_count == 0) + { + return SS_USER_RDVLD_TIMEOUT; + } + } + + /* Read the status returned by System Controller */ + status = HAL_get_32bit_reg(g_css_pf_base_addr, SS_STAT); + + return (uint8_t)status; +} + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h new file mode 100644 index 0000000..8e0ebb6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h @@ -0,0 +1,1249 @@ +/******************************************************************************* + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the + * CoreSysServices_PF bare metal driver. + */ +/*=========================================================================*//** + @mainpage CoreSysServices_PF Bare Metal Driver. + + @section intro_sec Introduction + The PolarFire System Services (PF_SYSTEM_SERVICES) SgCore enables executing + the system services on the PolarFire and PolarFire SoC device. The system services + are the system controller actions initiated by the System Controller's System + Service Interface (SSI). The PolarFire System Services "SgCore" provides a + method to initiate these system services. The PF_SYSTEM_SERVICES interacts + with the system controller on SSI and Mailbox interface to initiate system + services, exchange data required for that services, and to know the successful + completion or error status. + + The PF_SYSTEM_SERVICES provides an APB interface for controlling the registers + functions for controlling the PF_SYSTEM_SERVICES as part of a bare metal system + register implemented within it. This software driver provides a set of where no + part of an operating system but the implementation of the adaptation layer + operating system is available. This driver is adapted for use in + between this driver and the operating system's driver model is outside the + scope of this driver. + + ## Features + The CoreSysServices_PF driver provides the following features: + - Executing device and design information services + - Executing design services + - Executing data security services + - Executing Fabric services + + The CoreSysServices_PF driver is provided as C source code. + + @section Driver Configuration + The application software should configure the CoreSysServices_PF driver through + calling the SYS_init() function. Only one instance of PF_SYSTEM_SERVICES SgCore is + supported. No additional configuration files are required to use the driver. + If using this driver on RT PolarFire device FPGA, define RT_DEVICE_FAMILY + macro in application. + + @section theory_op Theory of Operation + The CoreSysServices_PF driver provides access to the PolarFire system services. + These system services are grouped into the following categories: + + Device and Design Information Service + - Serial Number Service + - USERCODE Service + - Design Info Service + - Device Certificate Services + - Read Digests + - Query Security + - Read Debug Info + - Read eNVM param + + Design Services + - Bitstream authentication service + - IAP bitstream authentication service + + Data Security Services + - Digital Signature Service + - Secure NVM (SNVM) Functions + - PUF Emulation Service + - Nonce Service + + Fabric Services + - Digest Check Service + - In Application programming(IAP)/Auto-Update service + + Initialization and Configuration + + The CoreSysServices_PF driver is initialized by calling the SYS_init() + function. The SYS_init() function must be called before calling any other + CoreSysServices_PF driver functions. + + Device and Design Information Services + + The CoreSysServices_PF driver is used to read information about the device + and the design using the following functions: + - SYS_get_serial_number() + - SYS_get_user_code() + - SYS_get_design_info() + - SYS_get_device_certificate() + - SYS_read_digest() + - SYS_query_security() + - SYS_read_debug_info() + + Design Authentication Services + + The CoreSysServices_PF driver is used to execute design services using the + following functions: + - SYS_bitstream_authenticate_service() + - SYS_IAP_image_authenticate_service() + + Data Security Services + + The CoreSysServices_PF driver is used to execute data security services + using the following functions: + - SYS_digital_signature_service() + - SYS_secure_nvm_write() + - SYS_secure_nvm_read() + - SYS_puf_emulation_service () + - SYS_nonce_service () + + Executing Fabric Services + + The CoreSysServices_PF driver is used to execute fabric services using the + following functions: + - SYS_digest_check_service() + - SYS_iap_service() + + All the service execution functions return the 8-bit status, which is returned + by the system controller on executing the given service. A '0' value indicates + successful execution of that service. A non-zero value indicates error. + The error codes for each service are different. See individual function + description to know the exact meanings of the error codes for each service. + + The function descriptions in this file mainly focus on the details required + by the user to use the APIs provided by this driver to execute the services. + To know the complete details of the system services, see the + PolarFire FPGA and PolarFire SoC FPGA System Services [document](https://onlinedocs.microchip.com/pr/GUID-1409CF11-8EF9-4C24-A94E-70979A688632-en-US-3/index.html) + + *//*=========================================================================*/ +#ifndef __CORE_SYSSERV_PF_H +#define __CORE_SYSSERV_PF_H 1 + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#include "hal_assert.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** +* # Service Execution Success and Error Status Codes +* +* The following status codes are the return values from the system service functions. +* For any service, a return value '0' indicates that the service was executed +* successfully. A non-zero return value indicates that the service was not +* executed successfully. For all the services, the return value represents the +* status code returned by the system controller for the respective service, +* except the values SYS_PARAM_ERR, SS_USER_BUSY_TIMEOUT, and SS_USER_RDVLD_TIMEOUT. +* These three values indicate the error conditions detected by this driver and +* they do not overlap with the status code returned by the system controller for +* any of the system service. +* +* SYS_SUCCESS +* System service executed successfully +* +* SYS_PARAM_ERR +* System service cannot be executed as one or more parameters are not as +* expected by this driver. No read/write access is performed with the +* IP. +* +* SS_USER_BUSY_TIMEOUT +* The System service request is initiated and the driver timed-out while +* waiting for the system service to complete. The System Service +* completion is indicated by de-assertion of the SS_USER_BUSY bit by the +* IP. +* +* SS_USER_RDVLD_TIMEOUT +* The System service request is initiated and the driver timed-out while +* waiting for SS_USER_RDVLD bit, which indicates availability of data to +* be read from the mailbox, to become active. +*/ +#define SYS_SUCCESS 0u +#define SYS_PARAM_ERR 0xFFu +#define SS_USER_BUSY_TIMEOUT 0xFAu +#define SS_USER_RDVLD_TIMEOUT 0xFBu + +/** +* # System Service Timeout Count +* +* The SS_TIMEOUT_COUNT value is used by the driver as a timeout count +* while waiting for either the SS_USER_BUSY or SS_USER_RDVLD. This empirical +* value is sufficiently large so that the operations are falsely +* timeout in the normal circumstance. It is provided as a way to provide +* more debug information to the application in case there are some +* unforeseen issues. You may change this value for your need based on your +* system design. +*/ +#define SS_TIMEOUT_COUNT 40000u +/* + * SYS_DCF_DEVICE_MISMATCH + * Public key or FSN do not match device + * + * + * SYS_DCF_INVALID_SIGNATURE + * Certificate signature is invalid + * + * SYS_DCF_SYSTEM_ERROR + * PUF or storage failure + */ +#define SYS_DCF_DEVICE_MISMATCH 1u +#define SYS_DCF_INVALID_SIGNATURE 2u +#define SYS_DCF_SYSTEM_ERROR 3u + +/* + * SYS_NONCE_PUK_FETCH_ERROR + * Error fetching PUK + * + * SYS_NONCE_SEED_GEN_ERROR + * Error generating seed + */ +#define SYS_NONCE_PUK_FETCH_ERROR 1u +#define SYS_NONCE_SEED_GEN_ERROR 2u + +/** + * # Secure Nvm Write Error Codes + * + * SNVM_WRITE_INVALID_SNVMADDR + * Illegal page address + * + * SNVM_WRITE_FAILURE + * PNVM program/verify failed + * + * SNVM_WRITE_SYSTEM_ERROR + * PUF or storage failure + * + * SNVM_WRITE_NOT_PERMITTED + * Write is not permitted + */ +#define SNVM_WRITE_INVALID_SNVMADDR 1u +#define SNVM_WRITE_FAILURE 2u +#define SNVM_WRITE_SYSTEM_ERROR 3u +#define SNVM_WRITE_NOT_PERMITTED 4u + +/** + * # Secure Nvm Read Error Codes + * + * SNVM_READ_INVALID_SNVMADDR + * Illegal page address + * + * SNVM_READ_AUTHENTICATION_FAILURE + * Storage corrupt or incorrect USK + * + * SNVM_READ_SYSTEM_ERROR + * PUF or storage failure + * + */ +#define SNVM_READ_INVALID_SNVMADDR 1u +#define SNVM_READ_AUTHENTICATION_FAILURE 2u +#define SNVM_READ_SYSTEM_ERROR 3u + +/** + * # Digital Signature Service Error Codes + * + * DIGITAL_SIGNATURE_FEK_FAILURE_ERROR + * Error retrieving FEK + * + * DIGITAL_SIGNATURE_DRBG_ERROR + * Failed to generate nonce + * + * DIGITAL_SIGNATURE_ECDSA_ERROR + * ECDSA failed + */ +#define DIGITAL_SIGNATURE_FEK_FAILURE_ERROR 1u +#define DIGITAL_SIGNATURE_DRBG_ERROR 2u +#define DIGITAL_SIGNATURE_ECDSA_ERROR 3u + +/** + * # Digest Check Error Codes + * + * NOTE: When these error occur, the DIGEST tamper flag is triggered. + * + * DIGEST_CHECK_FABRICERR + * Fabric digest check error + * + * DIGEST_CHECK_CCERR + * UFS Fabric Configuration (CC) segment digest check error + * + * DIGEST_CHECK_SNVMERR + * ROM digest in SNVM segment digest check error + * + * DIGEST_CHECK_ULERR + * UFS UL segment digest check error + * + * DIGEST_CHECK_UK0ERR + * UKDIGEST0 in User Key segment digest check error + * + * DIGEST_CHECK_UK1ERR + * UKDIGEST1 in User Key segment digest check error + * + * DIGEST_CHECK_UK2ERR + * UKDIGEST2 in User Key segment (UPK1) digest check error + * + * DIGEST_CHECK_UK3ERR + * UKDIGEST3 in User Key segment (UK1) digest check error + * + * DIGEST_CHECK_UK4ERR + * UKDIGEST4 in User Key segment (DPK) digest check error + * + * DIGEST_CHECK_UK5ERR + * UKDIGEST5 in User Key segment (UPK2) digest check error + * + * DIGEST_CHECK_UK6ERR + * UKDIGEST6 in User Key segment (UK2) digest check error + * + * DIGEST_CHECK_UPERR + * UFS Permanent Lock (UPERM) segment digest check error + * + * DIGEST_CHECK_SYSERR + * M3 ROM, Factory and Factory Key Segments digest check error + * + */ +#define DIGEST_CHECK_FABRICERR 0x00u +#define DIGEST_CHECK_CCERR 0x01u +#define DIGEST_CHECK_SNVMERR 0x02u +#define DIGEST_CHECK_ULERR 0x03u +#define DIGEST_CHECK_UK0ERR 0x04u +#define DIGEST_CHECK_UK1ERR 0x05u +#define DIGEST_CHECK_UK2ERR 0x06u +#define DIGEST_CHECK_UK3ERR 0x07u +#define DIGEST_CHECK_UK4ERR 0x08u +#define DIGEST_CHECK_UK5ERR 0x09u +#define DIGEST_CHECK_UK6ERR 0x10u +#define DIGEST_CHECK_UPERR 0x11u +#define DIGEST_CHECK_SYSERR 0x12u + +/** + * # Bitstream Authentication and Iap Bitstream Authentication Return Status + * + * BSTREAM_AUTH_CHAINING_MISMATCH_ERR + * Validator or hash chaining mismatch. Incorrectly constructed bitstream or + * wrong key used. + * + * BSTREAM_AUTH_UNEXPECTED_DATA_ERR + * Unexpected data received. + * Additional data received after end of EOB component. + * + * BSTREAM_AUTH_INVALID_ENCRY_KEY_ERR + * Invalid/corrupt encryption key. + * The requested key mode is disabled or the key could not be read/reconstructed. + * + * BSTREAM_AUTH_INVALID_HEADER_ERR + * Invalid component header + * + * BSTREAM_AUTH_BACK_LEVEL_NOT_SATISFIED_ERR + * Back level not satisfied + * + * BSTREAM_AUTH_ILLEGAL_BITSTREAM_MODE_ERR + * Illegal bitstream mode. + * Requested bitstream mode is disabled by user security. + * + * BSTREAM_AUTH_DNS_BINDING_MISMATCH_ERR + * DSN binding mismatch + * + * BSTREAM_AUTH_ILLEGAL_COMPONENT_SEQUENCE_ERR + * Illegal component sequence + * + * BSTREAM_AUTH_INSUFF_DEVICE_CAPAB_ERR + * Insufficient device capabilities + * + * BSTREAM_AUTH_INCORRECT_DEVICEID_ERR + * Incorrect DEVICEID + * + * BSTREAM_AUTH_PROTOCOL_VERSION_ERR + * Unsupported bitstream protocol version (regeneration required) + * + * BSTREAM_AUTH_VERIFY_ERR + * Verify not permitted on this bitstream + * + * BSTREAM_AUTH_INVALID_DEV_CERT_ERR + * Invalid Device Certificate. + * Device SCAC is invalid or not present. + * + * BSTREAM_AUTH_INVALID_DIB_ERR + * Invalid DIB + * + * BSTREAM_AUTH_SPI_NOT_MASTER_ERR + * Device not in SPI Master Mode. + * Error may occur only when bitstream is executed through IAP mode. + * + * BSTREAM_AUTH_AUTOIAP_NO_VALID_IMAGE_ERR + * No valid images found. + * Error may occur when bitstream is executed through Auto Update mode. + * Occurs when no valid image pointers are found. + * + * BSTREAM_AUTH_INDEXIAP_NO_VALID_IMAGE_ERR + * No valid images found. + * Error may occur when bitstream is executed through IAP mode via Index Mode. + * Occurs when No valid image pointers are found. + * + * BSTREAM_AUTH_NEWER_DESIGN_VERSION_ERR + * Programmed design version is newer than AutoUpdate image found. + * Error may occur when bitstream is executed through Auto Update mode. + * + * BSTREAM_AUTH_INVALID_IMAGE_ERR + * Selected image was invalid and no recovery was performed due to valid design + * in device. + * Error may occur only when bitstream is executed through Auto Update or IAP mode + * (This error is here for completeness but only can be observed by running the + * READ_DEBUG_INFO instruction and looking at IAP Error code field). + * + * BSTREAM_AUTH_IMAGE_PROGRAM_FAILED_ERR + * Selected and Recovery image failed to program. + * Error may occur only when bitstream is executed through Auto Update or + * IAP mode + * (This error is here for completeness but only can be observed by running the + * READ_DEBUG_INFO instruction and looking at IAP Error code field). + * + * BSTREAM_AUTH_ABORT_ERR + * Abort. + * Non-bitstream instruction executed during bitstream loading. + * + * BSTREAM_AUTH_NVMVERIFY_ERR + * Fabric/UFS verification failed (min or weak limit) + * + * BSTREAM_AUTH_PROTECTED_ERR + * Device security prevented modification of non-volatile memory + * + * BSTREAM_AUTH_NOTENA + * Programming mode not enabled + * + * BSTREAM_AUTH_PNVMVERIFY + * pNVM verify operation failed + * + * BSTREAM_AUTH_SYSTEM + * System hardware error (PUF or DRBG) + * + * BSTREAM_AUTH_BADCOMPONENT + * An internal error was detected in a component payload + * + * BSTREAM_AUTH_HVPROGERR + * HV programming subsystem failure (pump failure) + * + * BSTREAM_AUTH_HVSTATE + * HV programming subsystem in unexpected state (internal error) + * + */ +#define BSTREAM_AUTH_CHAINING_MISMATCH_ERR 1 +#define BSTREAM_AUTH_UNEXPECTED_DATA_ERR 2 +#define BSTREAM_AUTH_INVALID_ENCRY_KEY_ERR 3 +#define BSTREAM_AUTH_INVALID_HEADER_ERR 4 +#define BSTREAM_AUTH_BACK_LEVEL_NOT_SATISFIED_ERR 5 +#define BSTREAM_AUTH_ILLEGAL_BITSTREAM_MODE_ERR 6 +#define BSTREAM_AUTH_DNS_BINDING_MISMATCH_ERR 7 +#define BSTREAM_AUTH_ILLEGAL_COMPONENT_SEQUENCE_ERR 8 +#define BSTREAM_AUTH_INSUFF_DEVICE_CAPAB_ERR 9 +#define BSTREAM_AUTH_INCORRECT_DEVICEID_ERR 10 +#define BSTREAM_AUTH_PROTOCOL_VERSION_ERR 11 +#define BSTREAM_AUTH_VERIFY_ERR 12 +#define BSTREAM_AUTH_INVALID_DEV_CERT_ERR 13 +#define BSTREAM_AUTH_INVALID_DIB_ERR 14 +#define BSTREAM_AUTH_SPI_NOT_MASTER_ERR 21 +#define BSTREAM_AUTH_AUTOIAP_NO_VALID_IMAGE_ERR 22 +#define BSTREAM_AUTH_INDEXIAP_NO_VALID_IMAGE_ERR 23 +#define BSTREAM_AUTH_NEWER_DESIGN_VERSION_ERR 24 +/* 25 Reserved */ +#define BSTREAM_AUTH_INVALID_IMAGE_ERR 26 +#define BSTREAM_AUTH_IMAGE_PROGRAM_FAILED_ERR 27 +#define BSTREAM_AUTH_ABORT_ERR 127 +#define BSTREAM_AUTH_NVMVERIFY_ERR 128 +#define BSTREAM_AUTH_PROTECTED_ERR 129 +#define BSTREAM_AUTH_NOTENA 130 +#define BSTREAM_AUTH_PNVMVERIFY 131 +#define BSTREAM_AUTH_SYSTEM 132 +#define BSTREAM_AUTH_BADCOMPONENT 133 +#define BSTREAM_AUTH_HVPROGERR 134 +#define BSTREAM_AUTH_HVSTATE 135 + +/***************************************************************************//** + * # Mailbox ECC Status + * Provides ECC status when the mailbox is read. The values are as follows: + * 00: No ECC errors detected, data is correct. + * 01: Exactly one bit error occurred and has been corrected. + * 10: Exactly two bits error occurred and no correction performed. + * 11: Reserved. + */ +#define SYS_MBOX_ECC_NO_ERROR_MASK 0x00u +#define SYS_MBOX_ONEBIT_ERROR_CORRECTED_MASK 0x40u +#define SYS_MBOX_TWOBIT_ERROR_MASK 0xC0u + +/***************************************************************************//** + * Service request command opcodes: +*/ +#define SERIAL_NUMBER_REQUEST_CMD 0x00u +#define USERCODE_REQUEST_CMD 0x01u +#define DESIGN_INFO_REQUEST_CMD 0x02u +#define DEVICE_CERTIFICATE_REQUEST_CMD 0x03u +#define READ_DIGEST_REQUEST_CMD 0x04u +#define QUERY_SECURITY_REQUEST_CMD 0x05u +#define READ_DEBUG_INFO_REQUEST_CMD 0x06u +#define READ_ENVM_PARAM_REQUEST_CMD 0x07u +#define SNVM_NON_AUTHEN_TEXT_REQUEST_CMD 0x10u +#define SNVM_AUTHEN_TEXT_REQUEST_CMD 0x11u +#define SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD 0x12u +#define SNVM_READ_REQUEST_CMD 0x18u +#define DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD 0x19u +#define PUF_EMULATION_SERVICE_REQUEST_CMD 0x20u +#define NONCE_SERVICE_REQUEST_CMD 0x21u +#define DIGITAL_SIGNATURE_DER_FORMAT_REQUEST_CMD 0x1Au + +#define BITSTREAM_AUTHENTICATE_CMD 0x23u +#define IAP_BITSTREAM_AUTHENTICATE_CMD 0x22u + +#define DIGEST_CHECK_CMD 0x47u + +#define IAP_PROGRAM_BY_SPIIDX_CMD 0x42u +#define IAP_VERIFY_BY_SPIIDX_CMD 0x44u +#define IAP_PROGRAM_BY_SPIADDR_CMD 0x43u +#define IAP_VERIFY_BY_SPIADDR_CMD 0x45u +#define IAP_AUTOUPDATE_CMD 0x46u + +/***************************************************************************//** + * Service request Mailbox return data length + */ +#define SERIAL_NUMBER_RESP_LEN 16u +#define USERCODE_RESP_LEN 4u +#define DESIGN_INFO_RESP_LEN 36u +#define DEVICE_CERTIFICATE_RESP_LEN 1024u +#define READ_DIGEST_RESP_LEN 416u +#define QUERY_SECURITY_RESP_LEN 9u +#define READ_DEBUG_INFO_RESP_LEN 76u +#define READ_ENVM_PARAM_RESP_LEN 256u +#define NONCE_SERVICE_RESP_LEN 32u + +#define PUF_EMULATION_SERVICE_CMD_LEN 20u +#define PUF_EMULATION_SERVICE_RESP_LEN 32u + +#define DIGITAL_SIGNATURE_HASH_LEN 48u +#define DIGITAL_SIGNATURE_RAW_FORMAT_RESP_SIZE 96u +#define DIGITAL_SIGNATURE_DER_FORMAT_RESP_SIZE 104u + +#define USER_SECRET_KEY_LEN 12u + +/* Same driver can be used on PolarFire SoC platform and the response length + * is different for PolarFire SoC. Constants defined below are used only when the + * PF System services driver is used with PolarFire SoC Platform. + */ +#define READ_DIGEST_MPFS_RESP_LEN 576u +#define QUERY_SECURITY_MPFS_RESP_LEN 33u + +/* SNVM Input data length from sNVM write. */ +#ifndef RT_DEVICE_FAMILY +/* SNVMADDR + RESERVED + PT + USK */ +#define NON_AUTHENTICATED_TEXT_DATA_LEN 256u + +/* SNVMADDR + RESERVED + PT */ +#define AUTHENTICATED_TEXT_DATA_LEN 252u +#else +/* SNVMADDR + RESERVED + PT + USK */ +#define NON_AUTHENTICATED_TEXT_DATA_LEN 224u + +/* SNVMADDR + RESERVED + PT */ +#define AUTHENTICATED_TEXT_DATA_LEN 220u +#endif + +/** + * # Digest Check Input Options + * + * DIGEST_CHECK_FABRIC + * Carry out digest check on Fabric + * + * DIGEST_CHECK_CC + * Carry out digest check on UFS Fabric Configuration (CC) segment + * + * DIGEST_CHECK_SNVM + * Carry out digest check on ROM digest in SNVM segment + * + * DIGEST_CHECK_UL + * Carry out digest check on UFS UL segment + * + * DIGEST_CHECK_UKDIGEST0 + * Carry out digest check on UKDIGEST0 in User Key segment + * + * DIGEST_CHECK_UKDIGEST1 + * Carry out digest check on UKDIGEST1 in User Key segment + * + * DIGEST_CHECK_UKDIGEST2 + * Carry out digest check on UKDIGEST2 in User Key segment (UPK1) + * + * DIGEST_CHECK_UKDIGEST3 + * Carry out digest check on UKDIGEST3 in User Key segment (UK1) + * + * DIGEST_CHECK_UKDIGEST4 + * Carry out digest check on UKDIGEST4 in User Key segment (DPK) + * + * DIGEST_CHECK_UKDIGEST5 + * Carry out digest check on UKDIGEST5 in User Key segment (UPK2) + * + * DIGEST_CHECK_UKDIGEST6 + * Carry out digest check on UKDIGEST6 in User Key segment (UK2) + * + * DIGEST_CHECK_UPERM + * Carry out digest check on UFS Permanent lock (UPERM) segment + * + * DIGEST_CHECK_SYS + * Carry out digest check on Factory and Factory Key Segments + * + */ +#define DIGEST_CHECK_FABRIC (0x01<<0x00u) /*Fabric digest*/ +#define DIGEST_CHECK_CC (0x01<<0x01u) /*UFS Fabric Configuration (CC) segment*/ +#define DIGEST_CHECK_SNVM (0x01<<0x02u) /*ROM digest in SNVM segment*/ +#define DIGEST_CHECK_UL (0x01<<0x03u) /*UFS UL segment*/ +#define DIGEST_CHECK_UKDIGEST0 (0x01<<0x04u) /*UKDIGEST0 in User Key segment*/ +#define DIGEST_CHECK_UKDIGEST1 (0x01<<0x05u) /*UKDIGEST1 in User Key segment*/ +#define DIGEST_CHECK_UKDIGEST2 (0x01<<0x06u) /*UKDIGEST2 in User Key segment (UPK1)*/ +#define DIGEST_CHECK_UKDIGEST3 (0x01<<0x07u) /*UKDIGEST3 in User Key segment (UK1)*/ +#define DIGEST_CHECK_UKDIGEST4 (0x01<<0x08u) /*UKDIGEST4 in User Key segment (DPK)*/ +#define DIGEST_CHECK_UKDIGEST5 (0x01<<0x09u) /*UKDIGEST5 in User Key segment (UPK2)*/ +#define DIGEST_CHECK_UKDIGEST6 (0x01<<0x0au) /*UKDIGEST6 in User Key segment (UK2)*/ +#define DIGEST_CHECK_UPERM (0x01<<0x0bu) /*UFS Permanent lock (UPERM) segment*/ +#define DIGEST_CHECK_SYS (0x01<<0x0cu) /*Factory and Factory Key Segments.*/ + +/***************************************************************************//** + * The function SYS_init() is used to initialize the internal data structures of + * this driver. Currently this function is empty. + * + * @param base_addr The base_addr parameter specifies the base address of the + * PF_System_services core. + * + * @return This function does not return a value. + */ +void +SYS_init +( + uint32_t base_addr +); + +/***************************************************************************//** + * The function SYS_get_serial_number() is used to execute "serial number" system + * service. + * + * @param p_serial_number The p_serial_number parameter is a pointer to a buffer + * in which the data returned by system controller + * is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t +SYS_get_serial_number +( + const uint8_t * p_serial_number, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_get_user_code() is used to execute "USERCODE" system + * service. + * @param p_user_code The p_user_code parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t +SYS_get_user_code +( + const uint8_t * p_user_code, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_get_design_info() is used to execute "Get Design Info" system + * service. + * + * @param p_design_info The p_design_info parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. Total size of debug information is 36 bytes. + * The data from the system controller includes the 256-bit + * user-defined design ID, 16-bit design version, and 16-bit + * design back level. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t +SYS_get_design_info +( + const uint8_t * p_design_info, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_get_device_certificate() is used to execute "Get Device + * Certificate" system service. + * + * @param p_device_certificate The p_device_certificate parameter is a pointer + * to a buffer in which the data returned by the + * system controller is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code means that + * the service was executed successfully. + * + */ +uint8_t +SYS_get_device_certificate +( + const uint8_t * p_device_certificate, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_read_digest() is used to execute "Read Digest" system service. + * + * @param p_digest The p_digest parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t SYS_read_digest +( + const uint8_t * p_digest, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_query_security() is used to execute "Query Security" system + * service. + * + * @param p_security_locks The p_security_locks parameter is a pointer to a buffer + * in which the data returned by system controller is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code means that + * the service was executed successfully. + */ +uint8_t SYS_query_security +( + uint8_t * p_security_locks, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_read_debug_info() is used to execute "Read Debug info" system + * service. + * + * @param p_debug_info The p_debug_info parameter is a pointer to a buffer + * in which the data returned by system controller is + * copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code + * means that the service was executed successfully. + */ +uint8_t SYS_read_debug_info +( + const uint8_t * p_debug_info, + uint16_t mb_offset +); + +#ifdef CORESYSSERVICES_PFSOC +/***************************************************************************//** + * The function SYS_read_envm_parameter() is used to retrieve all parameters needed + * for the eNVM operation and programming. + * + * NOTE: This service is available only on PolarFire SoC Platform. + * This service is not yet supported by PF_SYSTEM_SERVICES 3.0.100. + * + * @param p_envm_param The p_envm_param parameter is a pointer to a buffer + * in which the data returned by system controller is copied. + * This buffer stores all the eNVM parameters. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_read_envm_parameter service will return zero if the + * service executed successfully, otherwise, it will return + * one indicating error. + */ +uint8_t SYS_read_envm_parameter +( + uint8_t * p_envm_param, + uint16_t mb_offset +); +#endif +/***************************************************************************//** + * The function SYS_puf_emulation_service() is used to authenticate a device. + * + * The SYS_puf_emulation_service() function accept a challenge comprising a + * 8-bit optype and 128-bit challenge and return a 256-bit response unique to + * the given challenge and the device. + * + * @param p_challenge The p_challenge parameter specifies the 128-bit challenge + * to generate the 256-bits unique response. + * + * @param op_type The op_type parameter specifies the operational parameter + * to generate the 256-bits unique response. + * + * @param p_response The p_response parameter is a pointer to a buffer where + * the data returned which is the response by system controller + * is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_puf_emulation_service function will return zero + * if the service executed successfully, otherwise, it will + * return one indicating error. + */ +uint8_t SYS_puf_emulation_service +( + const uint8_t * p_challenge, + uint8_t op_type, + uint8_t* p_response, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_digital_signature_service() function is used to generate P-384 ECDSA + * signature based on SHA384 hash value. + * + * @param p_hash The p_hash parameter is a pointer to the buffer which + * contain the 48 bytes SHA384 Hash value (input value). + * + * @param format The format parameter specifies the output format of + * generated SIGNATURE field. The different types of output + * signature formats are as follow: + * - DIGITAL_SIGNATURE_RAW_FORMAT + * - DIGITAL_SIGNATURE_DER_FORMAT + * + * @param p_response The p_response parameter is a pointer to a buffer that + * contains the generated ECDSA signature. The field may be + * 96 bytes or 104 bytes depending upon the output format. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digital_signature_service function returns + * zero if the service executed successfully, otherwise, it + * returns non-zero values indicating error. + */ +uint8_t SYS_digital_signature_service +( + const uint8_t* p_hash, + uint8_t format, + uint8_t* p_response, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_secure_nvm_write() function writes data in the sNVM region. + * Data gets stored in the following format: + * - Non-authenticated plaintext + * - Authenticated plaintext + * - Authenticated ciphertext + * + * Note: If you are executing this function with Authenticated plaintext + * or Authenticated ciphertext on a device whose sNVM was never previously + * written to, then the service may fail. For it to work, you must first write + * Authenticated data to the sNVM using Libero along with USK client and + * custom security. This flow generates the SMK. See UG0753 PolarFire FPGA + * Security User Guide for further details. + + * @param format The format parameter specifies the format used to write + * data in sNVM region. The different type of text formats + * are as follow: + * - NON_AUTHENTICATED_PLAINTEXT_FORMAT + * - AUTHENTICATED_PLAINTEXT_FORMAT + * - AUTHENTICATED_CIPHERTEXT_FORMAT + * + * @param snvm_module The snvm_module parameter specifies the the sNVM module + * in which the data need to be written. + * + * @param p_data The p_data parameter is a pointer to a buffer which + * contains the data to be stored in sNVM region. The data + * length to be written is fixed depending on the format + * parameter. If NON_AUTHENTICATED_PLAINTEXT_FORMAT is + * selected, then you can write 252 bytes in the sNVM module. + * For other two formats the data length is 236 bytes. + * + * @param p_user_key The p_user_key parameter is a pointer to a buffer which + * contain the 96-bit key USK (user secret key). This user + * secret key will enhance the security when authentication + * is used. That is, when Authenticated plaintext and + * Authenticated ciphertext format is selected. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digital_signature_service function returns + * zero if the service executed successfully, otherwise, it + * returns non-zero values indicating error. + */ +uint8_t SYS_secure_nvm_write +( + uint8_t format, + uint8_t snvm_module, + const uint8_t* p_data, + const uint8_t* p_user_key, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_secure_nvm_read() function is used to read data present in sNVM region. + * User should provide USK key, if the data was programmed using authentication. + * If the data was written in the sNVM using the authenticated plaintext or the + * authenticated ciphertext service option then this service will return the + * valid data only when authentication is successful. For more details, see + * SYS_secure_nvm_write() function. If the data was written in + * the sNVM using the authenticated plaintext or the authenticated ciphertext + * service option then this service will return the valid data only when + * authentication is successful. For more details, see SYS_secure_nvm_write() + * function and its parameter description. + * + * @param snvm_module The snvm_module parameter specifies the sNVM module + * from which the data need to be read. + * + * @param p_user_key The p_user_key parameter is a pointer to a buffer which + * contain the 96-bit key USK (user secret key). User should + * provide same secret key which is previously used for + * authentication while writing data in sNVM region. + * + * @param p_admin The p_admin parameter is a pointer to the buffer where + * the output page admin data is stored. The page admin + * data is 4 bytes long. + * + * @param p_data The p_data parameter is a pointer to a buffer which + * contains the data read from sNVM region. User should + * provide the buffer large enough to store the read data. + * + * @param data_len The data_len parameter specifies the number of bytes to be + * read from sNVM. + * The application should know whether the data written in the + * chose sNVM module was previously stored using Authentication + * or not. + * The data_len should be 236 bytes, for authenticated data. + * For not authenticated data the data_len should be 252 bytes. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digital_signature_service function returns + * zero if the service executed successfully, otherwise, it + * returns non-zero values indicating error. + */ +uint8_t SYS_secure_nvm_read +( + uint8_t snvm_module, + const uint8_t* p_user_key, + uint8_t* p_admin, + uint8_t* p_data, + uint16_t data_len, + uint16_t mb_offset +); + +/***************************************************************************//** + * The function SYS_nonce_service() is used to issue "Nonce Service" system + * service to the system controller. + * + * @param p_nonce The p_nonce parameter is a pointer to a buffer + * in which the data returned by system controller is copied. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return This function returns the status code returned by the + * system controller for this service. A '0' status code means + * that the service was executed successfully and a non-zero + * value indicates error. See the document link + * provided in the theory of operation section to know more + * about the service and service response. + */ +uint8_t SYS_nonce_service +( + const uint8_t * p_nonce, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_bitstream_authenticate_service() function is used to authenticate + * the Bitstream which is located in SPI through a system service routine. Prior + * to using the IAP service, it may be required to first validate the new + * bitstream before committing the device to reprogramming, thus avoiding the + * need to invoke recovery procedures if the bitstream is invalid. + * + * This service is applicable to bitstreams stored in SPI Flash memory only. + * + * @param spi_flash_address + * The spi_flash_address parameter specifies the address within + * SPI Flash memory where the bit-stream is stored. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_bitstream_authenticate_service function will return + * zero if the service executed successfully and the non-zero + * response from system controller indicates error. See + * the document link provided in the theory of + * operation section to know more about the service and service + * response. + */ +uint8_t SYS_bitstream_authenticate_service +( + uint32_t spi_flash_address, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_IAP_image_authenticate_service() function is used to authenticate + * the IAP image which is located in SPI through a system service routine. The + * service checks the image descriptor and the referenced bitstream and optional + * initialization data. If the image is authenticated successfully, then the + * image is guaranteed to be valid when used by an IAP function. + * + * This service is applicable to bitstreams stored in SPI Flash memory only. + * + * @param spi_idx + * The spi_idx parameter specifies the index in the SPI directory to + * be used where the IAP bit-stream is stored. + * Note: To support recovery SPI_IDX=1 should be an empty slot and the recovery + * image should be located in SPI_IDX=0. Since SPI_IDX=1 should be an + * empty slot, it shouldn’t be passed into the system service. + * + * @return The SYS_IAP_image_authenticate_service function will return + * zero if the service executed successfully the non-zero + * response from system controller indicates error. Please + * refer to the document link provided in the theory of + * operation section to know more about the service and service + * response. + */ +uint8_t SYS_IAP_image_authenticate_service +( + uint8_t spi_idx +); + +/***************************************************************************//** + * The SYS_digest_check_service() function is used to Recalculates and compares + * digests of selected non-volatile memories. If the fabric digest is to be + * checked, then the user design must follow all prerequisite steps for the + * FlashFreeze service before invoking this service. + * This service is applicable to bitstreams stored in SPI Flash memory only. + * @param options + * The options parameter specifies the digest check options which + * indicate the area on which the digest check should be performed. + * Below is the list of options. You can OR these options to indicate + * to perform digest check on multiple segments. + * Note: The options parameter is of 2 bytes when used with PF + * device and 4 bytes when used with PolarFire SoC device. + * Options[i] | Description + * ---------------|---------------------------------- + * 0x01 | Fabric digest + * 0x02 | Fabric Configuration (CC) segment + * 0x04 | ROM digest in SNVM segment + * 0x08 | UL segment + * 0x10 | UKDIGEST0 in User Key segment + * 0x20 | UKDIGEST1 in User Key segment + * 0x40 | UKDIGEST2 in User Key segment (UPK1) + * 0x80 | UKDIGEST3 in User Key segment (UK1) + * 0x100 | UKDIGEST4 in User Key segment (DPK) + * 0x200 | UKDIGEST5 in User Key segment (UPK2) + * 0x400 | UKDIGEST6 in User Key segment (UK2) + * 0x800 | UFS Permanent lock (UPERM) segment + * 0x1000 | Factory and Factory Key Segments. + * 0x2000 | UKDIGEST7 in User Key segment (HWM) (PFSoC) + * 0x4000 | ENVMDIGEST (PFSoC only) + * 0x8000 | UKDIGEST8 for MSS Boot Info (PFSoC only) + * 0x10000 | SNVM_RW_ACCESS_MAP Digest (PFSoC only) + * 0x20000 | SBIC revocation digest (PFSoC only) + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * + * @return The SYS_digest_check_service function will return + * zero if the service executed successfully the non-zero + * response from system controller indicates error. Pleaes + * refer to the document link provided in the theory of + * operation section to know more about the service and service + * response. + */ +uint8_t SYS_digest_check_service +( + uint32_t options, + uint16_t mb_offset +); + +/***************************************************************************//** + * The SYS_iap_service() function is used to IAP service. The IAP service allows + * the user to reprogram the device without the need for an external master. The + * user design writes the bitstream to be programmed into a SPI Flash connected + * to the SPI port. When the service is invoked, the System Controller + * automatically reads the bitstream from the SPI flash and programs the device. + * The service allows the image to be executed in either VERIFY or PROGRAM modes. + * Another option for IAP is to perform the auto-update sequence. In this case + * the newest image of the first two images in the SPI directory is chosen to be + * programmed. + * + * @param iap_cmd + * The iap_cmd parameter specifies the specific IAP command which + * depends upon VERIFY or PROGRAM modes and the SPI address method. + * iap_cmd | Description + * -----------------------|------------ + * IAP_PROGRAM_BY_SPIIDX_CMD | IAP program. + * IAP_VERIFY_BY_SPIIDX_CMD | Fabric Configuration (CC) segment + * IAP_PROGRAM_BY_SPIADDR_CMD | ROM digest in SNVM segment + * IAP_VERIFY_BY_SPIADDR_CMD | UL segment + * IAP_AUTOUPDATE_CMD | UKDIGEST0 in User Key segment + * + * @param spiaddr + * The spiaddr parameter specifies either the index + * in the SPI directory or the SPI address in the SPI Flash memory. + * Below is the list of the possible meaning of spiaddr parameter + * in accordance with the iap_cmd parameter. + * iap_cmd | spiaddr + * ----------------------|----------------- + * IAP_PROGRAM_BY_SPIIDX_CMD | Index in the SPI directory. + * IAP_VERIFY_BY_SPIIDX_CMD | Index in the SPI directory. + * IAP_PROGRAM_BY_SPIADDR_CMD | SPI address in the SPI Flash memory + * IAP_VERIFY_BY_SPIADDR_CMD | SPI address in the SPI Flash memory + * IAP_AUTOUPDATE_CMD | spiaddr is ignored as No index/address required for this command. + * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. + * Note: For the IAP services with command IAP_PROGRAM_BY_SPIIDX_CMD and + * IAP_VERIFY_BY_SPIIDX_CMD To support recovery SPI_IDX=1 should be an + * empty slot and the recovery image should be located in SPI_IDX=0. + * Since SPI_IDX=1 should be an empty slot it shouldn’t be passed into + * the system service. + * + * @return The SYS_iap_service function will return zero if the service + * executed successfully and the non-zero response from system + * controller indicates error. Please refer to the document + * link provided in the theory of operation section to know + * more about the service and service response. + */ +uint8_t SYS_iap_service +( + uint8_t iap_cmd, + uint32_t spiaddr, + uint16_t mb_offset +); + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_SYSSERV_PF_H */ diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h new file mode 100644 index 0000000..8b14b7e --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h @@ -0,0 +1,149 @@ +/******************************************************************************* + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Register bit offsets and masks definitions for CoreSysServices_PF driver. + */ + +#ifndef __CORE_SYSSERV_PF_REGISTERS +#define __CORE_SYSSERV_PF_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * SYS_SERV_CMD (offset 0x04) register details + */ +#define SS_CMD_REG_OFFSET 0x04u + +#define SS_CMD_OFFSET 0x04 +#define SS_CMD_MASK 0x0000FFFFu +#define SS_CMD_SHIFT 0u + +/*------------------------------------------------------------------------------ + * SYS_SERV_STAT (offset 0x08) register details + */ +#define SS_STAT_REG_OFFSET 0x08u + +#define SS_STAT_OFFSET 0x08 +#define SS_STAT_MASK 0x0000FFFFu +#define SS_STAT_SHIFT 0u + +/*------------------------------------------------------------------------------ + * SYS_SERV_REQ (offset 0x0C) register details + */ +#define SS_REQ_REG_OFFSET 0x0Cu + + +#define SS_REQ_REQ_OFFSET 0x0Cu +#define SS_REQ_REQ_MASK 0x00000001UL +#define SS_REQ_REQ_SHIFT 0u + +#define SS_REQ_ABUSY_OFFSET 0x0Cu +#define SS_REQ_ABUSY_MASK 0x00000002UL +#define SS_REQ_ABUSY_SHIFT 1u + +#define SS_REQ_NABUSY_OFFSET 0x0Cu +#define SS_REQ_NABUSY_MASK 0x00000004UL +#define SS_REQ_NABUSY_SHIFT 2u + +#define SS_REQ_SSBUSY_OFFSET 0x0Cu +#define SS_REQ_SSBUSY_MASK 0x00000008UL +#define SS_REQ_SSBUSY_SHIFT 3u + +#define SS_REQ_AREQ_OFFSET 0x0Cu +#define SS_REQ_AREQ_MASK 0x00000010UL +#define SS_REQ_AREQ_SHIFT 4u + +#define SS_REQ_NAREQ_OFFSET 0x0Cu +#define SS_REQ_NAREQ_MASK 0x00000020UL +#define SS_REQ_NAREQ_SHIFT 5u +/*------------------------------------------------------------------------------ + * MBX_ECCSTATUS (offset 0x10) register details + */ +#define MBX_ECCSTATUS_REG_OFFSET 0x10u + +#define MBX_ECCSTATUS_OFFSET 0x10 +#define MBX_ECCSTATUS_MASK 0x03u +#define MBX_ECCSTATUS_SHIFT 0u + + +/*------------------------------------------------------------------------------ + * MBX_WCNT (offset 0x14) register details + */ +#define MBX_WCNT_REG_OFFSET 0x14u + +#define MBX_WCNT_OFFSET 0x14 +#define MBX_WCNT_MASK 0x000001FFu +#define MBX_WCNT_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_RWCNT (offset 0x18) register details + */ +#define MBX_RCNT_REG_OFFSET 0x18u + +#define MBX_RCNT_OFFSET 0x18 +#define MBX_RCNT_MASK 0x000001FFu +#define MBX_RCNT_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_WADRDESC (offset 0x1C) register details + */ +#define MBX_WADDR_REG_OFFSET 0x1Cu + +#define MBX_WADDR_OFFSET 0x1C +#define MBX_WADDR_MASK 0x000001FFu +#define MBX_WADDR_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_RADRDESC (offset 0x20) register details + */ +#define MBX_RADDR_REG_OFFSET 0x20u + +#define MBX_RADDR_OFFSET 0x20 +#define MBX_RADDR_MASK 0x000001FFu +#define MBX_RADDR_SHIFT 0u + +/*------------------------------------------------------------------------------ + * MBX_WDATA (offset 0x28) register details + */ +#define MBX_WDATA_REG_OFFSET 0x28u + +#define MBX_WDATA_OFFSET 0x28 +#define MBX_WDATA_MASK 0xFFFFFFFFu +#define MBX_WDATA_SHIFT 0u + + +/*------------------------------------------------------------------------------ + * MBX_RDATA (offset 0x2C) register details + */ +#define MBX_RDATA_REG_OFFSET 0x2Cu + +#define MBX_RDATA_OFFSET 0x2C +#define MBX_RDATA_MASK 0xFFFFFFFFu +#define MBX_RDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * SS_USER (offset 0x30) register details + */ +#define SS_USER_REG_OFFSET 0x30u + +#define SS_USER_BUSY_OFFSET 0x30 +#define SS_USER_BUSY_MASK 0x00000001u +#define SS_USER_BUSY_SHIFT 0u + +#define SS_USER_RDVLD_OFFSET 0x30 +#define SS_USER_RDVLD_MASK 0x00000002u +#define SS_USER_RDVLD_SHIFT 1u + +#define SS_USER_CMDERR_OFFSET 0x30 +#define SS_USER_CMDERR_MASK 0x00000004u +#define SS_USER_CMDERR_SHIFT 2u + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_SYSSERV_PF_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c new file mode 100644 index 0000000..0c0a866 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c @@ -0,0 +1,297 @@ +/******************************************************************************* + * (c) Copyright 2007-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file core_uart_apb.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreUARTapb driver implementation. See file "core_uart_apb.h" for + * description of the functions implemented in this file. + * + */ + +#include "coreuartapb_regs.h" +#include "core_uart_apb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define NULL_INSTANCE ( ( UART_instance_t* ) 0 ) +#define NULL_BUFFER ( ( uint8_t* ) 0 ) + +#define MAX_LINE_CONFIG ( ( uint8_t )( DATA_8_BITS | ODD_PARITY ) ) +#define MAX_BAUD_VALUE ( ( uint16_t )( 0x1FFF ) ) +#define STATUS_ERROR_MASK ( ( uint8_t )( STATUS_PARITYERR_MASK | \ + STATUS_OVERFLOW_MASK | \ + STATUS_FRAMERR_MASK ) ) +#define BAUDVALUE_LSB ( (uint16_t) (0x00FF) ) +#define BAUDVALUE_MSB ( (uint16_t) (0xFF00) ) +#define BAUDVALUE_SHIFT ( (uint8_t) (5) ) + +#define STATUS_ERROR_OFFSET STATUS_PARITYERR_SHIFT + +/***************************************************************************//** + * UART_init() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_init +( + UART_instance_t * this_uart, + addr_t base_addr, + uint16_t baud_value, + uint8_t line_config +) +{ + uint8_t rx_full; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( line_config <= MAX_LINE_CONFIG ) + HAL_ASSERT( baud_value <= MAX_BAUD_VALUE ) + + if( ( this_uart != NULL_INSTANCE ) && + ( line_config <= MAX_LINE_CONFIG ) && + ( baud_value <= MAX_BAUD_VALUE ) ) + { + /* + * Store lower 8-bits of baud value in CTRL1. + */ + HAL_set_8bit_reg( base_addr, CTRL1, (uint_fast8_t)(baud_value & + BAUDVALUE_LSB ) ); + + /* + * Extract higher 5-bits of baud value and store in higher 5-bits + * of CTRL2, along with line configuration in lower 3 three bits. + */ + HAL_set_8bit_reg( base_addr, CTRL2, (uint_fast8_t)line_config | + (uint_fast8_t)((baud_value & + BAUDVALUE_MSB) >> BAUDVALUE_SHIFT ) ); + + this_uart->base_address = base_addr; +#ifndef NDEBUG + { + uint8_t config; + uint8_t temp; + uint16_t baud_val; + baud_val = HAL_get_8bit_reg( this_uart->base_address, CTRL1 ); + config = HAL_get_8bit_reg( this_uart->base_address, CTRL2 ); + /* + * To resolve operator precedence between & and << + */ + temp = ( config & (uint8_t)(CTRL2_BAUDVALUE_MASK ) ); + baud_val |= (uint16_t)( (uint16_t)(temp) << BAUDVALUE_SHIFT ); + config &= (uint8_t)(~CTRL2_BAUDVALUE_MASK); + HAL_ASSERT( baud_val == baud_value ); + HAL_ASSERT( config == line_config ); + } +#endif + + /* + * Flush the receive FIFO of data that may have been received before the + * driver was initialized. + */ + rx_full = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_RXFULL_MASK; + while ( rx_full ) + { + HAL_get_8bit_reg( this_uart->base_address, RXDATA ); + rx_full = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_RXFULL_MASK; + } + + /* + * Clear status of the UART instance. + */ + this_uart->status = (uint8_t)0; + } +} + +/***************************************************************************//** + * UART_send() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_send +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +) +{ + size_t char_idx; + uint8_t tx_ready; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( tx_buffer != NULL_BUFFER ) + HAL_ASSERT( tx_size > 0 ) + + if( (this_uart != NULL_INSTANCE) && + (tx_buffer != NULL_BUFFER) && + (tx_size > (size_t)0) ) + { + for ( char_idx = (size_t)0; char_idx < tx_size; char_idx++ ) + { + /* Wait for UART to become ready to transmit. */ + do { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( !tx_ready ); + /* Send next character in the buffer. */ + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)tx_buffer[char_idx] ); + } + } +} + +/***************************************************************************//** + * UART_fill_tx_fifo() + * See "core_uart_apb.h" for details of how to use this function. + */ +size_t +UART_fill_tx_fifo +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +) +{ + uint8_t tx_ready; + size_t size_sent = 0u; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( tx_buffer != NULL_BUFFER ) + HAL_ASSERT( tx_size > 0 ) + + /* Fill the UART's Tx FIFO until the FIFO is full or the complete input + * buffer has been written. */ + if( (this_uart != NULL_INSTANCE) && + (tx_buffer != NULL_BUFFER) && + (tx_size > 0u) ) + { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + if ( tx_ready ) + { + do { + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)tx_buffer[size_sent] ); + size_sent++; + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( (tx_ready) && ( size_sent < tx_size ) ); + } + } + return size_sent; +} + +/***************************************************************************//** + * UART_get_rx() + * See "core_uart_apb.h" for details of how to use this function. + */ +size_t +UART_get_rx +( + UART_instance_t * this_uart, + uint8_t * rx_buffer, + size_t buff_size +) +{ + uint8_t new_status; + uint8_t rx_full; + size_t rx_idx = 0u; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( rx_buffer != NULL_BUFFER ) + HAL_ASSERT( buff_size > 0 ) + + if( (this_uart != NULL_INSTANCE) && + (rx_buffer != NULL_BUFFER) && + (buff_size > 0u) ) + { + rx_idx = 0u; + new_status = HAL_get_8bit_reg( this_uart->base_address, STATUS ); + this_uart->status |= new_status; + rx_full = new_status & STATUS_RXFULL_MASK; + while ( ( rx_full ) && ( rx_idx < buff_size ) ) + { + rx_buffer[rx_idx] = HAL_get_8bit_reg( this_uart->base_address, + RXDATA ); + rx_idx++; + new_status = HAL_get_8bit_reg( this_uart->base_address, STATUS ); + this_uart->status |= new_status; + rx_full = new_status & STATUS_RXFULL_MASK; + } + } + return rx_idx; +} + +/***************************************************************************//** + * UART_polled_tx_string() + * See "core_uart_apb.h" for details of how to use this function. + */ +void +UART_polled_tx_string +( + UART_instance_t * this_uart, + const uint8_t * p_sz_string +) +{ + uint32_t char_idx; + uint8_t tx_ready; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + HAL_ASSERT( p_sz_string != NULL_BUFFER ) + + if( ( this_uart != NULL_INSTANCE ) && ( p_sz_string != NULL_BUFFER ) ) + { + char_idx = 0U; + while( 0U != p_sz_string[char_idx] ) + { + /* Wait for UART to become ready to transmit. */ + do { + tx_ready = HAL_get_8bit_reg( this_uart->base_address, STATUS ) & + STATUS_TXRDY_MASK; + } while ( !tx_ready ); + /* Send next character in the buffer. */ + HAL_set_8bit_reg( this_uart->base_address, TXDATA, + (uint_fast8_t)p_sz_string[char_idx] ); + char_idx++; + } + } +} + +/***************************************************************************//** + * UART_get_rx_status() + * See "core_uart_apb.h" for details of how to use this function. + */ +uint8_t +UART_get_rx_status +( + UART_instance_t * this_uart +) +{ + uint8_t status = UART_APB_INVALID_PARAM; + + HAL_ASSERT( this_uart != NULL_INSTANCE ) + /* + * Extract UART error status and place in lower bits of "status". + * Bit 0 - Parity error status + * Bit 1 - Overflow error status + * Bit 2 - Frame error status + */ + if( this_uart != NULL_INSTANCE ) + { + status = ( ( this_uart->status & STATUS_ERROR_MASK ) >> + STATUS_ERROR_OFFSET ); + /* + * Clear the sticky status for this instance. + */ + this_uart->status = (uint8_t)0; + } + return status; +} + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h new file mode 100644 index 0000000..c016403 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h @@ -0,0 +1,451 @@ +/******************************************************************************* + * (c) Copyright 2007-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file core_uart_apb.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief This file contains the application programming interface for the + * CoreUARTapb bare metal driver. + * + */ +/*=========================================================================*//** + @mainpage CoreUARTapb Bare Metal Driver. + + @section intro_sec Introduction + CoreUARTapb is an implementation of the Universal Asynchronous + Receiver/Transmitter aimed at minimal FPGA tile usage within a Microchip FPGA. + The CoreUARTapb bare metal software driver is designed to be used in systems + with no operating system. + + The CoreUARTapb driver provides functions for basic polled transmitting and + receiving operations. It also provide functions that allow the use of the + CoreUARTapb in interrupt-driven mode but leaves the management of interrupts + to the calling application, as interrupt enabling and disabling are not + controlled through the CoreUARTapb registers. The CoreUARTapb driver is + provided as C source code. + + @section driver_configuration Driver Configuration + Your application software should configure the CoreUARTapb driver by calling + the UART_init() function for each CoreUARTapb instance in the hardware design. + The configuration parameters include the CoreUARTapb hardware instance base + address and other runtime parameters, such as baud rate, bit width, and + parity. No CoreUARTapb hardware configuration parameters are needed by the + driver, apart from the CoreUARTapb hardware instance base address. Hence, no + additional configuration files are required to use the driver. + + A CoreUARTapb hardware instance is generated with fixed baud rate, character + size, and parity configuration settings as part of the hardware flow. The + baud_value and line_config parameter values passed to the UART_init() function + have no effect if fixed values were selected for the baud rate, character + size, and parity in the hardware configuration of CoreUARTapb. When fixed + values are selected for these hardware configuration parameters, the driver is + unable to overwrite the fixed values in the CoreUARTapb control registers, + CTRL1 and CTRL2. + + @section theory_op Theory of Operation + The CoreUARTapb software driver is designed to allow the control of multiple + instances of CoreUARTapb. Each instance of CoreUARTapb in the hardware design + is associated with a single instance of the UART_instance_t structure in the + software. You need to allocate memory for one unique UART_instance_t structure + instance for each CoreUARTapb hardware instance. The contents of these data + structures are initialized while calling the UART_init() function. A pointer + to the structure is passed to the subsequent driver functions in order to + identify the CoreUARTapb hardware instance you wish to perform the requested + operation on. + + Note: Do not attempt to directly manipulate the content of UART_instance_t + structures. This structure is only intended to be modified by the driver + function. + + Once initialized, the driver transmits and receives data. Transmit is + performed using the UART_send() function. If this function blocks, then it + returns only when the data passed to it has been sent to the CoreUARTapb + hardware. Data received by the CoreUARTapb hardware is read by the user + application using the UART_get_rx() function. + + The UART_fill_tx_fifo() function is also provided as a part of the + interrupt-driven transmit. This function fills the CoreUARTapb hardware + transmit FIFO with the content of a data buffer passed as a parameter before + returning. The control of the interrupts must be implemented outside the + driver, as the CoreUARTapb hardware does not provide the ability to enable + or disable its interrupt sources. + + The UART_polled_tx_string() function is provided to transmit a NULL-terminated + string in polled mode. If this function blocks, then it returns only when the + data passed to it has been sent to the CoreUARTapb hardware. + + The UART_get_rx_status() function returns the error status of the CoreUARTapb + receiver. This is used by applications to take appropriate action in case of + receiver errors. +*//*=========================================================================*/ +#ifndef __CORE_UART_APB_H +#define __CORE_UART_APB_H 1 + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + Data Bits Length Defines + ======================== + These constants define the data length in a UART packet. + | Constant | Description | + |-------------|---------------------------------------| + | DATA_7_BITS | Data length is 7-bits | + | DATA_8_BITS | Data length is 8-bits | + */ +#define DATA_7_BITS 0x00u +#define DATA_8_BITS 0x01u + +/***************************************************************************//** + Parity Defines + ============== + These constants define parity check options. + | Constant | Description | + |-------------|---------------------------------------| + | NO_PARITY | No Parity bit | + | EVEN_PARITY | Even Parity bit | + | ODD_PARITY | ODD Parity bit | + */ +#define NO_PARITY 0x00u +#define EVEN_PARITY 0x02u +#define ODD_PARITY 0x06u + +/***************************************************************************//** + Error Status Definitions + ======================== + These constants define the different types of possible errors in UART + transmission of data. + | Constant | Description | + |-------------------------|---------------------------------------| + | UART_APB_PARITY_ERROR | Data parity error | + | UART_APB_OVERFLOW_ERROR | Data overflow error | + | UART_APB_FRAMING_ERROR | Data framing error | + | UART_APB_NO_ERROR | No error | + | UART_APB_INVALID_PARAM | Invalid parameter | + */ +#define UART_APB_PARITY_ERROR 0x01u +#define UART_APB_OVERFLOW_ERROR 0x02u +#define UART_APB_FRAMING_ERROR 0x04u +#define UART_APB_NO_ERROR 0x00u +#define UART_APB_INVALID_PARAM 0xFFu + +/***************************************************************************//** + * There should be one instance of this structure for each instance of + * CoreUARTapb in your system. This structure instance identifies various UARTs + * in a system and should be passed as first parameter to UART functions to + * identify which UART performs the requested operation. The 'status' element in + * the structure is used to provide sticky status information. + */ +typedef struct +{ + addr_t base_address; + uint8_t status; +} UART_instance_t; + +/***************************************************************************//** + * The UART_init() function initializes the UART with the configuration passed + * as parameters. The configuration parameters are the baud_value that generates + * the baud rate and the line configuration (bit length and parity). + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data regarding + * this instance of the CoreUARTapb. This pointer is used to + * identify the target CoreUARTapb hardware instance in + * subsequent calls to the CoreUARTapb functions. + * @param base_addr The base_address parameter is the base address in the + * processor's memory map for the registers of the + * CoreUARTapb instance being initialized. + * @param baud_value The baud_value parameter selects the baud rate for the + * UART. The baud value is calculated from the frequency of + * the system clock in hertz and the desired baud rate using + * the following equation: + * baud_value = (clock / (baud_rate * 16)) - 1. + * The baud_value parameter must be a value in the range 0 + * to 8191 (or 0x0000 to 0x1FFF). + * @param line_config This parameter is the line configuration, specifies the + * bit length and parity settings. This is the logical OR of: + * - DATA_7_BITS + * - DATA_8_BITS + * - NO_PARITY + * - EVEN_PARITY + * - ODD_PARITY + * For example, 8 bits even parity would be specified as + * (DATA_8_BITS | EVEN_PARITY). + * @return This function does not return a value. + * @example + * @code + * #define BAUD_VALUE_57600 25 + * + * #define COREUARTAPB0_BASE_ADDR 0xC3000000UL + * + * UART_instance_t g_uart; + * int main() + * { + * UART_init(&g_uart, COREUARTAPB0_BASE_ADDR, + BAUD_VALUE_57600, (DATA_8_BITS | EVEN_PARITY)); + * } + * @endcode + */ +void +UART_init +( + UART_instance_t * this_uart, + addr_t base_addr, + uint16_t baud_value, + uint8_t line_config +); + +/***************************************************************************//** + * The UART_send() function is used to transmit data. It transfers the content + * of the transmitter data buffer, passed as a function parameter, into the + * UART's hardware transmitter FIFO. It returns when the full content of the + * transmitter data buffer has been transferred to the UART's transmitter FIFO. + * + * Note: You should not assume that the data you are sending using this function + * has been received at the other end by the time this function returns. The + * actual transmission over the serial connection is still be taking place at + * the time of the function return. It is safe to release or reuse the memory + * used as the transmit buffer once this function returns. + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data + * regarding this instance of the CoreUARTapbUART. + * @param tx_buffer The tx_buffer parameter is a pointer to a buffer that + * contains the data to be transmitted. + * @param tx_size The tx_size parameter is the size in bytes of the + * transmitted data. + * + * @return This function does not return a value. + * + * @example + * @code + * uint8_t testmsg1[] = {"\n\r\n\r\n\rUART_send() test message 1"}; + * UART_send(&g_uart,(const uint8_t *)&testmsg1,sizeof(testmsg1)); + * @endcode + */ +void +UART_send +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +); + +/***************************************************************************//** + * The UART_fill_tx_fifo() function fills the UART's transmitter hardware FIFO + * with the data found in the transmitter buffer that is passed in as a + * function parameter. The function returns either when the FIFO is full or + * when the complete contents of the transmitter buffer have been copied into + * the FIFO. It returns the number of bytes copied into the UART's transmitter + * hardware FIFO. This function is intended to be used as part of + * interrupt-driven transmission. + * + * Note: You should not assume that the data you transmit using this function + * has been received at the other end by the time this function returns. The + * actual transmission over the serial connection is still be taking place at + * the time of the function return. + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data + * regarding this instance of the UART. + * @param tx_buffer The tx_buffer parameter is a pointer to a buffer that + * contains the data to be transmitted. + * @param tx_size The tx_size parameter is the size in bytes of the + * transmitted data. + * @return This function returns the number of bytes copied into + * the UART's transmitter hardware FIFO. + * + * @example + * @code + * void send_using_interrupt + * ( + * uint8_t * pbuff, + * size_t tx_size + * ) + * { + * size_t size_in_fifo; + * size_in_fifo = UART_fill_tx_fifo( &g_uart, pbuff, tx_size ); + * } + * @endcode + */ +size_t +UART_fill_tx_fifo +( + UART_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +); + +/***************************************************************************//** + * The UART_get_rx() function reads the content of the UART's receiver hardware + * FIFO and stores it in the receiver buffer that is passed in as a function + * parameter. It copies either the full contents of the FIFO into the receiver + * buffer, or just enough data from the FIFO to fill the receiver buffer, + * depending on the size of the receiver buffer. The size of the receiver + * buffer is passed in as a function parameter. UART_get_rx() returns the number + * of bytes copied into the receiver buffer. If no data was received at the time + * the function is called, the function returns 0. + * + * Note: This function reads and accumulates the receiver status of the + * CoreUARTapb instance before reading each byte from the receiver's + * data register/FIFO. This allows the driver to maintain a sticky + * record of any receiver errors that occur as the UART receives each + * data byte; receiver errors would otherwise be lost after each read + * from the receiver's data register. A call to the UART_get_rx_status() + * function returns any receiver errors accumulated during the execution + * of the UART_get_rx() function. + * + * Note: When FIFO mode is disabled in the CoreUARTapb hardware configuration, + * the driver accumulates a sticky record of any parity errors, framing + * errors, or overflow errors. When FIFO mode is enabled, the driver + * accumulates a sticky record of overflow errors only; in this case, + * interrupts must be used to handle parity errors or framing errors. + * + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data + * regarding this instance of the UART. + * @param rx_buffer The rx_buffer parameter is a pointer to a buffer where + * the received data is copied. + * @param buff_size The buff_size parameter is the size of the receive + * buffer in bytes. + * @return This function returns the number of bytes copied into + * the receive buffer. + * + * @example + * @code + * #define MAX_RX_DATA_SIZE 256 + * + * uint8_t rx_data[MAX_RX_DATA_SIZE]; + * uint8_t rx_size = 0; + * + * rx_size = UART_get_rx( &g_uart, rx_data, sizeof(rx_data) ); + * @endcode + */ +size_t +UART_get_rx +( + UART_instance_t * this_uart, + uint8_t * rx_buffer, + size_t buff_size +); + +/***************************************************************************//** + * The UART_polled_tx_string() function is used to transmit a NULL ('\0') + * terminated string. Internally, it polls for the transmit ready status and + * transfers the text starting at the address pointed by p_sz_string into + * the UART's hardware transmitter FIFO. It is a blocking function and returns + * only when the complete string has been transferred to the UART's transmit + * FIFO. + * + * Note: You should not assume that the data you transmit using this function + * has been received at the other end by the time this function returns. The + * actual transmission over the serial connection is still be taking place at + * the time of the function return. + * + * @param this_uart The this_uart parameter is the pointer to a + * UART_instance_t structure, which holds all data + * regarding this instance of the UART. + * @param p_sz_string The p_sz_string parameter is a pointer to a buffer + * containing the NULL ('\0') terminated string to be + * transmitted. + * @return This function does not return a value. + * + * @example + * @code + * uint8_t testmsg1[] = {"\r\n\r\nUART_polled_tx_string() test message 1\0"}; + * UART_polled_tx_string(&g_uart,(const uint8_t *)&testmsg1); + * @endcode + */ +void +UART_polled_tx_string +( + UART_instance_t * this_uart, + const uint8_t * p_sz_string +); + +/***************************************************************************//** + * The UART_get_rx_status() function returns the receiver error status of the + * CoreUARTapb instance. It reads both the current error status of the receiver + * and the accumulated error status from preceding calls to the UART_get_rx() + * function and combines them using a bitwise OR. It returns the cumulative + * parity, framing, and overflow error status of the receiver, since the + * previous call to UART_get_rx_status() as an 8-bit encoded value. + * + * Note: The UART_get_rx() function reads and accumulates the receiver status + * of the CoreUARTapb instance before reading each byte from the receiver's data + * register/FIFO. The driver maintains a sticky record of the cumulative error + * status, which persists after the UART_get_rx() function returns. The + * UART_get_rx_status() function clears this accumulated record of receiver + * errors before returning. + * + * @param this_uart The this_uart parameter is a pointer to a + * UART_instance_t structure which holds all data regarding + * this instance of the UART. + * @return This function returns the UART receiver error status as + * an 8-bit encoded value. The return value is 0, if there + * are no receiver errors occurred. The driver provides a + * set of bit mask constants, which should be compared with + * and/or used to mask the returned value to determine the + * receiver error status. + * When the return value is compared to the following bit + * masks, a non-zero result indicates that the + * corresponding error occurred: + * UART_APB_PARITY_ERROR (bit mask = 0x01) + * UART_APB_OVERFLOW_ERROR (bit mask = 0x02) + * UART_APB_FRAMING_ERROR (bit mask = 0x04) + * When the return value is compared to the following bit + * mask, a non-zero result indicates that no error + * occurred: + * UART_APB_NO_ERROR (0x00) + * + * @example + * @code + * UART_instance_t g_uart; + * uint8_t rx_data[MAX_RX_DATA_SIZE]; + * uint8_t err_status; + * err_status = UART_get_err_status(&g_uart); + * + * if(UART_APB_NO_ERROR == err_status ) + * { + * rx_size = UART_get_rx( &g_uart, rx_data, MAX_RX_DATA_SIZE ); + * } + * @endcode + */ +uint8_t +UART_get_rx_status +( + UART_instance_t * this_uart +); + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_UART_APB_H */ diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h new file mode 100644 index 0000000..c123cc3 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h @@ -0,0 +1,133 @@ +/******************************************************************************* + * (c) Copyright 2007-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file coreuartapb_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreUARTapb register definitions + */ + +#ifndef __CORE_UART_APB_REGISTERS +#define __CORE_UART_APB_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * TxData register details + */ +#define TXDATA_REG_OFFSET 0x0u + +/* + * TxData bits. + */ +#define TXDATA_OFFSET 0x0u +#define TXDATA_MASK 0xFFu +#define TXDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * RxData register details + */ +#define RXDATA_REG_OFFSET 0x4u + +/* + * RxData bits. + */ +#define RXDATA_OFFSET 0x4u +#define RXDATA_MASK 0xFFu +#define RXDATA_SHIFT 0u + +/*------------------------------------------------------------------------------ + * ControReg1 register details + */ +#define CTRL1_REG_OFFSET 0x8u + +/* + * Baud value (Lower 8-bits) + */ +#define CTRL1_BAUDVALUE_OFFSET 0x8u +#define CTRL1_BAUDVALUE_MASK 0xFFu +#define CTRL1_BAUDVALUE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * ControReg2 register details + */ +#define CTRL2_REG_OFFSET 0xCu + +/* + * Bit length + */ +#define CTRL2_BIT_LENGTH_OFFSET 0xCu +#define CTRL2_BIT_LENGTH_MASK 0x01u +#define CTRL2_BIT_LENGTH_SHIFT 0u + +/* + * Parity enable. + */ +#define CTRL2_PARITY_EN_OFFSET 0xCu +#define CTRL2_PARITY_EN_MASK 0x02u +#define CTRL2_PARITY_EN_SHIFT 1u + +/* + * Odd/even parity selection. + */ +#define CTRL2_ODD_EVEN_OFFSET 0xCu +#define CTRL2_ODD_EVEN_MASK 0x04u +#define CTRL2_ODD_EVEN_SHIFT 2u + +/* + * Baud value (Higher 5-bits) + */ +#define CTRL2_BAUDVALUE_OFFSET 0xCu +#define CTRL2_BAUDVALUE_MASK 0xF8u +#define CTRL2_BAUDVALUE_SHIFT 3u + +/*------------------------------------------------------------------------------ + * StatusReg register details + */ +#define StatusReg_REG_OFFSET 0x10u + +#define STATUS_REG_OFFSET 0x10u + +/* + * Transmit ready. + */ +#define STATUS_TXRDY_OFFSET 0x10u +#define STATUS_TXRDY_MASK 0x01u +#define STATUS_TXRDY_SHIFT 0u + +/* + * Receive full. + */ +#define STATUS_RXFULL_OFFSET 0x10u +#define STATUS_RXFULL_MASK 0x02u +#define STATUS_RXFULL_SHIFT 1u + +/* + * Parity error. + */ +#define STATUS_PARITYERR_OFFSET 0x10u +#define STATUS_PARITYERR_MASK 0x04u +#define STATUS_PARITYERR_SHIFT 2u + +/* + * Overflow. + */ +#define STATUS_OVERFLOW_OFFSET 0x10u +#define STATUS_OVERFLOW_MASK 0x08u +#define STATUS_OVERFLOW_SHIFT 3u + +/* + * Frame Error. + */ +#define STATUS_FRAMERR_OFFSET 0x10u +#define STATUS_FRAMERR_MASK 0x10u +#define STATUS_FRAMERR_SHIFT 4u + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_UART_APB_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.c b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.c new file mode 100644 index 0000000..a2f4911 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.c @@ -0,0 +1,765 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Mi-V I2C Soft IP bare-metal driver. This module is delivered as part of + * Extended Sub System(ESS) MIV_ESS. + * Please refer to miv_i2c.h file for more information. + */ + +#include "miv_i2c.h" + +#define MIV_I2C_ERROR 0xFFu + +/*------------------------------------------------------------------------------ + * MIV I2C transaction direction. + */ +#define MIV_I2C_WRITE_DIR 0u +#define MIV_I2C_READ_DIR 1u + +/* -- TRANSACTIONS TYPES -- */ +#define MIV_I2C_NO_TRANSACTION 0u +#define MIV_I2C_MASTER_WRITE_TRANSACTION 1u +#define MIV_I2C_MASTER_READ_TRANSACTION 2u +#define MIV_I2C_MASTER_SEQUENTIAL_READ_TRANSACTION 3u + +/*------------------------------------------------------------------------------ + * MIV I2C HW states + */ +#define MIV_I2C_IDLE 0x00u +#define MIV_I2C_TX_STA_CB 0x01u +#define MIV_I2C_TX_DATA 0x02u +#define MIV_I2C_RX_DATA 0x03u + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_disable_irq() disables the Mi-V I2C interrupt. + */ +void +MIV_I2C_disable_irq +( + void +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_enable_irq() enables the Mi-V I2C interrupt. + */ +void +MIV_I2C_enable_irq +( + void +); + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_init +( + miv_i2c_instance_t *this_i2c, + addr_t base_addr +) +{ + /* Assign the base address + * Clock Prescale value set + * MIV_I2C interrupt enabled + * I2C core enable + */ + psr_t processor_state; + + /* Disabling the interrupts */ + processor_state = HAL_disable_interrupts(); + + /* + * Initialize all items of the this_miv_i2c data structure to zero. This + * initializes all state variables to their init value. It relies on + * the fact that NO_TRANSACTION, MIV_I2C_SUCCESS and I2C_RELEASE_BUS all + * have an actual value of zero. + */ + memset(this_i2c, 0, sizeof(miv_i2c_instance_t)); + + this_i2c->base_addr = base_addr; + + HAL_restore_interrupts(processor_state); +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_config +( + miv_i2c_instance_t *this_i2c, + uint16_t clk_prescale +) +{ + /* Assign the base address + * Clock Prescale value set + * MIV_I2C interrupt enabled + * I2C core enable + */ + psr_t processor_state; + + /* Disabling the interrupts */ + processor_state = HAL_disable_interrupts(); + + /* Before writing to prescale reg, the core enable must be zero */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CTRL_CORE_EN, 0x00u); + + /* Set the prescale value */ + HAL_set_16bit_reg(this_i2c->base_addr, PRESCALE, clk_prescale); + + /* Enable the MIV I2C interrupts */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CTRL_IRQ_EN, 0x01u); + + /* Enable the MIV I2C core */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CTRL_CORE_EN, 0x01u); + + this_i2c->master_state = MIV_I2C_IDLE; + + HAL_restore_interrupts(processor_state); +} + +/* + * Please refer to miv_i2c.h for more info + */ +uint8_t +MIV_I2C_start +( + miv_i2c_instance_t *this_i2c +) +{ + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + /* Generate I2C start condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + HAL_restore_interrupts(processor_state); + + return 0u; +} + +/* + * Please refer to miv_i2c.h for more info + */ +uint8_t +MIV_I2C_stop +( + miv_i2c_instance_t *this_i2c +) +{ + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + /* Generate I2C stop condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + HAL_restore_interrupts(processor_state); + + return 0u; +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_write +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t bus_options, + uint8_t ack_polling_options +) +{ + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + /* I2C write flow + * + * Check I2C status for ongoing transaction + * Populate the structure with input data + * Generate start condition + * Set the write_direction and target address. + */ + + /* Update the transaction only when there is no ongoing I2C transaction */ + if (this_i2c->transaction == MIV_I2C_NO_TRANSACTION) + { + this_i2c->transaction = MIV_I2C_MASTER_WRITE_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MIV_I2C_MASTER_WRITE_TRANSACTION ; + + /* Populate the i2c instance structure */ + + /* Set the target addr */ + this_i2c->target_addr = i2c_target_addr; + this_i2c->dir = MIV_I2C_WRITE_DIR; + + /* Set up the tx buffer */ + this_i2c->master_tx_buffer = write_buffer; + this_i2c->master_tx_size = write_size; + this_i2c->master_tx_idx = 0u; + + /* Set the I2C status in progress and setup the options */ + this_i2c->bus_options = bus_options; + this_i2c->ack_polling_options = ack_polling_options; + this_i2c->master_status = MIV_I2C_IN_PROGRESS; + + + /* Generate I2C start condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* write target address and write bit */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, MIV_I2C_WRITE_DIR); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, i2c_target_addr); + + /* Set WR bit to transmit start condition and control byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + /* Set current master hw state -> transmitted start condition and + * control byte + */ + this_i2c->master_state = MIV_I2C_TX_STA_CB; + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( MIV_I2C_HOLD_BUS == this_i2c->bus_status ) + { + /* Must toggle IACK bit to clear the MIV_I2C IRQ*/ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00); + } + + MIV_I2C_enable_irq(); + + HAL_restore_interrupts(processor_state); + +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_read +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +) +{ + psr_t processor_state; + uint8_t status = MIV_I2C_SUCCESS; + + processor_state = HAL_disable_interrupts(); + + /* MIV I2C Read operation flow + * + * Check for ongoing transaction + * Populate the i2c instance structure + * Generate the start condition + * Set the READ_direction bit and target addr + */ + + uint8_t read_stat = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_TIP); + + /* Update the transaction only when there is no ongoing I2C transaction */ + if (this_i2c->transaction == MIV_I2C_NO_TRANSACTION) + { + this_i2c->transaction = MIV_I2C_MASTER_READ_TRANSACTION; + } + + this_i2c->pending_transaction = MIV_I2C_MASTER_READ_TRANSACTION; + + /* Populate the MIV I2C instance structure */ + + this_i2c->target_addr = i2c_target_addr; + this_i2c->dir = MIV_I2C_READ_DIR; + + /* Populate read buffer */ + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set the BUS and ACK polling options */ + this_i2c->bus_options = bus_options; + this_i2c->ack_polling_options = ack_polling_options; + + /* Generate the start condition */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* Set the DIR bit and target addr */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, MIV_I2C_READ_DIR); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, i2c_target_addr); + + /* Set the WR bit to transmit the start condition and command byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + /* Set the i2c master state and status transmitting STA and Command Byte */ + this_i2c->master_state = MIV_I2C_TX_STA_CB; + this_i2c->master_status = MIV_I2C_IN_PROGRESS; + + /* Toggle the IACK bit if required */ + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( MIV_I2C_HOLD_BUS == this_i2c->bus_status ) + { + /* Must toggle IACK bit to clear the MIV_I2C IRQ*/ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00); + } + /* Enable the I2C interrupt */ + MIV_I2C_enable_irq(); + + HAL_restore_interrupts(processor_state); +} + +/* + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_write_read +( + miv_i2c_instance_t *this_i2c, + uint8_t target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +) +{ + uint8_t status = MIV_I2C_SUCCESS; + psr_t processor_state; + + processor_state = HAL_disable_interrupts(); + + uint8_t read_stat = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_TIP); + + /* I2C write read operation flow + * + * Used to read the data from set address offset + * + * Configure the i2c instance structure + * generate the start and configure the dir and target addr + * set wr bit to transmit the start and command byte + * + */ + + /* Update the transaction only when there is no ongoing I2C transaction */ + if (this_i2c->transaction == MIV_I2C_NO_TRANSACTION) + { + this_i2c->transaction = MIV_I2C_MASTER_READ_TRANSACTION; + } + + this_i2c->pending_transaction = MIV_I2C_MASTER_READ_TRANSACTION; + + /* Populate the I2C instance */ + + this_i2c->target_addr = target_addr; + + /* setup the i2c direction */ + this_i2c->dir = MIV_I2C_WRITE_DIR; + + /* set up transmit buffer */ + this_i2c->master_tx_buffer = write_buffer; + this_i2c->master_tx_size = write_size; + this_i2c->master_tx_idx = 0u; + + /* set up receive buffer */ + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set the bus and ack polling options */ + this_i2c->bus_options = bus_options; + this_i2c->ack_polling_options = ack_polling_options; + + /* Generate the start command */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* Set the DIR and target addr */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + /* Set the WR bit to transmit the start command and command byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + /* Set the i2c master state and status transmitting STA and Command Byte */ + this_i2c->master_state = MIV_I2C_TX_STA_CB; + this_i2c->master_status = MIV_I2C_IN_PROGRESS; + + /* + * Clear interrupt if required + */ + if ( MIV_I2C_HOLD_BUS == this_i2c->bus_status ) + { + /* Must toggle IACK bit to clear the MIV_I2C IRQ*/ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00u); + } + + /* Enable the I2C interrupt */ + MIV_I2C_enable_irq(); + + HAL_restore_interrupts(processor_state); +} + +/* MIV_I2C_isr() + * Please refer to miv_i2c.h for more info + */ +void +MIV_I2C_isr +( + miv_i2c_instance_t *this_i2c +) +{ + uint8_t i2c_state; + uint8_t i2c_ack_status; + uint8_t i2c_al_status; + uint8_t hold_bus; + + /* Read the I2C master state */ + i2c_state = this_i2c->master_state; + + /* Read the ack and al status */ + i2c_ack_status = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_RXACK); + i2c_al_status = HAL_get_8bit_reg_field(this_i2c->base_addr, STAT_AL); + + switch (i2c_state) + { + /* I2C ISR State Machine + * + * Cases: + * - Transmit start condition and control byte + * - Received ACK and bus arbitration was not lost (Read or Write) + * - Received NACK + * - Bus arbitration lost + * + * - Transmit data + * - Received ACK and bus arbitration was not lost (Read or Write) + * - Received NACK + * - Bus arbitration lost + * + * - Receive data + * - Received ACK and bus arbitration was not lost (Read or Write) + * - Bus arbitration lost + */ + + case MIV_I2C_TX_STA_CB: + + /* Received ACK from target and I2C bus arbitration is not lost */ + if (i2c_ack_status == 0u && i2c_al_status == 0u) + { + /* If I2C master write operation */ + if (this_i2c->dir == MIV_I2C_WRITE_DIR) + { + /* write first byte of data and set the WR bit to transfer the data */ + HAL_set_8bit_reg(this_i2c->base_addr, TRANSMIT, + this_i2c->master_tx_buffer[this_i2c->master_tx_idx]); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + /* Increment the index */ + this_i2c->master_tx_idx++; + + /* Set the master state to TX data */ + this_i2c->master_state = MIV_I2C_TX_DATA; + } + /* Master read operation */ + else + { + if (this_i2c->master_rx_size == 1u) + { + /* Send the ACK if the rx size is 1, transmit NACK to slave + * after receiving 1 byte to indicate slave to stop sending + * the data + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_ACK, 0x01u); + } + + /* Send the RD command to slave */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_RD, 0x01u); + + /* Increment the index */ + this_i2c->master_rx_idx++; + + /* Change state to receive data */ + this_i2c->master_state = MIV_I2C_RX_DATA; + } + } + else if (i2c_ack_status == 1u) + { + if (this_i2c->ack_polling_options == MIV_I2C_ACK_POLLING_ENABLE) + { + /* Target responded with NACK and ACK polling option is enabled + * + * Re-send the start condition and control byte + * + * TO-DO: This might become infinite loop check for timeout + * options. + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + this_i2c->master_tx_idx = 0u; + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + else + { + /* Target responded with NACK and ACK polling is disabled + * Abort the transaction and move to IDLE state + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + + this_i2c->master_status = MIV_I2C_FAILED; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + + this_i2c->master_state = MIV_I2C_IDLE; + } + } + + else if (i2c_al_status == 1u) + { + /* Arbitration was lost on the BUS during the transmission of + * previous start condition and control byte. + * Re-send the STA and CB + */ + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + break; + + /* Transmit master data */ + case MIV_I2C_TX_DATA: + + /* ACK received and arbitration was not lost */ + if (i2c_ack_status == 0u && i2c_al_status == 0u) + { + uint8_t tx_buff[this_i2c->master_tx_size]; + if (this_i2c->master_tx_idx < this_i2c->master_tx_size) + { + HAL_set_8bit_reg(this_i2c->base_addr, TRANSMIT, + this_i2c->master_tx_buffer[this_i2c->master_tx_idx]); + + tx_buff[this_i2c->master_tx_idx] = this_i2c->master_tx_buffer[this_i2c->master_tx_idx]; + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + /* Increment the index */ + this_i2c->master_tx_idx++; + + /* Set the master state to TX data */ + this_i2c->master_state = MIV_I2C_TX_DATA; + } + + /* All the bytes are transmitted */ + else if (this_i2c->master_tx_idx == this_i2c->master_tx_size) + { + /* If this is a MASTER_READ_TRANSACTION, hold bus and start a + new transfer in read mode now that the read address has been + written to the slave */ + if(this_i2c->transaction == MIV_I2C_MASTER_READ_TRANSACTION) + + { + //Switch direction to READ + this_i2c->dir = MIV_I2C_READ_DIR; + + // Set the STA bit + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + /* Set the DIR bit and target addr */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, MIV_I2C_READ_DIR); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, this_i2c->target_addr); + + /* Set the WR bit to transmit the start condition and command byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01u); + + // Reset the buffer index + this_i2c->master_tx_idx = 0u; + this_i2c->master_rx_idx = 0u; + + /* Set the master state to RX data */ + this_i2c->master_state = MIV_I2C_RX_DATA; + } + + else + { + /* If releasing the bus, transmit the stop condition at the end + * of the transfer. + */ + hold_bus = this_i2c->bus_status & MIV_I2C_HOLD_BUS; + + if (hold_bus == 0) + { + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + } + else + { + MIV_I2C_disable_irq(); + } + this_i2c->master_status = MIV_I2C_SUCCESS; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + this_i2c->master_state = MIV_I2C_IDLE; + } + } + } + + else if (i2c_ack_status == 1u) + { + /* Received NACK from target device + * + * Release the bus and end the transfer + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + + this_i2c->master_status = MIV_I2C_FAILED; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + + this_i2c->master_state = MIV_I2C_IDLE; + } + + else if (i2c_al_status == 1u) + { + /* Arbitration was lost on the BUS during the transmission of + * previous start condition and control byte. + * Re-send the STA and CB + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, + this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + break; + + /* Receive target device data */ + case MIV_I2C_RX_DATA: + + if (i2c_al_status == 0u) + { + if (this_i2c->master_rx_idx < this_i2c->master_rx_size) + { + this_i2c->master_rx_buffer[this_i2c->master_rx_idx - 1u] = + HAL_get_8bit_reg(this_i2c->base_addr, RECEIVE); + + /* If next byte is last one + * Send NACK to target device to stop sending data + */ + if (this_i2c->master_rx_idx == (this_i2c->master_rx_size - 1u)) + { + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_ACK, 0x01u); + } + + else + { + /* Send ACK to receive next bytes */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_ACK, 0x00u); + } + + /* Set RD bit to receive next byte */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_RD, 0x01u); + + this_i2c->master_rx_idx++; + } + + /* Received all bytes */ + else //if (this_i2c->master_rx_idx == this_i2c->master_rx_size) + { + this_i2c->master_rx_buffer[this_i2c->master_rx_idx - 1] = + HAL_get_8bit_reg(this_i2c->base_addr, RECEIVE); + + hold_bus = this_i2c->bus_status & MIV_I2C_HOLD_BUS; + + if (hold_bus == 0) + { + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STO, 0x01u); + } + else + { + MIV_I2C_disable_irq(); + } + this_i2c->master_status = MIV_I2C_SUCCESS; + this_i2c->transaction = MIV_I2C_NO_TRANSACTION; + + this_i2c->master_state = MIV_I2C_IDLE; + } + } + + else if (i2c_al_status == 1u) + { + /* Arbitration was lost on the BUS during the transmission of + * previous start condition and control byte. + * Re-send the STA and CB + */ + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_TARGET_ADDR, + this_i2c->target_addr); + HAL_set_8bit_reg_field(this_i2c->base_addr, TX_DIR, this_i2c->dir); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_STA, 0x01u); + + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_WR, 0x01); + + this_i2c->master_state = MIV_I2C_TX_STA_CB; + } + + break; + } + + /* Toggle the IACK bit to clear interrupt */ + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_addr, CMD_IACK, 0x00u); +} + +/* + * Please refer to miv_i2c.h for more info + */ +uint8_t +MIV_I2C_get_status +( + miv_i2c_instance_t *this_i2c +) +{ + uint8_t i2c_status; + + i2c_status = HAL_get_8bit_reg(this_i2c->base_addr, STATUS); + + return i2c_status; +} diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.h b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.h new file mode 100644 index 0000000..c5e704d --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.h @@ -0,0 +1,854 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * I2C module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(MIV_ESS). + */ + +/*=========================================================================*//** + @mainpage Mi-V I2C Bare Metal Driver + + ============================================================================== + Introduction + ============================================================================== + The Mi-V I2C driver provides a set of functions for controlling the Mi-V I2C + Soft-IP module. This module is delivered as a part of the Mi-V Extended + Sub System(MIV_ESS). The driver provides a minimal APB-driven I2C interface, + supporting initiator read and write access to peripheral I2C devices. + + The major features provided by the Mi-V I2C driver are: + - Support for configuring the I2C instance. + - I2C master operations. + - I2C ISR. + + This driver can be used as part of a bare metal system where no operating + system is available. The driver can be adapted for use as part of an + operating system, but the implementation of the adaptation layer between the + driver and the operating system's driver model is outside the scope of this + driver. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + The application software should initialize and configure the Mi-V I2C through + the call to the MIV_I2C_init() and MIV_I2C_config() function for Mi-V I2C + instance in the design. The configuration parameter include base address and + Prescaler value. + + ------------------------------ + Interrupt Control + ------------------------------ + The Mi-V I2C driver has to enable and disable the generation of interrupts by + Mi-V I2C at various times while operating. This enabling and disabling of the + interrupts must be done through the Mi-V RV32 HAL provided interrupt handlers. + For that reason, the method controlling the Mi-V I2C interrupts is system + specific and it is necessary to customize the MIV_I2C_enable_irq() and + MIV_I2C_disable_irq() functions as per requirement. + + The implementation of MIV_I2C_enable_irq() should permit the interrupts + generated by the Mi-V I2C to the processor through a call to respective miv-hal + interrupt handler. The implementation of MIV_I2C_disable_irq() should prevent + the interrupts generated by a Mi-V I2C from interrupting the processor. + Please refer to the miv_i2c_interrupt.c for more information about the + implementation. + + No MIV_I2C hardware configuration parameters are used by the driver, apart + from the MIV_I2C base address. Hence, no additional configuration files + are required to use the driver. + + ============================================================================== + Theory of Operation + ============================================================================== + The Mi-V I2C software driver is designed to allow the control of multiple + instances of Mi-V I2C. Each instance of Mi-V I2C in the hardware design is + associated with a single instance of the miv_i2c_instance_t structure in the + software. User must allocate memory for one unique miv_i2c_instance_t + structure for each instance of Mi-V I2C in the hardware. + A pointer to the structure is passed to the subsequent driver functions in + order to identify the MIV_I2C hardware instance and to perform requested + operation. + + Note: Do not attempt to directly manipulate the contents of the + miv_i2c_instance_t structure. These structures are only intended to be modified + by the driver functions. + + The Mi-V I2C driver functions are grouped into following categories: + - Initialization and configuration + - I2C master operation functions to handle write, read and write_read + operations. + - Interrupt control + + -------------------------------- + Initialization and configuration + -------------------------------- + The Mi-V I2C device is first initialized by the call to MIV_I2C_init(). This + function initializes the instance of Mi-V I2C with the base address. + MIV_I2C_init() function must be called before any other Mi-V I2C driver API. + + The configuration of the Mi-V I2C instance is done via call to the + MIV_I2C_config() function. This function will set the prescale value which is + used to set the frequency of the I2C clock(SCLK) generated by I2C module. + + --------------------------------- + Transaction types + --------------------------------- + The driver is designed to handle three types of transactions: + - Write transactions + - Read transactions + - Write-Read transaction + + ### Write Transaction + The write transaction begins with master sending a start condition, followed + by device address byte with the R/W bit set to logic '0', and then by the + word address bytes. The slave acknowledges the receipt of its address with + acknowledge bit. The master sends one byte at a time to the slave, which must + acknowledge the receipt of each byte for the next byte to be sent. The master + sends STOP condition to complete the transaction. The slave can abort the + transaction by replying with negative acknowledge. + + The application programmer can choose not to send the STOP bit at the end of + the transaction causing repetitive start conditions. + + ### Read Transaction + The master I2C device initiates a read transaction by sending a START bit + as soon as the bus becomes free. The start condition is followed by the + control byte which contains 7-bit slave address followed by R/W bit set to + logic '1'. The slave sends data one byte at a time to the master, which must + acknowledge receipt of each byte for the next byte to be sent. The master + sends a non-acknowledge bit following the last byte it wishes to read + followed by a STOP bit. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ### Write-Read Transaction + The write read transaction is a combination of a write transaction + immediately followed by a read transaction. There is no STOP condition sent + between the write and read phase of write-read transaction. A repeated START + condition is sent between the write and read phases. + + Whilst the write handler is being executed, the slave holds the clock line + low to stretch the clock until the response is ready. + + The write-read transaction is typically used to send an memory/register + address in the write transaction specifying the start address of the data to + be transferred during the read phase. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ------------------------------------- + Interrupt Control + ------------------------------------- + The Mi-V I2C driver is interrupt driven and it uses the MIV_I2C_irq() function + to drive the ISR state machine which is at the heart of the driver. The + application is responsible for providing the link between the interrupt + generating hardware and the Mi-V I2C interrupt handler and must ensure that + the MIV_I2C_isr() function is called with the correct miv_i2c_instance_t + structure pointer for the Mi-V I2C instance initiating the interrupt. + +*//*=========================================================================*/ +#ifndef MIV_I2C_H_ +#define MIV_I2C_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "miv_i2c_regs.h" +#include + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#else +#include "hal.h" +#endif + +/*-------------------------------------------------------------------------*//** + The miv_i2c_status_t type is used to report the status of I2C transactions. + */ +typedef enum miv_i2c_status +{ + MIV_I2C_SUCCESS = 0u, + MIV_I2C_IN_PROGRESS, + MIV_I2C_FAILED, + MIV_I2C_TIMED_OUT +}miv_i2c_status_t; + +/*-------------------------------------------------------------------------*//** + This structure is used to identify the MIV_I2C hardware instances in a system. + Your application software should declare one instance of this structure for + each instance of the MIV_I2C in your system. The function MIV_I2C_init() + Initializes this structure. A pointer to an initialised instance of the structure + should be passed as the first parameter to the MIV_I2C driver functions, to + identify which MIV_I2C hardware instance should perform the requested operation. + + The contents of this data structure should not be modified or used outside of + the MIV_I2C driver. Software using the MIV_I2C driver should only need to + create one single instance of this data structure for each MIV_I2C hardware + instance in the system, then pass a pointer to these data structures with each + call to the MIV_I2C driver in order to identify the MIV_I2C hardware instance + it wishes to use. +*/ + +typedef struct miv_i2c_instance +{ + addr_t base_addr; + + /* Transmit related info:*/ + uint_fast8_t target_addr; + + /* Current transaction type */ + uint8_t transaction; + + uint8_t bus_options; + + uint8_t ack_polling_options; + + /* Current State of the I2C master */ + uint8_t master_state; + + /* Master TX INFO: */ + const uint8_t * master_tx_buffer; + uint_fast16_t master_tx_size; + uint_fast16_t master_tx_idx; + uint_fast8_t dir; + + /* Master RX INFO: */ + uint8_t * master_rx_buffer; + uint_fast16_t master_rx_size; + uint_fast16_t master_rx_idx; + + /* Master Status */ + volatile miv_i2c_status_t master_status; + uint32_t master_timeout_ms; + + /* user specific data */ + void *p_user_data ; + + /* I2C bus status */ + uint8_t bus_status; + + /* Is transaction pending flag */ + uint8_t is_transaction_pending; + + /* I2C Pending transaction */ + uint8_t pending_transaction; + +}miv_i2c_instance_t; + + +/*-------------------------------------------------------------------------*//** + MIV_I2C_RELEASE_BUS + ===================== + The MIV_I2C_RELEASE_BUS constant is used to specify the bus_options parameter + for MIV_I2C_read(), MIV_I2C_write() and MIV_I2C_write_read() to indicate + that a STOP bit must be generated at the end of the I2C transaction to release + the bus. + */ +#define MIV_I2C_RELEASE_BUS 0x00u + + +/*-------------------------------------------------------------------------*//** + MIV_I2C_HOLD_BUS + ===================== + The MIV_I2C_HOLD_BUS constant is used to specify the bus_optionsparameter + for MIV_I2C_read(), MIV_I2C_write() and MIV_I2C_write_read() to indicate + that a STOP bit must not be generated at the end of the I2C transaction in + order to retain the bus ownership. This causes the next transaction to + begin with a repeated START bit and no STOP bit between the transactions. + */ +#define MIV_I2C_HOLD_BUS 0x01u + +/*-------------------------------------------------------------------------*//** + MIV_I2C_ACK_POLLING_DISABLE + ===================== + The MIV_I2C_ACK_POLLING_DISABLE constant is used to specify the + ack_polling_options parameter to functions MIV_I2C_write(), + MIV_I2C_write_read() and MIV_I2C_read(). Acknowledgment polling is used when + working with I2C memory devices such as EEPROM, which feature an internal + write cycle. + + With acknowledgment polling disabled, if the target slave device responds to the + control byte with a NACK, the MIV_I2C will abort the transfer. + */ +#define MIV_I2C_ACK_POLLING_DISABLE 0x00u + +/*-------------------------------------------------------------------------*//** + MIV_I2C_ACK_POLLING_ENABLE + ===================== + The MIV_I2C_ACK_POLLING_ENABLE constant is used to specify the + ack_polling_options parameter to functions MIV_I2C_write(), + MIV_I2C_write_read() and MIV_I2C_read(). acknowledgment polling is used when + working with I2C memory devices such as EEPROM, which feature an internal + write cycle. + + With acknowledgment polling enabled, if the slave device responds to the + control byte with a NACK, the MIV_I2C will repeatedly transmit another control + byte until the slave device accepts the connection with an ACK, or the timeout + specified in the MIV_I2C_wait_complete() function is reached. Acknowledgment + polling allows for the next read/write operation to be started as soon as the + EEPROM has completed its internal write cycle. + */ +#define MIV_I2C_ACK_POLLING_ENABLE 0x01u + +/*--------------------------------Public APIs---------------------------------*/ + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_init() function is used to initialize the Mi-V I2C module instance + with the base address. + + Note: This function should be called before calling any other Mi-V I2C + functions. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + @param base_addr + Base address of the Mi-V I2C module instance in the MIV_ESS + soft IP. + + @return + This function does not return any value. + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + } + @endcode + */ +void +MIV_I2C_init +( + miv_i2c_instance_t *this_i2c, + addr_t base_addr +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_config() function is used to configure the Mi-V I2C module. This + function will set the prescale value which is used to set the frequency of + the I2C clock(SCLK) generated by I2C module and also enables the I2C core and + interrupts. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param clk_prescale + The value used to set the frequency of Mi-V I2C serial clock + (SCLK) generated by the Mi-V I2C module instance. The + prescaler value required to set particular frequency of + Mi-V I2C can be calculated using following formula: + + prescaler = (System Clock Frequency) / (5 * (Desired I2C Clock Frequency)) - 1 + + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + } + @endcode + */ +void +MIV_I2C_config +( + miv_i2c_instance_t *this_i2c, + uint16_t clk_prescale +); + + +uint8_t +MIV_I2C_start +( + miv_i2c_instance_t *this_i2c +); + + +uint8_t +MIV_I2C_stop +( + miv_i2c_instance_t *this_i2c +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_write() is used to set up and start the Mi-V I2C master write + transaction. This function is used for all Mi-V master write operation. + + For more information about the operation, please refer to the 'theory of + operations' section at the start of this document. + + This function returns immediately after initiating the transaction. The content + of the write buffer passed as parameter should not be modified until the write + transaction completes. It also means that the memory allocated for the write + buffer should not be freed or should not go out of scope before the write + completes. + You can check for the write transaction completion by polling the master_status + from miv_i2c_instance_t structure as shown in the sample code. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param i2c_target_addr + This parameter specifies the serial address for the slave + device. + + @param write_buffer + This parameter is a pointer to the buffer holding data to be + written to target I2C device. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param write_size + Number of bytes held in the write_buffer to be written to the + I2C device. + @param bus_options: + The bus_options parameter is used to indicate if the I2C bus + should be released on completion of the write transaction. + Using the MIV_I2C_RELEASE_BUS constant for the bus_options + parameter causes a STOP bit to be generated at the end of the + write transaction causing the bus to be released for other I2C + devices to use. Using the MIV_I2C_HOLD_BUS constant as + bus_options parameter prevents a STOP bit from being generated + at the end of the write transaction, preventing other I2C + devices from initiating a bus transaction. + + @param ack_polling_options: + The ack_polling_options parameter is used to indicate how the + MIV_I2C will respond if the slave device transmits a NACK to + the I2C control byte. Using the MIV_I2C_ACK_POLLING_DISABLE + constant for the ack_polling_options parameter causes the + MIV_I2C to abort the transfer if the slave device responds to + the I2C control byte with a NACK. Using the + MIV_I2C_ACK_POLLING_ENABLE constant for the ack_polling_options + parameter causes the MIV_I2C to repeatedly transmit a control + byte to the slave device until the slave device responds with + an ACK. + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + + MIV_I2C_write (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_tx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + } + @endcode + */ +void +MIV_I2C_write +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t bus_options, + uint8_t ack_polling_options +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_read() is used to set up and start the Mi-V I2C master read + transaction. This function is used for all MIV_I2C master read operation. + + For more information about the operation, please refer to the 'theory of + operations' section at the start of this document. + + This function returns immediately after initiating the transaction. The content + of the read buffer passed as parameter should not be modified until the write + transaction completes. It also means that the memory allocated for the read + buffer should not be freed or should not go out of scope before the read + completes. + You can check for the write transaction completion by polling the master_status + from miv_i2c_instance_t structure as shown in the sample code. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param i2c_target_addr + This parameter specifies the serial address for the slave + device. + + @param read_buffer + This parameter is a pointer to the buffer where the data + received from the I2C slave device is stored. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param read_size + Number of bytes held in the write_buffer to be read from the + I2C device. + + @param bus_options: + The bus_options parameter is used to indicate if the I2C bus + should be released on completion of the write transaction. + Using the MIV_I2C_RELEASE_BUS constant for the bus_options + parameter causes a STOP bit to be generated at the end of the + write transaction causing the bus to be released for other I2C + devices to use. Using the MIV_I2C_HOLD_BUS constant as + bus_options parameter prevents a STOP bit from being generated + at the end of the write transaction, preventing other I2C + devices from initiating a bus transaction. + + @param ack_polling_options: + The ack_polling_options parameter is used to indicate how the + MIV_I2C will respond if the slave device transmits a NACK to + the I2C control byte. Using the MIV_I2C_ACK_POLLING_DISABLE + constant for the ack_polling_options parameter causes the + MIV_I2C to abort the transfer if the slave device responds to + the I2C control byte with a NACK. Using the + MIV_I2C_ACK_POLLING_ENABLE constant for the ack_polling_options + parameter causes the MIV_I2C to repeatedly transmit a control + byte to the slave device until the slave device responds with + an ACK. + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + + MIV_I2C_write (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_tx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + + // reset miv_i2c_status variable + miv_i2c_status = 0u; + + MIV_I2C_read (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_rx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + } + @endcode + */ +void +MIV_I2C_read +( + miv_i2c_instance_t *this_i2c, + uint8_t i2c_target_addr, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_write_read() is used to set up and start the Mi-V I2C master + write_read transaction. This function is used for all MIV_I2C master write_read + operation. + + This function is used in cases where data is being requested from a specific + address offset inside the target I2C slave device. + In this type of I2C operation, the I2C master starts by initiating a write + operation. During this write operation, the specific address offset is written + to the I2C slave. Once the address offset has been written to the I2C slave, + the I2C master transmits a repeated start, and initiates a read operation to + read data from the set address. + + For more information about the operation, please refer to the 'theory of + operations' section at the start of this document. + + This function returns immediately after initiating the transaction. The content + of the write and read buffer passed as parameter should not be modified until + the write transaction completes. It also means that the memory allocated for + the write and read buffer should not be freed or should not go out of scope + before the operation completes. + You can check for the write_read transaction completion by polling the + master_status from miv_i2c_instance_t structure. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + + @param i2c_target_addr + This parameter specifies the serial address for the slave + device. + + @param write_buffer + This parameter is a pointer to the buffer holding data to be + written to target I2C device. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param write_size + Number of bytes held in the write_buffer to be written to the + I2C device. + + @param read_buffer + This parameter is a pointer to the buffer where the data + received from the I2C slave device is stored. + Care must be taken not to release the memory used by this + buffer before the write transaction completes. + + @param read_size + Number of bytes held in the write_buffer to be read from the + I2C device. + + @param bus_options: + The bus_options parameter is used to indicate if the I2C bus + should be released on completion of the write transaction. + Using the MIV_I2C_RELEASE_BUS constant for the bus_options + parameter causes a STOP bit to be generated at the end of the + write transaction causing the bus to be released for other I2C + devices to use. Using the MIV_I2C_HOLD_BUS constant as + bus_options parameter prevents a STOP bit from being generated + at the end of the write transaction, preventing other I2C + devices from initiating a bus transaction. + + @param ack_polling_options: + The ack_polling_options parameter is used to indicate how the + MIV_I2C will respond if the slave device transmits a NACK to + the I2C control byte. Using the MIV_I2C_ACK_POLLING_DISABLE + constant for the ack_polling_options parameter causes the + MIV_I2C to abort the transfer if the slave device responds to + the I2C control byte with a NACK. Using the + MIV_I2C_ACK_POLLING_ENABLE constant for the ack_polling_options + parameter causes the MIV_I2C to repeatedly transmit a control + byte to the slave device until the slave device responds with + an ACK or the timeout specified in the MIV_I2C_wait_complete() + function is reached. + @return + This function does not return any value. + + + Example: + @code + #define MIV_I2C_BASE_ADDR 0x7A000000u + + miv_i2c_instance_t g_miv_i2c_inst; + + void main( void ) + { + MIV_I2C_init( &g_miv_i2c_inst, MIV_I2C_BASE_ADDR); + + Configuring Mi-V I2C core at Normal Speed (100MHz) for 50MHz Sys clock. + MIV_I2C_config(&g_miv_i2c_inst, 0x63); + + MIV_I2C_write (&g_miv_i2c_inst, + DUALEE_SLAVEADDRESS_1, + i2c_tx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + + // reset miv_i2c_status variable + miv_i2c_status = 0u; + + uint8_t addr_offset[2] = {0x00, 0x00}; + MIV_I2C_write_read(&miv_i2c, + DUALEE_SLAVEADDRESS_1, + addr_offset, + sizeof(addr_offset), + i2c_rx_buffer, + transfer_size, + MIV_I2C_RELEASE_BUS, + MIV_I2C_ACK_POLLING_ENABLE + ); + + // Wait till the miv i2c status changes + do { + miv_i2c_status = miv_i2c.master_status; + }while (MIV_I2C_IN_PROGRESS == miv_i2c_status); + } + @endcode + */ +void +MIV_I2C_write_read +( + miv_i2c_instance_t *this_i2c, + uint8_t target_addr, + const uint8_t *write_buffer, + uint16_t write_size, + uint8_t *read_buffer, + uint16_t read_size, + uint8_t bus_options, + uint8_t ack_polling_options +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_isr() function contains the MIV_I2C's interrupt service routine. + This ISR is at the heart of the MIV_I2C driver, and is used to control the + interrupt-driven, byte-by-byte I2C read and write operations. + + The ISR operates as a Finite State Machine (FSM), which uses the previously + completed I2C operation and its result to determine which I2C operation will + be performed next. + + The ISR operation is divided into following categories: + - MIV_I2C_IDLE + - MIV_I2C_TX_STA_CB + - MIV_I2C_TX_DATA + - MIV_I2C_RX_DATA + + ##### MIV_I2C_IDLE + The MIV_I2C_IDLE is entered on reset, or when an I2C master operation has been + completed or aborted. + Upon entering, the FSM will remain in this state until a write, read, or + write-read operation is requested + + ##### MIV_I2C_STA_CB + The MIV_I2C_TX_STA_CB operation is performed when the start condition and + control byte(i2c target address(7-bit) and direction of transaction(1-bit)) is + transmitted by the Mi-V I2C master device to the slave. + If the target I2C slave device responded to the previous START Condition + + Control Byte with an ACK, the MIV_I2C will start the requested I2C + read/write operation. + If the target slave I2C slave device responds with NACK, the MIV_I2C will + remain in this state or return to the idle state based on ack_polling + configuration. + + ##### MIV_I2C_TX_DATA + The MIV_I2C_TX_DATA state is entered after the target slave device accepts a + write request with an ACK. + This state is used to handle the byte-by-byte MIV_I2C write operations. + The FSM will remain in this state until either all data bytes have been + written to the target slave device, or an error occurs during the write + operation. + + ##### MIV_I2C_RX_DATA + The MIV_I2C_RX_DATA state is entered after the target slave device accepts a + read request with an ACK. + This state is used to handle the byte-by-byte MIV_I2C read operations. + The FSM will remain in this state until either all data bytes have been + received from the target slave device, or an error occurs. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + */ +void +MIV_I2C_isr +( + miv_i2c_instance_t *this_i2c +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_get_status() returns the 8-bit Mi-V I2C status register value. + + @param this_i2c + A pointer to the miv_i2c_instance_t data structure which + will hold all the data related to the Mi-V I2C module + instance being used. A pointer to this structure is passed to + rest of the Mi-V I2C driver functions for operation. + @return + This function returns 8-bit Mi-V I2C status register value. + */ +uint8_t +MIV_I2C_get_status +( + miv_i2c_instance_t *this_i2c +); + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_I2C_H_ */ diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_interrupt.c b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_interrupt.c new file mode 100644 index 0000000..871eafe --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_interrupt.c @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains functions used for MIV_I2C driver interrupt control. + * User should enable and disable the interrupts according to their design. + * Please refer to miv_i2c.h file for more information. + */ + +#include "miv_rv32_hal/miv_rv32_hal.h" + +void MIV_I2C_disable_irq(void) +{ +/* Disable I2C interrupt */ + MRV_disable_local_irq(MRV32_MSYS_EIE2_IRQn); +} + +void MIV_I2C_enable_irq(void) +{ +/* Enable I2C interrupt */ + MRV_enable_local_irq(MRV32_MSYS_EIE2_IRQn); +} + + diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_regs.h b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_regs.h new file mode 100644 index 0000000..9a4bfbf --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_regs.h @@ -0,0 +1,158 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP I2C module driver. This module is delivered as a part of Mi-V extended + * Sub-System(MIV_ESS). + */ + +#ifndef MIV_I2C_APB_REGISTERS +#define MIV_I2C_APB_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * Prescale register details + */ +#define PRESCALE_REG_OFFSET 0x00u + +/* Prescale register bits */ +#define PRESCALE_OFFSET 0x00u +#define PRESCALE_MASK 0xFFFFu +#define PRESCALE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Control register details + */ +#define CONTROL_REG_OFFSET 0x04u + +/* Control register bits */ +#define CONTROL_OFFSET 0x04u +#define CONTROL_MASK 0xC0u +#define CONTROL_SHIFT 0u + +/* Control register Core Enable Bit */ +#define CTRL_CORE_EN_OFFSET 0x04u +#define CTRL_CORE_EN_MASK 0x80u +#define CTRL_CORE_EN_SHIFT 7u + +/* Control register IRQ Enable bit */ +#define CTRL_IRQ_EN_OFFSET 0x04u +#define CTRL_IRQ_EN_MASK 0x40u +#define CTRL_IRQ_EN_SHIFT 6u + +/*------------------------------------------------------------------------------ + * Transmit register details + */ +#define TRANSMIT_REG_OFFSET 0x08u + +/* Transmit register bits */ +#define TRANSMIT_OFFSET 0x08u +#define TRANSMIT_MASK 0xFFu +#define TRANSMIT_SHIFT 0u + +/* Transmit register DIR bit */ +#define TX_DIR_OFFSET 0x08u +#define TX_DIR_MASK 0x01u +#define TX_DIR_SHIFT 0u + +/* Transmit register TARGET_ADDR bit */ +#define TX_TARGET_ADDR_OFFSET 0x08u +#define TX_TARGET_ADDR_MASK 0xFEu +#define TX_TARGET_ADDR_SHIFT 1u + +/*------------------------------------------------------------------------------ + * Receive register details + */ +#define RECEIVE_REG_OFFSET 0x0Cu + +/* Receive register bits */ +#define RECEIVE_OFFSET 0x0Cu +#define RECEIVE_MASK 0xFFu +#define RECEIVE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Command register details + */ +#define COMMAND_REG_OFFSET 0x10u + +/* Command register bits */ +#define COMMAND_OFFSET 0x10u +#define COMMAND_MASK 0xF9u +#define COMMAND_SHIFT 0u + +/* Command register IACK bit */ +#define CMD_IACK_OFFSET 0x10u +#define CMD_IACK_MASK 0x01u +#define CMD_IACK_SHIFT 0u + +/* Command register ACK bit */ +#define CMD_ACK_OFFSET 0x10u +#define CMD_ACK_MASK 0x08u +#define CMD_ACK_SHIFT 3u + +/* Command register WR bit */ +#define CMD_WR_OFFSET 0x10u +#define CMD_WR_MASK 0x10u +#define CMD_WR_SHIFT 4u + +/* Command register RD bit */ +#define CMD_RD_OFFSET 0x10u +#define CMD_RD_MASK 0x20u +#define CMD_RD_SHIFT 5u + +/* Command register STO bit */ +#define CMD_STO_OFFSET 0x10u +#define CMD_STO_MASK 0x40u +#define CMD_STO_SHIFT 6u + +/* Command register STA bit */ +#define CMD_STA_OFFSET 0x10u +#define CMD_STA_MASK 0x80u +#define CMD_STA_SHIFT 7u + +/*------------------------------------------------------------------------------ + * Status register details + */ +#define STATUS_REG_OFFSET 0x14u + +/* Command register bits */ +#define STATUS_OFFSET 0x14u +#define STATUS_MASK 0xFFu +#define STATUS_SHIFT 0u + +/* Status register Interrupt Flag(IF) bit */ +#define STAT_IF_OFFSET 0x14u +#define STAT_IF_MASK 0x01u +#define STAT_IF_SHIFT 0u + +/* Status register Transfer in Progress(TIP) bit */ +#define STAT_TIP_OFFSET 0x14u +#define STAT_TIP_MASK 0x02u +#define STAT_TIP_SHIFT 1u + +/* Status register Arbitration Lost(AL) bit */ +#define STAT_AL_OFFSET 0x14u +#define STAT_AL_MASK 0x20u +#define STAT_AL_SHIFT 5u + +/* Status register Busy(BUSY) bit */ +#define STAT_BUSY_OFFSET 0x14u +#define STAT_BUSY_MASK 0x40u +#define STAT_BUSY_SHIFT 6u + +/* Status register Ack received(RXACK) bit */ +#define STAT_RXACK_OFFSET 0x14u +#define STAT_RXACK_MASK 0x80u +#define STAT_RXACK_SHIFT 7u + + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_I2C_APB_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.c b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.c new file mode 100644 index 0000000..903f029 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.c @@ -0,0 +1,283 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * MI-V Soft IP fabric bare-metal driver for Mi-V PLIC module. This module is + * delivered as a part of Mi-V Extended Sub System(MIV_ESS). + * Please refer to miv_plic.h file for more information. + */ + +#include "miv_plic.h" + +/***************************************************************************//** + * Mi-V PLIC interrupt handler function declaration. + * These functions are called by the external interrupt handler of the MIV_RV32 + * core base on the PLIC source causing the interrupt. + */ +uint8_t Invalid_IRQHandler(void); +uint8_t MIV_PLIC_EXT0_IRQHandler(void); +uint8_t MIV_PLIC_EXT1_IRQHandler(void); +uint8_t MIV_PLIC_EXT2_IRQHandler(void); +uint8_t MIV_PLIC_EXT3_IRQHandler(void); +uint8_t MIV_PLIC_EXT4_IRQHandler(void); +uint8_t MIV_PLIC_EXT5_IRQHandler(void); +uint8_t MIV_PLIC_EXT6_IRQHandler(void); +uint8_t MIV_PLIC_EXT7_IRQHandler(void); +uint8_t MIV_PLIC_EXT8_IRQHandler(void); +uint8_t MIV_PLIC_EXT9_IRQHandler(void); +uint8_t MIV_PLIC_EXT10_IRQHandler(void); +uint8_t MIV_PLIC_EXT11_IRQHandler(void); +uint8_t MIV_PLIC_EXT12_IRQHandler(void); +uint8_t MIV_PLIC_EXT13_IRQHandler(void); +uint8_t MIV_PLIC_EXT14_IRQHandler(void); +uint8_t MIV_PLIC_EXT15_IRQHandler(void); +uint8_t MIV_PLIC_EXT16_IRQHandler(void); +uint8_t MIV_PLIC_EXT17_IRQHandler(void); +uint8_t MIV_PLIC_EXT18_IRQHandler(void); +uint8_t MIV_PLIC_EXT19_IRQHandler(void); +uint8_t MIV_PLIC_EXT20_IRQHandler(void); +uint8_t MIV_PLIC_EXT21_IRQHandler(void); +uint8_t MIV_PLIC_EXT22_IRQHandler(void); +uint8_t MIV_PLIC_EXT23_IRQHandler(void); +uint8_t MIV_PLIC_EXT24_IRQHandler(void); +uint8_t MIV_PLIC_EXT25_IRQHandler(void); +uint8_t MIV_PLIC_EXT26_IRQHandler(void); +uint8_t MIV_PLIC_EXT27_IRQHandler(void); +uint8_t MIV_PLIC_EXT28_IRQHandler(void); +uint8_t MIV_PLIC_EXT29_IRQHandler(void); +uint8_t MIV_PLIC_EXT30_IRQHandler(void); + +/***************************************************************************//** + * MIV_PLIC interrupt handler for external interrupts. + * The array of the function pointers pointing to the weak handler of the Mi-V + * PLIC interrupt handlers. + * These functions are called by the external interrupt handler of the MIV_RV32 + * core base on the PLIC source causing the interrupt. + */ +uint8_t (* const ext_irq_handler_table[32]) (void) = +{ + Invalid_IRQHandler, + MIV_PLIC_EXT0_IRQHandler, + MIV_PLIC_EXT1_IRQHandler, + MIV_PLIC_EXT2_IRQHandler, + MIV_PLIC_EXT3_IRQHandler, + MIV_PLIC_EXT4_IRQHandler, + MIV_PLIC_EXT5_IRQHandler, + MIV_PLIC_EXT6_IRQHandler, + MIV_PLIC_EXT7_IRQHandler, + MIV_PLIC_EXT8_IRQHandler, + MIV_PLIC_EXT9_IRQHandler, + MIV_PLIC_EXT10_IRQHandler, + MIV_PLIC_EXT11_IRQHandler, + MIV_PLIC_EXT12_IRQHandler, + MIV_PLIC_EXT13_IRQHandler, + MIV_PLIC_EXT14_IRQHandler, + MIV_PLIC_EXT15_IRQHandler, + MIV_PLIC_EXT16_IRQHandler, + MIV_PLIC_EXT17_IRQHandler, + MIV_PLIC_EXT18_IRQHandler, + MIV_PLIC_EXT19_IRQHandler, + MIV_PLIC_EXT20_IRQHandler, + MIV_PLIC_EXT21_IRQHandler, + MIV_PLIC_EXT22_IRQHandler, + MIV_PLIC_EXT23_IRQHandler, + MIV_PLIC_EXT24_IRQHandler, + MIV_PLIC_EXT25_IRQHandler, + MIV_PLIC_EXT26_IRQHandler, + MIV_PLIC_EXT27_IRQHandler, + MIV_PLIC_EXT28_IRQHandler, + MIV_PLIC_EXT29_IRQHandler, + MIV_PLIC_EXT30_IRQHandler +}; + +/* Mi-V PLIC interrupt weak handlers */ +__attribute__((weak)) uint8_t Invalid_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT0_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT1_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT2_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT3_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT4_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT5_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT6_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT7_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT8_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT9_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT10_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT11_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT12_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT13_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT14_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT15_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT16_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT17_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT18_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT19_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT20_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT21_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT22_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT23_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT24_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT25_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT26_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT27_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT28_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT29_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t MIV_PLIC_EXT30_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +/*-------------------------------------------------------------------------*//** + * Please refer to miv_plic.h for more information about this function. +*/ +void +MIV_PLIC_isr +( + miv_plic_instance_t *this_plic +) +{ + unsigned long hart_id = read_csr(mhartid); + + /* claim the interrupt from PLIC controller */ + + uint32_t int_num = HAL_get_32bit_reg(this_plic->base_addr + + (0x1000 * hart_id), INT_CLAIM_COMPLETE); + + uint8_t disable = EXT_IRQ_KEEP_ENABLED; + disable = ext_irq_handler_table[int_num](); + + /* Indicate the PLIC controller that the interrupt is processed and claim is + * complete. */ + HAL_set_32bit_reg(this_plic->base_addr + + (0x1000 * hart_id), INT_CLAIM_COMPLETE, int_num); + + if (EXT_IRQ_DISABLE == disable) + { + MIV_PLIC_disable_irq(this_plic, (miv_plic_irq_num_t)int_num); + } +} diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.h b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.h new file mode 100644 index 0000000..f5d64cd --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic.h @@ -0,0 +1,425 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * PLIC module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(ESS). + */ + /*=========================================================================*//** + @mainpage Mi-V PLIC Bare Metal Driver + + ============================================================================== + Introduction + ============================================================================== + The Mi-V driver provides a set of functions for controlling the Mi-V PLIC + (platform level interrupt controller) soft-IP module. This module is delivered + as a part of the MIV_ESS. The PLIC multiplexes external interrupt signals into + a single interrupt signal that is connected to an external interrupt of the + processor. + + The major features provided by the driver are: + - Support for configuring the PLIC instances. + - Enabling and Disabling interrupts + - Interrupt Handling + + This driver can be used as part of a bare metal system where no operating + system is available. The driver can be adapted for use as part of an + operating system, but the implementation of the adaptation layer between the + driver and the operating system's driver model is outside the scope of this + driver. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + The application software should initialize the Mi-V PLIC through the call to + the MIV_PLIC_init() function for Mi-V PLIC instance in the design. + + No Mi-V PLIC hardware configuration parameters are used by the driver, apart + from the Mi-V PLIC base address. Hence, no additional configuration files + are required to use the driver. + + ============================================================================== + Theory of Operation + ============================================================================== + The operation of Mi-V PLIC driver is divided into following steps: + - Initialization + - Enabling and Disabling interrupts + - Interrupt control + + -------------------------------------------- + Initialization + -------------------------------------------- + The Mi-V PLIC module is first initialized by the call to MIV_PLIC_init(). This + function takes a pointer to the Mi-V PLIC instance data structure and the base + address of the Mi-V PLIC instance is defined by the hardware design. The + instance data structure is used to store the base address of the Mi-V PLIC + module and a pointer to the Mi-V PLIC register data structure. The Mi-V PLIC + register data structure maps the address of the Mi-V PLIC registers. + + --------------------------------------------- + Enabling and Disabling interrupts + --------------------------------------------- + The MIV_PLIC_enable_irq() function enables the specific interrupt provided by + user. A call to this function will allow the enabling of each of the global + interrupts corresponding to the bit in the interrupt enable register of Mi-V + PLIC. + The MIV_PLIC_disable_irq() function disables the specific interrupt provided + by the user. This function can be used to disable the interrupts from outside + of the external interrupt handler. + + ---------------------------------------- + Interrupt Control + ---------------------------------------- + When an interrupt occurs on an enabled interrupt, the PLIC gateway captures + the interrupt and asserts the corresponding interrupt pending bit. Once + the enable bit and pending bit are asserted, then the PLIC_IRQ signal asserts + until the interrupt is claimed by the driver interrupt handler MIV_PLIC_irq() + function. + When multiple interrupts assert then the lowest interrupt number will be + serviced first, for example, if interrupt 1 and 6 assert at the same time, + interrupt 1 will be serviced first, followed by interrupt 6. + +*/ + +#ifndef MIV_PLIC_H_ +#define MIV_PLIC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "miv_plic_regs.h" + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#include "miv_rv32_hal/miv_rv32_hal.h" +#else +#include "hal.h" +#include "miv_rv32_hal.h" +#endif + +/*-------------------------------------------------------------------------*//** + This enumeration is used to select a specific Mi-V PLIC interrupt. It is + used as a parameter to enable or disable the interrupt. +*/ +typedef enum miv_plic_irq_num +{ + NoInterrupt_IRQn = 0, + MIV_PLIC_EXT0_IRQn = 1, + MIV_PLIC_EXT1_IRQn = 2, + MIV_PLIC_EXT2_IRQn = 3, + MIV_PLIC_EXT3_IRQn = 4, + MIV_PLIC_EXT4_IRQn = 5, + MIV_PLIC_EXT5_IRQn = 6, + MIV_PLIC_EXT6_IRQn = 7, + MIV_PLIC_EXT7_IRQn = 8, + MIV_PLIC_EXT8_IRQn = 9, + MIV_PLIC_EXT9_IRQn = 10, + MIV_PLIC_EXT10_IRQn = 11, + MIV_PLIC_EXT11_IRQn = 12, + MIV_PLIC_EXT12_IRQn = 13, + MIV_PLIC_EXT13_IRQn = 14, + MIV_PLIC_EXT14_IRQn = 15, + MIV_PLIC_EXT15_IRQn = 16, + MIV_PLIC_EXT16_IRQn = 17, + MIV_PLIC_EXT17_IRQn = 18, + MIV_PLIC_EXT18_IRQn = 19, + MIV_PLIC_EXT19_IRQn = 20, + MIV_PLIC_EXT20_IRQn = 21, + MIV_PLIC_EXT21_IRQn = 22, + MIV_PLIC_EXT22_IRQn = 23, + MIV_PLIC_EXT23_IRQn = 24, + MIV_PLIC_EXT24_IRQn = 25, + MIV_PLIC_EXT25_IRQn = 26, + MIV_PLIC_EXT26_IRQn = 27, + MIV_PLIC_EXT27_IRQn = 28, + MIV_PLIC_EXT28_IRQn = 29, + MIV_PLIC_EXT29_IRQn = 30, + MIV_PLIC_EXT30_IRQn = 31 +} miv_plic_irq_num_t; + +/*--------------------------------------------------------------------------*//* + * This structure maps the priority threshold and claim complete register in + * the memory. + */ +typedef struct +{ + volatile uint32_t PRIORITY_THRESHOLD; + volatile uint32_t CLAIM_COMPLETE; + volatile uint32_t reserved[1022]; +} IRQ_Target_Type; + +/*--------------------------------------------------------------------------*//* + * This structure maps the Interrupt enable sources from 0 - 1023 for one + * context. + */ +typedef struct +{ + volatile uint32_t ENABLES[32]; +} Target_Enables_Type; + +/*-------------------------------------------------------------------------*//** + This structure holds the base address of the Mi-V PLIC module. This structure + is used by all the functions to access the Mi-V PLIC registers. +*/ +typedef struct miv_plic_instance +{ + addr_t base_addr; +} miv_plic_instance_t; + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_isr is the top level interrupt handler function for the Mi-V PLIC + * driver. You must call the MIV_PLIC_isr() from the system level interrupt + * handler(External_IRQHandler). + * This function must be called from the external interrupt handler function + * provided by the processor hardware abstraction layer. In case of MIV_RV32 + * soft processor, it must be called from External_IRQHandler() function + * provided by MIV_RV32 HAL. + * + * The MIV_PLIC_isr() function claims the interrupt number + * that triggered the interrupt and then invokes the appropriate PLIC interrupt + * handler. + * After handling the PLIC interrupt, this function will complete the interrupt + * by clearing the claim complete bit for the particular interrupt source. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * + * @return + * This function does not return any value. + * + * Example: + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * uint8_t MIV_PLIC_EXT0_IRQHandler(void) + * { + * *** ISR operation *** + * + * return(EXT_IRQ_KEEP_ENABLED); + * } + * + * void External_IRQHandler(void) + * { + * uint32_t reg_val = read_csr(mip); + * MIV_PLIC_isr(&g_plic); + * } + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * } + * @endcode + */ +void MIV_PLIC_isr(miv_plic_instance_t *this_plic); + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_init() function initializes the Mi-V PLIC instance with base + * address. This function resets the PLIC controller by disabling all the PLIC + * interrupts. + * + * Note: This function must be called before calling any other Mi-V PLIC driver + * function. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * + * @param base_addr + * Base address of the Mi-V PLIC instance in the MIV_ESS soft-IP. + * + * @param ext_intr_sources + * Number of interrupts initialized in the design. + * + * @return + * This function does not return any value. + * + * Example + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * } + * @endcode + */ +static inline void +MIV_PLIC_init +( + miv_plic_instance_t *this_plic, + addr_t base_addr, + uint8_t ext_intr_sources +) +{ + uint32_t inc; + unsigned long hart_id = read_csr(mhartid); + + this_plic->base_addr = base_addr; + + /* Disable all interrupts for the current hart. + * The PLIC_EXT_INTR_SOURCES should be defined in the hw_platform.h. This + * macro holds the number of PLIC interrupts enabled in the design. + */ + for(inc = 0; inc < ((ext_intr_sources + 32u) / 32u); ++inc) + { + HAL_set_32bit_reg( + (this_plic->base_addr + inc + (hart_id * 128)), INT_ENABLE , 0x0u); + } +} + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_enable_irq() function enables the PLIC interrupt provided with + * IRQn parameter. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * @param IRQn + * Number of PLIC interrupt to enable. + * + * @return + * This function does not return any value. + * + * Example + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * } + * @endcode + */ +static inline void +MIV_PLIC_enable_irq +( + miv_plic_instance_t *this_plic, + miv_plic_irq_num_t IRQn +) +{ + unsigned long hart_id = read_csr(mhartid); + + uint32_t current = HAL_get_32bit_reg( + (this_plic->base_addr + (IRQn/32) + (hart_id * 128)) , INT_ENABLE); + + current |= (uint32_t)1 << (IRQn % 32); + + HAL_set_32bit_reg( + (this_plic->base_addr + (IRQn/32) + (hart_id * 128)), INT_ENABLE, current); + +} + +/*-------------------------------------------------------------------------*//** + * The MIV_PLIC_disable_irq() function disables the PLIC interrupt provided with + * IRQn parameter. + * + * NOTE: + * This function can be used to disable the PLIC interrupt from outside the + * external interrupt handler functions. + * If you wish to disable the PLIC interrupt from the external interrupt handler, + * you should use the return value of EXT_IRQ_DISABLE. This will disable the + * selected PLIC interrupt from the Mi-V PLIC driver interrupt handler. + * + * @param this_plic + * A pointer to the miv_plic_instance_t data structure which + * will hold all the data related to the Mi-V PLIC instance + * being used. A pointer to this data structure is passed to + * rest of Mi-V PLIC driver functions for operation. + * @param IRQn + * Number of PLIC interrupt to disable. + * + * @return + * This function does not return any value. + * + * Example + * @code + * #define MIV_PLIC_BASE_ADDR 0x70000000 + * #define PLIC_EXT_INTR_SOURCES 31 + * + * miv_plic_instance_t g_plic; + * + * void main(void) + * { + * MIV_PLIC_init(&g_plic, MIV_PLIC_BASE_ADDR, PLIC_EXT_INTR_SOURCES); + * + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_enable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT0_IRQn); + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT1_IRQn); + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT2_IRQn); + * MIV_PLIC_disable_irq(&g_plic, MIV_PLIC_EXT3_IRQn); + * } + * @endcode + */ +static inline void +MIV_PLIC_disable_irq +( + miv_plic_instance_t *this_plic, + miv_plic_irq_num_t IRQn +) +{ + unsigned long hart_id = read_csr(mhartid); + + uint32_t current = HAL_get_32bit_reg((this_plic->base_addr + (IRQn/32) + (hart_id * 128)) , INT_ENABLE); + + current &= ~((uint32_t)1 << (IRQn % 32)); + + HAL_set_32bit_reg((this_plic->base_addr + (IRQn/32) + (hart_id * 128)), INT_ENABLE, current); + +} + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_PLIC_H_ */ diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic_regs.h b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic_regs.h new file mode 100644 index 0000000..76cbc0b --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_plic/miv_plic_regs.h @@ -0,0 +1,31 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP PLIC module driver. This module is delivered as a part of Mi-V extended + * Sub-System(MIV_ESS). + */ + +#ifndef MIV_PLIC_REGISTERS +#define MIV_PLIC_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Interrupt pending register offset */ +#define INT_PENDING_REG_OFFSET 0x1000u + +/* Interrupt enable register */ +#define INT_ENABLE_REG_OFFSET 0x2000u + +/* Interrupt claim complete register */ +#define INT_CLAIM_COMPLETE_REG_OFFSET 0x200004u + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_PLIC_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_timer/miv_timer.h b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_timer/miv_timer.h new file mode 100644 index 0000000..5f00889 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_timer/miv_timer.h @@ -0,0 +1,329 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Mi-V Timer Soft IP bare-metal driver. This module is delivered as part of + * the Mi-V Extended Sub System(ESS) MIV_ESS. + */ + +/*=========================================================================*//** + @mainpage Mi-V Timer Bare Metal Driver. + The Mi-V Timer bare metal software driver supports the timer module which + serves as a system timer for the Mi-V Extended Sub System(ESS). + + @section intro_sec Introduction + The MI-V Timer driver supports set of functions for controlling the Mi-V + Timer module. + The Mi-V Timer can generate a timer interrupt signal for the system based on + special system clock intervals specified by the parameters that can be passed + in by the user. + + The major features provided by Mi-V Timer driver are: + - Support for Mi-V Timer instance for each Mi-V Timer peripheral. + - Read current time + - Write to the machine time compare register + + @section hw_dependencies Hardware Flow dependency + The application should configure the Mi-V Timer driver through calls to + MIV_TIMER_init() functions for each MIV_TIMER instance in the hardware + design. The configuration parameter include the MIV_TIMER hardware instance, + base address and number of ticks to generate timer interrupt. + + MIV_RV32 core offers flexibility in terms of generating the MTIME and MTIMECMP + registers internal to the core or using external time reference. + When MIV_ESS is interfaced with MIV_RV32 core, the timer module in the MIV_ESS + can be configured as follows: + - Internal MTIME External MTIME IRQ + Generate the MTIME internally(MIV_RV32) and have a timer interrupt input + to the core as external pin(from MIV_ESS). + + - External MTIME Internal MTIME IRQ + Generate the time value externally(from MIV_ESS), in this case a 64-bit + port will open in the MIV_RV32 core as input and MIV_ESS will output the + 64-bit TIME_COUNT value. The generation of mtimecmp and interrupt is + done internally(MIV_RV32). + + - External MTIME External MTIME IRQ + Generate both the time and timer interrupt externally. + In this case 64-bit port will be available on the Mi-V RV32 core as input + and a 1 pin port will be available for timer interrupt. + + The design must be configured accordingly to use these combinations in the + firmware. + + No MIV_TIMER hardware configuration parameters are used by the driver, apart + from MIV_TIMER base address. Hence, no additional configuration files are + required to use the driver. + + @section theory_op Theory of Operation + + The MIV_TIMER module is a simple systick timer which can generate a timer + interrupt signal for the system at specific intervals specified by the + parameters that can be passed by the user. + These interrupt signal are then fed to the MIV_RV32 core via timer interrupt. + + The operation of MIV_TIMER is divided into following steps: + - Initialization + - Configuration + - Read/Write TIME + + ## Initialization + The MIV_TIMER is first initialized by a call to MIV_TIMER_init(). This + function initializes the instance of Mi-V TIMER with the base address. + The MIV_TIMER_init() function must be called before any other Mi-V Timer driver + function. + + ## Configuration + The Mi-V TIMER configuration includes writing the mtimecmp register with the + initial time value at which timer interrupt should be generated. + When the mtime register value becomes greater than or equal to mtimecmp value, + a timer interrupt signal(TIMER_IRQ) is generated. + + ## Read/Write TIME + The time value can be read by reading the mtime register via call to the + MIV_TIMER_read_mtime(). This function reads the MTIME register which contains + the 64-bit value of the timer count. The count increments by 1 every time the + prescale ticks. This function returns 64-bit MTIME_COUNT value which is the + current value of timer count. + + The time value read in the MIV_TIMER_read_mtime() function can be written to + the mtimecmp register by calling MIV_TIMER_write_mtimecmp() to generate + periodic interrupts. + The writing of the mtimecmp register should be done in the systick_handler() + function. + */ + +#ifndef MIV_TIMER_H_ +#define MIV_TIMER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#endif +/*-------------------------------------------------------------------------*//** +MIV_TIMER_SUCCESS +===================== + +The MIV_TIMER_SUCCESS constant indicates successful configuration of +Mi-V Timer module. +*/ +#define MIV_TIMER_SUCCESS 0u + +/*-------------------------------------------------------------------------*//** +MIV_TIMER_ERROR +===================== + +The MIV_TIMER_ERROR constant indicates that there is an error with +configuring the Mi-V Timer module. +*/ +#define MIV_TIMER_ERROR 1u + +/*-------------------------------------------------------------------------*//* +MIV_TIMER_MASK_32BIT +===================== + +32-bit mask constant used in calculation of 64-bit register value. +*/ +#define MIV_TIMER_MASK_32BIT 0xFFFFFFFFu + +/*-------------------------------------------------------------------------*//* +Mi-V Timer register offsets +===================== +The MTIMECMP is the 64-bit timer compare register, it pre-sets the threshold +which needs to be reached by the timer count register. +This 64-bit register is accessed with 2 32-bit address offset, lower 32-bits +and higher 32-bits. + - MIV_TIMER_MTIMECMP_L_REG_OFFSET + - MIV_TIMER_MTIMECMP_H_REG_OFFSET + +The MTIME is the 64-bit register that contains the 64-bit timer count. The +count increments by 1 every time the prescaler ticks. +This 64-bit register is accessed with 2 32-bit address offset, lower 32-bits +and higher 32-bits. + - MIV_TIMER_MTIME_L_REG_OFFSET + - MIV_TIMER_MTIME_H_REG_OFFSET + +The PRESCALE register is used to determine the amount of clock cycles the +selected clock needs to go through, for MTIME register to increment count. + - MIV_TIMER_PRESCALAR_REG_OFFSET +*/ + +/// @cond private +#define MIV_TIMER_MTIMECMP_L_REG_OFFSET 0x4000u +#define MIV_TIMER_MTIMECMP_H_REG_OFFSET 0x4004u + +#define MIV_TIMER_MTIME_L_REG_OFFSET 0xBFF8u +#define MIV_TIMER_MTIME_H_REG_OFFSET 0xBFFCu + +#define MIV_TIMER_PRESCALAR_REG_OFFSET 0x5000u +/// @endcond + +/*-------------------------------------------------------------------------*//** + This structure holds the base address of the Mi-V Timer module and instance + of the Mi-V Timer register structure. +*/ +typedef struct miv_timer_instance +{ + addr_t base_addr; +} miv_timer_instance_t; + +/** The MIV_TIMER_init() is used to initialize the Mi-V Timer module. This + function will assign the base addresses of the Mi-V Timer module. + User should call this function before calling any of the Mi-V Timer driver + APIs. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @param base_address + Base address of the Mi-V Timer module. + + @return + This function does not return any value. + */ +static inline void +MIV_TIMER_init +( + miv_timer_instance_t* this_timer, + addr_t base_addr +) +{ + this_timer->base_addr = base_addr; +} + +/** MIV_TIMER_read_current_time() is used to read the mtimecmp register values. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @return + This function returns 64-bit mtimecmp register value. + */ +static inline uint64_t +MIV_TIMER_read_current_time +( + miv_timer_instance_t* this_timer +) +{ + volatile uint64_t read_data = 0u; + volatile uint32_t mtime_hi = 0u; + volatile uint32_t mtime_lo = 0u; + + /* when mtime lower word is 0xFFFFFFFF, there will be rollover and + * returned value could be wrong. */ + do { + mtime_hi = HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIME_H); + mtime_lo = HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIME_L); + + } while(mtime_hi != HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIME_H)); + + read_data = mtime_hi; + + return(((read_data) << 32u) | mtime_lo); +} + +/** MIV_TIMER_write_compare_time() is used to write to the MTIMECMP register in + the event of interrupt. User must use this function in the interrupt handler + to de-assert the MIV_TIMER interrupt. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @param write_value + Value to write into the mtimecmp register. + + @return + This function does not return any value. + */ +static inline void +MIV_TIMER_write_compare_time +( + miv_timer_instance_t* this_timer, + uint64_t compare_reg_value +) +{ + HAL_set_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIMECMP_H, MIV_TIMER_MASK_32BIT); + + HAL_set_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIMECMP_L, + (compare_reg_value & MIV_TIMER_MASK_32BIT)); + + HAL_set_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIMECMP_H, + ((compare_reg_value >> 32u) & MIV_TIMER_MASK_32BIT)); +} + +/** The MIV_TIMER_config() is used to configure the MIV_ESS Timer module. The + prescale value serves to divide the count of clock cycles for the timer and + provides control over what point in time, the timer interrupt gets + asserted. + + @param this_timer + Timer structure which holds the base address for the Mi-V Timer hardware + instance. + + @param ticks + Number of ticks after which interrupt will be generated. + + @return + This function returns Mi-V Timer configuration status. + */ +static inline uint32_t +MIV_TIMER_config +( + miv_timer_instance_t* this_timer, + uint64_t ticks +) +{ + uint32_t ret_val = MIV_TIMER_ERROR; + uint64_t mtime_val = 0u; + uint32_t prescalar = 0u; + uint64_t miv_timer_increment = 0U; + + prescalar = HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_PRESCALAR); + + miv_timer_increment = (uint64_t)(ticks) / prescalar; + + if (miv_timer_increment > 0U) + { + mtime_val = MIV_TIMER_read_current_time(this_timer); + + MIV_TIMER_write_compare_time(this_timer ,(mtime_val + miv_timer_increment)); + + ret_val = MIV_TIMER_SUCCESS; + } + + return ret_val; +} + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_TIMER_H */ diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c new file mode 100644 index 0000000..cbd9652 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c @@ -0,0 +1,109 @@ +/******************************************************************************* + * (c) Copyright 2022-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Mi-V uDMA Soft IP bare-metal driver. This module is delivered as part of + * Mi-V Extended Sub System(MIV_ESS) + */ + +#include "miv_udma_regs.h" +#include "miv_udma.h" + +/***************************************************************************//** + * MIV_uDMA_init() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_init +( + miv_udma_instance_t* this_udma, + addr_t base_addr +) +{ + /* Assign the Mi-V uDMA base address to the uDMA instance structure */ + this_udma->base_address = base_addr; +} + +/***************************************************************************//** + * MIV_uDMA_config() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_config +( + miv_udma_instance_t* this_udma, + addr_t src_addr, + addr_t dest_addr, + uint32_t transfer_size, + uint32_t irq_config +) +{ + /* Source memory start address */ + HAL_set_32bit_reg(this_udma->base_address, SRC_START_ADDR, src_addr); + + /* Destination memory start address */ + HAL_set_32bit_reg(this_udma->base_address, DEST_START_ADDR, dest_addr); + + /* Data transfer size */ + HAL_set_32bit_reg(this_udma->base_address, BLK_SIZE, transfer_size); + + /* Configure the uDMA IRQ */ + HAL_set_32bit_reg(this_udma->base_address, IRQ_CFG, irq_config); +} + +/***************************************************************************//** + * MIV_uDMA_start() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_start +( + miv_udma_instance_t* this_udma +) +{ + /* Start the uDMA transfer */ + HAL_set_32bit_reg(this_udma->base_address, CONTROL_SR, CTRL_START_TX_MASK); +} + +/***************************************************************************//** + * MIV_uDMA_reset() + * See "miv_udma.h" for details of how to use this function. + */ +void +MIV_uDMA_reset +( + miv_udma_instance_t* this_udma +) +{ + /* Toggle the uDMA_reset bit to reset the uDMA. + * Resetting the uDMA will clear all the configuration made by + * MIV_uDMA_config(). + * + * This function should be called from the interrupt handler to clear the + * IRQ. + */ + HAL_set_32bit_reg_field(this_udma->base_address, CTRL_RESET_TX, 0x1u); + HAL_set_32bit_reg_field(this_udma->base_address, CTRL_RESET_TX, 0x0u); +} + +/***************************************************************************//** + * MIV_uDMA_read_status() + * See "miv_udma.h" for details of how to use this function. + */ +uint32_t +MIV_uDMA_read_status +( + miv_udma_instance_t* this_udma +) +{ + uint32_t status = 0u; + + /* Read the status of the uDMA transfer. + * The transfer status register can be Error or Busy depending on the + * current uDMA transfer. + */ + status = HAL_get_32bit_reg(this_udma->base_address, TX_STATUS); + + return status; +} diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h new file mode 100644 index 0000000..efa8731 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h @@ -0,0 +1,290 @@ +/******************************************************************************* + * Copyright 2022-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * uDMA module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(MIV_ESS). + */ + +/*=========================================================================*//** + @mainpage Mi-V uDMA Bare Metal Driver. + The Mi-V uDMA bare metal software driver. + + @section intro_sec Introduction + The Mi-V uDMA driver provides a set of functions to control the Mi-V uDMA + module in the Mi-V Extended Subsystem (MIV_ESS) soft-IP. The Mi-V uDMA module + allows peripherals with AHB interfaces to transfer data independently of the + MIV_RV32 RISC-V processor. + + Following are the major features provided by the Mi-V uDMA driver: + - Initialization and configuration + - Start and reset the transaction + + This driver can be used as part of a bare metal system where no operating + system is available. The driver can be adapted for use as part of an + operating system, but the implementation of the adaptation layer between the + driver and the operating system's driver model is outside the scope of this + driver. + + @section hw_dependencies Hardware Flow Dependency + The application software should initialize and configure the Mi-V uDMA through + calling the MIV_uDMA_init() and MIV_uDMA_config() functions for each Mi-V + uDMA instance in the design. + + The uDMA can operate in two possible transfer configurations: + + - AHBL Read -> AHBL Write: + In this configuration, the uDMA reads data from the source memory over an + AHBL (mirrored main/initiator) read interface and writes data to the + destination memory over an AHBL (mirrored main/initiator) write interface. + + - AHBL Read -> TAS Write: + In this configuration, the uDMA reads data from the source memory over an + AHBL (mirrored main/initiator) read interface and writes data to the + destination memory over the TAS (mirrored main/initiator) write interface. + + Note: The AHBL Read -> TAS Write configuration is out of scope for this + driver. + + @section theory_op Theory of Operation + The uDMA module in the Mi-V Extended Sub System (MIV_ESS) is a single-channel + uDMA module that allows peripherals to perform read-write operations between + source and destination memory. The Mi-V uDMA driver is used in + interrupt-driven mode and uses the Mi-V uDMA IRQ signal to drive the + interrupt service routine (ISR), which signifies a transfer has completed. + The status is checked in the ISR to ensure the transfer is completed + successfully. + The reset operation in the ISR resets the Mi-V uDMA controller. Once the Mi-V + uDMA transfer is complete, Mi-V uDMA retires. To initiate another + transaction, Mi-V uDMA needs to be configured again. + + The operation of the Mi-V uDMA driver is divided into the following + categories: + - Initialization + - Configuration + - Start and reset the transfer + + Initialization and configuration: + Mi-V uDMA is first initialized by calling MIV_uDMA_init() function. This + function initializes the instance of Mi-V uDMA with the base address. The + MIV_uDMA_init() function must be called before calling any other Mi-V uDMA + driver functions. + + The Mi-V uDMA is configured by calling MIV_uDMA_config() function. This + function configures the source_addr and dest_addr registers of the Mi-V + uDMA with source and destination addresses for Mi-V uDMA transfers. + This function also configures the transfer size and interrupt preference for + successful transfers using Mi-V uDMA. + + Start and reset the transfer: + Once the Mi-V uDMA is configured, initiate the transfers by calling the + MIV_uDMA_start() function. Once the Mi-V uDMA transfer is started, it cannot + be aborted, and the status of the transfer should be read from the ISR by + calling the MIV_uDMA_read_status() function. + + Reset the Mi-V uDMA to the default state by calling the MIV_uDMA_reset() + function. After performing the reset operation, reconfigure the Mi-V uDMA to + perform transfers as MIV_uDMA_reset() resets the Mi-V uDMA controller. + */ + +#ifndef MIV_uDMA_H_ +#define MIV_uDMA_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#include "hal/cpu_types.h" + +#else +#include "hal.h" +#include "cpu_types.h" +#endif + +/*-------------------------------------------------------------------------*//** + MIV_uDMA_CTRL_IRQ_CONFIG + ===================== + + The MIV_uDMA_CTRL_IRQ_CONFIG macro is used to assert the uDMA IRQ when an error + occurs during a uDMA transfer or on the completion of a uDMA transfer. + */ +#define MIV_uDMA_CTRL_IRQ_CONFIG 1u + +/*-------------------------------------------------------------------------*//** + MIV_uDMA_STATUS_BUSY + ===================== + + The MIV_uDMA_STATUS_BUSY macro is used to indicate that the uDMA transfer is + in progress. + */ +#define MIV_uDMA_STATUS_BUSY 1u + +/*-------------------------------------------------------------------------*//** + MIV_uDMA_STATUS_ERROR + ===================== + + The MIV_uDMA_STATUS_ERROR macro is used to indicate that the last uDMA + transfer has caused an error. + */ +#define MIV_uDMA_STATUS_ERROR 2u + +/***************************************************************************//** + * This structure holds the base of the Mi-V uDMA module, which is used in the + * other functions of the driver to access the uDMA registers. + */ +typedef struct miv_udma_instance +{ + addr_t base_address; +} miv_udma_instance_t; + +/***************************************************************************//** + * The MIV_uDMA_init() function assigns the base address of the Mi-V uDMA module + * to the uDMA instance structure. + * This address is used in a later part of the driver to access the uDMA + * registers. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure. + * + * @param base_addr + * Base address of the Mi-V uDMA module. + * + * @return + * This function does not return a value. + */ +void +MIV_uDMA_init +( + miv_udma_instance_t* this_udma, + addr_t base_addr +); + +/***************************************************************************//** + * The MIV_uDMA_config() function is used to configure the Mi-V uDMA controller. + * This function will set the source address, destination address, block size, + * and IRQ configuration register. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @param base_addr + * Base address of the Mi-V uDMA. + * + * @param src_addr + * Source address of memory from where the uDMA reads the data. + * + * @param dest_addr + * Destination address where the data is written from src_addr. + * + * @param transfer_size + * Number of 32-bit words to transfer. + * + * @param irq_config + * uDMA IRQ configuration + * - When set, the IRQ is asserted when an error occurs during a uDMA + * transfer or on the completion of the uDMA transfer. + * - When clear, the IRQ is only asserted when an error occurs during a + * uDMA transfer. + * + * @return + * This function does not return any value. + */ +void +MIV_uDMA_config +( + miv_udma_instance_t* this_udma, + addr_t src_addr, + addr_t dest_addr, + uint32_t transfer_size, + uint32_t irq_config +); + +/***************************************************************************//** + * The MIV_uDMA_start() function is used to start the uDMA transfer. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @return + * This function does not return any value. + */ +void +MIV_uDMA_start +( + miv_udma_instance_t* this_udma +); + +/***************************************************************************//** + * The MIV_uDMA_reset() function is used to clear the uDMA interrupt and reset + * the uDMA transfer. + * + * This function should be called from the interrupt handler to reset the values + * set during MIV_uDMA_config(). + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @return + * This function does not return any value. + */ +void +MIV_uDMA_reset +( + miv_udma_instance_t* this_udma +); + +/***************************************************************************//** + * The MIV_uDMA_read_status() function is used to read the status of the uDMA + * transfer. When interrupt is enabled, this function can be called from the + * interrupt handler to know the reason for a uDMA interrupt. + * + * @param this_udma + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. + * + * @return + * The return value indicates an error due to the busy status of the uDMA + * channel. + * + * |Bit Number| Name | Description | + * |----------|---------|------------------------------------------------------| + * | 0 | Busy | When set indicates that uDMA transfer is in progress| + * | 1 | Error | When set indicates that last uDMA transfer caused an| + * | | | error. | + */ +uint32_t +MIV_uDMA_read_status +( + miv_udma_instance_t* this_pdma +); + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_uDMA_H_ */ diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h new file mode 100644 index 0000000..14d0759 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h @@ -0,0 +1,94 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP uDMA module driver. This module is delivered as a part of Mi-V + * extended Sub-System(ESS) MIV_ESS. + */ + +#ifndef MIV_UDMA_APB_REGISTERS +#define MIV_UDMA_APB_REGISTERS 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/**************************************************************************//** + * Control start/Reset register details + */ + +#define CONTROL_SR_REG_OFFSET 0x0u + +/* Control start/Reset register bits */ +#define CONTROL_SR_OFFSET 0x00u +#define CONTROL_SR_MASK 0x03u +#define CONTROL_SR_SHIFT 0u + +/* uDMA Control Start Transfer */ + +#define CTRL_START_TX_OFFSET 0x00u +#define CTRL_START_TX_MASK 0x01u +#define CTRL_START_TX_SHIFT 0u + +/* uDMA Control Reset Transfer */ +#define CTRL_RESET_TX_OFFSET 0x00u +#define CTRL_RESET_TX_MASK 0x02u +#define CTRL_RESET_TX_SHIFT 1u + +/**************************************************************************//** + * IRQ Configuration register details + */ +#define IRQ_CFG_REG_OFFSET 0x4u + +/* Control start/Reset register bits */ +#define IRQ_CFG_OFFSET 0x04u +#define IRQ_CFG_MASK 0x01u +#define IRQ_CFG_SHIFT 0u + +/***************************************************************************//** + * Transfer Status register details + */ +#define TX_STATUS_REG_OFFSET 0x08u + +/* Transfer status register bits */ +#define TX_STATUS_OFFSET 0x08u +#define TX_STATUS_MASK 0x03u +#define TX_STATUS_SHIFT 0u + +/***************************************************************************//** + * Source Memory Start Address Register + */ +#define SRC_START_ADDR_REG_OFFSET 0x0cu + +/* Source Memory Start Address Register bits */ +#define SRC_START_ADDR_OFFSET 0x0cu +#define SRC_START_ADDR_MASK 0xFFFFFFFFu +#define SRC_START_ADDR_SHIFT 0u + +/***************************************************************************//** + * Destination Memory Start Address register details + */ +#define DEST_START_ADDR_REG_OFFSET 0x10u + +/* Destination Memory Start Address register bits */ +#define DEST_START_ADDR_OFFSET 0x10u +#define DEST_START_ADDR_MASK 0xFFFFFFFFu +#define DEST_START_ADDR_SHIFT 0x0u + +/***************************************************************************//** + * Block Size register details + */ +#define BLK_SIZE_REG_OFFSET 0x14u + +/* Destination Memory Start Address register bits */ +#define BLK_SIZE_OFFSET 0x14u +#define BLK_SIZE_MASK 0xFFFFFFFFu +#define BLK_SIZE_SHIFT 0x0u + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_UDMA_APB_REGISTERS */ diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c new file mode 100644 index 0000000..525928a --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Mi-V Watchdog Soft IP bare-metal driver. This module is delivered as part of + * Extended Sub System(ESS) MIV_ESS. + * Please refer to miv_watchdog.h file for more information. + */ + +#include "miv_watchdog.h" + +addr_t g_this_wdog; + +/***************************************************************************//* + * Please refer to miv_watchdog.h for more info about this function + */ +void +MIV_WDOG_init +( + addr_t base_addr +) +{ + /* Register the Mi-V Watchdog base address to the driver */ + g_this_wdog = base_addr; +} + +/***************************************************************************//* + * Please refer to miv_watchdog.h for more info about this function + */ +uint8_t MIV_WDOG_configure +( + const miv_wdog_config_t *config +) +{ + uint8_t error = 0u; + + /* check load value and trigger max value */ + if (config->timeout_val <= MIV_WDOG_TRIGGER_MAX) + { + HAL_set_32bit_reg(g_this_wdog, WDOGTRIG,(config->timeout_val)); + } + else + { + error = 1u; + } + + if (config->time_val <= MIV_WDOG_TIMER_MAX) + { + HAL_set_32bit_reg(g_this_wdog, WDOGMSVP,(config->mvrp_val)); + } + else + { + error = 1u; + } + + HAL_set_32bit_reg_field(g_this_wdog, WDOGCNTL_NEXT_ENFORBIDDEN, + config->forbidden_en); + + /* Reload watchdog with new load if it is not in forbidden window */ + if (!(WDOGSTAT_FORBIDDEN_MASK & (HAL_get_32bit_reg(g_this_wdog, WDOGSTAT)))) + { + HAL_set_32bit_reg(g_this_wdog, WDOGRFSH, MIV_WDOG_REFRESH_KEY); + } + else + { + error = 1u; + } + + return (error); +} + +/***************************************************************************//* + * Please refer to miv_watchdog.h for more info about this function + */ +void MIV_WDOG_get_config +( + miv_wdog_config_t *config +) +{ + if (0 != g_this_wdog) + { + + config->time_val = HAL_get_32bit_reg(g_this_wdog, WDOGTIME); + + config->timeout_val = HAL_get_32bit_reg(g_this_wdog, WDOGTRIG); + + config->mvrp_val = HAL_get_32bit_reg(g_this_wdog, WDOGMSVP); + + config->forbidden_en = HAL_get_32bit_reg_field(g_this_wdog, + WDOGCNTL_NEXT_ENFORBIDDEN); + } +} + diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h new file mode 100644 index 0000000..8877e55 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h @@ -0,0 +1,553 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * This file contains the application programming interface for the MI-V Soft IP + * Watchdog module driver. This module is delivered as a part of Mi-V Extended + * Sub-System(MIV_ESS). + */ +/*=========================================================================*//** + @mainpage MiV Watchdog Bare Metal Driver + + ============================================================================== + Introduction + ============================================================================== + The Mi-V Watchdog module in the MIV_ESS is used to generate a reset for the + system automatically if the software doesn't periodically update or refresh + the timer countdown register. This software driver provides set of functions + for controlling Mi-V Watchdog module as a part of bare metal system where no + operating system is available. The driver can be adapted for use as a part of + an operating system, but the implementation of the adaptation layer between + the driver and the operating system's driver model is outside the scope of the + driver. + + Mi-V Watchdog provides following features: + - Initializing the Mi-V Watchdog + - Reading current value and status of watchdog timer + - Refreshing the watchdog timer value + - Enabling, disabling and clearing timeout and Maximum Value up to which + Refresh is Permitted (MVRP) interrupts. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + The application software should initialize and configure the Mi-V Watchdog + module the the call to the MIV_WDOG_init() and MIV_WDOG_configure() functions. + + No MIV_WDOG hardware configuration parameter are used by the driver, apart + from the MIV_WDOG base address. Hence, no additional configuration files are + required to use the driver. + + ============================================================================== + Theory of Operation + ============================================================================== + The Mi-V Watchdog driver functions are grouped into the following categories: + - Initialization and configuration + - Reading the current value and status of the watchdog timer + - Refreshing the watchdog timer value + - Support for enabling, disabling and clearing time-out and MVRP interrupts. + + -------------------------------- + Initialization and Configuration + -------------------------------- + The MIV_WDOG_init() function stores the base of MIV_WDT module in the MIV_ESS. + This base address is used by rest of the functions to access the Mi-V Watchdog + registers. Please make call this function before calling any other function + from this driver. + Note: The Mi-V Watchdog driver supports only one instance of MIV_WDT in the + hardware. + The Mi-V Watchdog driver provides the MIV_WDOG_configure() function to + configure the MIV_WDOG module with desired configuration values. It also + provides the MIV_WDOG_get_config() to read back the current configuration of + the MIV_WDOG. You can use this function to retrieve the current configurations + and then overwrite them with the application specific values, such as initial + watchdog timer value, Maximum Value (up to which) Refresh (is) Permitted, + watchdog time-out value, enable/disable forbidden region, enable/disable + MVRP interrupt and interrupt type. + + -------------------------------------------- + Reading the Watchdog Timer Value and Status + -------------------------------------------- + Mi-V Watchdog is a down counter. A refresh forbidden window can be created by + configuring the watchdog Maximum Value up to which Refresh is Permitted (MVRP). + When the current value of the watchdog timer is greater than the MVRP value, + refreshing the watchdog is forbidden. Attempting to refresh the watchdog timer + in the forbidden window will assert a timeout interrupt. The + MIV_WDOG_forbidden_status() function can be used to know whether the watchdog + timer is in forbidden window or has crossed it. By default, the forbidden + window is disabled. It can be enabled by providing an appropriate value as + parameter to the MIV_WDOG_configure() function. When the forbidden window is + disabled, any attempt to refresh the watchdog timer is ignored and the counter + keeps on down counting. + + The current value of the watchdog timer can be read using the + MIV_WDOG_current_value() function. This function can be called at any time. + + -------------------------------------------- + Refreshing the Watchdog Timer Value + -------------------------------------------- + The watchdog timer value is refreshed using the MIV_WDOG_reload() function. + The value reloaded into the watchdog timer down-counter is specified at the + configuration time with an appropriate value as parameter to the + MIV_WDOG_get_config() function. + + -------------------------------------------- + Interrupt Control + -------------------------------------------- + The Mi-V Watchdog generates two interrupts, The MVRP interrupt and + the timeout interrupt. + The MVRP interrupt is generated when the watchdog down-counter crosses the + Maximum Value up to which Refresh is Permitted (MVRP). Following functions to + control MVRP interrupt: + - MIV_WDOG_enable_mvrp_irq + - MIV_WDOG_disable_mvrp_irq + - MIV_WDOG_clear_mvrp_irq + + The timeout interrupt is generated when the watchdog down-counter crosses the + watchdog timeout value. The timeout value is a non-zero value and it can be + set to a maximum of MIV_WDOG_TRIGGER_MAX. The non-maskable interrupt is + generated when the watchdog crosses this timeout value, the down counter + keeps on down counting and a reset signal is generated when reaches zero. + Following functions to control timeout interrupt: + - MIV_WDOG_enable_timeout_irq + - MIV_WDOG_disable_timeout_irq + - MIV_WDOG_clear_timeout_irq + +*//*=========================================================================*/ + +#ifndef MIV_WATCHDOG_H_ +#define MIV_WATCHDOG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "miv_watchdog_regs.h" + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" +#else +#include "hal.h" +#endif + +/****************************************************************************//* + * The following constants can be used to configure the Mi-V Watchdog where a + * zero or non-zero value such as enable or disable is to be provided as a input + * parameter as shown below: + */ +#define MIV_WDOG_ENABLE 1u +#define MIV_WDOG_DISABLE 0u + +/***************************************************************************//** + The miv_wdog_config_t type for the watchdog Configuration structure. This + type is used as a parameter for the MIV_WDOG_configure() and the + MIV_WDOG_get_config() functions. + + Following are the values as part of this structure +| Parameter | Description | +|------------------|-----------------------------------------------------------| +| time_val | The value from which the watchdog timer counts down | +| mvrp_val | The Watchdog MVRP value | +| timeout_val | The watchdog timeout value | +| forbidden_en | Enable/disable the forbidden window | +| | When set, if a refresh occurs in the forbidden window, | +| | the watchdog timeout interrupt will be generated. | + +Time calculation example: + + time_val = 0xFFFFF0u + mvrp_val = 0x989680u + timeout_val = 0x3e8u + + A prescaler = 256 is used. + Considering clock = 50Mhz + + The MVRP interrupt will happen after + (0xFFFFF0 - 0x989680) * ( 1/(50MHz/256)) + mvrp interrupt will happen after 34 sec. after system reset + + (0xFFFFF0 - 0x3e8) * ( 1/(50MHz/256)) + timeout interrupt will happen after 85 sec. after system reset + */ +typedef struct miv_wdog_config +{ + uint32_t time_val; + uint32_t mvrp_val; + uint32_t timeout_val; + uint32_t forbidden_en; + uint32_t intr_type; +}miv_wdog_config_t; + +extern addr_t g_this_wdog; + +/***************************************************************************//* + Internal constants and types +*******************************************************************************/ + +/// @cond private +#define MIV_WDOG_TRIGGER_MAX 4095u +#define MIV_WDOG_TIMER_MAX 16777200u +/// @endcond + +/*-------------------------------------------------------------------------*//* +MIV_WDOG_REFRESH_KEY +===================== + +The MIV_WDOG_REFRESH_KEY macro holds the magic value which will cause a +reload of the watchdog's down counter when written to the watchdog's +WDOGREFRESH register. +*/ +#define MIV_WDOG_REFRESH_KEY (uint32_t)0xDEADC0DEU + +/*-------------------------------------------------------------------------*//* +MIV_WDOG_FORCE_RESET_KEY +===================== +The MIV_WDOG_FORCE_RESET_KEY macro holds the magic value which will force a +reset if the watchdog is already timeout. Writing any other value or writing +TRIGGER register at other times will trigger the watchdog NMI sequence +(i.e raise a timeout interrupt) + */ +#define MIV_WDOG_FORCE_RESET_KEY (uint32_t)0xDEADU + +/***************************************************************************//** + * The MIV_WDOG_init() is used to register the Mi-V Watchdog module base + * address to the driver. + * + * Note: User should call this function before calling any other Mi-V watchdog + * driver function. + * + * @param base_addr + * The base address of the Mi-V watchdog module. This address is used by + * rest of the watchdog driver functions to access the registers. + * + * @return + * This function does not return any value. + */ +void +MIV_WDOG_init +( + addr_t base_addr +); + +/***************************************************************************//** + * The MIV_WDOG_get_config() function returns the current configurations of the + * Mi-V Watchdog. The Mi-V Watchdog is pre-initialized by the flash + * bits at the design time. When used for the first time before calling the + * MIV_WDOG_configure() function, this function will return the default + * configurations as configured at the design time. + * + * @param config + * The config parameter is used to store the current configuration of the Mi-V + * Watchdog. + * + * Please see the description of miv_wdog_config_t for details. + * + * @return + * This function does not return any value. + * + * Example: + */ +void +MIV_WDOG_get_config +( + miv_wdog_config_t* config +); + +/***************************************************************************//** + * The MIV_WDOG_configure() function configures the watchdog module. The + * Watchdog module is pre-initialized by the flash bits at the design time to the + * default values. You can reconfigure the Watchdog module using + * MIV_WDOG_configure() function. + * + * Note that the MIV_WDOG_configure() function can be used only once, as it + * writes into the TIME register. After a write into the TIME register, the TIME, + * TRIGGER and MSVP register values are frozen and can't be altered again unless + * a system reset happens. + * + * Note also that the Mi-V Watchdog is not enabled at reset, calling this function + * will start the watchdog, it cannot then be disabled and must be refreshed + * periodically. + * + * @param config + * The config parameter is the input parameter in which the configurations to + * be applied to the watchdog module are provided by the application. + * Please see the description of miv_wdog_config_t for details. + * + * @return + * This function returns a zero value when executed successfully. A non-zero + * value is returned when the configuration values are out of bound. + * + * Example: + */ +uint8_t +MIV_WDOG_configure +( + const miv_wdog_config_t * config +); + +/***************************************************************************//** + * The MIV_WDOG_reload() function causes the watchdog to reload its down-counter + * timer with the load value configured through interrupt handler. This function + * must be called regularly to avoid a system reset or a watchdog interrupt. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_reload +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg(g_this_wdog, WDOGRFSH, MIV_WDOG_REFRESH_KEY); + } +} + +/***************************************************************************//** + * The MIV_WDOG_current_value() function returns the current value of the + * watchdog's down-counter. + * + * @param + * Void + * + * @return + * This function returns the current value of the watchdog’s down-counter as + * a 32-bit unsigned integer. + */ +static inline uint32_t +MIV_WDOG_current_value +( + void +) +{ + return (HAL_get_32bit_reg(g_this_wdog, WDOGRFSH)); +} + +/***************************************************************************//** + * The MIV_WDOG_forbidden_status() function returns the refresh status of the + * Mi-V Watchdog. + * + * @param + * Void + * + * @return + * This function returns the refresh status of the watchdog. A value of 1 + * indicates that watchdog's down-counter is within the forbidden window and + * that a reload should not be done. A value of 0 indicates that the watchdog's + * down counter is within the permitted window and that a reload is allowed. + */ +static inline uint32_t +MIV_WDOG_forbidden_status +( + void +) +{ + return (HAL_get_32bit_reg_field(g_this_wdog, WDOGSTAT_FORBIDDEN)); +} + +/***************************************************************************//** + * The MIV_WDOG_enable_mvrp_irq() function enables the MVRP interrupt. + * This interrupt is asserted when the timer countdown register leaves the + * maximum value up to which refresh is permitted (MVRP) window. + * + * @param + * Void + * + * @return + * This function does not return a value. + * + * Example: + */ +static inline void +MIV_WDOG_enable_mvrp_irq +( + void +) +{ + + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGCNTL_NEXT_INTENT_MSVP, 0x01u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_disable_mvrp_irq() function disables the generation of the + * MVRP interrupt. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_disable_mvrp_irq +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGCNTL_NEXT_INTENT_MSVP, 0x0u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_clear_timeout_irq() function clears the watchdog’s timeout + * interrupt which is connected to the MIV-RV32 interrupt. Calling + * MIV_WDOG_clear_timeout_irq() results in clearing the MIV-RV32 interrupt. + * Note: You must call the MIV_WDOG_clear_timeout_irq() function as part of your + * implementation of the interrupt handler in order to prevent the same + * interrupt event re-triggering a call to the timeout ISR. + * + * @param + * Void + * + * @return + * This function does not return any value. + * + */ +static inline void +MIV_WDOG_clear_timeout_irq +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_WDOG_TRIPPED, 0x01u); + /* + * Perform a second write to ensure that the first write completed before + * returning from this function. This is to account for posted writes across + * the AHB matrix. The second write ensures that the first write has + * completed and that the interrupt line has been de-asserted by the time + * the function returns. Omitting the second write may result in a delay + * in the de-assertion of the interrupt line going to the RISC-V and a + * retriggering of the interrupt. + */ + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_WDOG_TRIPPED, 0x01u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_clear_mvrp_irq() function clears the mvrp interrupt. + * + * Note: You must call the MIV_WDOG_clear_mvrp_irq() function as part of your + * implementation of the interrupt service routine (ISR) in order to + * prevent the same interrupt event re-triggering a call to the mvrp ISR. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_clear_mvrp_irq +( + void +) +{ + if (0 != g_this_wdog) + { + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_MSVP_TRIPPED, 0x01u); + /* + * Perform a second write to ensure that the first write completed before + * returning from this function. This is to account for posted writes across + * the AHB matrix. The second write ensures that the first write has + * completed and that the interrupt line has been de-asserted by the time + * the function returns. Omitting the second write may result in a delay + * in the de-assertion of the interrupt line going to the RISC-V and a + * re-triggering of the interrupt. + */ + HAL_set_32bit_reg_field(g_this_wdog, WDOGSTAT_MSVP_TRIPPED, 0x01u); + } +} + +/***************************************************************************//** + * The MIV_WDOG_timeout_occured() function reports the occurrence of a timeout + * event. + * + * @param + * Void + * + * @return + * A zero value indicates no watchdog timeout event occurred. A value of 1 + * indicates that a timeout event occurred. + */ +static inline uint32_t +MIV_WDOG_timeout_occured +( + void +) +{ + return (HAL_get_32bit_reg_field(g_this_wdog, WDOGSTAT_TRIGGERED)); +} + +/***************************************************************************//** + * The MIV_WDOG_force_reset() function is used to force an immediate reset + * if the watchdog has already triggered. Writing any value in this condition + * will result in watchdog timeout. + * The time out interrupt WDOG_IRQ will be set to high and watchdog timer + * countdown register updated with watchdog trigger timeout register value. + * If the Watchdog has timed out, a special 16-bit value needs to be written + * to the register to force a reset on CPU_RESETN, 0xDEAD + * Then the Watchdog countdown is reset/updated with the top Watchdog Runtime + * register value. + * + * @param + * Void + * + * @return + * This function does not return a value. + */ +static inline void +MIV_WDOG_force_reset +( + void +) +{ + if (WDOGSTAT_TRIGGERED_MASK == + HAL_get_32bit_reg_field(g_this_wdog, WDOGSTAT_TRIGGERED)) + + { + HAL_set_32bit_reg(g_this_wdog, WDOGFORCE, MIV_WDOG_FORCE_RESET_KEY); + } + + else + { + HAL_set_32bit_reg(g_this_wdog, WDOGFORCE, 0x0u); + } +} + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_WATCHDOG_H_ */ diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h new file mode 100644 index 0000000..2fca983 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h @@ -0,0 +1,122 @@ + /******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * This file contains Register bit offsets and masks definitions for MI-V Soft + * IP watchdog module driver. This module is delivered as a part of Mi-V + * extended Sub-System(ESS) MIV_ESS. + */ + +#ifndef MIV_WDOG_REGISTERS +#define MIV_WDOG_REGISTERS 1u + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * Refresh register details + */ +#define WDOGRFSH_REG_OFFSET 0x00u + +/* Refresh register bits */ +#define WDOGRFSH_OFFSET 0x00u +#define WDOGRFSH_MASK 0xFFFFFFFFu +#define WDOGRFSH_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Control register details + */ +#define WDOGCNTL_REG_OFFSET 0x04u + +/* Control register next intent msvp bit */ +#define WDOGCNTL_NEXT_INTENT_MSVP_OFFSET 0x04u +#define WDOGCNTL_NEXT_INTENT_MSVP_MASK 0x01u +#define WDOGCNTL_NEXT_INTENT_MSVP_SHIFT 0u + +/* Control register next intent wdog bit */ +#define WDOGCNTL_NEXT_INTENT_WDOG_OFFSET 0x04u +#define WDOGCNTL_NEXT_INTENT_WDOG_MASK 0x02u +#define WDOGCNTL_NEXT_INTENT_WDOG_SHIFT 1u + +/* Control register next enforbidden bit */ +#define WDOGCNTL_NEXT_ENFORBIDDEN_OFFSET 0x04u +#define WDOGCNTL_NEXT_ENFORBIDDEN_MASK 0x10u +#define WDOGCNTL_NEXT_ENFORBIDDEN_SHIFT 4u + +/*------------------------------------------------------------------------------ + * Watchdog status register + */ +#define WDOGSTAT_REG_OFFSET 0x08u + +/* msvp_tripped bit */ +#define WDOGSTAT_MSVP_TRIPPED_OFFSET 0x08u +#define WDOGSTAT_MSVP_TRIPPED_MASK 0x01u +#define WDOGSTAT_MSVP_TRIPPED_SHIFT 0u + +/* WDOG Tripped bit */ +#define WDOGSTAT_WDOG_TRIPPED_OFFSET 0x08u +#define WDOGSTAT_WDOG_TRIPPED_MASK 0x02u +#define WDOGSTAT_WDOG_TRIPPED_SHIFT 1u + +/* Forbidden bit */ +#define WDOGSTAT_FORBIDDEN_OFFSET 0x08u +#define WDOGSTAT_FORBIDDEN_MASK 0x04u +#define WDOGSTAT_FORBIDDEN_SHIFT 2u + +/* Triggered bit */ +#define WDOGSTAT_TRIGGERED_OFFSET 0x08u +#define WDOGSTAT_TRIGGERED_MASK 0x08u +#define WDOGSTAT_TRIGGERED_SHIFT 3u + +/* wdoglocked bit */ +#define WDOGSTAT_WDOGLOCKED_OFFSET 0x08u +#define WDOGSTAT_WDOGLOCKED_MASK 0x10u +#define WDOGSTAT_WDOGLOCKED_SHIFT 4u + +/*------------------------------------------------------------------------------ + * Watchdog runtime register + */ +#define WDOGTIME_REG_OFFSET 0x0Cu + +/* wdogmsvp bit */ +#define WDOGTIME_WDOGVALUE_OFFSET 0x0Cu +#define WDOGTIME_WDOGVALUE_MASK 0xFFFFFFu +#define WDOGTIME_WDOGVALUE_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Watchdog MVRP register + */ +#define WDOGMSVP_REG_OFFSET 0x10u + +/* wdogmsvp bit */ +#define WDOGMSVP_OFFSET 0x10u +#define WDOGMSVP_MASK 0xFFFFFFu +#define WDOGMSVP_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Watchdog Trigger Timeout register + */ +#define WDOGTRIG_REG_OFFSET 0x14u + +/* wdogmsvp bit */ +#define WDOGTRIG_WDOGRST_OFFSET 0x14u +#define WDOGTRIG_WDOGRST_MASK 0xFFFFFFu +#define WDOGTRIG_WDOGRST_SHIFT 0u + +/*------------------------------------------------------------------------------ + * Watchdog Force Reset register details + */ +#define WDOGFORCE_REG_OFFSET 0x18u + +/* Refresh register bits */ +#define WDOGFORCE_OFFSET 0x18u +#define WDOGFORCE_MASK 0xFFFFFFFFu +#define WDOGFORCE_SHIFT 0u + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_WATCHDOG_REGS_H_ */ diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/hal/cpu_types.h b/applications/user-crypto/miv-rv32-rsa-services/src/platform/hal/cpu_types.h new file mode 100644 index 0000000..ef8ab20 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/hal/cpu_types.h @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file cpu_types.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Type definitions which can be commonly used by the fabric-ip drivers. + * + */ +#ifndef __CPU_TYPES_H +#define __CPU_TYPES_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned int size_t; + +/*------------------------------------------------------------------------------ + * addr_t: address type. + * Used to specify the address of peripherals present in the processor's memory + * map. + */ +typedef unsigned int addr_t; + +/*------------------------------------------------------------------------------ + * psr_t: processor state register. + * Used by HAL_disable_interrupts() and HAL_restore_interrupts() to store the + * processor's state between disabling and restoring interrupts. + */ +typedef unsigned int psr_t; + +#ifdef __cplusplus +} +#endif + +#endif /* CPU_TYPES_H */ + diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/hal/hal.h b/applications/user-crypto/miv-rv32-rsa-services/src/platform/hal/hal.h new file mode 100644 index 0000000..7eec17a --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/hal/hal.h @@ -0,0 +1,235 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file hal.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware abstraction layer functions for peripheral register accesses. + * + */ +#ifndef __HAL_H +#define __HAL_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include "cpu_types.h" +#include "hw_reg_access.h" +#include "hal_assert.h" +/***************************************************************************//** + * Enable all interrupts at the processor level. + */ +void HAL_enable_interrupts( void ); + +/***************************************************************************//** + * Disable all interrupts at the processor core level. + * Return the interrupts enable state before disabling occurred so that it can + * later be restored. + */ +psr_t HAL_disable_interrupts( void ); + +/***************************************************************************//** + * Restore the interrupts enable state at the processor core level. + * This function is normally passed the value returned from a previous call to + * HAL_disable_interrupts(). + */ +void HAL_restore_interrupts( psr_t saved_psr ); + +/***************************************************************************//** + */ +#define FIELD_OFFSET(FIELD_NAME) (FIELD_NAME##_OFFSET) +#define FIELD_SHIFT(FIELD_NAME) (FIELD_NAME##_SHIFT) +#define FIELD_MASK(FIELD_NAME) (FIELD_NAME##_MASK) + +/***************************************************************************//** + * The macro HAL_set_32bit_reg() allows writing a 32 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint32_t containing the value to write. + */ +#define HAL_set_32bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_32bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_32bit_reg() is used to read the value of a 32 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint32_t value. + */ +#define HAL_get_32bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_32bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)) )) + +/***************************************************************************//** + * The macro HAL_set_32bit_reg_field() is used to write a field within a + * 32 bits wide register. The field written can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * VALUE: A variable of type uint32_t containing the field value to write. + */ +#define HAL_set_32bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_32bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_32bit_reg_field() is used to read a register field from + * within a 32 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint32_t value. + */ +#define HAL_get_32bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_32bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +/***************************************************************************//** + * The macro HAL_set_16bit_reg() allows writing a 16 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint_fast16_t containing the value to write. + */ +#define HAL_set_16bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_16bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_16bit_reg() is used to read the value of a 16 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint16_t value. + */ +#define HAL_get_16bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_16bit_reg( (BASE_ADDR) + (REG_NAME##_REG_OFFSET) )) + +/***************************************************************************//** + * The macro HAL_set_16bit_reg_field() is used to write a field within a + * 16 bits wide register. The field written can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * VALUE: A variable of type uint16_t containing the field value to write. + */ +#define HAL_set_16bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_16bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_16bit_reg_field() is used to read a register field from + * within a 8 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint16_t value. + */ +#define HAL_get_16bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_16bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +/***************************************************************************//** + * The macro HAL_set_8bit_reg() allows writing a 8 bits wide register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to write. These strings are + * specified in a header file associated with the peripheral. + * VALUE: A variable of type uint_fast8_t containing the value to write. + */ +#define HAL_set_8bit_reg(BASE_ADDR, REG_NAME, VALUE) \ + (HW_set_8bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) + +/***************************************************************************//** + * The macro HAL_get_8bit_reg() is used to read the value of a 8 bits wide + * register. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * REG_NAME: A string identifying the register to read. These strings are + * specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint8_t value. + */ +#define HAL_get_8bit_reg(BASE_ADDR, REG_NAME) \ + (HW_get_8bit_reg( (BASE_ADDR) + (REG_NAME##_REG_OFFSET) )) + +/***************************************************************************//** + */ +#define HAL_set_8bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ + (HW_set_8bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME),\ + (VALUE))) + +/***************************************************************************//** + * The macro HAL_get_8bit_reg_field() is used to read a register field from + * within a 8 bit wide peripheral register. The field can be one or more bits. + * + * BASE_ADDR: A variable of type addr_t specifying the base address of the + * peripheral containing the register. + * FIELD_NAME: A string identifying the register field to write. These strings + * are specified in a header file associated with the peripheral. + * RETURN: This function-like macro returns a uint8_t value. + */ +#define HAL_get_8bit_reg_field(BASE_ADDR, FIELD_NAME) \ + (HW_get_8bit_reg_field(\ + (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ + FIELD_SHIFT(FIELD_NAME),\ + FIELD_MASK(FIELD_NAME))) + +#ifdef __cplusplus +} +#endif + +#endif /*HAL_H*/ + diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/hal/hal_assert.h b/applications/user-crypto/miv-rv32-rsa-services/src/platform/hal/hal_assert.h new file mode 100644 index 0000000..1e18b54 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/hal/hal_assert.h @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hal_assert.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief HAL assert functions + */ +#ifndef __HAL_ASSERT_HEADER +#define __HAL_ASSERT_HEADER 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Disable assertions if we do not recognize the compiler. */ +#if defined ( __GNUC__ ) +#if defined(NDEBUG) +/***************************************************************************//** + * HAL_ASSERT() is defined out when the NDEBUG symbol is used. + ******************************************************************************/ +#define HAL_ASSERT(CHECK) + +#else + +/***************************************************************************//** + * Default behavior for HAL_ASSERT() macro: + *------------------------------------------------------------------------------ + The behavior is toolchain specific and project setting specific. + ******************************************************************************/ +#define HAL_ASSERT(CHECK)\ + do { \ + if (!(CHECK)) \ + { \ + __asm__ volatile ("ebreak"); \ + }\ + } while(0); + +#endif /* NDEBUG */ +#endif /*__GNUC__*/ + +#ifdef __cplusplus +} +#endif +#endif /* __HAL_ASSERT_HEADER */ + diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/hal/hal_irq.c b/applications/user-crypto/miv-rv32-rsa-services/src/platform/hal/hal_irq.c new file mode 100644 index 0000000..95a0775 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/hal/hal_irq.c @@ -0,0 +1,45 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hal_irq.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Legacy interrupt control functions for the Microchip driver library + * hardware abstraction layer. + * + */ +#include "hal.h" +#include "miv_rv32_hal/miv_rv32_hal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * + */ +void HAL_enable_interrupts(void) { + MRV_enable_interrupts(); +} + +/*------------------------------------------------------------------------------ + * + */ +psr_t HAL_disable_interrupts(void) { + psr_t psr; + psr = read_csr(mstatus); + MRV_disable_interrupts(); + return(psr); +} + +/*------------------------------------------------------------------------------ + * + */ +void HAL_restore_interrupts(psr_t saved_psr) { + write_csr(mstatus, saved_psr); +} + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/hal/hw_macros.h b/applications/user-crypto/miv-rv32-rsa-services/src/platform/hal/hw_macros.h new file mode 100644 index 0000000..189609c --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/hal/hw_macros.h @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hw_macros.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware registers access macros. + * + * THE MACROS DEFINED IN THIS FILE ARE DEPRECATED. DO NOT USE FOR NEW + * DEVELOPMENT. + * + * These macros are used to access peripheral registers. They allow access to + * 8, 16 and 32 bit wide registers. All accesses to peripheral registers should + * be done through these macros in order to ease porting across different + * processors/bus architectures. + * + * Some of these macros also allow access to a specific register field. + * + */ +#ifndef __HW_REGISTER_MACROS_H +#define __HW_REGISTER_MACROS_H 1 +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * 32 bits registers access: + */ +#define HW_get_uint32_reg(BASE_ADDR, REG_OFFSET) (*((uint32_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint32_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint32_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint32_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint32_t) \ + ( \ + (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint32_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint32_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 32 bits memory access: + */ +#define HW_get_uint32(BASE_ADDR) (*((uint32_t volatile *)(BASE_ADDR))) + +#define HW_set_uint32(BASE_ADDR, VALUE) (*((uint32_t volatile *)(BASE_ADDR)) = (VALUE)) + +/*------------------------------------------------------------------------------ + * 16 bits registers access: + */ +#define HW_get_uint16_reg(BASE_ADDR, REG_OFFSET) (*((uint16_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint16_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint16_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint16_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint16_t) \ + ( \ + (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint16_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint16_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 8 bits registers access: + */ +#define HW_get_uint8_reg(BASE_ADDR, REG_OFFSET) (*((uint8_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) + +#define HW_set_uint8_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint8_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) + +#define HW_set_uint8_reg_field(BASE_ADDR, FIELD, VALUE) \ + (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ + ( \ + (uint8_t) \ + ( \ + (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ + (uint8_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ + ) \ + ) + +#define HW_get_uint8_reg_field( BASE_ADDR, FIELD ) \ + (( (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) + +/*------------------------------------------------------------------------------ + * 8 bits memory access: + */ +#define HW_get_uint8(BASE_ADDR) (*((uint8_t volatile *)(BASE_ADDR))) + +#define HW_set_uint8(BASE_ADDR, VALUE) (*((uint8_t volatile *)(BASE_ADDR)) = (VALUE)) + +#ifdef __cplusplus +extern "C" { +#endif + +#endif /* __HW_REGISTER_MACROS_H */ + diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/hal/hw_reg_access.S b/applications/user-crypto/miv-rv32-rsa-services/src/platform/hal/hw_reg_access.S new file mode 100644 index 0000000..dd29223 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/hal/hw_reg_access.S @@ -0,0 +1,215 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hw_reg_access.S + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware registers access functions. + * The implementation of these function is platform and toolchain specific. + * The functions declared here are implemented using assembler as part of the + * processor/toolchain specific HAL. This implementation is for the combination + * of the 32 bit RISC-V processors and GNU tool chain. + * + */ + +.section .text + .globl HW_set_32bit_reg + .globl HW_get_32bit_reg + .globl HW_set_32bit_reg_field + .globl HW_get_32bit_reg_field + .globl HW_set_16bit_reg + .globl HW_get_16bit_reg + .globl HW_set_16bit_reg_field + .globl HW_get_16bit_reg_field + .globl HW_set_8bit_reg + .globl HW_get_8bit_reg + .globl HW_set_8bit_reg_field + .globl HW_get_8bit_reg_field + + +/***************************************************************************//** + * HW_set_32bit_reg is used to write the content of a 32 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint32_t value + */ +HW_set_32bit_reg: + sw a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_32bit_reg is used to read the content of a 32 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + + * @return 32 bits value read from the peripheral register. + */ +HW_get_32bit_reg: + lw a0, 0(a0) + ret + +/***************************************************************************//** + * HW_set_32bit_reg_field is used to set the content of a field in a 32 bits + * wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint32_t mask + * a3: uint32_t value + */ +HW_set_32bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lw t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sw t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_32bit_reg_field is used to read the content of a field out of a + * 32 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint32_t mask + * + * @return 32 bits value containing the register field value specified + * as parameter. + */ +HW_get_32bit_reg_field: + lw a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +/***************************************************************************//** + * HW_set_16bit_reg is used to write the content of a 16 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint_fast16_t value + */ +HW_set_16bit_reg: + sh a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_16bit_reg is used to read the content of a 16 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + + * @return 16 bits value read from the peripheral register. + */ +HW_get_16bit_reg: + lh a0, (a0) + ret + +/***************************************************************************//** + * HW_set_16bit_reg_field is used to set the content of a field in a 16 bits + * wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast16_t mask + * a3: uint_fast16_t value + * @param value Value to be written in the specified field. + */ +HW_set_16bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lh t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sh t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_16bit_reg_field is used to read the content of a field from a + * 16 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast16_t mask + * + * @return 16 bits value containing the register field value specified + * as parameter. + */ +HW_get_16bit_reg_field: + lh a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +/***************************************************************************//** + * HW_set_8bit_reg is used to write the content of a 8 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + * a1: uint_fast8_t value + */ +HW_set_8bit_reg: + sb a1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_8bit_reg is used to read the content of a 8 bits wide peripheral + * register. + * + * a0: addr_t reg_addr + + * @return 8 bits value read from the peripheral register. + */ +HW_get_8bit_reg: + lb a0, 0(a0) + ret + +/***************************************************************************//** + * HW_set_8bit_reg_field is used to set the content of a field in a 8 bits + * wide peripheral register. + * + * a0: addr_t reg_addr, + * a1: int_fast8_t shift + * a2: uint_fast8_t mask + * a3: uint_fast8_t value + */ +HW_set_8bit_reg_field: + mv t3, a3 + sll t3, t3, a1 + and t3, t3, a2 + lb t1, 0(a0) + mv t2, a2 + not t2, t2 + and t1, t1, t2 + or t1, t1, t3 + sb t1, 0(a0) + ret + +/***************************************************************************//** + * HW_get_8bit_reg_field is used to read the content of a field from a + * 8 bits wide peripheral register. + * + * a0: addr_t reg_addr + * a1: int_fast8_t shift + * a2: uint_fast8_t mask + * + * @return 8 bits value containing the register field value specified + * as parameter. + */ +HW_get_8bit_reg_field: + lb a0, 0(a0) + and a0, a0, a2 + srl a0, a0, a1 + ret + +.end diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/hal/hw_reg_access.h b/applications/user-crypto/miv-rv32-rsa-services/src/platform/hal/hw_reg_access.h new file mode 100644 index 0000000..1a24309 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/hal/hw_reg_access.h @@ -0,0 +1,239 @@ +/***************************************************************************//** + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file hw_reg_access.S + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware registers access functions. + * The implementation of these function is platform and tool-chain specific. + * The functions declared here are implemented using assembler as part of the + * processor/tool-chain specific HAL. This implementation is for the combination + * of the 32 bit RISC-V processors and GNU tool chain. + * + */ +#ifndef __HW_REG_ACCESS +#define __HW_REG_ACCESS +#ifdef __cplusplus +extern "C" { +#endif + +#include "cpu_types.h" +/***************************************************************************//** + * HW_set_32bit_reg is used to write the content of a 32 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_32bit_reg +( + addr_t reg_addr, + uint32_t value +); + +/***************************************************************************//** + * HW_get_32bit_reg is used to read the content of a 32 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 32 bits value read from the peripheral register. + */ +uint32_t +HW_get_32bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_32bit_reg_field is used to set the content of a field in a 32 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void +HW_set_32bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint32_t mask, + uint32_t value +); + +/***************************************************************************//** + * HW_get_32bit_reg_field is used to read the content of a field out of a + * 32 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 32 bits value containing the register field value specified + * as parameter. + */ +uint32_t +HW_get_32bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint32_t mask +); + +/***************************************************************************//** + * HW_set_16bit_reg is used to write the content of a 16 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_16bit_reg +( + addr_t reg_addr, + uint_fast16_t value +); + +/***************************************************************************//** + * HW_get_16bit_reg is used to read the content of a 16 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 16 bits value read from the peripheral register. + */ +uint16_t +HW_get_16bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_16bit_reg_field is used to set the content of a field in a 16 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void HW_set_16bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast16_t mask, + uint_fast16_t value +); + +/***************************************************************************//** + * HW_get_16bit_reg_field is used to read the content of a field from a + * 16 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 16 bits value containing the register field value specified + * as parameter. + */ +uint16_t HW_get_16bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast16_t mask +); + +/***************************************************************************//** + * HW_set_8bit_reg is used to write the content of a 8 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * write. + * @param value Value to be written into the peripheral register. + */ +void +HW_set_8bit_reg +( + addr_t reg_addr, + uint_fast8_t value +); + +/***************************************************************************//** + * HW_get_8bit_reg is used to read the content of a 8 bits wide peripheral + * register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @return 8 bits value read from the peripheral register. + */ +uint8_t +HW_get_8bit_reg +( + addr_t reg_addr +); + +/***************************************************************************//** + * HW_set_8bit_reg_field is used to set the content of a field in a 8 bits + * wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * be written. + * @param shift Bit offset of the register field to be read within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * @param value Value to be written in the specified field. + */ +void HW_set_8bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast8_t mask, + uint_fast8_t value +); + +/***************************************************************************//** + * HW_get_8bit_reg_field is used to read the content of a field from a + * 8 bits wide peripheral register. + * + * @param reg_addr Address in the processor's memory map of the register to + * read. + * @param shift Bit offset of the register field to be written within the + * register. + * @param mask Bit mask to be applied to the raw register value to filter + * out the other register fields values. + * + * @return 8 bits value containing the register field value specified + * as parameter. + */ +uint8_t HW_get_8bit_reg_field +( + addr_t reg_addr, + int_fast8_t shift, + uint_fast8_t mask +); + +#ifdef __cplusplus +} +#endif + +#endif /* __HW_REG_ACCESS */ + diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld b/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld new file mode 100644 index 0000000..474eb43 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv-rv32-execute-in-place.ld @@ -0,0 +1,154 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-execute-in-place.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * image executing from a one address space whereas the data, sdata and stack + * sections are placed in another address space. This could be used in cases such + * as: + * 1) When using MIV_RV32, the reset vector points to the LSRAM at address + * 0x80000000 and the data, sdata, bss and stack sections are placed in the + * TCM region. + * + * 2) Executing from a Non Volatile memory. The actual memory will depend on + * the FPGA platform. For exameple, it could be the eNVM on SmartFusion2, + * Igloo2 or on-board non-volatile memory which supports code execution. + * + * NOTE: Modify the memory section addresses and the sizes according to your + * Libero design. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + + +MEMORY +{ + rom (rx) : ORIGIN = 0x80000000, LENGTH = 16k + ram (rwx) : ORIGIN = 0x80004000, LENGTH = 16k +} + +STACK_SIZE = 1k; /* needs to be calculated for your application */ +HEAP_SIZE = 1k; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > rom + + .text : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.text.entry))) + . = ALIGN(0x10); + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } >rom + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } >ram AT>rom + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } >ram AT>rom + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram +} + diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv-rv32-ram.ld b/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv-rv32-ram.ld new file mode 100644 index 0000000..53076a0 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv-rv32-ram.ld @@ -0,0 +1,150 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * file name : miv-rv32-ram.ld + * Mi-V soft processor linker script for creating a SoftConsole downloadable + * debug image executing in SRAM. + * + * This linker script assumes that a RAM is connected at on Mi-V soft processor + * memory space pointed by the reset vector address. + * + * NOTE : Modify the memory section address and the size according to your + * Libero design. + * For example: + * 1) If you want to download and step debug at a different RAM memory address in + * your design (For example TCM base address) than the one provided in this file. + * 2) The MIV_RV32, when used with MIV_ESS IP, provides ways to copy the executable + * HEX file from external Non-Volatile memory into the TCM at reset. In this + * case your executable must be linked to the TCM address. + * + * To know more about the memory map of the MIV_RV32 based Libero design, open + * the MIV_RV32 IP configurator and look for "Reset Vector Address" and the + * "Memory Map" tab. + * + */ + +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +MEMORY +{ + ram (rwx) : ORIGIN = 0x80000000, LENGTH = 32k +} + +STACK_SIZE = 2k; /* needs to be calculated for your application */ +HEAP_SIZE = 1k; /* needs to be calculated for your application */ + +SECTIONS +{ + .entry : ALIGN(0x10) + { + KEEP (*(SORT_NONE(.entry))) + . = ALIGN(0x10); + } > ram + + .text : ALIGN(0x10) + { + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + . = ALIGN(0x10); + + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(0x10); + + } > ram + + /* short/global data section */ + .sdata : ALIGN(0x10) + { + __sdata_load = LOADADDR(.sdata); + __sdata_start = .; + PROVIDE( __global_pointer$ = . + 0x800); + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) + *(.srodata*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + . = ALIGN(0x10); + __sdata_end = .; + } > ram + + /* data section */ + .data : ALIGN(0x10) + { + __data_load = LOADADDR(.data); + __data_start = .; + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(0x10); + __data_end = .; + } > ram + + /* sbss section */ + .sbss : ALIGN(0x10) + { + __sbss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + . = ALIGN(0x10); + __sbss_end = .; + } > ram + + /* sbss section */ + .bss : ALIGN(0x10) + { + __bss_start = .; + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(0x10); + __bss_end = .; + } > ram + + /* End of uninitialized data segment */ + _end = .; + + .heap : ALIGN(0x10) + { + __heap_start = .; + . += HEAP_SIZE; + __heap_end = .; + . = ALIGN(0x10); + _heap_end = __heap_end; + } > ram + + .stack : ALIGN(0x10) + { + __stack_bottom = .; + . += STACK_SIZE; + __stack_top = .; + } > ram +} + diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv_rv32_assert.h b/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv_rv32_assert.h new file mode 100644 index 0000000..b3912ed --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv_rv32_assert.h @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * MIV_RV32 HAL Embedded Software + * + */ +#ifndef MIV_RV32_ASSERT_HEADER +#define MIV_RV32_ASSERT_HEADER + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + * ASSERT() implementation. + ******************************************************************************/ +/* Disable assertions if we do not recognize the compiler. */ +#if defined ( __GNUC__ ) +#if defined(NDEBUG) +#define ASSERT(CHECK) +#else +#define ASSERT(CHECK)\ + do { \ + if (!(CHECK)) \ + { \ + __asm__ volatile ("ebreak"); \ + }\ + } while(0); + +#endif /* NDEBUG check */ +#endif /* compiler check */ + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_RV32_ASSERT_HEADER */ + diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv_rv32_entry.S b/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv_rv32_entry.S new file mode 100644 index 0000000..0ea3172 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv_rv32_entry.S @@ -0,0 +1,590 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_entry.S + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor vectors, trap handling and startup code. + * + */ +#ifndef ENTRY_S +#define ENTRY_S + +#define A_EXTENSION_MASK 0x00000001u +#define MTVEC_MODE_BIT_MASK 0x00000003u +#define MTVEC_VECTORED_MODE_VAL 0x00000001u + +#define MTIMEH_ADDR 0x200BFFCu + + +#if __riscv_xlen == 64 +# define LREG ld +# define SREG sd +# define REGBYTES 8 +#else +# define LREG lw +# define SREG sw +# define REGBYTES 4 +#endif + +#if defined(MIV_FP_CONTEXT_SAVE) && defined(__riscv_flen) +#define SP_SHIFT_OFFSET 64 +#else +#define SP_SHIFT_OFFSET 32 +#endif + +.macro STORE_CONTEXT + addi sp, sp, -SP_SHIFT_OFFSET*REGBYTES + SREG x1, 0 * REGBYTES(sp) + SREG x1, 0 * REGBYTES(sp) + SREG x2, 1 * REGBYTES(sp) + SREG x3, 2 * REGBYTES(sp) + SREG x4, 3 * REGBYTES(sp) + SREG x5, 4 * REGBYTES(sp) + SREG x6, 5 * REGBYTES(sp) + SREG x7, 6 * REGBYTES(sp) + SREG x8, 7 * REGBYTES(sp) + SREG x9, 8 * REGBYTES(sp) + SREG x10, 9 * REGBYTES(sp) + SREG x11, 10 * REGBYTES(sp) + SREG x12, 11 * REGBYTES(sp) + SREG x13, 12 * REGBYTES(sp) + SREG x14, 13 * REGBYTES(sp) + SREG x15, 14 * REGBYTES(sp) + SREG x16, 15 * REGBYTES(sp) + SREG x17, 16 * REGBYTES(sp) + SREG x18, 17 * REGBYTES(sp) + SREG x19, 18 * REGBYTES(sp) + SREG x20, 19 * REGBYTES(sp) + SREG x21, 20 * REGBYTES(sp) + SREG x22, 21 * REGBYTES(sp) + SREG x23, 22 * REGBYTES(sp) + SREG x24, 23 * REGBYTES(sp) + SREG x25, 24 * REGBYTES(sp) + SREG x26, 25 * REGBYTES(sp) + SREG x27, 26 * REGBYTES(sp) + SREG x28, 27 * REGBYTES(sp) + SREG x29, 28 * REGBYTES(sp) + SREG x30, 29 * REGBYTES(sp) + SREG x31, 30 * REGBYTES(sp) + + #ifdef __riscv_flen + #ifdef MIV_FP_CONTEXT_SAVE + fsw f0, 31*REGBYTES(sp) + fsw f1, 32*REGBYTES(sp) + fsw f2, 33*REGBYTES(sp) + fsw f3, 34*REGBYTES(sp) + fsw f4, 35*REGBYTES(sp) + fsw f5, 36*REGBYTES(sp) + fsw f6, 37*REGBYTES(sp) + fsw f7, 38*REGBYTES(sp) + fsw f8, 39*REGBYTES(sp) + fsw f9, 40*REGBYTES(sp) + fsw f10, 41*REGBYTES(sp) + fsw f11, 42*REGBYTES(sp) + fsw f12, 43*REGBYTES(sp) + fsw f13, 44*REGBYTES(sp) + fsw f14, 45*REGBYTES(sp) + fsw f15, 46*REGBYTES(sp) + fsw f16, 47*REGBYTES(sp) + fsw f17, 48*REGBYTES(sp) + fsw f18, 49*REGBYTES(sp) + fsw f19, 50*REGBYTES(sp) + fsw f20, 51*REGBYTES(sp) + fsw f21, 52*REGBYTES(sp) + fsw f22, 53*REGBYTES(sp) + fsw f23, 54*REGBYTES(sp) + fsw f24, 55*REGBYTES(sp) + fsw f25, 56*REGBYTES(sp) + fsw f26, 57*REGBYTES(sp) + fsw f27, 58*REGBYTES(sp) + fsw f28, 59*REGBYTES(sp) + fsw f29, 60*REGBYTES(sp) + fsw f30, 61*REGBYTES(sp) + fsw f31, 62*REGBYTES(sp) + #endif /* __riscv_flen */ + #endif /* MIV_FP_CONTEXT_SAVE */ +.endm + + .section .entry, "ax" + .globl _start + +_start: + j handle_reset + +/* Some of the Mi-V soft IP cores support compressed 'C' extension. If the Mi-V + core in your design doesn't support 'C' extension and you enable 'C' extension + in firmware project compiler options, then it would result in a trap. For this + case, we are avoiding compressed instruction here so you can put a breakpoint + at the jump and you can at least look at mcause, mepc and get some hints + about the crash. */ +trap_entry: +.option push +.option norvc +j generic_trap_handler +.option pop + .word 0 + .word 0 + +sw_trap_entry: + j vector_sw_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + +tmr_trap_entry: + j vector_tmr_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + +ext_trap_entry: + j vector_ext_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + .word 0 + +#ifndef MIV_LEGACY_RV32 +MGEUI_trap_entry: + j vector_MGEUI_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MGECI_trap_entry: + j vector_MGECI_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + .word 0 + .word 0 + .word 0 + .word 0 + +#ifndef MIV_RV32_V3_0 +MSYS_MIE22_trap_entry: +#ifndef MIV_RV32_V3_0 + j vector_SUBSYSR_IRQHandler +#endif /*MIV_RV32_V3_0*/ +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE23_trap_entry: + j vector_SUBSYS_IRQHandler +#ifdef __riscv_compressed + .2byte 0 +#endif +#endif /*MIV_RV32_V3_0*/ + +MSYS_MIE24_trap_entry: + j vector_MSYS_EI0_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE25_trap_entry: + j vector_MSYS_EI1_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE26_trap_entry: + j vector_MSYS_EI2_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE27_trap_entry: + j vector_MSYS_EI3_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE28_trap_entry: + j vector_MSYS_EI4_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE29_trap_entry: + j vector_MSYS_EI5_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE30_trap_entry: +#ifndef MIV_RV32_V3_0 + j vector_MSYS_EI6_trap_handler +#else + j vector_SUBSYS_IRQHandler +#endif +#ifdef __riscv_compressed + .2byte 0 +#endif + +#ifndef MIV_RV32_V3_0 +MSYS_MIE31_trap_entry: + j vector_MSYS_EI7_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif +#endif /* MIV_RV32_V3_0 */ +#endif /* MIV_LEGACY_RV32 */ + +.align 4 +generic_trap_handler: + STORE_CONTEXT + csrr a0, mcause + csrr a1, mepc + jal handle_trap + j generic_restore + +vector_sw_trap_handler: + STORE_CONTEXT + jal handle_m_soft_interrupt + j generic_restore + +vector_tmr_trap_handler: + STORE_CONTEXT + jal handle_m_timer_interrupt + j generic_restore + +vector_ext_trap_handler: + STORE_CONTEXT +#ifdef MIV_LEGACY_RV32 + jal handle_m_ext_interrupt +#else + jal External_IRQHandler +#endif /* MIV_LEGACY_RV32 */ + j generic_restore + +#ifndef MIV_LEGACY_RV32 +vector_MGEUI_trap_handler: + STORE_CONTEXT + jal MGEUI_IRQHandler + j generic_restore + +vector_MGECI_trap_handler: + STORE_CONTEXT + jal MGECI_IRQHandler + j generic_restore + +vector_MSYS_EI0_trap_handler: + STORE_CONTEXT + jal MSYS_EI0_IRQHandler + j generic_restore + +vector_MSYS_EI1_trap_handler: + STORE_CONTEXT + jal MSYS_EI1_IRQHandler + j generic_restore + +vector_MSYS_EI2_trap_handler: + STORE_CONTEXT + jal MSYS_EI2_IRQHandler + j generic_restore + +vector_MSYS_EI3_trap_handler: + STORE_CONTEXT + jal MSYS_EI3_IRQHandler + j generic_restore + +vector_MSYS_EI4_trap_handler: + STORE_CONTEXT + jal MSYS_EI4_IRQHandler + j generic_restore + +vector_MSYS_EI5_trap_handler: + STORE_CONTEXT + jal MSYS_EI5_IRQHandler + j generic_restore + +vector_SUBSYS_IRQHandler: + STORE_CONTEXT + jal SUBSYS_IRQHandler + j generic_restore + +#ifndef MIV_RV32_V3_0 +vector_MSYS_EI6_trap_handler: + STORE_CONTEXT + jal MSYS_EI6_IRQHandler + j generic_restore + +vector_MSYS_EI7_trap_handler: + STORE_CONTEXT + jal MSYS_EI7_IRQHandler + j generic_restore + + +vector_SUBSYSR_IRQHandler: + STORE_CONTEXT + jal SUBSYSR_IRQHandler + j generic_restore + +#endif /*MIV_RV32_V3_0*/ +#endif /* MIV_LEGACY_RV32 */ + +generic_restore: + LREG x1, 0 * REGBYTES(sp) + LREG x2, 1 * REGBYTES(sp) + LREG x3, 2 * REGBYTES(sp) + LREG x4, 3 * REGBYTES(sp) + LREG x5, 4 * REGBYTES(sp) + LREG x6, 5 * REGBYTES(sp) + LREG x7, 6 * REGBYTES(sp) + LREG x8, 7 * REGBYTES(sp) + LREG x9, 8 * REGBYTES(sp) + LREG x10, 9 * REGBYTES(sp) + LREG x11, 10 * REGBYTES(sp) + LREG x12, 11 * REGBYTES(sp) + LREG x13, 12 * REGBYTES(sp) + LREG x14, 13 * REGBYTES(sp) + LREG x15, 14 * REGBYTES(sp) + LREG x16, 15 * REGBYTES(sp) + LREG x17, 16 * REGBYTES(sp) + LREG x18, 17 * REGBYTES(sp) + LREG x19, 18 * REGBYTES(sp) + LREG x20, 19 * REGBYTES(sp) + LREG x21, 20 * REGBYTES(sp) + LREG x22, 21 * REGBYTES(sp) + LREG x23, 22 * REGBYTES(sp) + LREG x24, 23 * REGBYTES(sp) + LREG x25, 24 * REGBYTES(sp) + LREG x26, 25 * REGBYTES(sp) + LREG x27, 26 * REGBYTES(sp) + LREG x28, 27 * REGBYTES(sp) + LREG x29, 28 * REGBYTES(sp) + LREG x30, 29 * REGBYTES(sp) + LREG x31, 30 * REGBYTES(sp) + + #ifdef __riscv_flen + #ifdef MIV_FP_CONTEXT_SAVE + flw f0, 0 * REGBYTES(sp) + flw f1, 1 * REGBYTES(sp) + flw f2, 2 * REGBYTES(sp) + flw f3, 3 * REGBYTES(sp) + flw f4, 4 * REGBYTES(sp) + flw f5, 5 * REGBYTES(sp) + flw f6, 6 * REGBYTES(sp) + flw f7, 7 * REGBYTES(sp) + flw f8, 8 * REGBYTES(sp) + flw f9, 9 * REGBYTES(sp) + flw f10, 10 * REGBYTES(sp) + flw f11, 11 * REGBYTES(sp) + flw f12, 12 * REGBYTES(sp) + flw f13, 13 * REGBYTES(sp) + flw f14, 14 * REGBYTES(sp) + flw f15, 15 * REGBYTES(sp) + flw f16, 16 * REGBYTES(sp) + flw f17, 17 * REGBYTES(sp) + flw f18, 18 * REGBYTES(sp) + flw f19, 19 * REGBYTES(sp) + flw f20, 20 * REGBYTES(sp) + flw f21, 21 * REGBYTES(sp) + flw f22, 22 * REGBYTES(sp) + flw f23, 23 * REGBYTES(sp) + flw f24, 24 * REGBYTES(sp) + flw f25, 25 * REGBYTES(sp) + flw f26, 26 * REGBYTES(sp) + flw f27, 27 * REGBYTES(sp) + flw f28, 28 * REGBYTES(sp) + flw f29, 29 * REGBYTES(sp) + flw f30, 30 * REGBYTES(sp) + flw f31, 31 * REGBYTES(sp) + #endif /* __riscv_flen */ + #endif /* MIV_FP_CONTEXT_SAVE */ + + addi sp, sp, SP_SHIFT_OFFSET*REGBYTES + mret + + .section .text, "ax" +handle_reset: +/* Ensure instructions are not relaxed, since gp is not yet set */ +.option push +.option norelax + +#ifndef MIV_RV32_V3_0 + csrwi mstatus, 0 + csrwi mie, 0 + la ra, _start + +/* Clearnig this to be on safer side as RTL doesnt seem to clear it on reset. */ +#ifndef MIV_LEGACY_RV32 + li t0, MTIMEH_ADDR + sw x0, 0(t0) +#endif + + csrr t0, misa + andi t0, t0, A_EXTENSION_MASK + bnez t0, ima_cores_setup /* Jump to IMA core handling */ + + +/* For MIV_RV32 cores the mtvec exception base address is fixed at Reset vector + address + 0x4. Check the mode bits. */ +/* In the MIV_RV32 v3.1, the MTVEC exception base address is WARL, and can be + configured by the user at runtime */ + + csrr t0, mtvec + andi t0, t0, MTVEC_MODE_BIT_MASK + li t1, MTVEC_VECTORED_MODE_VAL + bne t0, t1, ima_cores_setup /* Jump to IMA core handling */ + + /* When mode = 1 => this is vectored mode on MIV_RV32 core. + Verify that the trap_handler address matches the configuration in MTVEC */ + csrr t0, mtvec + andi t0, t0, 0xFFFFFFFC + la t1, trap_entry + bne t0, t1, vector_address_not_matching + j generic_reset_handling + +#else /* MIV_RV32_V3_0 */ + +/* Clearnig this to be on safer side as RTL doesnt seem to clear it on reset. */ +#ifndef MIV_LEGACY_RV32 + li t0, MTIMEH_ADDR + sw x0, 0(t0) +#endif + +/* In the MIV_RV32 v3.1, the MTVEC exception base address is WARL, and can be + configured by the user at runtime */ + csrr t0, mtvec + andi t0, t0, MTVEC_MODE_BIT_MASK + li t1, MTVEC_VECTORED_MODE_VAL + bne t0, t1, ima_cores_setup /* Jump to IMA core handling */ + +/* When mode = 1 => this is vectored mode on MIV_RV32 core. + Verify that the trap_handler address matches the configuration in MTVEC */ + csrr t0, mtvec + andi t0, t0, 0xFFFFFFFC + la t1, trap_entry + bne t0, t1, vector_address_not_matching + j generic_reset_handling +#endif /*MIV_RV32_V3_0*/ + +ima_cores_setup: + la t0, trap_entry + +#ifdef MIV_LEGACY_RV32_VECTORED_INTERRUPTS + addi t0, t0, 0x01 /* Set the mode bit for IMA cores. + For both MIV_RV32 v3.1 and v3.0 cores this is done by configurator. */ +#endif + csrw mtvec, t0 + +generic_reset_handling: +/* Copy sdata section first so that the gp is set and linker relaxation can be + used */ + la a4, __sdata_load + la a5, __sdata_start + la a6, __sdata_end + beq a4, a5, 1f /* Exit if source and dest are same */ + beq a5, a6, 1f /* Exit if section start and end addresses are same */ + call block_copy + +1: + /* initialize global pointer */ + la gp, __global_pointer$ + +.option pop + +/* Floating point support configuration */ +#ifdef __riscv_flen + csrr t0, mstatus + lui t1, 0xffffa + addi t1, t1, -1 + and t0, t0, t1 + lui t1, 0x4 + or t1, t0, t1 + csrw mstatus, t1 + + lui t0, 0x0 + fscsr t0 +#endif + call initializations + /* Initialize stack pointer */ + la sp, __stack_top + + /* Jump into C code */ + j _init + +/* Error: trap_entry is not at the expected address of reset_vector+mtvec offset + as configured in the MIV_RV32 core vectored mode */ +vector_address_not_matching: + ebreak + +initializations: +/* Initialize the .bss section */ + mv t0, ra /* Store ra for future use */ + la a5, __bss_start + la a6, __bss_end + beq a5, a6, 1f /* Section start and end address are the same */ + call zeroize_block + +1: +/* Initialize the .sbss section */ + la a5, __sbss_start + la a6, __sbss_end + beq a5, a6, 1f /* Section start and end address are the same */ + call zeroize_block + +/* Clear heap */ + la a5, __heap_start + la a6, __heap_end + beq a5, a6, 1f /* Section start and end address are the same */ + call zeroize_block + +1: +/* Copy data section */ + la a4, __data_load + la a5, __data_start + la a6, __data_end + beq a4, a5, 1f /* Exit early if source and dest are same */ + beq a5, a6, 1f /* Section start and end addresses are the same */ + call block_copy + +1: + mv ra, t0 /* Retrieve ra */ + ret + +zeroize_block: + bltu a6, a5, block_copy_error /* Error. End address is less than start */ + or a7, a6, a5 /* Check if start or end is unalined */ + andi a7, a7, 0x03u + bgtz a7, block_copy_error /* Unaligned addresses error*/ +zeroize_loop: + sw x0, 0(a5) + add a5, a5, __SIZEOF_POINTER__ + blt a5, a6, zeroize_loop + ret + +block_copy: + bltu a6, a5, block_copy_error /* Error. End address is less than start */ + or a7, a6, a5 /* Check if start or end is unalined */ + andi a7, a7, 0x03u + bgtz a7, block_copy_error /* Unaligned addresses error*/ +block_copy_loop: + lw a7, 0(a4) + sw a7, 0(a5) + addi a5, a5, 0x04 + addi a4, a4, 0x04 + blt a5, a6, block_copy_loop + j block_copy_exit + +block_copy_error: + j block_copy_error + +block_copy_exit: + ret + +#endif /*ENTRY_S*/ diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv_rv32_hal.c b/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv_rv32_hal.c new file mode 100644 index 0000000..a112821 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv_rv32_hal.c @@ -0,0 +1,410 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_hal.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Implementation of Hardware Abstraction Layer for Mi-V soft processors + * + */ +#include +#include "miv_rv32_hal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SUCCESS 0U +#define ERROR 1U +#define MASK_32BIT 0xFFFFFFFFu + +/*------------------------------------------------------------------------------ + * Write in a sequence recommended by privileged spec to avoid spurious + * interrupts + + # New comparand is in a1:a0. + li t0, -1 + sw t0, mtimecmp # No smaller than old value. + sw a1, mtimecmp+4 # No smaller than new value. + sw a0, mtimecmp # New value. + */ +#ifndef MIV_RV32_EXT_TIMECMP +#define WRITE_MTIMECMP(value) MTIMECMPH = MASK_32BIT; \ + MTIMECMP = value & MASK_32BIT;\ + MTIMECMPH = (value >> 32u) & MASK_32BIT; +#else +#define WRITE_MTIMECMP(value) +#endif + +#ifndef MIV_RV32_EXT_TIMER +#define WRITE_MTIME(value) MTIME = value & MASK_32BIT;\ + MTIMEH = (value >> 32u) & MASK_32BIT; +#else +#define WRITE_MTIME(value) +#endif + +extern void Software_IRQHandler(void); + +#ifdef MIV_LEGACY_RV32 +#define MTIME_PRESCALER 100UL +/*------------------------------------------------------------------------------ + * + */ +uint8_t Invalid_IRQHandler(void); +uint8_t External_1_IRQHandler(void); +uint8_t External_2_IRQHandler(void); +uint8_t External_3_IRQHandler(void); +uint8_t External_4_IRQHandler(void); +uint8_t External_5_IRQHandler(void); +uint8_t External_6_IRQHandler(void); +uint8_t External_7_IRQHandler(void); +uint8_t External_8_IRQHandler(void); +uint8_t External_9_IRQHandler(void); +uint8_t External_10_IRQHandler(void); +uint8_t External_11_IRQHandler(void); +uint8_t External_12_IRQHandler(void); +uint8_t External_13_IRQHandler(void); +uint8_t External_14_IRQHandler(void); +uint8_t External_15_IRQHandler(void); +uint8_t External_16_IRQHandler(void); +uint8_t External_17_IRQHandler(void); +uint8_t External_18_IRQHandler(void); +uint8_t External_19_IRQHandler(void); +uint8_t External_20_IRQHandler(void); +uint8_t External_21_IRQHandler(void); +uint8_t External_22_IRQHandler(void); +uint8_t External_23_IRQHandler(void); +uint8_t External_24_IRQHandler(void); +uint8_t External_25_IRQHandler(void); +uint8_t External_26_IRQHandler(void); +uint8_t External_27_IRQHandler(void); +uint8_t External_28_IRQHandler(void); +uint8_t External_29_IRQHandler(void); +uint8_t External_30_IRQHandler(void); +uint8_t External_31_IRQHandler(void); + + +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for external interrupts. + */ +uint8_t (* const mrv_ext_irq_handler_table[32])(void) = +{ + + Invalid_IRQHandler, + External_1_IRQHandler, + External_2_IRQHandler, + External_3_IRQHandler, + External_4_IRQHandler, + External_5_IRQHandler, + External_6_IRQHandler, + External_7_IRQHandler, + External_8_IRQHandler, + External_9_IRQHandler, + External_10_IRQHandler, + External_11_IRQHandler, + External_12_IRQHandler, + External_13_IRQHandler, + External_14_IRQHandler, + External_15_IRQHandler, + External_16_IRQHandler, + External_17_IRQHandler, + External_18_IRQHandler, + External_19_IRQHandler, + External_20_IRQHandler, + External_21_IRQHandler, + External_22_IRQHandler, + External_23_IRQHandler, + External_24_IRQHandler, + External_25_IRQHandler, + External_26_IRQHandler, + External_27_IRQHandler, + External_28_IRQHandler, + External_29_IRQHandler, + External_30_IRQHandler, + External_31_IRQHandler +}; + +#else +/*------------------------------------------------------------------------------ + * Interrupt handlers as mapped into the MIE register of the MIV_RV32 + */ +extern void Reserved_IRQHandler(void); +extern void External_IRQHandler(void); +extern void MGEUI_IRQHandler(void); +extern void MGECI_IRQHandler(void); +extern void MSYS_EI0_IRQHandler(void); +extern void MSYS_EI1_IRQHandler(void); +extern void MSYS_EI2_IRQHandler(void); +extern void MSYS_EI3_IRQHandler(void); +extern void MSYS_EI4_IRQHandler(void); +extern void MSYS_EI5_IRQHandler(void); +extern void SUBSYS_IRQHandler(void); + +#ifndef MIV_RV32_V3_0 /*For MIV_RV32 v3.1*/ +extern void MSYS_EI6_IRQHandler(void); +extern void MSYS_EI7_IRQHandler(void); +extern void SUBSYSR_IRQHandler(void); // @suppress("Unused function declaration") +#endif /*MIV_RV32_V3_0*/ + +#endif /* MIV_LEGACY_RV32 */ + +/*------------------------------------------------------------------------------ + * Increment value for the mtimecmp register in order to achieve a system tick + * interrupt as specified through the MRV_systick_config() function. + */ +static uint64_t g_systick_increment = 0U; +static uint64_t g_systick_cmp_value = 0U; + +/*------------------------------------------------------------------------------ + * Configure the machine timer to generate an interrupt. + */ +uint32_t MRV_systick_config(uint64_t ticks) +{ + uint32_t ret_val = ERROR; + uint64_t remainder = ticks; + g_systick_increment = 0U; + g_systick_cmp_value = 0U; + + while (remainder >= MTIME_PRESCALER) + { + remainder -= MTIME_PRESCALER; + g_systick_increment++; + } + + g_systick_cmp_value = g_systick_increment + MRV_read_mtime(); + + if (g_systick_increment > 0U) + { + WRITE_MTIMECMP(g_systick_cmp_value); + set_csr(mie, MIP_MTIP); + MRV_enable_interrupts(); + ret_val = SUCCESS; + } + + return ret_val; +} + +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for machine timer interrupts. + */ +void handle_m_timer_interrupt(void) +{ + clear_csr(mie, MIP_MTIP); + + uint64_t mtime_at_irq = MRV_read_mtime(); + +#ifndef NDEBUG + static volatile uint32_t d_tick = 0u; +#endif + + while(g_systick_cmp_value < (mtime_at_irq + MTIME_DELTA)) { + g_systick_cmp_value = g_systick_cmp_value + g_systick_increment; + +#ifndef NDEBUG + d_tick += 1; +#endif + } +/***************************************************************************//** + /* + * Note: If d_tick > 1 it means, that a system timer interrupt has been + * missed. + * Please ensure that interrupt handlers are as short as possible to prevent + * them stopping other interrupts from being handled. For example, if a + * system timer interrupt occurs during a software interrupt, the system + * timer interrupt will not be handled until the software interrupt handling + * is complete. If the software interrupt handling time is more than one + * systick interval, it will result in d_tick > 1. + * If you are running the program using the debugger and halt the CPU at a + * breakpoint, MTIME will continue to increment and interrupts will be + * missed; resulting in d_tick > 1. + */ + + WRITE_MTIMECMP(g_systick_cmp_value); + + SysTick_Handler(); + + set_csr(mie, MIP_MTIP); +} + +void handle_m_soft_interrupt(void) +{ + Software_IRQHandler(); + MRV_clear_soft_irq(); +} +/*------------------------------------------------------------------------------ + * RISC-V interrupt handler for software interrupts. + */ +#ifdef MIV_LEGACY_RV32 +void handle_m_ext_interrupt(void) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; + uint8_t disable = EXT_IRQ_KEEP_ENABLED; + + if (0u !=int_num) + { + disable = mrv_ext_irq_handler_table[int_num](); + + PLIC->TARGET[hart_id].CLAIM_COMPLETE = int_num; + + if(EXT_IRQ_DISABLE == disable) + { + MRV_PLIC_disable_irq((IRQn_Type)int_num); + } + } +} +#else + +/*------------------------------------------------------------------------------ + * MSYS local interrupts table + */ +void (* const local_irq_handler_table[16])(void) = +{ +#ifndef MIV_RV32_V3_0 + MGEUI_IRQHandler, + MGECI_IRQHandler, + SUBSYS_IRQHandler, + SUBSYSR_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + MSYS_EI0_IRQHandler, + MSYS_EI1_IRQHandler, + MSYS_EI2_IRQHandler, + MSYS_EI3_IRQHandler, + MSYS_EI4_IRQHandler, + MSYS_EI5_IRQHandler, + MSYS_EI6_IRQHandler, + MSYS_EI7_IRQHandler +#else + MGEUI_IRQHandler, + MGECI_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + MSYS_EI0_IRQHandler, + MSYS_EI1_IRQHandler, + MSYS_EI2_IRQHandler, + MSYS_EI3_IRQHandler, + MSYS_EI4_IRQHandler, + MSYS_EI5_IRQHandler, + SUBSYS_IRQHandler, + Reserved_IRQHandler, +#endif +}; + +/*------------------------------------------------------------------------------ + * Jump to interrupt table containing local interrupts + */ +void handle_local_ei_interrupts(uint8_t irq_no) +{ + uint64_t mhart_id = read_csr(mhartid); + ASSERT(irq_no <= MIV_LOCAL_IRQ_MAX) + ASSERT(irq_no >= MIV_LOCAL_IRQ_MIN) + + uint8_t ei_no = (uint8_t)(irq_no - MIV_LOCAL_IRQ_MIN); + (*local_irq_handler_table[ei_no])(); +} +#endif /* MIV_LEGACY_RV32 */ + + +/*------------------------------------------------------------------------------ + * Trap handler. This function is invoked in the non-vectored mode. + */ +void handle_trap(uintptr_t mcause, uintptr_t mepc) +{ + uint64_t is_interrupt = mcause & MCAUSE_INT; + + if (is_interrupt) + { +#ifndef MIV_LEGACY_RV32 + if (((mcause & MCAUSE_CAUSE) >= MIV_LOCAL_IRQ_MIN) && ((mcause & MCAUSE_CAUSE) <= MIV_LOCAL_IRQ_MAX)) + { + handle_local_ei_interrupts((uint8_t)(mcause & MCAUSE_CAUSE)); + } + else if ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT) +#else + if ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT) +#endif + { +#ifndef MIV_LEGACY_RV32 + External_IRQHandler(); +#else + handle_m_ext_interrupt(); +#endif + } + else if ((mcause & MCAUSE_CAUSE) == IRQ_M_SOFT) + { + handle_m_soft_interrupt(); + } + else if ((mcause & MCAUSE_CAUSE) == IRQ_M_TIMER) + { + handle_m_timer_interrupt(); + } + } + else + { +#ifndef NDEBUG + /* + Arguments supplied to this function are mcause, mepc (exception PC) and + stack pointer. + Based on privileged-isa specification mcause values and meanings are: + + 0 Instruction address misaligned (mtval/mtval is the address) + 1 Instruction access fault (mtval/mtval is the address) + 2 Illegal instruction (mtval/mtval contains the + offending instruction opcode) + 3 Breakpoint + 4 Load address misaligned (mtval/mtval is the address) + 5 Load address fault (mtval/mtval is the address) + 6 Store/AMO address fault (mtval/mtval is the address) + 7 Store/AMO access fault (mtval/mtval is the address) + 8 Environment call from U-mode + 9 Environment call from S-mode + A Environment call from M-mode + B Instruction page fault + C Load page fault (mtval/mtval is the address) + E Store page fault (mtval/mtval is the address) + + # Please note: mtval is the newer name for register mbadaddr + # If you get a compile failure here, use the older name. + # At this point, both are supported in latest compiler, older compiler + # versions only support mbadaddr. + # See: https://github.com/riscv/riscv-gcc/issues/133 + */ + + /* interrupt pending */ + uintptr_t mip = read_csr(mip); + + /* additional info and meaning depends on mcause */ + uintptr_t mtval = read_csr(mtval); + + /* trap vector */ + uintptr_t mtvec = read_csr(mtvec); + + /* temporary, sometimes might hold temporary value of a0 */ + uintptr_t mscratch = read_csr(mscratch); + + /* status contains many smaller fields: */ + uintptr_t mstatus = read_csr(mstatus); + + /* PC value when the exception was taken*/ + uintptr_t mmepc = read_csr(mepc); + + /* breakpoint */ + __asm__("ebreak"); +#else + _exit(1 + mcause); +#endif /* NDEBUG */ + } +} + +#ifdef __cplusplus +} +#endif + diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv_rv32_hal.h b/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv_rv32_hal.h new file mode 100644 index 0000000..9ce9ef6 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv_rv32_hal.h @@ -0,0 +1,773 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_hal.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware Abstraction Layer functions for Mi-V soft processors + * + */ + +/*=========================================================================*//** + @mainpage MIV_RV32 Hardware Abstraction Layer + + ============================================================================== + Introduction + ============================================================================== + This document describes the Hardware Abstraction Layer (HAL) for the MIV_RV32 + Soft IP Core. This release of the HAL corresponds to the Soft IP core MIV_RV32 + v3.1 release. It also supports earlier versions of the MIV_RV32 as well as the + legacy RV32 IP cores. + The preprocessor macros provided with the MIV_RV32 HAL are used to customize + it to target the Soft Processor IP version being used in your project. + + The term "MIV_RV32" represents following two cores: + - MIV_RV32 v3.0 and later (the latest and greatest Mi-V soft processor) + - MIV_RV32IMC v2.1 (MIV_RV32 v3.0 is a drop in replacement for this core) + It is highly recommended to migrate your design to MIV_RV32 v3.1 + + The term, Legacy RV32 IP cores, represents following IP cores: + - MIV_RV32IMA_L1_AHB + - MIV_RV32IMA_L1_AXI + - MIV_RV32IMAF_L1_AHB + + These legacy RV32 IP cores are deprecated. It is highly recommended to migrate + your designs to MIV_RV32 v3.1 (and subsequent IP releases) for the latest + enhancements, bug fixes, and support. + + -------------------------------- + MIV_RV32 V3.1 + -------------------------------- + This is the latest release of the MIV_RV32 Soft IP core. For more details, + refer to the MIV_RV32 User [Guide](https://www.microchip.com/en-us/products/fpgas-and-plds/ip-core-tools/miv-rv32) + + The MIV_RV32 Core as well as this document use the terms defined below: + + -------------------------------- + - SUBSYS - Processor Subsystem for RISC-V + - OPSRV - Offload Processor Subsystem for RISC-V + - GPR - General Purpose Registers + - MGECIE - Machine GPR ECC Correctable Interrupt Enable + - MGEUIE - Machine GPR ECC Uncorrectable Interrupt Enable + - MTIE - Machine Timer Interrupt Enable + - MEIE - Machine External Interrupt Enable + - MSIE - Machine Software Interrupt Enable + - ISR - Interrupt Service Routine + + ============================================================================== + Customizing MIV_RV32 HAL + ============================================================================== + To use the HAL with older releases of MIV_RV32, preprocessor macros have been + provided. Using these macros, any of the IP version is targeted. + The HAL is used to target any of the mentioned platforms by adding the + following macros in the way : + Project Properties > C/C++ Build > Settings > Preprocessor in Assembler and + Compiler settings. + The table below shows the macros corresponding to the MIV Core being used in + your libero project. By default, the HAL targets v3.1 of the IP core and no + macros need to be set for this configutation. + + | Libero MI-V Soft IP Version | SoftConsole Macro | + |-----------------------------|-------------------| + | MIV_RV32 v3.1 | no macro required | + | MIV_RV32 v3.0 | MIV_CORE_V3_0 | + | Legacy RV32 Cores | MIV_LEGACY_RV32 | + + -------------------------------- + Interrupt Handling + -------------------------------- + The MIE Register is defined as a enum in the HAL, and the table below is used + as a reference when the vectored interrupts are enabled in the GUI core + configurator. + + The MIE register is a RISC-V Control and Status Register (CSR), which stands + for the Machine Interrupt Enable. This is used to enable the machine mode + interrupts in the MIV_RV32 hart. Refer to the RISC-V Priv spec for more details. + + The following table shows the trap entry addresses when an interrupt occurs and + the vectored interrupts are enabled in the GUI configurator. + + | MIE Register Bit | Interrupt Enable | Vector Address | + |-------------------|------------------|----------------| + | 31 | MSYS_IE7 | mtvec.BASE + 0x7C | + | 30 | MSYS_IE6 | mtvec.BASE + 0x78 | + | 29 | MSYS_IE5 | mtvec.BASE + 0x74 | + | 28 | MSYS_IE4 | mtvec.BASE + 0x70 | + | 27 | MSYS_IE3 | mtvec.BASE + 0x6C | + | 26 | MSYS_IE2 | mtvec.BASE + 0x68 | + | 25 | MSYS_IE1 | mtvec.BASE + 0x64 | + | 24 | MSYS_IE0 | mtvec.BASE + 0x60 | + | 23 | SUBSYS_EI | mtvec.BASE + 0x5C | + | 22 | SUBSYSR | mtvec.BASE + 0x58 | + | 17 | MGECIE | mtvec.BASE + 0x44 | + | 16 | MGEUIE | mtvec.BASE + 0x40 | + | 11 | MEIE | mtvec.BASE + 0x2C | + | 7 | MTIE | mtvec.BASE + 0x1C | + | 3 | MSIE | mtvec.BASE + 0x0C | + + + For changes in MIE register map, see the [MIE Register Map for MIV_RV32 v3.0] + (#mie-register-map-for-miv_rv32-v3.0) section. + + SUBSYSR is currently not being used by the core and is Reserved for future use. + + The mtvec.BASE field corresponds to the bits [31:2], where mtvec stands for + Machine Trap Vector, and all traps set the PC to the the value stored in the + mtvec.BASE field when in Non-Vectored mode. In this case, a generic trap + handler is as an interrupt service routine. + + When Vectored interrupts are enabled, use this formula to calculate the trap + address: (mtvec.BASE + 4*cause), where cause comes from the mcause CSR. The + mcause register is written with a code indicating the event that caused the trap. + For more details, see the RISC-V priv specification. + + The MIV_RV32 Soft IP core does not contain a Platfrom Level Interrup Controller + (PLIC). It is advised to use the PLIC contained within the MIV_ESS sub-system. + Connect the PLIC interrupt output of the MIV_ESS to the EXT_IRQ pin on the + MIV_RV32. + + The following table is the MIE register map for the MIV_RV32 Core V3.0. It only + highlights the differences between the V3.0 and V3.1 of the core. + + -------------------------------- + MIE Register Map for MIV_RV32 V3.0 + -------------------------------- + + | MIE Register Bit | Target Interrupt | Vector Address | + |-------------------|------------------|----------------| + | 31 | Not in use | top table | + | 30 | SUBSYS_EI | addr + 0x78 | + | 23 | Not in use | Not in use | + | 22 | Not in use | Not in use | + + Other interrupt bit postions like the MGEUIE and MSYS_IE5 to MSYS_IE0 remain + unchanged. + + -------------------------------- + Floating Point Interrupt Support + -------------------------------- + When an interrupt is taken and Floating Point instructions are used in the + ISR, the floating point register context must be saved to resume the application + correctly. To use this feature, enable the provided macro in the + Softconsole build settings. + This feature is turned off by default as it adds overhead which is not required + when the ISR does not used FP insturctions and saving the general purpose + register context is sufficient. + + | Macro Name | Definition | + |--------------------------|-------------------------------------------------| + | MIV_FP_CONTEXT_SAVE | Define to save the FP register file | + + + -------------------------------- + SUBSYS - SubSystem for RISC-V + -------------------------------- + SUBSYS stands for SubSystem for RISC-V. This was previously (MIV_RV32 v3.0) + known as OPSRV, which stands for "Offload Processor Subsystem + for RISC-V". See the earlier versions of the handbook for more details. + In the latest release of the MIV_RV32 IP core v3.1, OPSRV has been renamed to + SUBSYS. The MIV_RV32 HAL now uses SUBSYS instead of OPSRV. + + *//*=========================================================================*/ +#ifndef RISCV_HAL_H +#define RISCV_HAL_H + +#include "miv_rv32_regs.h" +#include "miv_rv32_plic.h" +#include "miv_rv32_assert.h" +#include "miv_rv32_subsys.h" + +#ifndef LEGACY_DIR_STRUCTURE +#include "fpga_design_config/fpga_design_config.h" +#else +#include "hw_platform.h" +#endif /*LEGACY_DIR_STRUCTURE*/ + +#ifdef __cplusplus +extern "C" { +#endif +/*-------------------------------------------------------------------------*//** + SUBSYS Backwards Compatibility + ======================================= + For application code using the older macro names and API functions, these macros + act as a compatibility layer and applications which use OPSRV API features work + due to these macro definitions. However, it is adviced to update your + application code to use the SUBSYS macros and API functions. + + | Macro Name | Now Called | + |-------------------------|--------------------------| + | OPSRV_TCM_ECC_CE_IRQ | SUBSYS_TCM_ECC_CE_IRQ | + | OPSRV_TCM_ECC_UCE_IRQ | SUBSYS_TCM_ECC_UCE_IRQ | + | OPSRV_AXI_WR_RESP_IRQ | SUBSYS_AXI_WR_RESP_IRQ | + | MRV32_MSYS_OPSRV_IRQn | MRV32_SUBSYS_IRQn | + | MRV32_opsrv_enable_irq | MRV32_subsys_enable_irq | + | MRV32_opsrv_disable_irq | MRV32_subsys_disable_irq | + | MRV32_opsrv_clear_irq | MRV32_subsys_clear_irq | + | OPSRV_IRQHandler | SUBSYS_IRQHandler | + */ + +/*-------------------------------------------------------------------------*//** + MTIME Timer Interrupt Constants + ======================================= + These values contain the register addresses for the registers used by the + machine timer interrupt + + MTIME_PRESCALER is not defined on the MIV_RV32IMC v2.0 and v2.1. By using this + definition the system crashes. For those core, use the following definition: + + #define MTIME_PRESCALER 100u + + MTIME and MTIMECMP + -------------------------------- + MIV_RV32 core offers flexibility in terms of generating MTIME and MTIMECMP + registers internal to the core or using external time reference. There four + possible combinations: + + - Internal MTIME and Internal MTIME IRQ enabled Generate the MTIME and MTIMECMP + registers internally. (The only combination available on legacy RV32 cores) + + - Internal MTIME enabled and Internal MTIME IRQ disabled Generate the MTIME + internally and have a timer interrupt input to the core as external pin. In + this case, 1 pin port will be available on MIV_RV32 for timer interrupt. + + - When the internal MTIME is disabled, and the Internal MTIME IRQ is enabled, the + system generates the time value externally and generates the mtimecmp and + interrupt internally (for example, a multiprocessor system with a shared time + between all cores). In this case, a 64-bit port is available on the MIV_RV32 + core as input. + + - Internal MTIME and Internal MTIME IRQ disabled Generate both the time and + timer interrupts externally. In this case a 64 bit port will be available on + the MIV_RV32 core as input, and a 1 pin port will be available for timer + interrupt. + + To handle all these combinations in the firmware, the following constants must + be defined in accordance with the configuration that you have made on your + MIV_RV32 core design. + + MIV_RV32_EXT_TIMER + -------------------------------- + When defined, it means that the MTIME register is not available internal to + the core. In this case, a 64 bit port will be available on the MIV_RV32 core as + input. When this macro is not defined, it means that the MTIME register is + available internally to the core. + + MIV_RV32_EXT_TIMECMP + -------------------------------- + When defined, it means the MTIMECMP register is not available internally to + the core and the Timer interrupt input to the core comes as an external pin. + When this macro is not defined it means the that MTIMECMP register exists + internal to the core and that the timer interrupt is generated internally. + +NOTE: All these macros must not be defined if you are using a MIV_RV32 core. + */ + +#define OPSRV_TCM_ECC_CE_IRQ SUBSYS_TCM_ECC_CE_IRQ +#define OPSRV_TCM_ECC_UCE_IRQ SUBSYS_TCM_ECC_UCE_IRQ +#define OPSRV_AXI_WR_RESP_IRQ SUBSYS_AXI_WR_RESP_IRQ +#define MRV32_MSYS_OPSRV_IRQn MRV32_SUBSYS_IRQn +#define MRV32_opsrv_enable_irq MRV32_subsys_enable_irq +#define MRV32_opsrv_disable_irq MRV32_subsys_disable_irq +#define MRV32_opsrv_clear_irq MRV32_subsys_clear_irq +#define OPSRV_IRQHandler SUBSYS_IRQHandler + +/*-------------------------------------------------------------------------*//** + External IRQ + ======================================= + Return value from External IRQ handler. This is used to disable the + External Interrupt. + + | Macro Name | Value | Description| + |-------------------|--------|----------------| + | EXT_IRQ_KEEP_ENABLED | 0 | Keep external interrupts enabled | + | EXT_IRQ_DISABLE | 1 | Disable external interrupts | + */ +#define EXT_IRQ_KEEP_ENABLED 0U +#define EXT_IRQ_DISABLE 1U + +#define MTIME_DELTA 5 +#ifdef MIV_LEGACY_RV32 +#define MSIP (*(uint32_t*)0x44000000UL) +#define MTIMECMP (*(uint32_t*)0x44004000UL) +#define MTIMECMPH (*(uint32_t*)0x44004004UL) +#define MTIME (*(uint32_t*)0x4400BFF8UL) +#define MTIMEH (*(uint32_t*)0x4400BFFCUL) + +/* To maintain backward compatibility with FreeRTOS config code */ +#define PRCI_BASE 0x44000000UL +#else /* MIV_LEGACY_RV32 */ + +/* To maintain backward compatibility with FreeRTOS config code */ +#define PRCI_BASE 0x02000000UL + +#ifndef MIV_RV32_EXT_TIMECMP +#define MTIMECMP (*(volatile uint32_t*)0x02004000UL) +#define MTIMECMPH (*(volatile uint32_t*)0x02004004UL) +#else +#define MTIMECMP (0u) +#define MTIMECMPH (0u) +#endif + +#define MTIME_PRESCALER (*(volatile uint32_t*)0x02005000UL) + +#ifndef MIV_RV32_EXT_TIMER +#define MTIME (*(volatile uint32_t*)0x0200BFF8UL) +#define MTIMEH (*(volatile uint32_t*)0x0200BFFCUL) + +/***************************************************************************//** + MIMPID Register + The MIMPID register is a RISC-V Control and Status Register In the v3.0 of + MIV_RV32, the value of `MIMPID = 0x000540AD`. In the v3.1 of MIV_RV32, the + value if `MIMPID = 0xE5010301` corresponding to (E)mbedded (5)ystem(01) core + version (03).(01) this terminology will be followed in the subsequent releases + of the core read the csr value and store it in a varible which may be used to + check the MIV_RV32 core version during runtime. + + Future releases of the core will increment the 03 and 01 as major and minor + releases respectively and the register can be read at runtime to find the + Soft IP core version. + + | Core Version | Register | Value | Notes | + |----------------|------------|---------|---------| + | MIV_RV32 V3.1 | mimpid | 0xE5010301 | implimentation ID | + | MIV_RV32 V3.0 | mimpid | 0x000540AD | implimentation ID | + */ +#define MIMPID read_csr(mimpid) + +/*Used as a mask to read and write to mte mtvec.BASE address*/ +#define MTVEC_BASE_ADDR_MASK 0xFFFFFFFC + +#else +#define MTIME (0u) +#define MTIMEH (0u) +#endif /*MIV_RV32_EXT_TIMER*/ + +/*-------------------------------------------------------------------------*//** + RISC-V Specification Interrupts + ======================================= + These definitions are provided for easy identification of the interrupt + in the MIE/MIP registers. + Apart from the standard software, timer, and external interrupts, the names + of the additional interrupts correspond to the names as used in the MIV_RV32 + handbook. Please refer the MIV_RV32 handbook for more details. + + All the interrups, provided by the MIV_RV32 core, follow the interrupt priority + order and register description as mentioned in the RISC-V spec. + + | Macro Name | Value | Description| + |-------------------|--------|----------------| + | MRV32_SOFT_IRQn | MIE_3_IRQn | Software interrupt enable | + | MRV32_TIMER_IRQn | MIE_7_IRQn | Timer interrupt enable | + | MRV32_EXT_IRQn | MIE_11_IRQn | External interrupt enable | + + */ +#define MRV32_SOFT_IRQn MIE_3_IRQn +#define MRV32_TIMER_IRQn MIE_7_IRQn +#define MRV32_EXT_IRQn MIE_11_IRQn + +/***************************************************************************//** + Interrupt numbers: + This enum represents the interrupt enable bits in the MIE register. + */ +enum +{ + MIE_0_IRQn = (0x01u), + MIE_1_IRQn = (0x01u<<1u), + MIE_2_IRQn = (0x01u<<2u), + MIE_3_IRQn = (0x01u<<3u), /*MSIE 0xC*/ + MIE_4_IRQn = (0x01u<<4u), + MIE_5_IRQn = (0x01u<<5u), + MIE_6_IRQn = (0x01u<<6u), + MIE_7_IRQn = (0x01u<<7u), /*MTIE 0x1C*/ + MIE_8_IRQn = (0x01u<<8u), + MIE_9_IRQn = (0x01u<<9u), + MIE_10_IRQn = (0x01u<<10u), + MIE_11_IRQn = (0x01u<<11u), /*MEIE 0x2C*/ + MIE_12_IRQn = (0x01u<<12u), + MIE_13_IRQn = (0x01u<<13u), + MIE_14_IRQn = (0x01u<<14u), + MIE_15_IRQn = (0x01u<<15u), + MIE_16_IRQn = (0x01u<<16u), /*MGEUIE ECC Uncorrectable 0x40*/ + MIE_17_IRQn = (0x01u<<17u), /*MGECIE ECC Correctable 0x44*/ + MIE_18_IRQn = (0x01u<<18u), + MIE_19_IRQn = (0x01u<<19u), + MIE_20_IRQn = (0x01u<<20u), + MIE_21_IRQn = (0x01u<<21u), + MIE_22_IRQn = (0x01u<<22u), /*SUBSYSR 0x58 (R)eserved*/ + MIE_23_IRQn = (0x01u<<23u), /*SUBSYS_IE 0x5C for MIV_RV32 v3.1*/ + MIE_24_IRQn = (0x01u<<24u), /*MSYS_IE0 0x60*/ + MIE_25_IRQn = (0x01u<<25u), /*MSYS_IE1 0x64*/ + MIE_26_IRQn = (0x01u<<26u), /*MSYS_IE2 0x68*/ + MIE_27_IRQn = (0x01u<<27u), /*MSYS_IE3 0x6C*/ + MIE_28_IRQn = (0x01u<<28u), /*MSYS_IE4 0x70*/ + MIE_29_IRQn = (0x01u<<29u), /*MSYS_IE5 0x74*/ + MIE_30_IRQn = (0x01u<<30u), /*MSYS_IE6 0x78, read comment below*/ + MIE_31_IRQn = (0x01u<<31u) /*MSYS_IE7 0x7C*/ +} MRV_LOCAL_IRQn_Type; + +#define MRV32_MGEUIE_IRQn MIE_16_IRQn +#define MRV32_MGECIE_IRQn MIE_17_IRQn +#define MRV32_MSYS_EIE0_IRQn MIE_24_IRQn +#define MRV32_MSYS_EIE1_IRQn MIE_25_IRQn +#define MRV32_MSYS_EIE2_IRQn MIE_26_IRQn +#define MRV32_MSYS_EIE3_IRQn MIE_27_IRQn +#define MRV32_MSYS_EIE4_IRQn MIE_28_IRQn +#define MRV32_MSYS_EIE5_IRQn MIE_29_IRQn +#ifndef MIV_RV32_V3_0 /*For MIV_RV32 v3.1*/ +#define MRV32_SUBSYSR_IRQn MIE_22_IRQn +#define MRV32_SUBSYS_IRQn MIE_23_IRQn +#define MRV32_MSYS_EIE6_IRQn MIE_30_IRQn +#define MRV32_MSYS_EIE7_IRQn MIE_31_IRQn +#else +#define MRV32_SUBSYS_IRQn MIE_30_IRQn +#endif /*MIV_RV32_V3_0*/ + +/*--------------------------------Public APIs---------------------------------*/ + +/***************************************************************************//** + The MRV32_clear_gpr_ecc_errors() function clears single bit ECC errors on the + GPRs. The ECC block does not write back corrected data to memory. Hence, when + ECC is enabled for the GPRs and if that data has a single bit error then the + data coming out of the ECC block is corrected and will not have the error, but + the data source will still have the error. Therefore, if data has a single bit + error, then the corrected data must be written back to prevent the single bit + error from becoming a double bit error. Clear the pending interrupt bit after + this using MRV32_mgeci_clear_irq() function to complete the ECC error handling. + + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline void MRV32_clear_gpr_ecc_errors(void) +{ + uint32_t temp; + + __asm__ __volatile__ ( + "sw x31, %0" + :"=m" (temp)); + + __asm__ volatile ( + "mv x31, x1;" + "mv x1, x31;" + + "mv x31, x2;" + "mv x2, x31;" + + "mv x31, x3;" + "mv x3, x31;" + + "mv x31, x4;" + "mv x4, x31;" + + "mv x31, x5;" + "mv x5, x31;" + + "mv x31, x6;" + "mv x6, x31;" + + "mv x31, x7;" + "mv x7, x31;" + + "mv x31, x8;" + "mv x8, x31;" + + "mv x31, x9;" + "mv x9, x31;" + + "mv x31, x10;" + "mv x10, x31;" + + "mv x31, x11;" + "mv x11, x31;" + + "mv x31, x12;" + "mv x12, x31;" + + "mv x31, x13;" + "mv x13, x31;" + + "mv x31, x14;" + "mv x14, x31;" + + "mv x31, x15;" + "mv x15, x31;" + + "mv x31, x16;" + "mv x16, x31;" + + "mv x31, x17;" + "mv x17, x31;" + + "mv x31, x18;" + "mv x18, x31;" + + "mv x31, x19;" + "mv x19, x31;" + + "mv x31, x20;" + "mv x20, x31;" + + "mv x31, x21;" + "mv x21, x31;" + + "mv x31, x22;" + "mv x22, x31;" + + "mv x31, x23;" + "mv x23, x31;" + + "mv x31, x24;" + "mv x24, x31;" + + "mv x31, x25;" + "mv x25, x31;" + + "mv x31, x26;" + "mv x26, x31;" + + "mv x31, x27;" + "mv x27, x31;" + + "mv x31, x28;" + "mv x28, x31;" + + "mv x31, x29;" + "mv x29, x31;" + + "mv x31, x30;" + "mv x30, x31;"); + + __asm__ __volatile__ ( + "lw x31, %0;" + : + :"m" (temp)); +} + + +/***************************************************************************//** + The MRV32_mgeui_clear_irq() function clears the GPR ECC Uncorrectable + Interrupt. MGEUI interrupt is available only when ECC is enabled in the MIV_RV32 + IP configurator. + + @return + This function does not return any value. + */ +static inline void MRV32_mgeui_clear_irq(void) +{ + clear_csr(mip, MRV32_MGEUIE_IRQn); +} + +/***************************************************************************//** + The MRV32_mgeci_clear_irq() function clears the GPR ECC Correctable Interrupt + MGECI interrupt is available only when ECC is enabled in the MIV_RV32 IP + configurator. + + @return + This function does not return any value. + */ +static inline void MRV32_mgeci_clear_irq(void) +{ + clear_csr(mip, MRV32_MGECIE_IRQn); +} + +/***************************************************************************//** + The MRV_enable_local_irq() function enables the local interrupts. It takes a + mask value as input. For each set bit in the mask value, the corresponding + interrupt bit in the MIE register is enabled. + + MRV_enable_local_irq( MRV32_SOFT_IRQn | MRV32_TIMER_IRQn | MRV32_EXT_IRQn | + MRV32_MSYS_EIE0_IRQn | + MRV32_MSYS_SUBSYS_IRQn); + */ +static inline void MRV_enable_local_irq(uint32_t mask) +{ + set_csr(mie, mask); +} + +/***************************************************************************//** + The MRV_disable_local_irq() function disables the local interrupts. It takes a + mask value as input. For each set bit in the mask value, the corresponding + interrupt bit in the MIE register is disabled. + + MRV_disable_local_irq( MRV32_SOFT_IRQn | MRV32_TIMER_IRQn | MRV32_EXT_IRQn | + MRV32_MSYS_EIE0_IRQn | + MRV32_MSYS_SUBSYS_IRQn); + */ +static inline void MRV_disable_local_irq(uint32_t mask) +{ + clear_csr(mie, mask); +} +#endif /* MIV_LEGACY_RV32 */ + +/***************************************************************************//** + The MRV_enable_interrupts() function enables all interrupts by setting the + machine mode interrupt enable bit in MSTATUS register. + + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline void MRV_enable_interrupts(void) +{ + set_csr(mstatus, MSTATUS_MIE); +} + +/***************************************************************************//** + The MRV_disable_interrupts() function disables all interrupts by clearing the + machine mode interrupt enable bit in MSTATUS register. + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline void MRV_disable_interrupts(void) +{ + clear_csr(mstatus, MSTATUS_MPIE); + clear_csr(mstatus, MSTATUS_MIE); +} + +/***************************************************************************//** + The MRV_read_mtvec_base() function reads the mtvec base value, which is the + addr used when an interrupt/trap occurs. In the mtvec register, [31:2] is the + BASE address. NOTE: The BASE address must be aligned on a 4B boundary. + + @param + The function does not take any parameters. + + @return + The function returns the value of the BASE field [31:2] as an unsigned 32-bit + value. + */ + +#ifndef MIV_LEGACY_RV32 +#ifndef MIV_RV32_v3_0 +static inline uint32_t MRV_read_mtvec_base (void) +{ + uint32_t mtvec_addr_base = read_csr(mtvec); + return mtvec_addr_base & MTVEC_BASE_ADDR_MASK; +} + +/***************************************************************************//** + The MRV_set_mtvec_base() function takes the mtvec_base address as a unsigned int + and writes the value into the BASE field [31:2] in the mtvec CSR, MODE[1:0] + is Read-only. BASE is 4B aligned, so the lowest 2 bits of mtvec_base are + ignored. + + @param mtvec_base + Any legal value is passed into the function, and it is used as the trap_entry + for interrupts. The PC jumps to this address provided when an interrupt occurs. + In case of vectored interrupts, the address value mentioned in the vector + table under the MIE Register Map is updated to the value passed to this + function parameter. + + @return + This function does not return any value. + */ +static inline void MRV_set_mtvec_base (uint32_t mtvec_base) +{ + mtvec_base = mtvec_base & MTVEC_BASE_ADDR_MASK; + write_csr(mtvec, mtvec_base); +} +#endif /*MIV_RV32_v3_0*/ +#endif /*MIV_LEGACY_RV32*/ + +/***************************************************************************//** + The MRV_read_mtime() function returns the current MTIME register value. + */ +static inline uint64_t MRV_read_mtime(void) +{ + volatile uint32_t hi = 0u; + volatile uint32_t lo = 0u; + + /* when mtime lower word is 0xFFFFFFFF, there will be rollover and + * returned value could be wrong. */ + do { + hi = MTIMEH; + lo = MTIME; + } while(hi != MTIMEH); + + return((((uint64_t)MTIMEH) << 32u) | lo); +} + +/***************************************************************************//** + The MRV_raise_soft_irq() function raises a synchronous software interrupt + by writing into the MSIP register. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV_raise_soft_irq(void) +{ + set_csr(mie, MIP_MSIP); /* Enable software interrupt bit */ + +#ifdef MIV_LEGACY_RV32 + /* You need to make sure that the global interrupt is enabled */ + MSIP = 0x01; /* raise soft interrupt */ +#else + /* Raise soft IRQ on MIV_RV32 processor */ + SUBSYS->soft_reg |= SUBSYS_SOFT_IRQ; +#endif +} + +/***************************************************************************//** + The MRV_clear_soft_irq() function clears a synchronous software interrupt + by clearing the MSIP register. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV_clear_soft_irq(void) +{ +#ifdef MIV_LEGACY_RV32 + MSIP = 0x00u; /* clear soft interrupt */ +#else + /* Clear soft IRQ on MIV_RV32 processor */ + SUBSYS->soft_reg &= ~SUBSYS_SOFT_IRQ; +#endif +} + +/***************************************************************************//** + System tick handler. This handler function gets called when the Machine + timer interrupt asserts. An implementation of this function must be provided + by the application to implement the application specific machine timer + interrupt handling. If application does not provide such implementation, the + weakly linked handler stub function implemented in riscv_hal_stubs.c gets + linked. + */ +void SysTick_Handler(void); + +/***************************************************************************//** + System timer tick configuration. + Configures the machine timer to generate a system tick interrupt at regular + intervals. Takes the number of system clock ticks between interrupts. + + Though this function can take any valid ticks value as parameter, we expect + that, for all practical purposes, a small tick value (to generate periodic + interrupts every few miliseconds) is passed. If you need to generate periodic + events in the range of seconds or more, you may use the SysTick_Handler() to + further count the number of interrupts and hence the larger time intervals. + + @param ticks + This is the number of ticks or clock cycles which are counted down from the + interrupt to be triggered. + + @return + Returns 0 if successful. + Returns 1 if the interrupt interval is not achieved. + */ +uint32_t MRV_systick_config(uint64_t ticks); + +#ifdef __cplusplus +} +#endif +#endif /* RISCV_HAL_H */ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv_rv32_hal_version.h b/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv_rv32_hal_version.h new file mode 100644 index 0000000..4922bf2 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv_rv32_hal_version.h @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_hal_version.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Hardware Abstraction Layer functions for Mi-V soft processors + * + */ + +#ifndef MIV_RV32_HAL_VERSION_H +#define MIV_RV32_HAL_VERSION_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MIV_RV32_HAL_VERSION_MAJOR 4 +#define MIV_RV32_HAL_VERSION_MINOR 2 +#define MIV_RV32_HAL_VERSION_PATCH 100 + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv_rv32_init.c b/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv_rv32_init.c new file mode 100644 index 0000000..85f8aca --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv_rv32_init.c @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_init.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor memory section initializations and start-up code. + * + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern void main(void); + +void _init(void) +{ + /* This function is a placeholder for the case where some more hardware + * specific initializations are required before jumping into the application + * code. You can implement it here. */ + + /* Jump to the application code after all initializations are completed */ + main(); +} + +/* Function called after main() finishes */ +void +_fini(void) +{ +} + +#ifdef __cplusplus +} +#endif + diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv_rv32_plic.h b/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv_rv32_plic.h new file mode 100644 index 0000000..3fd4103 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv_rv32_plic.h @@ -0,0 +1,214 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_plic.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V legacy RV32 soft processor PLIC access data structures and + * functions. + * Legacy RV32 soft processors are DEPRICATED. + * Migrate to MIV_RV32 v3.0 or later. + * + */ +#ifndef RISCV_PLIC_H +#define RISCV_PLIC_H + +#include +#include "miv_rv32_regs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================== + * Interrupt numbers: + */ +#ifdef MIV_LEGACY_RV32 +typedef enum +{ + MRV_NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + External_3_IRQn = 3, + External_4_IRQn = 4, + External_5_IRQn = 5, + External_6_IRQn = 6, + External_7_IRQn = 7, + External_8_IRQn = 8, + External_9_IRQn = 9, + External_10_IRQn = 10, + External_11_IRQn = 11, + External_12_IRQn = 12, + External_13_IRQn = 13, + External_14_IRQn = 14, + External_15_IRQn = 15, + External_16_IRQn = 16, + External_17_IRQn = 17, + External_18_IRQn = 18, + External_19_IRQn = 19, + External_20_IRQn = 20, + External_21_IRQn = 21, + External_22_IRQn = 22, + External_23_IRQn = 23, + External_24_IRQn = 24, + External_25_IRQn = 25, + External_26_IRQn = 26, + External_27_IRQn = 27, + External_28_IRQn = 28, + External_29_IRQn = 29, + External_30_IRQn = 30, + External_31_IRQn = 31 +} IRQn_Type; + +#define EXT_INTR_SOURCES 31 + +/*============================================================================== + * PLIC: Platform Level Interrupt Controller + */ +#define PLIC_BASE_ADDR 0x40000000UL + +typedef struct +{ + volatile uint32_t PRIORITY_THRESHOLD; + volatile uint32_t CLAIM_COMPLETE; + volatile uint32_t reserved[1022]; +} MRV_IRQ_Target_Type; + +typedef struct +{ + volatile uint32_t ENABLES[32]; +} MRV_Target_Enables_Type; + +typedef struct +{ + /*-------------------- Source Priority --------------------*/ + volatile uint32_t SOURCE_PRIORITY[1024]; + + /*-------------------- Pending array --------------------*/ + volatile const uint32_t PENDING_ARRAY[32]; + volatile uint32_t RESERVED1[992]; + + /*-------------------- Target enables --------------------*/ + volatile MRV_Target_Enables_Type TARGET_ENABLES[15808]; + + volatile uint32_t RESERVED2[16384]; + + /*--- Target Priority threshold and claim/complete---------*/ + MRV_IRQ_Target_Type TARGET[15872]; + +} PLIC_Type; + +#define PLIC ((PLIC_Type *)PLIC_BASE_ADDR) + +/*============================================================================== + * The function MRV_PLIC_init() initializes the PLIC controller and enables + * the global external interrupt bit. + */ +static inline void MRV_PLIC_init(void) +{ + uint32_t inc; + unsigned long hart_id = read_csr(mhartid); + + /* Disable all interrupts for the current hart. */ + for(inc = 0; inc < ((EXT_INTR_SOURCES + 32u) / 32u); ++inc) + { + PLIC->TARGET_ENABLES[hart_id].ENABLES[inc] = 0; + } + + /* Set priorities to zero. */ + for(inc = 0; inc < EXT_INTR_SOURCES; ++inc) + { + PLIC->SOURCE_PRIORITY[inc] = 0; + } + + /* Set the threshold to zero. */ + PLIC->TARGET[hart_id].PRIORITY_THRESHOLD = 0; + + /* Enable machine external interrupts. */ + set_csr(mie, MIP_MEIP); +} + +/*============================================================================== + * The function MRV_PLIC_enable_irq() enables the external interrupt for the + * interrupt number indicated by the parameter IRQn. + */ +static inline void MRV_PLIC_enable_irq(IRQn_Type IRQn) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t current = PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32]; + current |= (uint32_t)1 << (IRQn % 32); + PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32] = current; +} + +/*============================================================================== + * The function MRV_PLIC_disable_irq() disables the external interrupt for + * the interrupt number indicated by the parameter IRQn. + + * NOTE: + * This function can be used to disable the external interrupt from outside + * external interrupt handler function. + * This function MUST NOT be used from within the External Interrupt handler. + * If you wish to disable the external interrupt while the interrupt handler + * for that external interrupt is executing then you must use the return value + * EXT_IRQ_DISABLE to return from the extern interrupt handler. + */ +static inline void MRV_PLIC_disable_irq(IRQn_Type IRQn) +{ + unsigned long hart_id = read_csr(mhartid); + uint32_t current = PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32]; + + current &= ~((uint32_t)1 << (IRQn % 32)); + + PLIC->TARGET_ENABLES[hart_id].ENABLES[IRQn / 32] = current; +} + +/*============================================================================== + * The function MRV_PLIC_set_priority() sets the priority for the external + * interrupt for the interrupt number indicated by the parameter IRQn. + */ +static inline void MRV_PLIC_set_priority(IRQn_Type IRQn, uint32_t priority) +{ + PLIC->SOURCE_PRIORITY[IRQn] = priority; +} + +/*============================================================================== + * The function MRV_PLIC_get_priority() returns the priority for the external + * interrupt for the interrupt number indicated by the parameter IRQn. + */ +static inline uint32_t MRV_PLIC_get_priority(IRQn_Type IRQn) +{ + return PLIC->SOURCE_PRIORITY[IRQn]; +} + +/***************************************************************************//** + * MRV_PLIC_clear_pending_irq(void) + * This is only called by the startup hart and only once + * Clears any pending interrupts as PLIC can be in unknown state on startup + */ +static inline void MRV_PLIC_clear_pending_irq(void) +{ + unsigned long hart_id = read_csr(mhartid); + volatile uint32_t int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; + volatile int32_t wait_possible_int; + + while (MRV_NoInterrupt_IRQn != int_num) + { + PLIC->TARGET[hart_id].CLAIM_COMPLETE = int_num; + wait_possible_int = 0xFU; + while (wait_possible_int) + { + wait_possible_int--; + } + + int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; + } +} + +#endif /* MIV_LEGACY_RV32 */ + +#ifdef __cplusplus +} +#endif + +#endif /* RISCV_PLIC_H */ diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv_rv32_regs.h b/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv_rv32_regs.h new file mode 100644 index 0000000..07d58e7 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv_rv32_regs.h @@ -0,0 +1,520 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor register bit mask and shift constants encodings. + * + */ +#ifndef MIV_RV32_REGS_H +#define MIV_RV32_REGS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MSTATUS_UIE 0x00000001UL +#define MSTATUS_SIE 0x00000002UL +#define MSTATUS_HIE 0x00000004UL +#define MSTATUS_MIE 0x00000008UL +#define MSTATUS_UPIE 0x00000010UL +#define MSTATUS_SPIE 0x00000020UL +#define MSTATUS_HPIE 0x00000040UL +#define MSTATUS_MPIE 0x00000080UL +#define MSTATUS_SPP 0x00000100UL +#define MSTATUS_HPP 0x00000600UL +#define MSTATUS_MPP 0x00001800UL +#define MSTATUS_FS 0x00006000UL +#define MSTATUS_XS 0x00018000UL +#define MSTATUS_MPRV 0x00020000UL +#define MSTATUS_SUM 0x00040000UL +#define MSTATUS_MXR 0x00080000UL +#define MSTATUS_TVM 0x00100000UL +#define MSTATUS_TW 0x00200000UL +#define MSTATUS_TSR 0x00400000UL +#define MSTATUS_RES 0x7F800000UL +#define MSTATUS32_SD 0x80000000UL +#define MSTATUS64_SD 0x8000000000000000UL + +#define MCAUSE32_CAUSE 0x7FFFFFFFUL +#define MCAUSE64_CAUSE 0x7FFFFFFFFFFFFFFFUL +#define MCAUSE32_INT 0x80000000UL +#define MCAUSE64_INT 0x8000000000000000UL + +#define MIP_SSIP (1u << IRQ_S_SOFT) +#define MIP_HSIP (1u << IRQ_H_SOFT) +#define MIP_MSIP (1u << IRQ_M_SOFT) +#define MIP_STIP (1u << IRQ_S_TIMER) +#define MIP_HTIP (1u << IRQ_H_TIMER) +#define MIP_MTIP (1u << IRQ_M_TIMER) +#define MIP_SEIP (1u << IRQ_S_EXT) +#define MIP_HEIP (1u << IRQ_H_EXT) +#define MIP_MEIP (1u << IRQ_M_EXT) + +#define PRV_M 3U + +#define VM_MBARE 0U +#define VM_MBB 1U +#define VM_MBBID 2U +#define VM_SV32 8U +#define VM_SV39 9U +#define VM_SV48 10U + +#define IRQ_S_SOFT 1U +#define IRQ_H_SOFT 2U +#define IRQ_M_SOFT 3U +#define IRQ_S_TIMER 5U +#define IRQ_H_TIMER 6U +#define IRQ_M_TIMER 7U +#define IRQ_S_EXT 9U +#define IRQ_H_EXT 10U +#define IRQ_M_EXT 11U + +#define DEFAULT_RSTVEC 0x00001000 +#define DEFAULT_NMIVEC 0x00001004 +#define DEFAULT_MTVEC 0x00001010 +#define CONFIG_STRING_ADDR 0x0000100C +#define EXT_IO_BASE 0x40000000 +#define DRAM_BASE 0x80000000 + +#ifdef __riscv + +#if __riscv_xlen == 64 +# define MSTATUS_SD MSTATUS64_SD +# define SSTATUS_SD SSTATUS64_SD +# define MCAUSE_INT MCAUSE64_INT +# define MCAUSE_CAUSE MCAUSE64_CAUSE +# define RISCV_PGLEVEL_BITS 9 +#else +# define MSTATUS_SD MSTATUS32_SD +# define SSTATUS_SD SSTATUS32_SD +# define RISCV_PGLEVEL_BITS 10 +# define MCAUSE_INT MCAUSE32_INT +# define MCAUSE_CAUSE MCAUSE32_CAUSE +#endif + +#define RISCV_PGSHIFT 12U +#define RISCV_PGSIZE (1U << RISCV_PGSHIFT) + +#ifndef __ASSEMBLER__ + +#ifdef __GNUC__ + +#define read_csr(reg) ({ unsigned long __tmp; \ + __asm__ volatile ("csrr %0, " #reg : "=r"(__tmp)); \ + __tmp; }) + +#define write_csr(reg, val) ({ \ + __asm__ volatile ("csrw " #reg ", %0" :: "rK"(val)); }) + +#define swap_csr(reg, val) ({ unsigned long __tmp; \ + __asm__ volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "rK"(val)); \ + __tmp; }) + +#define set_csr(reg, bit) ({ unsigned long __tmp; \ + __asm__ volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ + __tmp; }) + +#define clear_csr(reg, bit) ({ unsigned long __tmp; \ + __asm__ volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ + __tmp; }) + +#ifdef __riscv_atomic + +#define MASK(nr) (1UL << nr) +#define MASK_NOT(nr) (~(1UL << nr)) + +/** + * atomic_read - read atomic variable + * @v: pointer of type int + * + * Atomically reads the value of @v. + */ +static inline int atomic_read(const int *v) +{ + return *((volatile int *)(v)); +} + +/** + * atomic_set - set atomic variable + * @v: pointer of type int + * @i: required value + * + * Atomically sets the value of @v to @i. + */ +static inline void atomic_set(int *v, int i) +{ + *v = i; +} + +/** + * atomic_add - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v. + */ +static inline void atomic_add(int i, int *v) +{ + __asm__ __volatile__ ( + "amoadd.w zero, %1, %0" + : "+A" (*v) + : "r" (i)); +} + +static inline int atomic_fetch_add(unsigned int mask, int *v) +{ + int out; + + __asm__ __volatile__ ( + "amoadd.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_sub - subtract integer from atomic variable + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v. + */ +static inline void atomic_sub(int i, int *v) +{ + atomic_add(-i, v); +} + +static inline int atomic_fetch_sub(unsigned int mask, int *v) +{ + int out; + + __asm__ __volatile__ ( + "amosub.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_add_return - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v and returns the result + */ +static inline int atomic_add_return(int i, int *v) +{ + register int c; + __asm__ __volatile__ ( + "amoadd.w %0, %2, %1" + : "=r" (c), "+A" (*v) + : "r" (i)); + return (c + i); +} + +/** + * atomic_sub_return - subtract integer from atomic variable + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v and returns the result + */ +static inline int atomic_sub_return(int i, int *v) +{ + return atomic_add_return(-i, v); +} + +/** + * atomic_inc - increment atomic variable + * @v: pointer of type int + * + * Atomically increments @v by 1. + */ +static inline void atomic_inc(int *v) +{ + atomic_add(1, v); +} + +/** + * atomic_dec - decrement atomic variable + * @v: pointer of type int + * + * Atomically decrements @v by 1. + */ +static inline void atomic_dec(int *v) +{ + atomic_add(-1, v); +} + +static inline int atomic_inc_return(int *v) +{ + return atomic_add_return(1, v); +} + +static inline int atomic_dec_return(int *v) +{ + return atomic_sub_return(1, v); +} + +/** + * atomic_sub_and_test - subtract value from variable and test result + * @i: integer value to subtract + * @v: pointer of type int + * + * Atomically subtracts @i from @v and returns + * true if the result is zero, or false for all + * other cases. + */ +static inline int atomic_sub_and_test(int i, int *v) +{ + return (atomic_sub_return(i, v) == 0); +} + +/** + * atomic_inc_and_test - increment and test + * @v: pointer of type int + * + * Atomically increments @v by 1 + * and returns true if the result is zero, or false for all + * other cases. + */ +static inline int atomic_inc_and_test(int *v) +{ + return (atomic_inc_return(v) == 0); +} + +/** + * atomic_dec_and_test - decrement and test + * @v: pointer of type int + * + * Atomically decrements @v by 1 and + * returns true if the result is 0, or false for all other + * cases. + */ +static inline int atomic_dec_and_test(int *v) +{ + return (atomic_dec_return(v) == 0); +} + +/** + * atomic_add_negative - add and test if negative + * @i: integer value to add + * @v: pointer of type int + * + * Atomically adds @i to @v and returns true + * if the result is negative, or false when + * result is greater than or equal to zero. + */ +static inline int atomic_add_negative(int i, int *v) +{ + return (atomic_add_return(i, v) < 0); +} + +static inline int atomic_xchg(int *v, int n) +{ + register int c; + __asm__ __volatile__ ( + "amoswap.w %0, %2, %1" + : "=r" (c), "+A" (*v) + : "r" (n)); + return c; +} + +/** + * atomic_and - Atomically clear bits in atomic variable + * @mask: Mask of the bits to be retained + * @v: pointer of type int + * + * Atomically retains the bits set in @mask from @v + */ +static inline void atomic_and(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoand.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_and(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoand.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_or - Atomically set bits in atomic variable + * @mask: Mask of the bits to be set + * @v: pointer of type int + * + * Atomically sets the bits set in @mask in @v + */ +static inline void atomic_or(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoor.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_or(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoor.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * atomic_xor - Atomically flips bits in atomic variable + * @mask: Mask of the bits to be flipped + * @v: pointer of type int + * + * Atomically flips the bits set in @mask in @v + */ +static inline void atomic_xor(unsigned int mask, int *v) +{ + __asm__ __volatile__ ( + "amoxor.w zero, %1, %0" + : "+A" (*v) + : "r" (mask)); +} + +static inline int atomic_fetch_xor(unsigned int mask, int *v) +{ + int out; + __asm__ __volatile__ ( + "amoxor.w %2, %1, %0" + : "+A" (*v), "=r" (out) + : "r" (mask)); + return out; +} + +/** + * test_and_set_bit - Set a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_set_bit(int nr, volatile unsigned long *addr) +{ + unsigned long __res, __mask; + __mask = MASK(nr); + __asm__ __volatile__ ( \ + "amoor.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to clear + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_clear_bit(int nr, volatile unsigned long *addr) +{ + unsigned long __res, __mask; + __mask = MASK_NOT(nr); + __asm__ __volatile__ ( \ + "amoand.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * test_and_change_bit - Change a bit and return its old value + * @nr: Bit to change + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static inline int test_and_change_bit(int nr, volatile unsigned long *addr) +{ + + unsigned long __res, __mask; + __mask = MASK(nr); + __asm__ __volatile__ ( \ + "amoxor.w %0, %2, %1" \ + : "=r" (__res), "+A" (*addr) \ + : "r" (__mask)); \ + + return ((__res & __mask) != 0); +} + +/** + * set_bit - Atomically set a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * This function is atomic and may not be reordered. + */ + +static inline void set_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOOR.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK(nr))); +} + +/** + * clear_bit - Clears a bit in memory + * @nr: Bit to clear + * @addr: Address to start counting from + * + * clear_bit() is atomic and may not be reordered. + */ +static inline void clear_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOAND.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK_NOT(nr))); +} + +/** + * change_bit - Toggle a bit in memory + * @nr: Bit to change + * @addr: Address to start counting from + * + * change_bit() is atomic and may not be reordered. + */ +static inline void change_bit(int nr, volatile unsigned long *addr) +{ + __asm__ __volatile__ ( \ + "AMOXOR.w zero, %1, %0" \ + : "+A" (*addr) \ + : "r" (MASK(nr))); +} + +#endif /* __riscv_atomic */ + +#endif /* __GNUC__ */ + +#endif /* __ASSEMBLER__ */ + +#endif /* __riscv */ + +#ifdef __cplusplus +} +#endif + +#endif /* RISCV_REGS_H */ diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv_rv32_stubs.c b/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv_rv32_stubs.c new file mode 100644 index 0000000..e26ecfc --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv_rv32_stubs.c @@ -0,0 +1,243 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_stubs.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Stubs for the Mi-V soft processor Interrupt handler. + * + * The functions below will only be linked with the application code if the user + * does not provide an implementation for these functions. These functions are + * defined with weak linking so that they can be overridden by a function with + * same prototype in the user's application code. + * + */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +__attribute__((weak)) void Software_IRQHandler(void) +{ + _exit(10); +} + +__attribute__((weak)) void SysTick_Handler(void) +{ + /* Default handler */ +} + +#ifdef MIV_LEGACY_RV32 +__attribute__((weak)) uint8_t Invalid_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_1_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_2_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_3_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_4_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_5_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_6_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_7_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_8_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_9_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_10_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_11_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_12_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_13_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_14_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_15_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_16_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_17_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_18_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_19_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_20_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_21_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_22_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_23_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_24_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_25_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_26_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_27_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_28_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_29_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_30_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +__attribute__((weak)) uint8_t External_31_IRQHandler(void) +{ + return(0U); /* Default handler */ +} + +#else +__attribute__((weak)) void External_IRQHandler(void) +{ +} +__attribute__((weak)) void MGECI_IRQHandler(void) +{ +} +__attribute__((weak)) void MGEUI_IRQHandler(void) +{ +} +__attribute__((weak)) void SUBSYS_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI0_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI1_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI2_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI3_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI4_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI5_IRQHandler(void) +{ +} +__attribute__((weak)) void Reserved_IRQHandler(void) +{ + _exit(10); +} +#ifndef MIV_RV32_V3_0 /* For MIV_RV32 v3.0 */ +__attribute__((weak)) void MSYS_EI6_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI7_IRQHandler(void) +{ +} +__attribute__((weak)) void SUBSYSR_IRQHandler(void) +{ +} +#endif /* MIV_RV32_V3_0 */ +#endif /* MIV_LEGACY_RV32 */ + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv_rv32_subsys.h b/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv_rv32_subsys.h new file mode 100644 index 0000000..509f13b --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv_rv32_subsys.h @@ -0,0 +1,293 @@ +/******************************************************************************* + * Copyright 2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_subsys.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor SUBSYS regsiter description and API fuctions. + * + */ +#ifndef MIV_RV32_SUBSYS_H +#define MIV_RV32_SUBSYS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef MIV_LEGACY_RV32 +#define MGEUI 16U +#define MGECI 17U +#define MSYS_EI0 24U +#define MSYS_EI1 25U +#define MSYS_EI2 26U +#define MSYS_EI3 27U +#define MSYS_EI4 28U +#define MSYS_EI5 29U + +#define MGEUI_MEIP (1u << MGEUI) +#define MGECI_MEIP (1u << MGECI) +#define MSYS_EI0IP (1u << MSYS_EI0) +#define MSYS_EI1IP (1u << MSYS_EI1) +#define MSYS_EI2IP (1u << MSYS_EI2) +#define MSYS_EI3IP (1u << MSYS_EI3) +#define MSYS_EI4IP (1u << MSYS_EI4) +#define MSYS_EI5IP (1u << MSYS_EI5) + +#define MIV_LOCAL_IRQ_MIN 16 +#ifndef MIV_RV32_V3_0 /*For MIV_RV32 v3.1*/ +#define SUBSYSR 22U +#define SUBSYS_EI 23U +#define MSYS_EI6 30U +#define MSYS_EI7 31U +#define MIV_SUBSYSR (1u << SUBSYSR) +#define MIV_SUBSYS (1u << SUBSYS_EI) +#define MSYS_EI6IP (1u << MSYS_EI6) +#define MSYS_EI7IP (1u << MSYS_EI7) +#define MIV_LOCAL_IRQ_MAX 31 + +#else /* MIV_RV32_V3_0 */ +#define MIV_LOCAL_IRQ_MAX 29 +#define SUBSYS_EI 30U +#define MIP_SUBSYS_REG (1u << SUBSYS_EI) + +#endif /* MIV_RV32_V3_0 */ +#endif /* MIV_LEGACY_RV32 */ + +#ifdef MIV_LEGACY_RV32 +#define MIV_LOCAL_IRQ_MAX 0U +#define MIV_LOCAL_IRQ_MIN 0U +#endif /* MIV_LEGACY_RV32 */ + +#ifdef __cplusplus +} +#endif + +/*-------------------------------------------------------------------------*//** + SUBSYS Register Configuration + ======================================= + For the SUBSYS registers configutation, the following definitions are used in + the SUBSUS API functions. For example, to raise soft interrupts, enable parity + checks, soft reset, and so on. + + | Configuration | Value | Description | + |--------------------------|-------|------------------------------------------------| + | SUBSYS_SOFT_REG_GRP_DED | 0x04 | Mask for the Core GPR DED Reset Register | + | SUBSYS_CFG_PARITY_CHECK | 0x01 | Use to set or clear the parity check on the TCM | + | SUBSYS_SOFT_RESET | 0x01 | Use the SUBSYS soft reset the MIV_RV32 IP core | + | SUBSYS_SOFT_IRQ | 0x02 | Use to raise a software interrupt through SUBSYS| + */ +/*Mask for the Core GPR DED Reset Register*/ +#define SUBSYS_SOFT_REG_GRP_DED 0x04U + +/*Use to set or clear the parity check on the TCM*/ +#define SUBSYS_CFG_PARITY_CHECK 0x01U + +/*Use the SUBSYS soft reset the MIV_RV32 IP core*/ +#define SUBSYS_SOFT_RESET 0x01U + +/*Use to raise a software interrupt through SUBSYS*/ +#define SUBSYS_SOFT_IRQ 0x02U + +/*-------------------------------------------------------------------------*//** + SUBSYS Interrupt Request Masks + ======================================= + The following values correspond to the bit value of the SUBSYS interrupt + enable and interrupt pending register. + + | Interrupt Mask | Value | Description | + |----------------------------|---------|-------------------------------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | TCM ECC controllable error irq enable | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | TCM ECC uncontrollable error irq enable | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | AXI write response error irq enable | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | Icache ECC Correctable error irq | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | Icache ECC Uncorrectable error irq | + | SUBSYS_BASE_ADDR | 0x6000u | Base address of the SUBSYS | + */ +/* TCM ECC correctable error irq enable mask value */ +#define SUBSYS_TCM_ECC_CE_IRQ 0x01u + +/* TCMECC uncorrectable error irq enable */ +#define SUBSYS_TCM_ECC_UCE_IRQ 0x02u + +/* AXI write response error irq enable */ +#define SUBSYS_AXI_WR_RESP_IRQ 0x10u + +/*Icache ECC Correctable error irq*/ +#define SUBSYS_ICACHE_ECC_CE_IRQ 0x40u + +/*Icache ECC Uncorrectable error irq*/ +#define SUBSYS_ICACHE_ECC_UCE_IRQ 0x80u + +/*Base address of the SUBSYS*/ +#define SUBSYS_BASE_ADDR 0x00006000UL + +/***************************************************************************//** + Subsys contains interrupt enable, interrupt pending and Subsys registers + which can be used to enable SUBSYS specific features such as ECC for vaious + memories. For more available features refer to the MIV_RV32 User Guide +*/ +typedef struct +{ + volatile uint32_t cfg; /*Parity is not supported by MIV_RV32 v3.1 and MIV_RV32 v3.0.100*/ + volatile uint32_t reserved0[3]; + volatile uint32_t irq_en; /*offset 0x10*/ + volatile uint32_t irq_pend; + volatile uint32_t reserved1[2]; + volatile uint32_t soft_reg; /*offset 0x20*/ +} SUBSYS_Type; + +#define SUBSYS ((SUBSYS_Type *)SUBSYS_BASE_ADDR) + +/***************************************************************************//** + The MRV32_subsys_enable_irq() function initializes the SUBSYS interrupts. It + takes the logical OR of the following defined IRQ masks as a parameter. + + @param irq_mask + | irq_mask | Value | + |------------------------|------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | + Use logical OR values of one or more interrupts to enable them in the SUBSYS + @return + This function does not return any value. + */ +static inline void MRV32_subsys_enable_irq(uint32_t irq_mask) +{ + SUBSYS->irq_en |= irq_mask; +} + +/***************************************************************************//** + The MRV32_subsys_disable_irq() function disables the SUBSYS interrupts. It + takes the logical OR of the following defined IRQ masks as a parameter. + + @param irq_mask + | irq_mask | Value | + |------------------------|------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | + Use logical OR values of one or more interrupts to disable them in the SUBSYS + @return + This function does not return any value. + */ +static inline void MRV32_subsys_disable_irq(uint32_t irq_mask) +{ + SUBSYS->irq_en &= ~irq_mask; +} + +/***************************************************************************//** + The MRV32_subsys_clear_irq() function clears the SUBSYS interrupts, which was + triggered. It takes the logical OR of the following defined IRQ masks as a + parameter. + @param irq_mask + | irq_mask | Value | + |------------------------|------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | + Use logical OR values of one or more interrupts to disable them in the SUBSYS + @return + This function does not return any value. + */ +static inline void MRV32_subsys_clear_irq(uint32_t irq_mask) +{ + SUBSYS->irq_pend |= irq_mask; +} + +/***************************************************************************//** + The MRV32_subsys_irq_cause() function returns the irq_pend register value which + is present in the SUBSYS. This is be used to check which irq_mask value + caused the SUBSYS interrupt to occur. + @param + This function does not take any parameters + + @return + This function returns the irq_pend regsiter value. +*/ +static inline uint32_t MRV32_subsys_irq_cause() +{ + return SUBSYS->irq_pend; +} + +/***************************************************************************//** + The MRV32_is_gpr_ded() function returns the core_gpr_ded_reset_reg bit value. + When ECC is enabled, the core_gpr_ded_reset_reg is set when the core was + reset due to GPR DED error. + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline uint32_t MRV32_is_gpr_ded(void) +{ + return((SUBSYS->soft_reg & SUBSYS_SOFT_REG_GRP_DED) >> 0x02u); +} + +/***************************************************************************//** + The MRV32_clear_gpr_ded() function must be used to clear the + core_gpr_ded_reset_reg bit. When ECC is enabled, the core_gpr_ded_reset_reg is + set when the core was previously reset due to GPR DED error. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV32_clear_gpr_ded(void) +{ + SUBSYS->soft_reg &= ~SUBSYS_SOFT_REG_GRP_DED; +} + +/***************************************************************************//** + The MRV32_enable_parity_check() function is used to enable parity check on + the TCM and it's interface transactions. This feature is not available on + MIV_RV32 v3.1 and MIV_RV32 v3.0.100 + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV32_enable_parity_check(void) +{ + SUBSYS->cfg |= SUBSYS_CFG_PARITY_CHECK; +} + +/***************************************************************************//** + The MRV32_disable_parity_check() function is used to disable parity check on + the TCM and it's interface transactions. + @param + This function does not take any parameters + + @return + This function does not return any value. + + */ +static inline void MRV32_disable_parity_check(void) +{ + SUBSYS->cfg &= ~SUBSYS_CFG_PARITY_CHECK; +} + +/***************************************************************************//** + The MRV32_cpu_soft_reset() function is used to cause a soft cpu reset on + the MIV_RV32 soft processor core. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV32_cpu_soft_reset(void) +{ + SUBSYS->soft_reg |= SUBSYS_SOFT_RESET; +} +#endif /* MIV_RV32_SUBSYS_H */ \ No newline at end of file diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv_rv32_syscall.c b/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv_rv32_syscall.c new file mode 100644 index 0000000..bd2f881 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/miv_rv32_syscall.c @@ -0,0 +1,364 @@ +/******************************************************************************* + * Copyright 2019 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_syscall.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief Stubs for system calls. + * + */ +#include +#include +#include +#include +#include "miv_rv32_hal.h" + +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +#include + +#ifndef LEGACY_DIR_STRUCTURE +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" +#else +#include "core_uart_apb.h" +#endif + +#endif /*MSCC_STDIO_THRU_CORE_UART_APB*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + +/*------------------------------------------------------------------------------ + * CoreUARTapb instance data for the CoreUARTapb instance used for standard + * output. + */ +static UART_instance_t g_stdio_uart; + +/*============================================================================== + * Flag used to indicate if the UART driver needs to be initialized. + */ +static int g_stdio_uart_init_done = 0; + +/* + * Disable semihosting apis + */ +#pragma import(__use_no_semihosting_swi) + +/*============================================================================== + * sendchar() + */ +int sendchar(int ch) +{ + /*-------------------------------------------------------------------------- + * Initialize the UART driver if it is the first time this function is + * called. + */ + if ( !g_stdio_uart_init_done ) + { + /****************************************************************************** + * Baud value: + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + UART_init( &g_stdio_uart, + MSCC_STDIO_UART_BASE_ADDR, + ((SYS_CLK_FREQ/(16 * MSCC_STDIO_BAUD_VALUE))-1), + (DATA_8_BITS | NO_PARITY)); + + g_stdio_uart_init_done = 1; + } + + /*-------------------------------------------------------------------------- + * Output text to the UART. + */ + UART_send( &g_stdio_uart, (uint8_t *)&ch, 1 ); + + return (ch); +} + +/*============================================================================== + * getachar() + */ +int getachar(void) +{ + uint8_t rx_size; + uint8_t rx_byte; + + if ( !g_stdio_uart_init_done ) + { + /****************************************************************************** + * Baud value: + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + UART_init( &g_stdio_uart, + MSCC_STDIO_UART_BASE_ADDR, + ((SYS_CLK_FREQ/(16 * MSCC_STDIO_BAUD_VALUE))-1), + (DATA_8_BITS | NO_PARITY)); + + g_stdio_uart_init_done = 1; + } + + do + { + rx_size = UART_get_rx(&g_stdio_uart, &rx_byte, 1); + } while(0u == rx_size); + + return rx_byte; +} + +#endif /*MSCC_STDIO_THRU_CORE_UART_APB*/ + +#undef errno +static int errno; + +static char *__env[1] = { 0 }; +char **environ = __env; + +void write_hex(int fd, uint32_t hex) +{ + char towrite; + + write( fd , "0x", 2U ); + + for (uint32_t ii = 8U ; ii > 0U; ii--) + { + uint32_t jj = ii-1U; + uint8_t digit = ((hex & (0xFU << (jj*4U))) >> (jj*4U)); + towrite = digit < 0xAU ? (0x48U + digit) : (0x65U + (digit - 0xAU)); + write( fd, &towrite, 1U); + } +} + + +#ifdef GDB_TESTING +void __attribute__((optimize("O0"))) _exit(int code) +#else +void _exit(int code) +#endif +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + const char * message = "\nProgam has exited with code:"; + + write(STDERR_FILENO, message, strlen(message)); + write_hex(STDERR_FILENO, code); +#endif + + while (1){}; +} + +void *_sbrk(ptrdiff_t incr) +{ + extern char _end; + extern char _heap_end; + extern char __heap_start; + extern char __heap_end; + static char *curbrk = &_end; + void * ret = NULL; + + /* + * Did we allocated memory for the heap in the linker script? + * You need to set HEAP_SIZE to a non-zero value in your linker script if + * the following assertion fires. + */ + ASSERT(&__heap_end > &__heap_start); + + if (((curbrk + incr) < &_end) || ((curbrk + incr) > &_heap_end)) + { + errno = ENOMEM; + ret = ((char *) - 1); + } + else + { + curbrk += incr; + ret = curbrk - incr; + } + + /* + * Did we run out of heap? + * You need to increase the heap size in the linker script if the following + * assertion fires. + * */ + ASSERT(curbrk <= &__heap_end); + + return(ret); +} + +int _isatty(int fd) +{ + int ret = 0; + + if (fd <= 2) /* one of stdin, stdout, stderr */ + { + ret = 1; + } + else + { + errno = EBADF; + ret = 0; + } + + return(ret); +} + +static int stub(int err) +{ + errno = err; + return -1; +} + +int _open(const char* name, int flags, int mode) +{ + return stub(ENOENT); +} + +int _openat(int dirfd, const char* name, int flags, int mode) +{ + return stub(ENOENT); +} + +int _close(int fd) +{ + return stub(EBADF); +} + +int _execve(const char* name, char* const argv[], char* const env[]) +{ + return stub(ENOMEM); +} + +int _fork(void) +{ + return stub(EAGAIN); +} + +int _fstat(int fd, struct stat *st) +{ + int ret = 0; + + if (isatty(fd)) + { + st->st_mode = S_IFCHR; + ret = 0; + } + else + { + ret = stub(EBADF); + } + + return ret; +} + +int _getpid(void) +{ + return 1; +} + +int _kill(int pid, int sig) +{ + return stub(EINVAL); +} + +int _link(const char *old_name, const char *new_name) +{ + return stub(EMLINK); +} + +off_t _lseek(int fd, off_t ptr, int dir) +{ + off_t ret = 0; + if (_isatty(fd)) + { + ret = 0; + } + else + { + ret = stub(EBADF); + } + + return ret; +} + +ssize_t _read(int fd, void* ptr, size_t len) +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + + char* ptr1 = (char*)ptr; + + if (_isatty(fd)) + { + int count; + + for (count = 0; count < len; count++) + { + ptr1[count] = getachar(); + sendchar(ptr1[count]); + + /* Return partial buffer if we get EOL */ + if (('\r' == ptr1[count])||('\n' == ptr1[count])) + { + ptr1[count] = '\n'; + return count; + } + } + + return count; /* Filled the buffer */ + } +#endif + + return stub(EBADF); +} + +int _stat(const char* file, struct stat* st) +{ + return stub(EACCES); +} + +clock_t _times(struct tms* buf) +{ + return stub(EACCES); +} + +int _unlink(const char* name) +{ + return stub(ENOENT); +} + +int _wait(int* status) +{ + return stub(ECHILD); +} + +ssize_t _write(int fd, const void* ptr, size_t len) +{ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB + int count_out; + char* ptr1 = (char*)ptr; + + /*-------------------------------------------------------------------------- + * Output text to the UART. + */ + count_out = 0; + while(len--) + { + sendchar(ptr1[count_out]); + count_out++; + } + + errno = 0; + return count_out; + +#else /* MSCC_STDIO_THRU_CORE_UART_APB */ + + return stub(EBADF); + +#endif /* MSCC_STDIO_THRU_CORE_UART_APB */ + +} + +#ifdef __cplusplus +} +#endif diff --git a/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/sample_fpga_design_config.h b/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/sample_fpga_design_config.h new file mode 100644 index 0000000..a380d96 --- /dev/null +++ b/applications/user-crypto/miv-rv32-rsa-services/src/platform/miv_rv32_hal/sample_fpga_design_config.h @@ -0,0 +1,167 @@ +/******************************************************************************* + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file sample_fpga_design_config.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Sample design configuration settings + * + */ + /*========================================================================*//** + @mainpage + Example file detailing how the fpga_design_config.h should be constructed + for the SoftConsole project targeted for Mi-V processors. + + @section intro_sec Introduction + The SoftConsole project targeted for Mi-V processors now have an improved + folder structure. Detailed description of the folder structure is available + at https://github.com/Mi-V-Soft-RISC-V/miv-rv32-documentation. + + The fpga_design_config.h must be stored as shown below + /boards//fpga_design_config.h + + Currently this file must be hand crafted when using the Mi-V Soft Processor. + In future, all the design and soft IP configurations will be automatically + generated from the Libero design description data. + + You can use this sample file as an example. + Rename this file from sample_fpga_design_config.h to fpga_design_config.h + and then customize it per your hardware design. + + @section Project configuration Instructions + 1. Change SYS_CLK_FREQ define to frequency of Mi-V Soft processor clock + 2 Add all the soft IP core BASE addresses + 3. Add the peripheral Core Interrupts to Mi-V Soft processor IRQ number + mappings + 4. Define MSCC_STDIO_UART_BASE_ADDR if you want a CoreUARTapb mapped to + STDIO + + **NOTE** + In the legacy folder structures, the file hw_config.h as was used at the + root of the project folder. This file is now depricated. + +*//*=========================================================================*/ + +#ifndef FPGA_DESIGN_CONFIG_H_ +#define FPGA_DESIGN_CONFIG_H_ + +/***************************************************************************//** + * Soft-processor clock definition + * This is the only clock brought over from the Mi-V Libero design. + */ +#ifndef SYS_CLK_FREQ +#define SYS_CLK_FREQ 50000000UL +#endif + +/***************************************************************************//** + * Peripheral base addresses. + * Format of define is: + * __BASE_ADDR + * The field is optional if there is only one instance of the core + * in the design + * MIV_ESS is an extended peripheral subsystem IP core with peripherals + * connections as defined below. + * The system can be further extended by attaching APB peripherals to the + * empty APB slots. + */ +#define MIV_ESS_PLIC_BASE_ADDR 0x70000000UL +#define COREUARTAPB0_BASE_ADDR 0x71000000UL +#define MIV_MTIMER_BASE_ADDR 0x72000000UL +#define MIV_ESS_APBSLOT3_BASE_ADDR 0x73000000UL +#define MIV_ESS_APBSLOT4_BASE_ADDR 0x74000000UL +#define COREGPIO_OUT_BASE_ADDR 0x75000000UL +#define CORESPI_BASE_ADDR 0x76000000UL +#define MIV_ESS_uDMA_BASE_ADDR 0x78000000UL +#define MIV_ESS_WDOG_BASE_ADDR 0x79000000UL +#define MIV_ESS_I2C_BASE_ADDR 0x7A000000UL +#define MIV_ESS_APBSLOTB_BASE_ADDR 0x7B000000UL +#define MIV_ESS_APBSLOTC_BASE_ADDR 0x7C000000UL +#define MIV_ESS_APBSLOTD_BASE_ADDR 0x7D000000UL +#define MIV_ESS_APBSLOTE_BASE_ADDR 0x7E000000UL +#define MIV_ESS_APBSLOTF_BASE_ADDR 0x7F000000UL + +/***************************************************************************//** + * Peripheral Interrupts are mapped to the corresponding Mi-V Soft processor + * interrupt in the Libero design. + * + * On the legacy RV32 cores, there can be up to 31 external interrupts (IRQ[30:0] + * pins). The legacy RV32 Soft processor external interrupts are defined in the + miv_rv32_plic.h + * + * These are of the form + * typedef enum +{ + NoInterrupt_IRQn = 0, + External_1_IRQn = 1, + External_2_IRQn = 2, + . + . + . + External_31_IRQn = 31 +} IRQn_Type; + + On the legacy RV32 processors, the PLIC identifies the interrupt and passes it + on to the processor core. The interrupt 0 is not used. The pin IRQ[0] should + map to External_1_IRQn likewise IRQ[30] should map to External_31_IRQn + +e.g + +#define TIMER0_IRQn External_30_IRQn +#define TIMER1_IRQn External_31_IRQn + + The MIV_RV32 soft processor has up to six optional system interrupts, MSYS_EI[n] + in addition to one EXT_IRQ. + The MIV_RV32 does not have an inbuilt PLIC and all the interrupts are directly + delivered to the processor core, hence unlike legacy RV32 cores, no interrupt + number mapping is necessary on MIV_RV32 core. + */ + +/**************************************************************************** + * Baud value to achieve a 115200 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ +#define BAUD_VALUE_115200 ((SYS_CLK_FREQ / (16 * 115200)) - 1) + +/****************************************************************************** + * Baud value to achieve a 57600 baud rate with system clock defined by + * SYS_CLK_FREQ. + * This value is calculated using the following equation: + * BAUD_VALUE = (CLOCK / (16 * BAUD_RATE)) - 1 + *****************************************************************************/ + #define BAUD_VALUE_57600 ((SYS_CLK_FREQ / (16 * 57600)) - 1) + +/***************************************************************************//** + * Define MSCC_STDIO_THRU_CORE_UART_APB in the project settings if you want the + * standard IOs to be redirected to a terminal via UART. + */ +#ifdef MSCC_STDIO_THRU_CORE_UART_APB +/* + * A base address mapping for the STDIO printf/scanf mapping to CortUARTapb + * must be provided if it is being used + * + * e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR + */ +#define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB0_BASE_ADDR + +#ifndef MSCC_STDIO_UART_BASE_ADDR +#error MSCC_STDIO_UART_BASE_ADDR not defined- e.g. #define MSCC_STDIO_UART_BASE_ADDR COREUARTAPB1_BASE_ADDR +#endif + +#ifndef MSCC_STDIO_BAUD_VALUE +/* + * The MSCC_STDIO_BAUD_VALUE define should be set in your project's settings to + * specify the baud value used by the standard output CoreUARTapb instance for + * generating the UART's baud rate if you want a different baud rate from the + * default of 115200 baud + */ +#define MSCC_STDIO_BAUD_VALUE 115200 +#endif /*MSCC_STDIO_BAUD_VALUE*/ + +#endif /* end of MSCC_STDIO_THRU_CORE_UART_APB */ +/******************************************************************************* + * End of user edit section + */ +#endif /* FPGA_DESIGN_CONFIG_H_ */