Index: firmware/App/Common.h =================================================================== diff -u -rfc4f469fe234371e8f2b9a0625acc66faa6899de -rba60692a9ecaf59cb5cb8490f4276917f43bcd01 --- firmware/App/Common.h (.../Common.h) (revision fc4f469fe234371e8f2b9a0625acc66faa6899de) +++ firmware/App/Common.h (.../Common.h) (revision ba60692a9ecaf59cb5cb8490f4276917f43bcd01) @@ -16,6 +16,12 @@ #define MASK_OFF_LSB 0xFF00 ///< Bits to mask off the least significant byte of a 2-byte word #define SHIFT_8_BITS_FOR_BYTE_SHIFT 8 ///< Number of bits to shift in order to shift a byte +#define GET_LSB_OF_WORD(w) ((U08)((w) & MASK_OFF_MSB)) ///< Macro returns the least signficant byte of a 2-byte word +#define GET_MSB_OF_WORD(w) ((U08)(((w) >> SHIFT_8_BITS_FOR_BYTE_SHIFT) & MASK_OFF_MSB)) ///< Macro returns the most signficant byte of a 2-byte word +#define MAKE_WORD_OF_BYTES(h, l) ((((U16)(h) << SHIFT_8_BITS_FOR_BYTE_SHIFT) & MASK_OFF_LSB) | ((U16)(l) & MASK_OFF_MSB)) ///< Macro merges two bytes into a 2-byte word +#define INC_WRAP(v, l, u) ((v) >= (u) ? (l) : ((v) + 1)) ///< Macro increments a value and wraps to a minimum when a maximum is reached + + // **** Types **** typedef float F32; ///< 32-bit floating point type Index: firmware/App/Services/Comm.c =================================================================== diff -u --- firmware/App/Services/Comm.c (revision 0) +++ firmware/App/Services/Comm.c (revision ba60692a9ecaf59cb5cb8490f4276917f43bcd01) @@ -0,0 +1,39 @@ +/* + * Comm.c + * + * Created on: Aug 19, 2024 + * Author: fw + */ + +#include "sci.h" +#include "sys_dma.h" + +#include "Comm.h" + +void setSCI2DMAReceiveInterrupt( void ) +{ + scilinREG->SETINT = SCI_DMA_RECEIVE_INT; +} + +void setSCI2DMATransmitInterrupt( void ) +{ + scilinREG->SETINT = SCI_DMA_TRANSMIT_INT; +} + +void clearSCI2DMAReceiveInterrupt( void ) +{ + scilinREG->CLEARINT = SCI_DMA_RECEIVE_INT; +} + +/*********************************************************************//** + * @brief + * The clearSCI2DMATransmitInterrupt function disables DMA transmit interrupts + * for the SCI2 peripheral. + * @details Inputs: none + * @details Outputs: DMA transmit interrupt is disabled. + * @return none + *************************************************************************/ +void clearSCI2DMATransmitInterrupt( void ) +{ + scilinREG->CLEARINT = SCI_DMA_TRANSMIT_INT; +} Index: firmware/App/Services/Comm.h =================================================================== diff -u --- firmware/App/Services/Comm.h (revision 0) +++ firmware/App/Services/Comm.h (revision ba60692a9ecaf59cb5cb8490f4276917f43bcd01) @@ -0,0 +1,21 @@ +/* + * Comm.h + * + * Created on: Aug 19, 2024 + * Author: fw + */ + +#ifndef __COMM_H__ +#define __COMM_H__ + +#include "BLCommon.h" + +#define SCI_DMA_TRANSMIT_INT 0x00010000 ///< Bit mask for setting/clearing serial DMA transmit interrupts. +#define SCI_DMA_RECEIVE_INT 0x00060000 ///< Bit mask for setting/clearing serial DMA receive interrupts. + +void setSCI2DMAReceiveInterrupt( void ); +void setSCI2DMATransmitInterrupt( void ); +void clearSCI2DMAReceiveInterrupt( void ); +void clearSCI2DMATransmitInterrupt( void ); + +#endif Index: firmware/App/Services/FPGA.c =================================================================== diff -u -rfc4f469fe234371e8f2b9a0625acc66faa6899de -rba60692a9ecaf59cb5cb8490f4276917f43bcd01 --- firmware/App/Services/FPGA.c (.../FPGA.c) (revision fc4f469fe234371e8f2b9a0625acc66faa6899de) +++ firmware/App/Services/FPGA.c (.../FPGA.c) (revision ba60692a9ecaf59cb5cb8490f4276917f43bcd01) @@ -10,6 +10,7 @@ #include "sci.h" #include "sys_dma.h" +#include "Comm.h" #include "FPGA.h" #include "Utilities.h" @@ -24,24 +25,29 @@ #define SCI2_RECEIVE_DMA_REQUEST 28 ///< Serial port 2 receive DMA request line. #define SCI2_TRANSMIT_DMA_REQUEST 29 ///< Serial port 2 transmit DMA request line. -#define GET_LSB_OF_WORD(w) ((U08)((w) & MASK_OFF_MSB)) ///< Macro returns the least signficant byte of a 2-byte word -#define GET_MSB_OF_WORD(w) ((U08)(((w) >> SHIFT_8_BITS_FOR_BYTE_SHIFT) & MASK_OFF_MSB)) ///< Macro returns the most signficant byte of a 2-byte word -#define MAKE_WORD_OF_BYTES(h, l) ((((U16)(h) << SHIFT_8_BITS_FOR_BYTE_SHIFT) & MASK_OFF_LSB) | ((U16)(l) & MASK_OFF_MSB)) ///< Macro merges two bytes into a 2-byte word -#define INC_WRAP(v, l, u) ((v) >= (u) ? (l) : ((v) + 1)) ///< Macro increments a value and wraps to a minimum when a maximum is reached +#define FPGA_CRC_LEN 2 ///< FPGA CRC byte length. +#define FPGA_WRITE_CMD_HDR_LEN 4 ///< FPGA write command header byte length. +#define FPGA_WRITE_RSP_HDR_LEN 3 ///< FPGA write command response header byte length. +#define FPGA_WRITE_CMD_CODE 0x55 ///< FPGA write command code. +#define FPGA_WRITE_CMD_ACK 0xA5 ///< FPGA write command ACK code. #define FPGA_READ_CMD_CODE 0x5A ///< FPGA read command code. +#define FPGA_READ_CMD_ACK 0xAA ///< FPGA read command ACK code. #define FPGA_HEADER_START_ADDR 0x0000 ///< Start address for FPGA header data. #define FPGA_BULK_READ_START_ADDR 0x0100 ///< Start address for FPGA continuous priority reads. -#define FPGA_READ_CMD_ACK 0xAA ///< FPGA read command ACK code. +#define FPGA_WRITE_START_ADDR 0x000B ///< Start address for FPGA continuous priority writes. // TODO does this vary? +#define FPGA_FLASH_CONTROL_REG_ADDR 0x090E +#define FPGA_FLASH_STATUS_REG_ADDR 0x0900 ///< FPGA flash status register address. +#define FPGA_FIFO_COUNT_REG_ADDR 0x0902 ///< FPGA FIFO count register address. +#define FPGA_FLASH_DATA_REG_ADDR 0x0A00 ///< FPGA flash data register address. + +#define FPGA_UPDATE_REGISTER_ADDR ( FPGA_WRITE_START_ADDR + 4 ) #define FPGA_READ_CMD_HDR_LEN 4 ///< FPGA read command header byte length. #define FPGA_READ_RSP_HDR_LEN 3 ///< FPGA read command response header byte length. #define FPGA_UPDATE_REQUEST_INDEX ( FPGA_READ_RSP_HDR_LEN + 1 ) // TODO Get this value from Noe, make sure the index is the same in all of the stacks #define UPDATE_REQUESTED_VALUE 1 -#define SCI_DMA_TRANSMIT_INT 0x00010000 ///< Bit mask for setting/clearing serial DMA transmit interrupts. -#define SCI_DMA_RECEIVE_INT 0x00060000 ///< Bit mask for setting/clearing serial DMA receive interrupts. - typedef enum { FPGA_COMM_IDLE = 0, @@ -58,10 +64,11 @@ FPGA_READ_UPDATE_REG, FPGA_WRITE_UPDATE_REG, FPGA_RESET_FLASH, - FPGA_ERASE_FLASH, + FPGA_ERASE_FIFO, FPGA_ENABLE_FLASH, - FPGA_CHECK_FIFO, - FPGA_WRITE_UPDATE_DATA, + FPGA_CHECK_FLASH_STATUS, + FPGA_CHECK_FIFO_COUNT, + FPGA_FLASH_UPDATE_DATA, NUM_OF_FPGA_JOBS, } FPGA_JOBS_T; @@ -76,18 +83,12 @@ } FPGA_STATE_T; #pragma pack(push,1) -/*typedef struct -{ - FPGA_COMM_STATE_T fpgaCommRead; // TODO remove - FPGA_COMM_STATE_T fpgaCommWrite; -} FPGA_COMM_STATUS_T; -*/ - typedef struct { U16 fpgaJobAddress; U08 fpgaJobSize; - BOOL read; + U08* fpgaWriteStartAddress; + U08 fpgaIsJobWrite; } FPGA_JOB_SPECS_T; typedef struct @@ -112,20 +113,6 @@ } FPGA_HEADER_T; // Read only on FPGA #pragma pack(pop) -static const U08 STACK_FPGA_ID[ NUM_OF_FW_STACKS ] = { 0x5A, 0x61, 0xFF }; // TODO update with the real FPGA IDs -static const FPGA_JOB_SPECS_T JOBS_SPECS[ NUM_OF_FPGA_JOBS ] = { - { FPGA_HEADER_START_ADDR, sizeof( FPGA_HEADER_T ), TRUE }, - { FPGA_BULK_READ_START_ADDR, FPGA_MAX_READ_SIZE, TRUE }, - - { FPGA_HEADER_START_ADDR, sizeof( FPGA_HEADER_T ), TRUE }, // TODO fill up - { FPGA_HEADER_START_ADDR, sizeof( FPGA_HEADER_T ), TRUE }, - { FPGA_HEADER_START_ADDR, sizeof( FPGA_HEADER_T ), TRUE }, - { FPGA_HEADER_START_ADDR, sizeof( FPGA_HEADER_T ), TRUE }, - { FPGA_HEADER_START_ADDR, sizeof( FPGA_HEADER_T ), TRUE }, - { FPGA_HEADER_START_ADDR, sizeof( FPGA_HEADER_T ), TRUE } -}; - - // FPGA comm buffers static U08 fpgaWriteCmdBuffer[ FPGA_WRITE_CMD_BUFFER_LEN ]; ///< FPGA write command buffer. Holds the next FPGA write command to be transmitted. static U08 fpgaReadCmdBuffer[ FPGA_READ_CMD_BUFFER_LEN ]; ///< FPGA read command buffer. Holds the next FPGA read command to be transmitted. @@ -143,15 +130,35 @@ static U08 fpgaUpdateRegisterStatus; static FPGA_JOBS_Q_STATUS_T fpgaJobsQStatus; +static const U08 STACK_FPGA_ID[ NUM_OF_FW_STACKS ] = { 0x5A, 0x61, 0xFF }; // TODO update with the real FPGA IDs +static const U16 DISABLE_UPDATE_REG_CMD = 5; // TODO what is this value? 0? +static const U08 FPGA_RESET_FLASH_CMD = 0x01; +static const U08 FPGA_ERASE_FIFO_CMD = 0x08; +static const U08 FPGA_ENABLE_FLASH_CMD = 0x00; +static const FPGA_JOB_SPECS_T JOBS_SPECS[ NUM_OF_FPGA_JOBS ] = { + { FPGA_HEADER_START_ADDR, sizeof( FPGA_HEADER_T ), 0, FALSE }, // FPGA_READ_HEADER + { FPGA_BULK_READ_START_ADDR, FPGA_MAX_READ_SIZE, 0, FALSE }, // FPGA_READ_UPDATE_REG + { FPGA_UPDATE_REGISTER_ADDR, sizeof( U16 ), (U08*)&DISABLE_UPDATE_REG_CMD, TRUE }, // FPGA_WRITE_UPDATE_REG + { FPGA_FLASH_CONTROL_REG_ADDR, sizeof( U08 ), (U08*)&FPGA_RESET_FLASH_CMD, TRUE }, // FPGA_RESET_FLASH + { FPGA_FLASH_CONTROL_REG_ADDR, sizeof( U08 ), (U08*)&FPGA_ERASE_FIFO_CMD, TRUE }, // FPGA_ERASE_FIFO + { FPGA_FLASH_CONTROL_REG_ADDR, sizeof( U08 ), (U08*)&FPGA_ENABLE_FLASH_CMD, TRUE }, // FPGA_ENABLE_FLASH + { FPGA_FLASH_STATUS_REG_ADDR, sizeof( U16 ), 0, FALSE }, // FPGA_CHECK_FLASH_STATUS + { FPGA_FIFO_COUNT_REG_ADDR, sizeof( U16 ), 0, FALSE }, // FPGA_CHECK_FIFO_COUNT + { FPGA_FLASH_DATA_REG_ADDR, SW_UPDATE_FLASH_BUFFER_SIZE, fpgaWriteCmdBuffer, TRUE } // FPGA_FLASH_UPDATE_DATA +}; static void initDMA( void ); static void consumeUnexpectedData( void ); -static void setSCI2DMAReceiveInterrupt( void ); -static void setSCI2DMATransmitInterrupt( void ); + static void setupDMAForReadResp( U32 bytes2Receive ); static void setupDMAForReadCmd( U32 bytes2Transmit ); static void startDMAReceiptOfReadResp( void ); static void startDMAReadCmd( void ); +static void setupDMAForWriteCmd( U32 bytes2Transmit ); +static void startDMAWriteCmd( void ); +static void setupDMAForWriteResp( U32 bytes2Receive ); +static void startDMAReceiptOfWriteResp( void ); + static void resetFPGACommFlags( void ); static void enqueue( FPGA_JOBS_T job ); static void dequeue( void ); @@ -193,6 +200,7 @@ case FPGA_RCV_WRITE_RESP_FROM_FPGA_STATE: fpgaState = handleFPGAReceiveWriteRespFromFPGAState(); + break; case FPGA_READ_FROM_FPGA_STATE: fpgaState = handleFPGAReadFromFPGAState(); @@ -222,24 +230,6 @@ } } -void clearSCI2DMAReceiveInterrupt( void ) -{ - scilinREG->CLEARINT = SCI_DMA_RECEIVE_INT; -} - -/*********************************************************************//** - * @brief - * The clearSCI2DMATransmitInterrupt function disables DMA transmit interrupts - * for the SCI2 peripheral. - * @details Inputs: none - * @details Outputs: DMA transmit interrupt is disabled. - * @return none - *************************************************************************/ -void clearSCI2DMATransmitInterrupt( void ) -{ - scilinREG->CLEARINT = SCI_DMA_TRANSMIT_INT; -} - BOOL hasUpdateBeenRequested( void ) { BOOL status = FALSE; @@ -361,16 +351,7 @@ } } -static void setSCI2DMAReceiveInterrupt( void ) -{ - scilinREG->SETINT = SCI_DMA_RECEIVE_INT; -} -void setSCI2DMATransmitInterrupt( void ) -{ - scilinREG->SETINT = SCI_DMA_TRANSMIT_INT; -} - static void setupDMAForReadResp( U32 bytes2Receive ) { // Verify # of bytes does not exceed buffer length @@ -403,6 +384,73 @@ setSCI2DMATransmitInterrupt(); } +/*********************************************************************//** + * @brief + * The setupDMAForWriteCmd function sets the byte count for the next DMA + * write command to the FPGA. + * @details Inputs: none + * @details Outputs: number of bytes for next FPGA write command is set + * @param bytes2Transmit number of bytes to be transmitted via DMA to the FPGA + * @return none + *************************************************************************/ +static void setupDMAForWriteCmd( U32 bytes2Transmit ) +{ + // Verify # of bytes does not exceed buffer length + if ( bytes2Transmit <= FPGA_WRITE_CMD_BUFFER_LEN ) + { + fpgaDMAWriteControlRecord.FRCNT = bytes2Transmit; + } +} + +/*********************************************************************//** + * @brief + * The startDMAWriteCmd function initiates the DMA transmit for the next + * DMA write command to the FPGA. + * @details Inputs: none + * @details Outputs: DMA write command to FPGA is initiated + * @return none + *************************************************************************/ +static void startDMAWriteCmd( void ) +{ + dmaSetCtrlPacket( DMA_CH2, fpgaDMAWriteControlRecord ); + dmaSetChEnable( DMA_CH2, DMA_HW ); + setSCI2DMATransmitInterrupt(); +} + +/*********************************************************************//** + * @brief + * The setupDMAForWriteResp function sets the expected byte count for the + * next DMA write command response from the FPGA. + * @details Inputs: none + * @details Outputs: number of expected bytes for next FPGA write command response is set + * @param bytes2Receive number of bytes expected to be transmitted via DMA from the FPGA + * @return none + *************************************************************************/ +static void setupDMAForWriteResp( U32 bytes2Receive ) +{ + // Verify # of bytes does not exceed buffer length + if ( bytes2Receive <= FPGA_WRITE_RSP_BUFFER_LEN ) + { + fpgaDMAWriteRespControlRecord.FRCNT = bytes2Receive; + } +} + +/*********************************************************************//** + * @brief + * The startDMAReceiptOfWriteResp function initiates readiness of the DMA + * receiver for the next DMA write command response from the FPGA. + * @details Inputs: none + * @details Outputs: DMA write command response is ready to be received from the FPGA + * @return none + *************************************************************************/ +static void startDMAReceiptOfWriteResp( void ) +{ + dmaSetCtrlPacket( DMA_CH0, fpgaDMAWriteRespControlRecord ); + dmaSetChEnable( DMA_CH0, DMA_HW ); + setSCI2DMAReceiveInterrupt(); +} + + static void resetFPGACommFlags( void ) { fpgaJobsQStatus.fpgaCommRead = FPGA_COMM_IDLE; @@ -449,41 +497,73 @@ { dequeue(); - state = ( TRUE == JOBS_SPECS[ fpgaJobsQStatus.fpgaCurrentJob ].read ? FPGA_READ_FROM_FPGA_STATE : FPGA_WRITE_TO_FPGA_STATE ); + state = ( FALSE == JOBS_SPECS[ fpgaJobsQStatus.fpgaCurrentJob ].fpgaIsJobWrite ? FPGA_READ_FROM_FPGA_STATE : FPGA_WRITE_TO_FPGA_STATE ); } return state; } static FPGA_STATE_T handleFPGAWriteToFPGAState( void ) { - FPGA_STATE_T state = FPGA_READ_FROM_FPGA_STATE; + FPGA_STATE_T state = FPGA_RCV_WRITE_RESP_FROM_FPGA_STATE; U16 crc = 0; + U16 jobAddress = JOBS_SPECS[ fpgaJobsQStatus.fpgaCurrentJob ].fpgaJobAddress; + U08 jobSize = JOBS_SPECS[ fpgaJobsQStatus.fpgaCurrentJob ].fpgaJobSize; + U08* value2Write = JOBS_SPECS[ fpgaJobsQStatus.fpgaCurrentJob ].fpgaWriteStartAddress; + U08 firstCRCIndex = FPGA_WRITE_CMD_HDR_LEN + jobSize; + U08 secondCRCIndex = FPGA_WRITE_CMD_HDR_LEN + jobSize + 1; + memcpy( &fpgaWriteCmdBuffer[ FPGA_WRITE_CMD_HDR_LEN ], value2Write, jobSize ); + // Construct bulk read command to read sensor data registers starting at address 8 - fpgaReadCmdBuffer[ 0 ] = FPGA_READ_CMD_CODE; - fpgaReadCmdBuffer[ 1 ] = GET_LSB_OF_WORD( FPGA_BULK_READ_START_ADDR ); - fpgaReadCmdBuffer[ 2 ] = GET_MSB_OF_WORD( FPGA_BULK_READ_START_ADDR ); - fpgaReadCmdBuffer[ 3 ] = FPGA_MAX_READ_SIZE; - crc = crc16( fpgaReadCmdBuffer, FPGA_READ_CMD_HDR_LEN ); - fpgaReadCmdBuffer[ 4 ] = GET_MSB_OF_WORD( crc ); - fpgaReadCmdBuffer[ 5 ] = GET_LSB_OF_WORD( crc ); + fpgaWriteCmdBuffer[ 0 ] = FPGA_WRITE_CMD_CODE; + fpgaWriteCmdBuffer[ 1 ] = GET_LSB_OF_WORD( jobAddress ); + fpgaWriteCmdBuffer[ 2 ] = GET_MSB_OF_WORD( jobAddress ); + fpgaWriteCmdBuffer[ 3 ] = jobSize; + crc = crc16( fpgaWriteCmdBuffer, FPGA_WRITE_CMD_HDR_LEN + jobSize ); + fpgaWriteCmdBuffer[ firstCRCIndex ] = GET_MSB_OF_WORD( crc ); + fpgaWriteCmdBuffer[ secondCRCIndex ] = GET_LSB_OF_WORD( crc ); // Prep DMA for sending the read cmd and receiving the response - //fpgaCommStatus.fpgaCommRead = FPGA_COMM_READ_IN_PROGRESS; + fpgaJobsQStatus.fpgaCommWrite = FPGA_COMM_WRITE_IN_PROGRESS; - setupDMAForReadResp( FPGA_READ_RSP_HDR_LEN + FPGA_MAX_READ_SIZE + sizeof( U16 ) ); - setupDMAForReadCmd( FPGA_READ_CMD_HDR_LEN + sizeof( U16 ) ); - startDMAReceiptOfReadResp(); - startDMAReadCmd(); + // Prep DMA for sending the bulk write cmd and receiving its response + setupDMAForWriteCmd( FPGA_WRITE_CMD_HDR_LEN + jobSize + FPGA_CRC_LEN ); + setupDMAForWriteResp( FPGA_WRITE_RSP_HDR_LEN + FPGA_CRC_LEN ); + // Initiate bulk write command and its receipt - read will follow + startDMAReceiptOfWriteResp(); + startDMAWriteCmd(); + return state; } static FPGA_STATE_T handleFPGAReceiveWriteRespFromFPGAState( void ) { FPGA_STATE_T state = FPGA_RCV_WRITE_RESP_FROM_FPGA_STATE; + if ( FPGA_COMM_WRITE_RESP_RECEIVED == fpgaJobsQStatus.fpgaCommWrite ) + { + if ( FPGA_WRITE_CMD_ACK == fpgaWriteResponseBuffer[ 0 ] ) + { + // Message is an ack - check CRC + U32 rspSize = FPGA_READ_RSP_HDR_LEN; + U32 crcPos = rspSize; + U16 crc = MAKE_WORD_OF_BYTES( fpgaWriteResponseBuffer[ crcPos ], fpgaWriteResponseBuffer[ crcPos + 1 ] ); + + // Does the FPGA response CRC checkout? + if ( crc == crc16( fpgaWriteResponseBuffer, rspSize ) ) + { + // CRC failed + state = FPGA_IDLE_STATE; + } + else + { + // TODO error handling + } + } + } + return state; } Index: firmware/App/Services/FPGA.h =================================================================== diff -u -rfc4f469fe234371e8f2b9a0625acc66faa6899de -rba60692a9ecaf59cb5cb8490f4276917f43bcd01 --- firmware/App/Services/FPGA.h (.../FPGA.h) (revision fc4f469fe234371e8f2b9a0625acc66faa6899de) +++ firmware/App/Services/FPGA.h (.../FPGA.h) (revision ba60692a9ecaf59cb5cb8490f4276917f43bcd01) @@ -16,9 +16,6 @@ void signalFPGAReceiptCompleted( void ); -void clearSCI2DMAReceiveInterrupt( void ); -void clearSCI2DMATransmitInterrupt( void ); - BOOL hasUpdateBeenRequested( void ); BOOL isFPGAIDValid( void ); Index: firmware/App/Services/Interrupts.c =================================================================== diff -u -rfc4f469fe234371e8f2b9a0625acc66faa6899de -rba60692a9ecaf59cb5cb8490f4276917f43bcd01 --- firmware/App/Services/Interrupts.c (.../Interrupts.c) (revision fc4f469fe234371e8f2b9a0625acc66faa6899de) +++ firmware/App/Services/Interrupts.c (.../Interrupts.c) (revision ba60692a9ecaf59cb5cb8490f4276917f43bcd01) @@ -11,6 +11,7 @@ #include "sys_dma.h" #include "BLCommon.h" +#include "Comm.h" #include "CommBuffers.h" #include "FPGA.h" #include "TaskGeneral.h" @@ -100,7 +101,7 @@ case DMA_CH2: // FPGA transmit channel clearSCI2DMATransmitInterrupt(); - //signalFPGATransmitCompleted(); + //signalFPGATransmitCompleted(); // TODO in HD this increments a counter that is not used anywhere, why? break; default: