/* */ #include #include #include #include #include #include #include #include #include #include #include #define ODR 0x0c #define IDR 0x08 /* #define __ASM __asm #define __STATIC_INLINE static inline __attribute__((always_inline)) __STATIC_INLINE void __enable_irq(void) { __ASM volatile ("cpsie i"); } __attribute__((always_inline)) __STATIC_INLINE void __disable_irq(void) { __ASM volatile ("cpsid i"); } */ #include "z80-if.h" #include "hdrom.h" #define USART_CONSOLE USART1 int _write(int fd, char *ptr, int len) __attribute__((used)); #define S_10MS_TO (1<<0) /* * LED Connections */ #define LED_PORT GPIOC #define LED_BLUE_PIN GPIO8 #define BLUE 8 #define LED_GREEN_PIN GPIO9 #define GREEN 9 #define LED_BLUE_ON() BBIO_PERIPH(LED_PORT+ODR, BLUE) = 1 #define LED_BLUE_OFF() BBIO_PERIPH(LED_PORT+ODR, BLUE) = 0 #define LED_BLUE_TOGGLE() BBIO_PERIPH(LED_PORT+ODR, BLUE) = !BBIO_PERIPH(LED_PORT+ODR, BLUE) #define LED_GREEN_ON() BBIO_PERIPH(LED_PORT+ODR, GREEN) = 1 #define LED_GREEN_OFF() BBIO_PERIPH(LED_PORT+ODR, GREEN) = 0 #define LED_GREEN_TOGGLE() BBIO_PERIPH(LED_PORT+ODR, GREEN) = !BBIO_PERIPH(LED_PORT+ODR, GREEN) /* * Button connections */ //BBIO_PERIPH(GPIOA+IDR, 0); #define KEY_PORT GPIOA_IDR #define KEY0 GPIO0 //#define KEY1 GPIO1 //#define KEY2 GPIO2 #define REPEAT_MASK KEY0 // repeat: key0 #define REPEAT_START 100 // after 1s #define REPEAT_NEXT 20 // every 200ms typedef enum { NOTHING, PULSE, BLINK1, BLINK2 } LED_MODE; typedef struct { uint8_t mode; uint8_t ontime, offtime; } led_stat_t; volatile uint8_t led_timer[2]; led_stat_t led_stat[2]; volatile int timeout_1s; volatile uint32_t Stat; /*--------------------------------------------------------------------------*/ static void clock_setup(void) { rcc_clock_setup_in_hse_8mhz_out_24mhz(); /* Enable clocks for: GPIO port A (for GPIO_USART1_TX and Button) GPIO port C (LEDs) USART1 TIM16 (RST-Pin) TIM1 (IOE) TODO: USART1 --> USART_CONSOLE */ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN | RCC_APB2ENR_USART1EN | RCC_APB2ENR_AFIOEN | RCC_APB2ENR_TIM1EN | RCC_APB2ENR_TIM16EN); /* Enable clocks for: TIM3 */ rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_TIM3EN); /* Enable clocks for: TIM3 */ rcc_peripheral_enable_clock(&RCC_AHBENR, RCC_AHBENR_DMA1EN); } static void systick_setup(void) { /* SysTick interrupt every N clock pulses: set reload to N-1 */ STK_RVR = 24000000/1000 - 1; /* Set source to core clock, enable int and start counting. */ STK_CSR = STK_CSR_CLKSOURCE_AHB | STK_CSR_TICKINT | STK_CSR_ENABLE; } #if 0 static void nvic_setup(void) { // nvic_enable_irq(NVIC_RTC_IRQ); // nvic_set_priority(NVIC_RTC_IRQ, 1); } #endif static void tim3_setup(void) { TIM3_CR1 = TIM_CR1_CMS_EDGE | TIM_CR1_DIR_UP; TIM3_CCMR2 = 0 | TIM_CCMR2_OC4M_FORCE_LOW /* | TIM_CCMR2_OC4M_FORCE_HIGH */ /* | TIM_CCMR2_OC4M_PWM2 */ /* | TIM_CCMR2_OC4PE */ /* | TIM_CCMR2_OC4FE */ | TIM_CCMR2_CC4S_OUT; TIM3_CCER = TIM_CCER_CC4E | TIM_CCER_CC4P; TIM3_ARR = 48; /* default */ TIM3_CCR4 = 1; /* */ } static void gpio_setup(void) { /* Disable JTAG-DP, but leave SW-DP Enabled. (free PA15, PB3, PB4) Remap SPI1 to PB3, PB4, PB5 and PA15. Remap TIM3 (CH1/PC6, CH2/PC7, CH3/PC8, CH4/PC9) */ gpio_primary_remap(AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_ON, AFIO_MAPR_SPI1_REMAP | AFIO_MAPR_TIM3_REMAP_FULL_REMAP); /* LEDs and User Button. */ gpio_set_mode(LED_PORT, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, LED_BLUE_PIN); gpio_set_mode(LED_PORT, GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, LED_GREEN_PIN); gpio_set_mode(GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO0); } static void usart_setup(void) { /* Setup GPIO pin GPIO_USART1_TX/LED_GREEN_PIN on GPIO port A for transmit. */ /* TODO: USART1 --> USART_CONSOLE */ gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART1_TX); /* Setup UART parameters. */ // usart_set_baudrate(USART_CONSOLE, 38400); usart_set_baudrate(USART_CONSOLE, 115200); usart_set_databits(USART_CONSOLE, 8); usart_set_stopbits(USART_CONSOLE, USART_STOPBITS_1); usart_set_mode(USART_CONSOLE, USART_MODE_TX_RX); usart_set_parity(USART_CONSOLE, USART_PARITY_NONE); usart_set_flow_control(USART_CONSOLE, USART_FLOWCONTROL_NONE); /* Finally enable the USART. */ usart_enable(USART_CONSOLE); } /*--------------------------------------------------------------------------*/ /** * Use USART_CONSOLE as a console. * This is a syscall for newlib * @param fd * @param ptr * @param len * @return */ int _write(int fd, char *ptr, int len) { int i; if (fd == STDOUT_FILENO || fd == STDERR_FILENO) { for (i = 0; i < len; i++) { if (ptr[i] == '\n') { usart_send_blocking(USART_CONSOLE, '\r'); } usart_send_blocking(USART_CONSOLE, ptr[i]); } return i; } errno = EIO; return -1; } /*--------------------------------------------------------------------------*/ void delay_systicks(int ticks) { int start, stop, now; start = STK_CVR; stop = start - ticks; if (stop < 0) { stop += STK_RVR; do { now = STK_CVR; } while ((now > stop) || (now <= start)); } else { do { now = STK_CVR; } while ((now > stop) && (now <= start)); } } /*--------------------------------------------------------------------------*/ static void led_toggle(uint8_t lednr) { if (lednr == 0) LED_BLUE_TOGGLE(); else if (lednr == 1) LED_GREEN_TOGGLE(); } static void led_on(uint8_t lednr) { if (lednr == 0) LED_BLUE_ON(); else if (lednr == 1) LED_GREEN_ON(); } static void led_off(uint8_t lednr) { if (lednr == 0) LED_BLUE_OFF(); else if (lednr == 1) LED_GREEN_OFF(); } static uint8_t led_is_on(uint8_t lednr) { if (lednr == 0) return BBIO_PERIPH(LED_PORT+ODR, BLUE); else if (lednr == 1) return BBIO_PERIPH(LED_PORT+ODR, GREEN); else return 0; } static void ledset(uint8_t lednr, uint8_t what, uint8_t len) { led_stat[lednr].mode = what; switch (what) { case PULSE: led_stat[lednr].ontime = len; led_stat[lednr].offtime = 0; led_timer[lednr] = len; led_on(lednr); break; case BLINK1: case BLINK2: if (what == BLINK1) led_stat[lednr].offtime = 100 - len; else led_stat[lednr].offtime = 200 - len; led_stat[lednr].ontime = len; led_timer[lednr] = len; led_on(lednr); break; default: break; } } /*--------------------------------------------------------------------------*/ static volatile uint16_t key_state, key_press, // key press detect key_rpt; // key long press and repeat static uint16_t get_key_press(uint16_t key_mask) { __disable_irq(); // read and clear atomic ! key_mask &= key_press; // read key(s) key_press ^= key_mask; // clear key(s) __enable_irq(); return key_mask; } static uint16_t get_key_rpt(uint16_t key_mask) { __disable_irq(); // read and clear atomic ! key_mask &= key_rpt; // read key(s) key_rpt ^= key_mask; // clear key(s) __enable_irq(); return key_mask; } static uint16_t get_key_short(uint16_t key_mask) { __disable_irq(); // read key state and key press atomic ! return get_key_press(key_state & key_mask); } /* static uint16_t get_key_long(uint16_t key_mask) { return get_key_press(get_key_rpt(key_mask)); } */ static void key_timerproc() { static uint16_t key_in_last, rpt; uint16_t key_in, c; key_in = KEY_PORT; c = key_in_last & key_in & ~key_state; // key_state = key_state & key_in_last | (key_state | key_in_last) & key_in; // key_state = key_state & key_in | (key_state | key_in) & key_in_last; key_state = c | ((key_in_last | key_in) & key_state); // key_state = (key_state&key_in_last) | (key_state&key_in) | (key_in_last&key_in); key_press |= c; key_in_last = key_in; if ((key_state & REPEAT_MASK) == 0) // check repeat function rpt = REPEAT_START; if (--rpt == 0) { rpt = REPEAT_NEXT; // repeat delay key_rpt |= key_state & REPEAT_MASK; } #if 0 static char ds[30]; int dsi = 0; ds[dsi++] = key_state & 1 ? '1' : '0'; ds[dsi++] = key_in_last & 1 ? '1' : '0'; ds[dsi++] = key_in & 1 ? '1' : '0'; ds[dsi++] = ' '; //ds[dsi++] = key_state & 1 ? '1' : '0'; //ds[dsi++] = key_in_last & 1 ? '1' : '0'; //ds[dsi++] = ' '; //ds[dsi++] = ' '; ds[dsi++] = 0; puts(ds); #endif } /*--------------------------------------------------------------------------*/ void sys_tick_handler(void) { static int tick_10ms = 0; static int count_ms = 0; int i; ++tick_10ms; if (tick_10ms == 10) { Stat |= S_10MS_TO; tick_10ms = 0; i = led_timer[0]; if (i) led_timer[0] = i - 1; i = led_timer[1]; if (i) led_timer[1] = i - 1; key_timerproc(); /* Drive timer procedure of low level disk I/O module */ //disk_timerproc(); } count_ms++; if (count_ms == 1000) { count_ms = 0; if (timeout_1s) --timeout_1s; } } void rtc_isr(void) { /* The interrupt flag isn't cleared by hardware, we have to do it. */ rtc_clear_flag(RTC_SEC); } /*--------------------------------------------------------------------------*/ void tim3_set(int mode) { uint16_t cc_mode; cc_mode = TIM_CCMR2_CC4S_OUT; TIM3_CR1 = TIM_CR1_CMS_EDGE | TIM_CR1_DIR_UP | TIM_CR1_OPM; if (mode < 0) cc_mode |= TIM_CCMR2_OC4M_FORCE_LOW; else if (mode == 0) cc_mode |= TIM_CCMR2_OC4M_FORCE_HIGH; else { TIM3_ARR = mode; cc_mode |= TIM_CCMR2_OC4M_PWM2; } TIM3_CCMR2 = cc_mode; if (mode > 0) TIM3_CR1 |= TIM_CR1_CEN; } /*--------------------------------------------------------------------------*/ static uint32_t z80_sram_cmp(uint32_t addr, int length, uint8_t wval, int inc) { uint8_t rval; int errors = 0; printf("SRAM: Check %#.5x byte... ", length); //fflush(stdout); while (length--) { if ((rval = z80_read(addr)) != wval) { if (errors == 0) { printf("\nSRAM: Address W R\n" \ " -------------\n"); // 12345 00 11 } printf(" %.5lx %.2x %.2x\n", addr, wval, rval); if (++errors > 16 ) break; } addr++; wval += inc; } printf("Done.\n"); return addr; } #if 0 static void z80_sram_fill(uint32_t addr, int length, uint8_t startval, int inc) { printf("SRAM: Write %#.5x byte... ", length); //fflush(stdout); while (length--) { z80_write(addr, startval); ++addr; startval += inc; } printf("Done.\n"); } void z80_sram_fill_string(uint32_t addr, int length, const char *text) { char c; const char *p = text; while (length--) { z80_write(addr++, c = *p++); if (c == 0) p = text; } } uint32_t z80_sram_cmp_string(uint32_t addr, int length, const char *text) { char c; const char *p = text; while (length--) { c = *p++; if (z80_read(addr) != c) break; ++addr; if (c == 0) p = text; } return addr; } const char * const qbfox = "Zhe quick brown fox jumps over the lazy dog!"; const char * const qbcat = "Zhe quick brown fox jumps over the lazy cat!"; #endif uint8_t z80_get_byte(uint32_t adr) { uint8_t data; z80_get_bus(); data = z80_read(adr), z80_release_bus(); return data; } /*--------------------------------------------------------------------------*/ static void do_10ms(void) { for (uint8_t i = 0; i < 2; i++) { switch (led_stat[i].mode) { case PULSE: if (led_timer[i] == 0) { led_off(i); led_stat[i].mode = NOTHING; } break; case BLINK1: case BLINK2: if (led_timer[i] == 0) { if (led_is_on(i)) led_timer[i] = led_stat[i].offtime; else led_timer[i] = led_stat[i].ontime; led_toggle(i); } break; default: break; } } } /*--------------------------------------------------------------------------*/ int main(void) { //uint32_t led_state = LED_BLUE_PIN; //uint32_t rc; //uint8_t startval = 0; //int count; int stat, ch; uint8_t c; clock_setup(); gpio_setup(); tim3_setup(); setvbuf(stdout, NULL, _IONBF, 0); usart_setup(); printf("Hello World!\n"); z80_setup_bus(); printf("z80_setup_bus done.\n"); /* * If the RTC is pre-configured just allow access, don't reconfigure. * Otherwise enable it with the LSE as clock source and 0x7fff as * prescale value. */ rtc_auto_awake(LSE, 0x7fff); systick_setup(); ///* Setup the RTC interrupt. */ //nvic_setup(); /* Enable the RTC interrupt to occur off the SEC flag. */ //rtc_interrupt_enable(RTC_SEC); printf("get bus..."); z80_busreq(LOW); z80_reset(HIGH); z80_get_bus(); printf(" got it!\n"); z80_memset(0, 0x76, 0x80000); //z80_sram_fill(0, 512 * 1024, 0x76, 0); z80_sram_cmp(0, 512 * 1024, 0x76, 0); z80_write_block((unsigned char *) hdrom, 0, hdrom_length); z80_reset(LOW); printf("bus released! "); z80_release_bus(); z80_reset(HIGH); printf(" reset released!\n"); timeout_1s = 6; while (timeout_1s) { static int to=0; uint8_t b, rc, tc, m; if (to != timeout_1s) { b = z80_get_byte(tx_fifo-0), rc = z80_get_byte(tx_fifo-1), tc = z80_get_byte(tx_fifo-2), m =z80_get_byte(tx_fifo-3); printf(" %.2x %.2x %.2x %.2x\n", b, rc, tc, m); to = timeout_1s; if ((rc==0) && (m==0x7f)) break; } } z80_fifo_init(); ledset(0, BLINK1, 50); while (1) { // static int tickstat = 0; if (Stat & S_10MS_TO) { Stat &= ~S_10MS_TO; do_10ms(); } // if (get_key_long(KEY0)) // ledset(1, PULSE, 100); if (get_key_short(KEY0)) z80_reset_pulse(); /* switch (tickstat) { case 0: if (BBIO_PERIPH(GPIOA+IDR, 0)) { tickstat = 1; LED_GREEN_ON(); LED_GREEN_OFF(); LED_GREEN_ON(); delay_systicks(12); LED_GREEN_OFF(); } break; default: if (!BBIO_PERIPH(GPIOA+IDR, 0)) tickstat = 0; } */ //BBIO_PERIPH(LED_PORT+0x0C, 9) = BBIO_PERIPH(GPIOA+0x08, 0); //BBIO_PERIPH(LED_PORT+0x0C, 9) = !z80_stat_halt(); //BBIO_PERIPH(LED_PORT+0x0C, 9) = (~key_state & KEY0) != 0; /* stat = z80_fifo_is_not_full(rx_fifo); if(stat) { z80_fifo_putc(rx_fifo, 'y'); if (++count == 154) { putchar('\n'); putchar('\r'); count = 0; } } */ stat = usart_get_flag(USART_CONSOLE, USART_SR_RXNE); if (stat) { c = usart_recv(USART_CONSOLE) & 0xff; switch (c) { case 'H': tim3_set(-1); break; case 'L': tim3_set(0); break; case 'P': tim3_set(24000000/1000000 * 5); /* 5 us */ break; default: z80_fifo_putc(fifo_out, c); } } if (timeout_1s == 0) { while (z80_fifo_is_not_empty(fifo_in)) { // LED_GREEN_ON(); c = z80_fifo_getc(fifo_in); putchar(c); // LED_GREEN_OFF(); } timeout_1s = 1; } while ((ch = z80_inbuf_getc()) >= 0) printf(" 0x%.2X ", ch); } return 0; } #if 0 static char ds[30]; int dsi = 0; ds[dsi++] = key_state1 & 1 ? '1' : '0'; ds[dsi++] = key_in_last & 1 ? '1' : '0'; ds[dsi++] = key_in & 1 ? '1' : '0'; ds[dsi++] = ' '; ds[dsi++] = key_state1 & 1 ? '1' : '0'; ds[dsi++] = key_in_last & 1 ? '1' : '0'; ds[dsi++] = ' '; ds[dsi++] = ' '; ds[dsi++] = key_state & 1 ? '1' : '0'; ds[dsi++] = ct1 & 1 ? '0' : '1'; ds[dsi++] = ct0 & 1 ? '0' : '1'; ds[dsi++] = ' '; ds[dsi++] = key_state & 1 ? '1' : '0'; //ds[dsi++] = '\r'; //ds[dsi++] = '\n'; ds[dsi++] = 0; puts(ds); #endif