/* 2012-10-19 Started RoJ 2012-12-13 BETA-version RoJ 2013-01-21 Version 1.0 RoJ 2014-xx-xx Version 1.1 RoJ Common generated Flisp control 2015-03-08 Version 1.2 RoJ Changed NF functionality to "step instruction" 2019-03-19 Version 1.3 RoJ Bugfixes, memory write at FE or FF locked DV * NOTE: Code breaks for optimizer -O2 and above, use -O1 2019-11-15 Version 1.4 RoJ NZVC=0, I=1 upon RESET * TODO: Move common code to console.h * Replace ST-library */ #include "misc.h" #include "stm32f10x_usart.h" #include "stm32f10x_exti.h" #include "stm32f10x_rcc.h" #include "stm32f10x_gpio.h" #include "console.h" #include "lu3.h" #include "flispcontrol.h" static unsigned short switch_status_array; static unsigned int debounce_counter; static unsigned char button_pressed; static unsigned char address; static unsigned char autoaddress; static unsigned char modifydata; static unsigned char run_mode; static unsigned char test_mode; /* Chip initialisation */ void initGPIO(void ) { EXTI_InitTypeDef EXTI_InitStructure; /* EXTI structure to init EXT */ NVIC_InitTypeDef NVIC_InitStructure; /* NVIC structure to set up NVIC controller */ GPIO_InitTypeDef GPIO_InitStructure; USART_ClockInitTypeDef USART_ClockInitStructure; USART_InitTypeDef USART_InitStructure; GPIO_AFIODeInit(); GPIO_DeInit(GPIOA); GPIO_DeInit(GPIOB); GPIO_DeInit(GPIOC); USART_DeInit(USART1); RCC_APB2PeriphClockCmd( RCC_APB2Periph_USART1, ENABLE ); RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE ); RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE ); RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE ); RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO, ENABLE); /* PA13 - JTMS */ /* PA14 - JTCK */ /* PA15 - JTDI */ /* PB4 - JTRST */ /* PB3 - JTDO */ /* PA9 - USART TX */ /* PA10 - USART RX */ /* PA11 - USART CTS not used*/ /* PA12 - USART RTS not used */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOA, &GPIO_InitStructure); USART_ClockStructInit(&USART_ClockInitStructure); USART_ClockInit(USART1, &USART_ClockInitStructure); USART_InitStructure.USART_BaudRate = 115200; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No ; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_Init(USART1, &USART_InitStructure); USART_Cmd(USART1, ENABLE); //configure NVIC NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //select NVIC channel to configure NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0xF; //set priority to lowest NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0xF; //set subpriority to lowest NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //enable IRQ channel NVIC_Init(&NVIC_InitStructure); //update NVIC registers USART_ITConfig(USART1, USART_IT_TXE, DISABLE); //disable Transmit Data Register empty interrupt USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //enable Receive Data register not empty interrupt /* PB7,6,5,2,1,0 - (One of) External interrupt lines */ /* PB 0 will be interrupt pin */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0); /* Connect EXTI Line to IRQ (port B, pin 0) */ EXTI_InitStructure.EXTI_Line = EXTI_Line0; /* Configure Button EXTI line */ EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; /* select interrupt mode */ EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; /* generate interrupt on falling edge */ EXTI_InitStructure.EXTI_LineCmd = ENABLE; /* enable EXTI line */ EXTI_Init(&EXTI_InitStructure); /* send values to registers */ /* configure NVIC */ NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; /* select NVIC channel to configure */ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F; /* set priority to lowest */ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F; /* set subpriority to lowest */ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; /* enable IRQ channel */ NVIC_Init(&NVIC_InitStructure); /* update NVIC registers */ /* PC0-PC7, 8-bit inport */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; /* */ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Pin = ((uint16_t)0xFF); /* eight low bits */ GPIO_Init( GPIOC, &GPIO_InitStructure); /* PC8-PC15, 8 bit outport, Chip select signals */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; /* push/pull */ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_InitStructure.GPIO_Pin = ((uint16_t) 0xFF00); GPIO_Init( GPIOC, &GPIO_InitStructure); /* PB8-PB15, 8-bit outport, (Outbus high ) */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; /* push/pull */ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Pin = ((uint16_t) 0xFF00); GPIO_Init( GPIOB, &GPIO_InitStructure); /* PA0-PA7, 8-bit outport, (Output low ) */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; /* push/pull */ GPIO_InitStructure.GPIO_Pin = ((uint16_t)0xFF); /* eight low bits */ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init( GPIOA, &GPIO_InitStructure); consoleInit( ); } /* Low level read and write */ unsigned char readIn( unsigned char i ) { unsigned short d,r; /* Activate chip select in signal */ r = i; r = r << 12; r = r & 0xF000; /* Write value to port C (high byte) */ GPIOC->BRR = 0xF000; /* reset port bits */ GPIOC->BSRR = r; /* set bits */ /* Read 16 bit value from port C */ //for( j = 0; j< 400; j++); d = GPIO_ReadInputData( GPIOC ); GPIOC->BRR = 0xFF00; /* reset port bits */ /* return low byte */ return (unsigned char) d ; } void outbusHigh( unsigned char c ) { // unsigned short j; unsigned int r = ( unsigned short ) c ; r = r << 8; /* Write byte to port B (high byte ) */ GPIOB->BRR = ((uint32_t) 0xFF00); /* reset port bits */ GPIOB->BSRR = r; /* set bits */ } void outbusLow( unsigned char c ) { unsigned short r; /* Write byte to port A (low byte ) */ r = c; GPIOA->BRR = ((uint32_t) 0xFF); /* reset port bits */ GPIOA->BSRR = r; /* set bits */ } void selectOut( unsigned char i ) { /* Activate chip select out signal */ unsigned short r = (unsigned short) (i & 0xF); r = r << 8; /* Write value to port C, high word, (low byte) */ GPIOC->BRR = ((uint32_t) 0x0F00); /* reset port bits */ GPIOC->BSRR = r; /* set bits */ // for( j = 0; j< 4000; j++); GPIOC->BRR = ((uint32_t) 0x0F00); /* reset port bits */ // for( j = 0; j< 4000; j++); } /* Refresh/Update routines refresh - copy from hardware to internal data structures update - copy from internal data structures to hardware */ void refreshSwitches(void) { unsigned char c1, c2; c1 = readIn( 1 ); c2 = readIn( 2 ); switch_status_array = ((unsigned short) c2 << 8 ); switch_status_array |= (unsigned short) c1; switch_status_array &= 0x3FFF; } /* Utility routines */ int isDataSetMode( void) { /* return setting for data set mode switch */ refreshSwitches(); return (DATA_SET_MODE & switch_status_array) ; } int isDataDisplayMode( void) { return ( ! isDataSetMode() ); } int isAddressSetMode( void) { /* return setting for data set mode switch */ return (ADDRESS_SET_MODE & switch_status_array) ; } int isAddressAutoMode( void) { return ( ! isAddressSetMode() ); } void clearDataPath( void ) { unsigned char i,j; outbusHigh (0); outbusLow (0); for( i = 1; i < 16; i++ ) { selectOut( i ); for( j = 0; j < 100; j++ ); } /* Clear displays */ outbusHigh(0xFF); outbusLow (0xFF); selectOut( 12 ); selectOut( 13 ); } unsigned char tosegcode( unsigned char c ) { switch (c) { case 0: return 0xC0; case 1: return 0xF9; case 2: return 0xA4; case 3: return 0xB0; case 4: return 0x99; case 5: return 0x92; case 6: return 0x82; case 7: return 0xF8; case 8: return 0x80; case 9: return 0x98; case 0xA: return 0x88; case 0xB: return 0x83; case 0xC: return 0xC6; case 0xD: return 0xA1; case 0xE: return 0x86; case 0xF: return 0x8E; default: return 0xFF; } } void setDataDisplay( unsigned char value ) { outbusLow ( tosegcode( value & 0xF) ); outbusHigh ( tosegcode( (value >> 4)&0xF ) ); selectOut( 12 ); } void setAddressDisplay( unsigned char value ) { outbusLow ( tosegcode( value & 0xF) ); outbusHigh ( tosegcode( (value >> 4)&0xF ) ); selectOut( 13 ); } static unsigned char mem_adr_toggle = 0; void ackFlipflops( void ) { outbusHigh( 0 ); outbusLow( 0) ; selectOut( 15 ); outbusHigh( 0xFF ); outbusLow( 0xFF) ; selectOut( 15 ); } #define KEY_DEBOUNCE_DELAY 100 void SysTick_Handler(void) { /* System 1msec ticks */ if(debounce_counter){ debounce_counter--; ackFlipflops( ); } } void EXTI0_IRQHandler(void) { unsigned short stat; CMD c; /* switch interrupt handler */ if( debounce_counter ) { goto ackirq; } debounce_counter = KEY_DEBOUNCE_DELAY; refreshSwitches(); stat = switch_status_array & 0xFFF; /* extract IRQ status bits */ c.message = NO_COMMAND; c.p1 = 0; c.p2 = 0; if( stat & IRQ0_DATA_HIGH_INCREMENT) { if (!(DATA_SET_MODE & switch_status_array)) goto ackirq; c.message = MEM_DATA_H_INC; mem_adr_toggle ^= 0x80; if( (mem_adr_toggle & 0x80 )==0) goto ackirq; }else if( stat & IRQ1_DATA_HIGH_DECREMENT) { if (!(DATA_SET_MODE & switch_status_array)) goto ackirq; c.message = MEM_DATA_H_DEC; mem_adr_toggle ^= 0x40; if( (mem_adr_toggle & 0x40 )==0) goto ackirq; }else if( stat & IRQ2_DATA_LOW_INCREMENT) { if (!(DATA_SET_MODE & switch_status_array)) goto ackirq; c.message = MEM_DATA_L_INC; mem_adr_toggle ^= 0x20; if( (mem_adr_toggle & 0x20 )==0) goto ackirq; }else if( stat & IRQ3_DATA_LOW_DECREMENT) { if (!(DATA_SET_MODE & switch_status_array)) goto ackirq; c.message = MEM_DATA_L_DEC; mem_adr_toggle ^= 0x10; if( (mem_adr_toggle & 0x10 )==0) goto ackirq; }else if( stat & IRQ4_ADDRESS_HIGH_INCREMENT) { if( isAddressAutoMode()) goto ackirq; c.message = MEM_ADDR_H_INC; mem_adr_toggle ^= 8; if( (mem_adr_toggle & 8 )== 0) goto ackirq; }else if( stat & IRQ5_ADDRESS_HIGH_DECREMENT) { if( isAddressAutoMode()) goto ackirq; c.message = MEM_ADDR_H_DEC; mem_adr_toggle ^= 4; if( (mem_adr_toggle & 4 )== 0) goto ackirq; }else if( stat & IRQ6_ADDRESS_LOW_INCREMENT) { if( isAddressAutoMode()) goto ackirq; c.message = MEM_ADDR_L_INC; mem_adr_toggle ^= 2; if( (mem_adr_toggle & 2 )== 0) goto ackirq; }else if( stat & IRQ7_ADDRESS_LOW_DECREMENT) { if( isAddressAutoMode()) goto ackirq; c.message = MEM_ADDR_L_DEC; mem_adr_toggle ^= 1; if( (mem_adr_toggle & 1 )== 0) goto ackirq; }else if( stat & IRQ8_DATA_SET) { c.message = MEM_DATA_SET; //setAddressDisplay( 8 ); }else if( stat & IRQ9_FLISP_RESET) { c.message = FLISP_RESET; //setAddressDisplay( 9 ); }else if( stat & IRQ10_FLISP_CLK) { c.message = FLISP_CLK; //setAddressDisplay( 10 ); }else if( stat & IRQ11_FLISP_NF) { c.message = FLISP_NF; //setAddressDisplay( 11 ); }else { /* spurious interrupt */ } putCmd( &c ); ackirq: ackFlipflops( ); /* Ack controller */ EXTI_ClearITPendingBit(EXTI_Line0); } void updateDataDisplay( unsigned char cmd ) { if( isDataDisplayMode() ) { /* just update the display */ if( isAddressAutoMode() ) setDataDisplay( getMemory( autoaddress , 0 ) ); else setDataDisplay( getMemory( address , 0 ) ); }else{ /* Data modify mode */ switch( cmd ) { case MEM_DATA_H_INC: modifydata += 0x10; break; case MEM_DATA_H_DEC: modifydata -= 0x10; break; case MEM_DATA_L_INC: modifydata = (modifydata & 0xF0 ) + ((modifydata + 1) & 0xF); break; case MEM_DATA_L_DEC: modifydata = (modifydata & 0xF0 ) + ((modifydata - 1) & 0xF); break; } setDataDisplay( modifydata ); } } void updateAddressDisplay( unsigned char cmd ) { if( isAddressAutoMode() ) { /* just update the display with memory address register */ setAddressDisplay( autoaddress ); }else{ /* Address modify mode */ switch( cmd ) { case MEM_ADDR_H_INC: address = address + 0x10; break; case MEM_ADDR_H_DEC: address = address - 0x10; break; case MEM_ADDR_L_INC: address = (address & 0xF0 ) + ((address + 1) & 0xF); break; case MEM_ADDR_L_DEC: address = (address & 0xF0 ) + ((address - 1) & 0xF); break; } setAddressDisplay( address ); } } void setAutoAddress(unsigned char add) { autoaddress = add; } void doTestMode( void ) { int i,j; /* Test displays and diodes */ for( i = 0; i <= 0xF ; i++ ) { setAddressDisplay( (unsigned char) i ); setDataDisplay( (unsigned char) i ); for( j = 0; j< 800000; j++); } for( i = 0x10; i < 0x100 ; i = i + 0x10 ) { setAddressDisplay( (unsigned char) i ); setDataDisplay( (unsigned char) i ); for( j = 0; j< 800000; j++); } /* Test diodes */ for( i = 1; i <= 11 ; i++ ) { outbusHigh( 0xFF ); outbusLow( 0xFF) ; selectOut( i ); for( j = 0; j< 1800000; j++); outbusHigh( 0 ); outbusLow( 0) ; selectOut( i ); } } int toggleTestMode(void) { if( test_mode ) { test_mode = 0; return 1; } return 0; } /* void banner(void) { unsigned char *cp; cp = BANNER_ID; while( *cp ) consoleOut (*cp++ ); sendEOT(); } */ int main( void ) { PCMD p; int i; // unsigned char ch; initGPIO(); /* core init, clock GPIO's, interrupt system etc uart init, console interface */ clearDataPath(); /* turn all LED's off */ /* Calm flipflops */ ackFlipflops( ); interactive_mode = 0; run_mode = 0; test_mode = 0; mem_adr_toggle = 0; debounce_counter = 0; button_pressed = 0; /* Clear FLISP memory */ for( i = 0; i < 256; i++) setMemory( (unsigned char) i, 0, 0 ); initCmd(); /* initialize buffered command handling */ doFlispReset(); /* reset state machine */ initSystick(); __enable_irq(); interactive_mode = 1; while(1) { if( (( p = getCmd() ) == ((PCMD) 0) )) { if( run_mode ) { doFlispClk(); } if( test_mode ) { doTestMode(); } /* monitor data_set and address_set switches */ updateAddressDisplay( 0 ); updateDataDisplay( 0 ); if(isExternalOpcode() ) { doExternalOpcode(); } }else{ /* do command */ switch( (int) p->message ) { /* Commands */ case SYSTEM_RESTART: Reset_Handler(); break; case UPDATE_ALL: updateAll(1); break; case RUN_MODE: if( run_mode == 0 ){ doFlispReset( ); run_mode = 1; }else{ run_mode = 0; } break; case TEST_MODE: if( test_mode == 0 ) test_mode = 1; else{ test_mode = 0; Reset_Handler(); } break; case QUIET_MODE: interactive_mode = 0; break; case INTERACTIVE_MODE: interactive_mode = 1; updateAll(1); break; case GET_VERSION: if( interactive_mode ){ consoleOut ( binToAscii( MAJOR_VERSION) ); sendAscii('.'); consoleOut ( binToAscii( MINOR_VERSION) ); sendEOT(); } ackFlipflops( ); break; case MEM_ADDR_H_INC: case MEM_ADDR_H_DEC: case MEM_ADDR_L_INC: case MEM_ADDR_L_DEC: updateAddressDisplay( p->message ); updateDataDisplay( 0 ); break; case MEM_DATA_H_INC: case MEM_DATA_H_DEC: case MEM_DATA_L_INC: case MEM_DATA_L_DEC: updateDataDisplay( p->message ); break; case FLISP_RESET: doFlispReset(); break; case FLISP_NF: doFlispNF(); break; case FLISP_CLK: doFlispClk(); break; case STEP_INSTRUCTION: doStepInstruction(); break; case MEM_DATA_SET: if( isDataSetMode() ) { if( isAddressAutoMode()) setMemory(autoaddress, modifydata, 0); else setMemory(address, modifydata, 0); } break; case MEMORY_WRITE: setMemory(p->p1, p->p2, 0); if( interactive_mode ) updateAll(1); break; case MEMORY_READ: sendAsAscii( getMemory( p->p1, 0 ) ); sendEOT(); break; case REGISTER_WRITE: setFlispRegisterValue(p->p1, p->p2); if( interactive_mode ) updateAll(1); break; case REGISTER_READ: sendAsAscii( getFlispRegisterValue( p->p1 ) ); sendEOT(); break; } } } return 0; /* never reached */ }