// // // File Name : MCL65_A2Plus_Fast.c // Used on : // Author : Ted Fried, MicroCore Labs // Creation : 9/26/2021 // // Description: // ============ // // ML65 Fast drop-in to replace the MOS 6502 in an Apple II Computer // // ** This code does not emulate the 6502 ** // // This code provides functions to allow the user to run C code compiled // compiled on the Arduino GUI and run it directly on the Teensy 4.1's // 600Mhz processor while using the Apple II's keyboard and display. // // // Functions provided: // // - xputchar - Accepts characters to display to the Apple II's video // - xprintf - Printf modified to display to the Apple II's video // - xscanf - Scanf modified to take input from th Apple II's keyboard // // //------------------------------------------------------------------------ // // Modification History: // ===================== // // Revision 1 9/26/2021 // Initial revision // // //------------------------------------------------------------------------ // // Copyright (c) 2021 Ted Fried // // 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. // //------------------------------------------------------------------------ #include #include #include #include // Teensy 4.1 pin assignments // #define PIN_CLK0 24 #define PIN_RESET 40 #define PIN_READY_n 26 #define PIN_IRQ 25 #define PIN_NMI 41 #define PIN_RDWR_n 12 #define PIN_SYNC 39 #define PIN_ADDR0 27 #define PIN_ADDR1 38 #define PIN_ADDR2 28 #define PIN_ADDR3 37 #define PIN_ADDR4 29 #define PIN_ADDR5 36 #define PIN_ADDR6 30 #define PIN_ADDR7 35 #define PIN_ADDR8 31 #define PIN_ADDR9 34 #define PIN_ADDR10 32 #define PIN_ADDR11 33 #define PIN_ADDR12 1 #define PIN_ADDR13 0 #define PIN_ADDR14 2 #define PIN_ADDR15 23 #define PIN_DATAIN0 14 #define PIN_DATAIN1 15 #define PIN_DATAIN2 16 #define PIN_DATAIN3 17 #define PIN_DATAIN4 18 #define PIN_DATAIN5 19 #define PIN_DATAIN6 20 #define PIN_DATAIN7 21 #define PIN_DATAOUT0 11 #define PIN_DATAOUT1 10 #define PIN_DATAOUT2 9 #define PIN_DATAOUT3 8 #define PIN_DATAOUT4 7 #define PIN_DATAOUT5 6 #define PIN_DATAOUT6 5 #define PIN_DATAOUT7 4 #define PIN_DATAOUT_OE_n 3 // 6502 Flags // #define flag_n (register_flags & 0x80) >> 7 // register_flags[7] #define flag_v (register_flags & 0x40) >> 6 // register_flags[6] #define flag_b (register_flags & 0x10) >> 4 // register_flags[4] #define flag_d (register_flags & 0x08) >> 3 // register_flags[3] #define flag_i (register_flags & 0x04) >> 2 // register_flags[2] #define flag_z (register_flags & 0x02) >> 1 // register_flags[1] #define flag_c (register_flags & 0x01) >> 0 // register_flags[0] // 6502 stack always in Page 1 // #define register_sp_fixed (0x0100 | register_sp) // CPU register for direct reads of the GPIOs // uint8_t register_flags=0x34; uint8_t next_instruction; uint8_t internal_memory_range=0; uint8_t nmi_n_old=1; uint8_t register_a=0; uint8_t register_x=0; uint8_t register_y=0; uint8_t register_sp=0xFF; uint8_t direct_datain=0; uint8_t direct_reset=0; uint8_t direct_ready_n=0; uint8_t direct_irq=0; uint8_t direct_nmi=0; uint8_t assert_sync=0; uint8_t global_temp=0; uint8_t last_access_internal_RAM=0; uint8_t rx_byte_state=0; uint8_t mode=1; uint8_t internal_RAM[65536]; uint8_t Video_RAM_Miror[0x0800]; uint16_t register_pc=0; uint16_t current_address=0; uint16_t effective_address=0; uint16_t current_video_character_location = 0x07D0; // ------------------------------------------------------------------------------ // ------------------------------------------------------------------------------ // Setup Teensy 4.1 IO's // void setup() { pinMode(PIN_CLK0, INPUT); pinMode(PIN_RESET, INPUT); pinMode(PIN_READY_n, INPUT); pinMode(PIN_IRQ, INPUT); pinMode(PIN_NMI, INPUT); pinMode(PIN_RDWR_n, OUTPUT); pinMode(PIN_SYNC, OUTPUT); pinMode(PIN_ADDR0, OUTPUT); pinMode(PIN_ADDR1, OUTPUT); pinMode(PIN_ADDR2, OUTPUT); pinMode(PIN_ADDR3, OUTPUT); pinMode(PIN_ADDR4, OUTPUT); pinMode(PIN_ADDR5, OUTPUT); pinMode(PIN_ADDR6, OUTPUT); pinMode(PIN_ADDR7, OUTPUT); pinMode(PIN_ADDR8, OUTPUT); pinMode(PIN_ADDR9, OUTPUT); pinMode(PIN_ADDR10, OUTPUT); pinMode(PIN_ADDR11, OUTPUT); pinMode(PIN_ADDR12, OUTPUT); pinMode(PIN_ADDR13, OUTPUT); pinMode(PIN_ADDR14, OUTPUT); pinMode(PIN_ADDR15, OUTPUT); pinMode(PIN_DATAIN0, INPUT); pinMode(PIN_DATAIN1, INPUT); pinMode(PIN_DATAIN2, INPUT); pinMode(PIN_DATAIN3, INPUT); pinMode(PIN_DATAIN4, INPUT); pinMode(PIN_DATAIN5, INPUT); pinMode(PIN_DATAIN6, INPUT); pinMode(PIN_DATAIN7, INPUT); pinMode(PIN_DATAOUT0, OUTPUT); pinMode(PIN_DATAOUT1, OUTPUT); pinMode(PIN_DATAOUT2, OUTPUT); pinMode(PIN_DATAOUT3, OUTPUT); pinMode(PIN_DATAOUT4, OUTPUT); pinMode(PIN_DATAOUT5, OUTPUT); pinMode(PIN_DATAOUT6, OUTPUT); pinMode(PIN_DATAOUT7, OUTPUT); pinMode(PIN_DATAOUT_OE_n, OUTPUT); // Serial.begin(9600); } // -------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------- // // Begin 6502 Bus Interface Unit // // -------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------- // ------------------------------------------------- // Wait for the CLK1 rising edge and sample signals // ------------------------------------------------- inline void wait_for_CLK_rising_edge() { register uint32_t GPIO6_data=0; register uint32_t GPIO6_data_d1=0; uint32_t d10, d2, d3, d4, d5, d76; while (((GPIO6_DR >> 12) & 0x1)!=0) {} // Teensy 4.1 Pin-24 GPIO6_DR[12] CLK //while (((GPIO6_DR >> 12) & 0x1)==0) {GPIO6_data=GPIO6_DR;} // This method is ok for VIC-20 and Apple-II+ non-DRAM ranges do { GPIO6_data_d1=GPIO6_DR; } while (((GPIO6_data_d1 >> 12) & 0x1)==0); // This method needed to support Apple-II+ DRAM read data setup time GPIO6_data=GPIO6_data_d1; d10 = (GPIO6_data&0x000C0000) >> 18; // Teensy 4.1 Pin-14 GPIO6_DR[19:18] D1:D0 d2 = (GPIO6_data&0x00800000) >> 21; // Teensy 4.1 Pin-16 GPIO6_DR[23] D2 d3 = (GPIO6_data&0x00400000) >> 19; // Teensy 4.1 Pin-17 GPIO6_DR[22] D3 d4 = (GPIO6_data&0x00020000) >> 13; // Teensy 4.1 Pin-18 GPIO6_DR[17] D4 d5 = (GPIO6_data&0x00010000) >> 11; // Teensy 4.1 Pin-19 GPIO6_DR[16] D5 d76 = (GPIO6_data&0x0C000000) >> 20; // Teensy 4.1 Pin-20 GPIO6_DR[27:26] D7:D6 direct_irq = (GPIO6_data&0x00002000) >> 13; // Teensy 4.1 Pin-25 GPIO6_DR[13] IRQ direct_ready_n = (GPIO6_data&0x40000000) >> 30; // Teensy 4.1 Pin-26 GPIO6_DR[30] READY direct_reset = (GPIO6_data&0x00100000) >> 20; // Teensy 4.1 Pin-40 GPIO6_DR[20] RESET direct_nmi = (GPIO6_data&0x00200000) >> 21; // Teensy 4.1 Pin-41 GPIO6_DR[21] NMI direct_datain = d76 | d5 | d4 | d3 | d2 | d10; return; } // ------------------------------------------------- // Wait for the CLK1 falling edge // ------------------------------------------------- inline void wait_for_CLK_falling_edge() { while (((GPIO6_DR >> 12) & 0x1)==0) {} // Teensy 4.1 Pin-24 GPIO6_DR[12] CLK while (((GPIO6_DR >> 12) & 0x1)!=0) {} return; } // ------------------------------------------------- // Drive the 6502 Address pins // ------------------------------------------------- inline void send_address(uint32_t local_address) { register uint32_t writeback_data=0; writeback_data = (0x6DFFFFF3 & GPIO6_DR); // Read in current GPIOx register value and clear the bits we intend to update writeback_data = writeback_data | (local_address & 0x8000)<<10 ; // 6502_Address[15] TEENSY_PIN23 GPIO6_DR[25] writeback_data = writeback_data | (local_address & 0x2000)>>10 ; // 6502_Address[13] TEENSY_PIN0 GPIO6_DR[3] writeback_data = writeback_data | (local_address & 0x1000)>>10 ; // 6502_Address[12] TEENSY_PIN1 GPIO6_DR[2] writeback_data = writeback_data | (local_address & 0x0002)<<27 ; // 6502_Address[1] TEENSY_PIN38 GPIO6_DR[28] GPIO6_DR = writeback_data | (local_address & 0x0001)<<31 ; // 6502_Address[0] TEENSY_PIN27 GPIO6_DR[31] writeback_data = (0xCFF3EFFF & GPIO7_DR); // Read in current GPIOx register value and clear the bits we intend to update writeback_data = writeback_data | (local_address & 0x0400)<<2 ; // 6502_Address[10] TEENSY_PIN32 GPIO7_DR[12] writeback_data = writeback_data | (local_address & 0x0200)<<20 ; // 6502_Address[9] TEENSY_PIN34 GPIO7_DR[29] writeback_data = writeback_data | (local_address & 0x0080)<<21 ; // 6502_Address[7] TEENSY_PIN35 GPIO7_DR[28] writeback_data = writeback_data | (local_address & 0x0020)<<13 ; // 6502_Address[5] TEENSY_PIN36 GPIO7_DR[18] GPIO7_DR = writeback_data | (local_address & 0x0008)<<16 ; // 6502_Address[3] TEENSY_PIN37 GPIO7_DR[19] writeback_data = (0xFF3BFFFF & GPIO8_DR); // Read in current GPIOx register value and clear the bits we intend to update writeback_data = writeback_data | (local_address & 0x0100)<<14 ; // 6502_Address[8] TEENSY_PIN31 GPIO8_DR[22] writeback_data = writeback_data | (local_address & 0x0040)<<17 ; // 6502_Address[6] TEENSY_PIN30 GPIO8_DR[23] GPIO8_DR = writeback_data | (local_address & 0x0004)<<16 ; // 6502_Address[2] TEENSY_PIN28 GPIO8_DR[18] writeback_data = (0x7FFFFF6F & GPIO9_DR); // Read in current GPIOx register value and clear the bits we intend to update writeback_data = writeback_data | (local_address & 0x4000)>>10 ; // 6502_Address[14] TEENSY_PIN2 GPIO9_DR[4] writeback_data = writeback_data | (local_address & 0x0800)>>4 ; // 6502_Address[11] TEENSY_PIN33 GPIO9_DR[7] GPIO9_DR = writeback_data | (local_address & 0x0010)<<27 ; // 6502_Address[4] TEENSY_PIN29 GPIO9_DR[31] return; } // ------------------------------------------------- // Full read cycle with address and data read in // ------------------------------------------------- inline uint8_t read_byte(uint16_t local_address) { digitalWriteFast(PIN_RDWR_n, 0x1); send_address(local_address); do { wait_for_CLK_rising_edge(); } while (direct_ready_n == 0x1); // Delay a clock cycle until ready is active return direct_datain; } // ------------------------------------------------- // Full write cycle with address and data written // ------------------------------------------------- inline void write_byte(uint16_t local_address , uint8_t local_write_data) { digitalWriteFast(PIN_RDWR_n, 0x0); digitalWriteFast(PIN_SYNC, 0x0); send_address(local_address); // Drive the data bus pins from the Teensy to the bus driver which is inactive // digitalWriteFast(PIN_DATAOUT0, (local_write_data & 0x01) ); digitalWriteFast(PIN_DATAOUT1, (local_write_data & 0x02)>>1 ); digitalWriteFast(PIN_DATAOUT2, (local_write_data & 0x04)>>2 ); digitalWriteFast(PIN_DATAOUT3, (local_write_data & 0x08)>>3 ); digitalWriteFast(PIN_DATAOUT4, (local_write_data & 0x10)>>4 ); digitalWriteFast(PIN_DATAOUT5, (local_write_data & 0x20)>>5 ); digitalWriteFast(PIN_DATAOUT6, (local_write_data & 0x40)>>6 ); digitalWriteFast(PIN_DATAOUT7, (local_write_data & 0x80)>>7 ); // During the second CLK phase, enable the data bus output drivers // wait_for_CLK_falling_edge(); digitalWriteFast(PIN_DATAOUT_OE_n, 0x0 ); wait_for_CLK_rising_edge(); digitalWriteFast(PIN_DATAOUT_OE_n, 0x1 ); return; } // -------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------- // // End 6502 Bus Interface Unit // // -------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------- // Begin xprintf code // -------------------------------------------------------------------------------------------------- /*- * Copyright (c) 1991 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)printf.c 5.6 (Berkeley) 5/25/91 */ #include #include /* * Note that stdarg.h and the ANSI style va_start macro is used for both * ANSI and traditional C compilers. */ #define KERNEL #include #undef KERNEL static void kprintn __P((u_long, int)); void inline xprintf(const char *fmt, ...) { register char *p; register int ch, n; unsigned long ul; int lflag, set; va_list ap; va_start(ap, fmt); for (;;) { while ((ch = *fmt++) != '%') { if (ch == '\0') return; xputchar(ch); } lflag = 0; reswitch: switch (ch = *fmt++) { case 'l': lflag = 1; goto reswitch; case 'b': ul = va_arg(ap, int); p = va_arg(ap, char *); kprintn(ul, *p++); if (!ul) break; for (set = 0; n = *p++;) { if (ul & (1 << (n - 1))) { xputchar(set ? ',' : '<'); for (; (n = *p) > ' '; ++p) xputchar(n); set = 1; } else for (; *p > ' '; ++p); } if (set) xputchar('>'); break; case 'c': ch = va_arg(ap, int); xputchar(ch & 0x7f); break; case 's': p = va_arg(ap, char *); while (ch = *p++) xputchar(ch); break; case 'd': ul = lflag ? va_arg(ap, long) : va_arg(ap, int); if ((long)ul < 0) { xputchar('-'); ul = -(long)ul; } kprintn(ul, 10); break; case 'o': ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); kprintn(ul, 8); break; case 'u': ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); kprintn(ul, 10); break; case 'x': ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); kprintn(ul, 16); break; default: xputchar('%'); if (lflag) xputchar('l'); xputchar(ch); } } va_end(ap); } inline static void kprintn ( unsigned long ul , int base ) { /* hold a long in base 8 */ char *p, buf[(sizeof(long) * 8 / 3) + 1]; p = buf; do { *p++ = "0123456789abcdef"[ul % base]; } while (ul /= base); do { xputchar(*--p); } while (p > buf); } inline void xputchar(uint16_t local_char) { // Force character to Apple II non-inverted and non-blinking // local_char = local_char & 0x3F; local_char = local_char | 0x80; // If we have reached the end of the bottom row, scroll all rows upwards and blank the bottom row // if (current_video_character_location==0x07F8 || local_char==0x8A) { // 0x0A is the character for \n for (uint8_t i=0 ; i<0x28 ; i++) { write_byte( 0x0400+i , Video_RAM_Miror[0x0480+i] ); Video_RAM_Miror[ 0x0400+i] = Video_RAM_Miror[0x0480+i]; write_byte( 0x0480+i , Video_RAM_Miror[0x0500+i] ); Video_RAM_Miror[ 0x0480+i] = Video_RAM_Miror[0x0500+i]; write_byte( 0x0500+i , Video_RAM_Miror[0x0580+i] ); Video_RAM_Miror[ 0x0500+i] = Video_RAM_Miror[0x0580+i]; write_byte( 0x0580+i , Video_RAM_Miror[0x0600+i] ); Video_RAM_Miror[ 0x0580+i] = Video_RAM_Miror[0x0600+i]; write_byte( 0x0600+i , Video_RAM_Miror[0x0680+i] ); Video_RAM_Miror[ 0x0600+i] = Video_RAM_Miror[0x0680+i]; write_byte( 0x0680+i , Video_RAM_Miror[0x0700+i] ); Video_RAM_Miror[ 0x0680+i] = Video_RAM_Miror[0x0700+i]; write_byte( 0x0700+i , Video_RAM_Miror[0x0780+i] ); Video_RAM_Miror[ 0x0700+i] = Video_RAM_Miror[0x0780+i]; write_byte( 0x0780+i , Video_RAM_Miror[0x0428+i] ); Video_RAM_Miror[ 0x0780+i] = Video_RAM_Miror[0x0428+i]; write_byte( 0x0428+i , Video_RAM_Miror[0x04a8+i] ); Video_RAM_Miror[ 0x0428+i] = Video_RAM_Miror[0x04a8+i]; write_byte( 0x04A8+i , Video_RAM_Miror[0x0528+i] ); Video_RAM_Miror[ 0x04A8+i] = Video_RAM_Miror[0x0528+i]; write_byte( 0x0528+i , Video_RAM_Miror[0x05a8+i] ); Video_RAM_Miror[ 0x0528+i] = Video_RAM_Miror[0x05a8+i]; write_byte( 0x05a8+i , Video_RAM_Miror[0x0628+i] ); Video_RAM_Miror[ 0x05a8+i] = Video_RAM_Miror[0x0628+i]; write_byte( 0x0628+i , Video_RAM_Miror[0x06a8+i] ); Video_RAM_Miror[ 0x0628+i] = Video_RAM_Miror[0x06a8+i]; write_byte( 0x06a8+i , Video_RAM_Miror[0x0728+i] ); Video_RAM_Miror[ 0x06a8+i] = Video_RAM_Miror[0x0728+i]; write_byte( 0x0728+i , Video_RAM_Miror[0x07a8+i] ); Video_RAM_Miror[ 0x0728+i] = Video_RAM_Miror[0x07a8+i]; write_byte( 0x07a8+i , Video_RAM_Miror[0x0450+i] ); Video_RAM_Miror[ 0x07a8+i] = Video_RAM_Miror[0x0450+i]; write_byte( 0x0450+i , Video_RAM_Miror[0x04d0+i] ); Video_RAM_Miror[ 0x0450+i] = Video_RAM_Miror[0x04d0+i]; write_byte( 0x04d0+i , Video_RAM_Miror[0x0550+i] ); Video_RAM_Miror[ 0x04d0+i] = Video_RAM_Miror[0x0550+i]; write_byte( 0x0550+i , Video_RAM_Miror[0x05d0+i] ); Video_RAM_Miror[ 0x0550+i] = Video_RAM_Miror[0x05d0+i]; write_byte( 0x05d0+i , Video_RAM_Miror[0x0650+i] ); Video_RAM_Miror[ 0x05d0+i] = Video_RAM_Miror[0x0650+i]; write_byte( 0x0650+i , Video_RAM_Miror[0x06d0+i] ); Video_RAM_Miror[ 0x0650+i] = Video_RAM_Miror[0x06d0+i]; write_byte( 0x06d0+i , Video_RAM_Miror[0x0750+i] ); Video_RAM_Miror[ 0x06d0+i] = Video_RAM_Miror[0x0750+i]; write_byte( 0x0750+i , Video_RAM_Miror[0x07D0+i] ); Video_RAM_Miror[ 0x0750+i] = Video_RAM_Miror[0x07D0+i]; write_byte( 0x07D0+i , 0xA0 ); Video_RAM_Miror[ 0x07D0+i] = 0xA0; } current_video_character_location = 0x07D0; // Reset video pointer to the first character on the bottom row } // Dont print the carriage return/linefeed character // if (local_char!=0x8A) { write_byte(current_video_character_location , local_char ); Video_RAM_Miror[current_video_character_location] = local_char; current_video_character_location++; } } // -------------------------------------------------------------------------------------------------- // Begin xscanf code // -------------------------------------------------------------------------------------------------- // Scanf source provided by: https://iq.opengenus.org/how-printf-and-scanf-function-works-in-c-internally/ // int xscanf (char * str, ...) { va_list vl; int i = 0, j=0, ret = 0; char buff[100] = {0}, tmp[20], c, xx; char *out_loc; // Clear out any existing keystrokes // xx = read_byte(0xC010); delay (1); xx = read_byte(0xC010); delay (1); while(c != 0x08D) { c = read_byte(0xC000); // Read character from keyboard if (c>=0x80) { if (c==0x8D) xprintf ("%c", 0x0A); else xprintf ("%c", c); // Echo each typed characteer buff[i] = c & 0x7F; i++; } xx=c; while(xx >= 0x80) { xx= read_byte(0xC010); } } va_start( vl, str ); i = 0; while (str && str[i]) { if (str[i] == '%') { i++; switch (str[i]) { case 'c': { *(char *)va_arg( vl, char* ) = buff[j]; j++; ret ++; break; } case 'd': { *(int *)va_arg( vl, int* ) =strtol(&buff[j], &out_loc, 10); j+=out_loc -&buff[j]; ret++; break; } case 'x': { *(int *)va_arg( vl, int* ) =strtol(&buff[j], &out_loc, 16); j+=out_loc -&buff[j]; ret++; break; } } } else { buff[j] =str[i]; j++; } i++; } va_end(vl); return ret; } // -------------------------------------------------------------------------------- // // User code begins here // // -------------------------------------------------------------------------------- bool isPrime(uint32_t n) { // Corner case if (n <= 1) return false; // Check from 2 to n-1 for (int i = 2; i < n; i++) if (n % i == 0) return false; return true; } // Function to print primes void printPrime(uint32_t n) { for (int i = 2; i <= n; i++) { if (isPrime(i)) xprintf("%d\n",i); } } void demo_countdown() { uint16_t ret=0; uint32_t i=0; xprintf ("ENTER NUMBER TO COUNT DOWN FROM: "); ret = xscanf("%d", &i); while (i>0) { xprintf ("%d\n", i--); } return; } void demo_prime() { uint16_t ret=0; uint32_t n=0; //xprintf ("ENTER MAX NUMBER FOR PRIMES: "); xprintf ("FIND PRIMES TO WHAT NUMBER: "); ret = xscanf("%d", &n); printPrime(n); return; } void demo_fillscreen() { uint16_t x=0; uint16_t ret=0; while (1) { xprintf ("%d ",x++); } return; } void demo_testmem() { uint16_t i=0; uint16_t x=0; for (i=0 ; i<0xC000 ; i++) { write_byte (i , i); x=read_byte(i); if ((0xFF&x) != (0xFF&i) ) xprintf ("FAIL WROTE %x READ %x\n",i,x); xprintf ("\n\n*** TEST PASSED ***\n"); return; } } // ------------------------------------------------- // // Main loop // // ------------------------------------------------- void loop() { int choice=0; int ret=0; // Give Teensy 4.1 a moment // delay (50); wait_for_CLK_rising_edge(); wait_for_CLK_rising_edge(); wait_for_CLK_rising_edge(); // Set Apple II Soft-Switches to the correct video mode and page // write_byte(0xC051 , 0x0 ); // Set Apple II Text Mode write_byte(0xC054 , 0x0 ); // Set Apple II Text Page 1 // Clear video memory by scrolliing text off the screen with printf's // for (uint16_t i=0 ; i<2000; i++) { xprintf (" "); } // Menu // while (1) { xprintf ("\n"); xprintf ("MICROCORE LABS\n"); xprintf ("MCL65-FAST DEMO\n"); xprintf ("---------------\n\n"); xprintf ("1) COUNTDOWN \n"); xprintf ("2) PRIME NUMBERS \n"); xprintf ("3) TEST APPLE II+ 48K MEMORY \n"); xprintf ("4) FILL SCREEN \n\n"); xprintf ("ENTER CHOICE: "); ret = xscanf("%d", &choice); switch (choice) { case 1: demo_countdown(); break; case 2: demo_prime(); break; case 3: demo_testmem(); break; case 4: demo_fillscreen(); break; } } }