From bba5edaee4f8f43e42d064c1760a2f74a407e232 Mon Sep 17 00:00:00 2001 From: Rafael Zurita Date: Fri, 19 Jun 2020 22:01:21 -0300 Subject: [PATCH] Wow basic --- README.md | 20 +- device/nam/naminit.c | 8 +- device/tty/ttyinit.c | 4 +- include/avr_messages.h | 3 + include/name.h | 4 +- include/prototypes.h | 4 +- include/shprototypes.h | 1 + lib/avr_messages.c | 1 + lib/avr_printf.c | 23 +- lib/printf.c | 30 +- shell/shell.c | 15 +- shell/text_buffer.h | 4 + shell/xsh_basic.c | 1818 ++++++++++++++++++++++++++++++++++++++++ shell/xsh_editor.c | 101 +++ shell/xsh_memstat.c | 50 +- system/getstk.c | 2 + system/initialize.c | 24 +- system/kprintf.c | 6 +- system/platinit.c | 1 - system/serial_avr.c | 9 +- xinu-avr-port.txt | 5 + 21 files changed, 2058 insertions(+), 75 deletions(-) create mode 100644 shell/text_buffer.h create mode 100644 shell/xsh_basic.c create mode 100644 shell/xsh_editor.c diff --git a/README.md b/README.md index 8e5694a..f32ac59 100644 --- a/README.md +++ b/README.md @@ -20,12 +20,20 @@ ventional operating systems supply. Xinu originally ran on Digital Equipment Corporation LSI 11's with only 64K bytes of memory, at the end of 1979 -and the inning of 1980. Over the years Xinu versions have been ported -to many architectures , CISC and RISC: including the IBM PC (x86), Sun 3, -Transputer, MacIntosh, ARM, PowerPC and MIPS. There -are current versions of Xinu for Galileo Intel boards, -Beagle Boards, several MIPS platforms, and for PC hardware and virtual -machines. +and the inning of 1980. Over the years Xinu versions +Xinu have been expanded and ported to a wide variety of architectures and platforms, including: IBM PC, +Macintosh, Digital Equipment Corporation VAX and DECStation 3100, Sun Microsystems Sun 2, +Sun 3 and Sparcstations, and for several ARM, MIPS and x86 embedded boards. +It has been used as the basis for many research projects. +Furthermore, Xinu has been used as an embedded system in products +by companies such as Motorola, Mitsubishi, Hewlett-Packard, and Lexmark. +There is a full TCP/IP stack, and even the original version of Xinu +(for the PDP-11) supported arbitrary processes and network I/O. +have been ported + +There are current versions of Xinu for Galileo Intel boards, +ARM Beagle Boards, several MIPS platforms, and for x86 PC hardware +and virtual machines. Xinu differs completely from the internal structure of Unix (or Linux). diff --git a/device/nam/naminit.c b/device/nam/naminit.c index 34dd8cf..44e3934 100644 --- a/device/nam/naminit.c +++ b/device/nam/naminit.c @@ -65,16 +65,16 @@ status naminit(void) if (len > NM_MAXLEN) { // RAFA kprintf("namespace: device name %s too long\r\n", - kprintf(&m5[0], - devptr->dvname); + avr_kprintf(m5); + kprintf("%s", devptr->dvname); continue; } retval = mount(tmpstr, NULLSTR, devptr->dvnum); if (retval == SYSERR) { // RAFA kprintf("namespace: cannot mount device %d\r\n", - kprintf(&m4[0], - devptr->dvname); + avr_kprintf(m4); + kprintf("%s", devptr->dvname); continue; } } diff --git a/device/tty/ttyinit.c b/device/tty/ttyinit.c index 918bcc3..b6463c4 100644 --- a/device/tty/ttyinit.c +++ b/device/tty/ttyinit.c @@ -13,7 +13,7 @@ devcall ttyinit( ) { struct ttycblk *typtr; /* Pointer to ttytab entry */ - struct uart_csreg *uptr; /* Address of UART's CSRs */ +// struct uart_csreg *uptr; /* Address of UART's CSRs */ typtr = &ttytab[ devptr->dvminor ]; @@ -52,6 +52,6 @@ devcall ttyinit( /* Initialize UART */ /* avr: TODO port uart to here */ - ttykickout(uptr); +// ttykickout(uptr); return OK; } diff --git a/include/avr_messages.h b/include/avr_messages.h index 0e38768..7931019 100644 --- a/include/avr_messages.h +++ b/include/avr_messages.h @@ -5,6 +5,9 @@ typedef unsigned int size_t; // extern const char CONSOLE_RESET[]; // extern const char m0[]; +extern const char m0[]; +extern const char m00[]; +extern const char m000[]; extern const char m1[]; extern const char m2[]; extern const char m3[]; diff --git a/include/name.h b/include/name.h index 4caf1de..5a2f1ed 100644 --- a/include/name.h +++ b/include/name.h @@ -4,10 +4,10 @@ /* Constants that define the namespace mapping table sizes */ -#define NM_PRELEN 8 /* Max size of a prefix string */ +#define NM_PRELEN 16 /* Max size of a prefix string */ #define NM_REPLLEN 8 /* Maximum size of a replacement*/ #define NM_MAXLEN 8 /* Maximum size of a file name */ -#define NNAMES 3 /* Number of prefix definitions */ +#define NNAMES 4 /* Number of prefix definitions */ /* Definition of the name prefix table that defines all name mappings */ diff --git a/include/prototypes.h b/include/prototypes.h index 8337117..4028967 100644 --- a/include/prototypes.h +++ b/include/prototypes.h @@ -631,7 +631,9 @@ extern devcall spiputc(struct dentry *, char); /* avr specific */ extern void avr_printf(char mess[]); -extern void avr_kprintf(char mess[]); +extern void avr_kprintf(const unsigned char *msg); + +// extern void avr_kprintf(char mess[]); extern void blink_avr(); typedef unsigned int size_t; #define hibyte(x) (unsigned char)(((int)(x)>>8)&0xff) diff --git a/include/shprototypes.h b/include/shprototypes.h index c644903..5036eb6 100644 --- a/include/shprototypes.h +++ b/include/shprototypes.h @@ -80,3 +80,4 @@ extern shellcmd xsh_help (int32, char *[]); // RAFA AGREGO TODO ESTO /* in file xsh_editor.c */ extern shellcmd xsh_editor (int32, char *[]); +extern shellcmd xsh_basic (int32, char *[]); diff --git a/lib/avr_messages.c b/lib/avr_messages.c index 93ff491..d277e5d 100644 --- a/lib/avr_messages.c +++ b/lib/avr_messages.c @@ -6,6 +6,7 @@ typedef unsigned int size_t; // const char CONSOLE_RESET[] PROGMEM = " \033[0m\033[2J\033[;H"; // const char m0[] PROGMEM = "Welcome to Xinu for AVR microcontrollers!\n v0.1 rafa@fi.uncoma.edu.ar"; +const char m0[] PROGMEM = "\nWelcome to Xinu!\n\n\r\tXinu OS Copyright (c) 2012, 2015\n\r\tDouglas E. Comer and CRC Press, Inc.\n\n\r\tThis version for AVR atmega328p v0.1 (c) 2020\n\r\tRafael Ignacio Zurita \n\n\r"; const char m1[] PROGMEM = "\n\nMain process recreating shell\n\n"; const char m2[] PROGMEM = "Port system ran out of message nodes"; const char m3[] PROGMEM = "\n\nAll user processes have completed.\n\n"; diff --git a/lib/avr_printf.c b/lib/avr_printf.c index 27fc492..6412123 100644 --- a/lib/avr_printf.c +++ b/lib/avr_printf.c @@ -4,16 +4,31 @@ void avr_printf(char mess[]) { char t[80]; - memset(t, 80, 0); + memset(t, 0, 80); strncpy_P(t, mess, 79); printf("%s", t); } -void avr_kprintf(char mess[]) +// void avr_kprintf(char mess[]) +void avr_kprintf(const unsigned char *msg) { - char t[80]; +// char t[80]; + + intmask mask; + + mask = disable(); + + + while( pgm_read_byte( msg ) != 0 ) { +// printf( "%c", pgm_read_byte( msg++ ) ); + putchar(pgm_read_byte( msg++ ) ); + }; + - memset(t, 80, 0); + restore(mask); +/* + memset(t, 0, 80); strncpy_P(t, mess, 79); printf("%s", t); +*/ } diff --git a/lib/printf.c b/lib/printf.c index ce7dab1..cce4284 100644 --- a/lib/printf.c +++ b/lib/printf.c @@ -11,22 +11,18 @@ extern int xinu_putc(did32, char); * printf - standard C printf function *------------------------------------------------------------------------ */ + +#define PRINTF_BUF 81 + int printf( const char *fmt, ... ) { -// va_list ap; - // //syscall putc(did32, char); - // int xinu_putc(did32, char); - - // va_start(ap, fmt); - //_fdoprnt((char *)fmt, ap, putc, stdout); - //va_end(ap); +/* va_list ap; - // RAFA char output[81]; char *c; @@ -41,6 +37,22 @@ int printf( putc(stdout, *c); c++; }; - +*/ + + + + char buf[PRINTF_BUF]; + va_list ap; + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + for(char *p = &buf[0]; *p; p++) // emulate cooked mode for newlines + { + if(*p == '\n') + { + putchar('\r'); + } + putchar(*p); + } + va_end(ap); return 0; } diff --git a/shell/shell.c b/shell/shell.c index 13d8ac8..5ee23aa 100644 --- a/shell/shell.c +++ b/shell/shell.c @@ -8,7 +8,9 @@ /* Table of Xinu shell commands and the function associated with each */ /************************************************************************/ const struct cmdent cmdtab[] = { - {"memstat", TRUE, xsh_memstat}, /* Make built-in */ + {"memstat", FALSE, xsh_memstat}, /* Make built-in */ + {"editor", FALSE, xsh_editor}, /* Make built-in */ + {"basic", FALSE, xsh_basic}, /* Make built-in */ {"echo", FALSE, xsh_echo} // {"argecho", TRUE, xsh_argecho}, // {"cat", FALSE, xsh_cat}, @@ -94,6 +96,10 @@ process shell ( while (TRUE) { + // RAFA + // fprintf(dev, "\033[2J"); + // fprintf(dev, "\033[H"); + /* Display prompt */ fprintf(dev, SHELL_PROMPT); @@ -269,6 +275,11 @@ process shell ( } } + // int eeprom_fd = open(RAM0, nombre, "w"); + // char raf[32] = "pepe"; + // write(fd, pepe, 32); + // int eeprom_fd = open(RAM0, nombre, "w"); + /* Spawn child thread for non-built-in commands */ // RAFA child = create(cmdtab[j].cfunc, @@ -276,7 +287,7 @@ process shell ( // RAFA cmdtab[j].cname, 2, ntok, &tmparg); /* 160 bytes de stack perfecto */ child = create(cmdtab[j].cfunc, - 160, SHELL_CMDPRIO, + 460, SHELL_CMDPRIO, cmdtab[j].cname, 2, ntok, &tmparg); /* If creation or argument copy fails, report error */ diff --git a/shell/text_buffer.h b/shell/text_buffer.h new file mode 100644 index 0000000..3210cc6 --- /dev/null +++ b/shell/text_buffer.h @@ -0,0 +1,4 @@ + +#define NLINES 6 +#define LINE_LEN 32 + diff --git a/shell/xsh_basic.c b/shell/xsh_basic.c new file mode 100644 index 0000000..bd0955b --- /dev/null +++ b/shell/xsh_basic.c @@ -0,0 +1,1818 @@ +/* xsh_editor.c - xsh_editor */ + +#include +#include + +#define NLINES 10 +#define LINE_LEN 24 + +void outchar( char ch ); + +#ifndef boolean + #define boolean int + #define true 1 + #define false 0 +#endif + + +#include "text_buffer.h" + +/*------------------------------------------------------------------------ + * xhs_editor - text editor + *------------------------------------------------------------------------ + */ +shellcmd xsh_basic(int nargs, char *args[]) +{ + + int dev = 0; + +// printf("stk: 0x%08x\n", &dev); + + control(dev, TC_MODER, 0, 0); + + setup(); + loop(); + + control(dev, TC_MODEC, 0, 0); + +// printf("stk: 0x%08x\n", &dev); + return 0; +} +//////////////////////////////////////////////////////////////////////////////// +// TinyBasic Plus +//////////////////////////////////////////////////////////////////////////////// +// +// Authors: +// Gordon Brandly (Tiny Basic for 68000) +// Mike Field (Arduino Basic) (port to Arduino) +// Scott Lawrence (TinyBasic Plus) (features, etc) +// +// Contributors: +// Brian O'Dell (INPUT) +// (full list tbd) + +// For full history of Tiny Basic, please see the wikipedia entry here: +// https://en.wikipedia.org/wiki/Tiny_BASIC + +// LICENSING NOTES: +// Mike Field based his C port of Tiny Basic on the 68000 +// Tiny BASIC which carried the following license: +/* +****************************************************************** +* * +* Tiny BASIC for the Motorola MC68000 * +* * +* Derived from Palo Alto Tiny BASIC as published in the May 1976 * +* issue of Dr. Dobb's Journal. Adapted to the 68000 by: * +* Gordon Brandly * +* 12147 - 51 Street * +* Edmonton AB T5W 3G8 * +* Canada * +* (updated mailing address for 1996) * +* * +* This version is for MEX68KECB Educational Computer Board I/O. * +* * +****************************************************************** +* Copyright (C) 1984 by Gordon Brandly. This program may be * +* freely distributed for personal use only. All commercial * +* rights are reserved. * +****************************************************************** +*/ +// ref: http://members.shaw.ca:80/gbrandly/68ktinyb.html +// +// However, Mike did not include a license of his own for his +// version of this. +// ref: http://hamsterworks.co.nz/mediawiki/index.php/Arduino_Basic +// +// From discussions with him, I felt that the MIT license is +// the most applicable to his intent. +// +// I am in the process of further determining what should be +// done wrt licensing further. This entire header will likely +// change with the next version 0.16, which will hopefully nail +// down the whole thing so we can get back to implementing +// features instead of licenses. Thank you for your time. + +#define kVersion "v0.15" + +// v0.15: 2018-06-23 +// Integrating some contributions +// Corrected some of the #ifdef nesting atop this page +// Licensing issues beginning to be addressed + +// v0.14: 2013-11-07 +// Modified Input command to accept an expression using getn() +// Syntax is "input x" where x is any variable +// NOTE: This only works for numbers, expressions. not strings. +// +// v0.13: 2013-03-04 +// Support for Arduino 1.5 (SPI.h included, additional changes for DUE support) +// +// v0.12: 2013-03-01 +// EEPROM load and save routines added: EFORMAT, ELIST, ELOAD, ESAVE, ECHAIN +// added EAUTORUN option (chains to EEProm saved program on startup) +// Bugfixes to build properly on non-arduino systems (PROGMEM #define workaround) +// cleaned up a bit of the #define options wrt TONE +// +// v0.11: 2013-02-20 +// all display strings and tables moved to PROGMEM to save space +// removed second serial +// removed pinMode completely, autoconf is explicit +// beginnings of EEPROM related functionality (new,load,save,list) +// +// v0.10: 2012-10-15 +// added kAutoConf, which eliminates the "PINMODE" statement. +// now, DWRITE,DREAD,AWRITE,AREAD automatically set the PINMODE appropriately themselves. +// should save a few bytes in your programs. +// +// v0.09: 2012-10-12 +// Fixed directory listings. FILES now always works. (bug in the SD library) +// ref: http://arduino.cc/forum/index.php/topic,124739.0.html +// fixed filesize printouts (added printUnum for unsigned numbers) +// #defineable baud rate for slow connection throttling +//e +// v0.08: 2012-10-02 +// Tone generation through piezo added (TONE, TONEW, NOTONE) +// +// v0.07: 2012-09-30 +// Autorun buildtime configuration feature +// +// v0.06: 2012-09-27 +// Added optional second serial input, used for an external keyboard +// +// v0.05: 2012-09-21 +// CHAIN to load and run a second file +// RND,RSEED for random stuff +// Added "!=" for "<>" synonym +// Added "END" for "STOP" synonym (proper name for the functionality anyway) +// +// v0.04: 2012-09-20 +// DELAY ms - for delaying +// PINMODE , INPUT|IN|I|OUTPUT|OUT|O +// DWRITE , HIGH|HI|1|LOW|LO|0 +// AWRITE , [0..255] +// fixed "save" appending to existing files instead of overwriting +// Updated for building desktop command line app (incomplete) +// +// v0.03: 2012-09-19 +// Integrated Jurg Wullschleger whitespace,unary fix +// Now available through github +// Project renamed from "Tiny Basic in C" to "TinyBasic Plus" +// +// v0.02b: 2012-09-17 Scott Lawrence +// Better FILES listings +// +// v0.02a: 2012-09-17 Scott Lawrence +// Support for SD Library +// Added: SAVE, FILES (mostly works), LOAD (mostly works) (redirects IO) +// Added: MEM, ? (PRINT) +// Quirk: "10 LET A=B+C" is ok "10 LET A = B + C" is not. +// Quirk: INPUT seems broken? + +// IF testing with Visual C, this needs to be the first thing in the file. +//#include "stdafx.h" + +// char eliminateCompileErrors = 1; // fix to suppress arduino build errors + +// hack to let makefiles work with this file unchanged +#undef ARDUINO + + +//////////////////////////////////////////////////////////////////////////////// +// Feature option configuration... + +// This enables LOAD, SAVE, FILES commands through the Arduino SD Library +// it adds 9k of usage as well. +//#define ENABLE_FILEIO 1 +#undef ENABLE_FILEIO + +// this turns on "autorun". if there's FileIO, and a file "autorun.bas", +// then it will load it and run it when starting up +//#define ENABLE_AUTORUN 1 +#undef ENABLE_AUTORUN + +// this will enable the "TONE", "NOTONE" command using a piezo +// element on the specified pin. Wire the red/positive/piezo to the kPiezoPin, +// and the black/negative/metal disc to ground. +// it adds 1.5k of usage as well. +//#define ENABLE_TONES 1 +#define kPiezoPin 5 + +// we can use the EEProm to store a program during powerdown. This is +// 1kbyte on the '328, and 512 bytes on the '168. Enabling this here will +// allow for this funcitonality to work. Note that this only works on AVR +// arduino. Disable it for DUE/other devices. + +// Sometimes, we connect with a slower device as the console. +// Set your console D0/D1 baud rate here (9600 baud default) +#define kConsoleBaud 9600 + + + +// Enable memory alignment for certain processers (e.g. some ESP8266-based devices) +#ifdef ESP8266 + // Uses up to one extra byte per program line of memory + #define ALIGN_MEMORY 1 +#else + #undef ALIGN_MEMORY +#endif + + // not an arduino, so we can disable these features. + // turn off EEProm +#undef ENABLE_EEPROM +#undef ENABLE_TONES + + +// includes, and settings for Arduino-specific features + + +// set up file includes for things we need, or desktop specific stuff. + +#include +#include + +// size of our program ram +// RAFA #define kRamSize 64*1024 /* arbitrary - not dependant on libraries */ +// RAFA #define kRamSize 24 /* arbitrary - not dependant on libraries */ + + +// RAFA AGREGA +// #define ALIGN_MEMORY 1 + +//////////////////// + +// memory alignment +// necessary for some esp8266-based devices +#ifdef ALIGN_MEMORY + // Align memory addess x to an even page + #define ALIGN_UP(x) ((unsigned char*)(((unsigned int)(x + 1) >> 1) << 1)) + #define ALIGN_DOWN(x) ((unsigned char*)(((unsigned int)x >> 1) << 1)) +#else + #define ALIGN_UP(x) x + #define ALIGN_DOWN(x) x +#endif + + +//////////////////// +// various other desktop-tweaks and such. + +#ifndef boolean + #define boolean int + #define true 1 + #define false 0 +#endif + +#ifndef byte + typedef unsigned char byte; +#endif + +// some catches for AVR based text string stuff... +#ifndef PROGMEM + #define PROGMEM +#endif + +#ifndef pgm_read_byte + #define pgm_read_byte( A ) *(A) +#endif + +//////////////////// + + +// some settings based things + +boolean inhibitOutput = false; +static boolean runAfterLoad = false; +static boolean triggerRun = false; + +// these will select, at runtime, where IO happens through for load/save +enum { + kStreamSerial = 0, + kStreamEEProm, + kStreamFile +}; +static unsigned char inStream = kStreamSerial; +static unsigned char outStream = kStreamSerial; + + +//////////////////////////////////////////////////////////////////////////////// +// ASCII Characters +#define CR '\r' +#define NL '\n' +#define LF 0x0a +#define TAB '\t' +#define BELL '\b' +#define SPACE ' ' +#define SQUOTE '\'' +#define DQUOTE '\"' +#define CTRLC 0x03 +#define CTRLH 0x08 +#define CTRLS 0x13 +#define CTRLX 0x18 + +typedef short unsigned LINENUM; +#define ECHO_CHARS 0 + +// RAFA +//unsigned char program[kRamSize]; +// extern unsigned char program[NLINES*LINE_LEN]; + +static const char * sentinel = "HELLO"; +static unsigned char *txtpos,*list_line, *tmptxtpos; +static unsigned char expression_error; +static unsigned char *tempsp; + +/***********************************************************/ +// Keyword table and constants - the last character has 0x80 added to it +const static unsigned char keywords[] PROGMEM = { + 'L','I','S','T'+0x80, + 'L','O','A','D'+0x80, + 'N','E','W'+0x80, + 'R','U','N'+0x80, + 'S','A','V','E'+0x80, + 'N','E','X','T'+0x80, + 'L','E','T'+0x80, + 'I','F'+0x80, + 'G','O','T','O'+0x80, + 'G','O','S','U','B'+0x80, + 'R','E','T','U','R','N'+0x80, + 'R','E','M'+0x80, + 'F','O','R'+0x80, + 'I','N','P','U','T'+0x80, + 'P','R','I','N','T'+0x80, + 'P','O','K','E'+0x80, + 'S','T','O','P'+0x80, + 'B','Y','E'+0x80, + 'F','I','L','E','S'+0x80, + 'M','E','M'+0x80, + '?'+ 0x80, + '\''+ 0x80, + 'A','W','R','I','T','E'+0x80, + 'D','W','R','I','T','E'+0x80, + 'D','E','L','A','Y'+0x80, + 'E','N','D'+0x80, + 'R','S','E','E','D'+0x80, + 'C','H','A','I','N'+0x80, +#ifdef ENABLE_TONES + 'T','O','N','E','W'+0x80, + 'T','O','N','E'+0x80, + 'N','O','T','O','N','E'+0x80, +#endif + 0 +}; + +// by moving the command list to an enum, we can easily remove sections +// above and below simultaneously to selectively obliterate functionality. +enum { + KW_LIST = 0, + KW_LOAD, KW_NEW, KW_RUN, KW_SAVE, + KW_NEXT, KW_LET, KW_IF, + KW_GOTO, KW_GOSUB, KW_RETURN, + KW_REM, + KW_FOR, + KW_INPUT, KW_PRINT, + KW_POKE, + KW_STOP, KW_BYE, + KW_FILES, + KW_MEM, + KW_QMARK, KW_QUOTE, + KW_AWRITE, KW_DWRITE, + KW_DELAY, + KW_END, + KW_RSEED, + KW_CHAIN, +#ifdef ENABLE_TONES + KW_TONEW, KW_TONE, KW_NOTONE, +#endif + KW_DEFAULT /* always the final one*/ +}; + +struct stack_for_frame { + char frame_type; + char for_var; + short int terminal; + short int step; + unsigned char *current_line; + unsigned char *txtpos; +}; + +struct stack_gosub_frame { + char frame_type; + unsigned char *current_line; + unsigned char *txtpos; +}; + +const static unsigned char func_tab[] PROGMEM = { + 'P','E','E','K'+0x80, + 'A','B','S'+0x80, + 'A','R','E','A','D'+0x80, + 'D','R','E','A','D'+0x80, + 'R','N','D'+0x80, + 0 +}; +#define FUNC_PEEK 0 +#define FUNC_ABS 1 +#define FUNC_AREAD 2 +#define FUNC_DREAD 3 +#define FUNC_RND 4 +#define FUNC_UNKNOWN 5 + +const static unsigned char to_tab[] PROGMEM = { + 'T','O'+0x80, + 0 +}; + +const static unsigned char step_tab[] PROGMEM = { + 'S','T','E','P'+0x80, + 0 +}; + +const static unsigned char relop_tab[] PROGMEM = { + '>','='+0x80, + '<','>'+0x80, + '>'+0x80, + '='+0x80, + '<','='+0x80, + '<'+0x80, + '!','='+0x80, + 0 +}; + +#define RELOP_GE 0 +#define RELOP_NE 1 +#define RELOP_GT 2 +#define RELOP_EQ 3 +#define RELOP_LE 4 +#define RELOP_LT 5 +#define RELOP_NE_BANG 6 +#define RELOP_UNKNOWN 7 + +const static unsigned char highlow_tab[] PROGMEM = { + 'H','I','G','H'+0x80, + 'H','I'+0x80, + 'L','O','W'+0x80, + 'L','O'+0x80, + 0 +}; +#define HIGHLOW_HIGH 1 +#define HIGHLOW_UNKNOWN 4 + +//RAFA ANTES DECIA 5 +//#define STACK_SIZE (sizeof(struct stack_for_frame)*5) +#define STACK_SIZE (sizeof(struct stack_for_frame)*4) + + +#define VAR_SIZE sizeof(short int) // Size of variables in bytes + +static unsigned char *stack_limit; +static unsigned char *program_start; +static unsigned char *program_end; +// static unsigned char *stack; // Software stack for things that should go on the CPU stack +static unsigned char *variables_begin; +static unsigned char *current_line; +static unsigned char *sp; +#define STACK_GOSUB_FLAG 'G' +#define STACK_FOR_FLAG 'F' +static unsigned char table_index; +static LINENUM linenum; + +static const unsigned char okmsg[] PROGMEM = "OK"; +static const unsigned char whatmsg[] PROGMEM = "What? "; +static const unsigned char howmsg[] PROGMEM = "How?"; +static const unsigned char sorrymsg[] PROGMEM = "Sorry!"; +static const unsigned char initmsg[] PROGMEM = "TinyBasic Plus " kVersion; +static const unsigned char memorymsg[] PROGMEM = " bytes free."; +static const unsigned char breakmsg[] PROGMEM = "break!"; +static const unsigned char unimplimentedmsg[] PROGMEM = "Unimplemented"; +static const unsigned char backspacemsg[] PROGMEM = "\b \b"; +static const unsigned char indentmsg[] PROGMEM = " "; +static const unsigned char sderrormsg[] PROGMEM = "SD card error."; +static const unsigned char sdfilemsg[] PROGMEM = "SD file error."; +static const unsigned char dirextmsg[] PROGMEM = "(dir)"; +static const unsigned char slashmsg[] PROGMEM = "/"; +static const unsigned char spacemsg[] PROGMEM = " "; + +static int inchar(void); +//static void outchar(unsigned char c); +static void line_terminator(void); +static short int expression(void); +static unsigned char breakcheck(void); +/***************************************************************************/ +static void ignore_blanks(void) +{ + while(*txtpos == SPACE || *txtpos == TAB) + txtpos++; +} + + +/***************************************************************************/ +static void scantable(const unsigned char *table) +{ + int i = 0; + table_index = 0; + while(1) + { + // Run out of table entries? + if(pgm_read_byte( table ) == 0) + return; + + // Do we match this character? + if(txtpos[i] == pgm_read_byte( table )) + { + i++; + table++; + } + else + { + // do we match the last character of keywork (with 0x80 added)? If so, return + if(txtpos[i]+0x80 == pgm_read_byte( table )) + { + txtpos += i+1; // Advance the pointer to following the keyword + ignore_blanks(); + return; + } + + // Forward to the end of this keyword + while((pgm_read_byte( table ) & 0x80) == 0) + table++; + + // Now move on to the first character of the next word, and reset the position index + table++; + table_index++; + ignore_blanks(); + i = 0; + } + } +} + +/***************************************************************************/ +static void pushb(unsigned char b) +{ + sp--; + *sp = b; +} + +/***************************************************************************/ +static unsigned char popb() +{ + unsigned char b; + b = *sp; + sp++; + return b; +} + +/***************************************************************************/ +void printnum(int num) +{ + int digits = 0; + + if(num < 0) + { + num = -num; + outchar('-'); + } + do { + pushb(num%10+'0'); + num = num/10; + digits++; + } + while (num > 0); + + while(digits > 0) + { + outchar(popb()); + digits--; + } +} + +void printUnum(unsigned int num) +{ + int digits = 0; + + do { + pushb(num%10+'0'); + num = num/10; + digits++; + } + while (num > 0); + + while(digits > 0) + { + outchar(popb()); + digits--; + } +} + +/***************************************************************************/ +static unsigned short testnum(void) +{ + unsigned short num = 0; + ignore_blanks(); + + while(*txtpos>= '0' && *txtpos <= '9' ) + { + // Trap overflows + if(num >= 0xFFFF/10) + { + num = 0xFFFF; + break; + } + + num = num *10 + *txtpos - '0'; + txtpos++; + } + return num; +} + +/***************************************************************************/ +static unsigned char print_quoted_string(void) +{ + int i=0; + unsigned char delim = *txtpos; + if(delim != '"' && delim != '\'') + return 0; + txtpos++; + + // Check we have a closing delimiter + while(txtpos[i] != delim) + { + if(txtpos[i] == NL) + return 0; + i++; + } + + // Print the characters + while(*txtpos != delim) + { + outchar(*txtpos); + txtpos++; + } + txtpos++; // Skip over the last delimiter + + return 1; +} + + +/***************************************************************************/ +void printmsgNoNL(const unsigned char *msg) +{ + while( pgm_read_byte( msg ) != 0 ) { + outchar( pgm_read_byte( msg++ ) ); + }; +} + +/***************************************************************************/ +void printmsg(const unsigned char *msg) +{ + printmsgNoNL(msg); + line_terminator(); +} + +/***************************************************************************/ +static void getln(char prompt) +{ + char s = ' '; + outchar(prompt); + outchar(s); + txtpos = program_end+sizeof(LINENUM); + + while(1) + { + char c = inchar(); + switch(c) + { + case NL: + //break; + case CR: + line_terminator(); + // Terminate all strings with a NL + txtpos[0] = NL; + return; + case CTRLH: + if(txtpos == program_end) + break; + txtpos--; + + printmsg(backspacemsg); + break; + default: + // We need to leave at least one space to allow us to shuffle the line into order + if(txtpos == variables_begin-2) + outchar(BELL); + else + { + txtpos[0] = c; + txtpos++; + outchar(c); + } + } + } +} + +/***************************************************************************/ +static unsigned char *findline(void) +{ + unsigned char *line = program_start; + while(1) + { + if(line == program_end) + return line; + + if(((LINENUM *)line)[0] >= linenum) + return line; + + // Add the line length onto the current address, to get to the next line; + line += line[sizeof(LINENUM)]; + } +} + +/***************************************************************************/ +static void toUppercaseBuffer(void) +{ + unsigned char *c = program_end+sizeof(LINENUM); + unsigned char quote = 0; + + while(*c != NL) + { + // Are we in a quoted string? + if(*c == quote) + quote = 0; + else if(*c == '"' || *c == '\'') + quote = *c; + else if(quote == 0 && *c >= 'a' && *c <= 'z') + *c = *c + 'A' - 'a'; + c++; + } +} + +/***************************************************************************/ +void printline() +{ + LINENUM line_num; + + line_num = *((LINENUM *)(list_line)); + list_line += sizeof(LINENUM) + sizeof(char); + + // Output the line */ + printnum(line_num); + outchar(' '); + while(*list_line != NL) + { + outchar(*list_line); + list_line++; + } + list_line++; +#ifdef ALIGN_MEMORY + // Start looking for next line on even page + if (ALIGN_UP(list_line) != list_line) + list_line++; +#endif + line_terminator(); +} + +/***************************************************************************/ +static short int expr4(void) +{ + // fix provided by Jurg Wullschleger wullschleger@gmail.com + // fixes whitespace and unary operations + ignore_blanks(); + + if( *txtpos == '-' ) { + txtpos++; + return -expr4(); + } + // end fix + + if(*txtpos == '0') + { + txtpos++; + return 0; + } + + if(*txtpos >= '1' && *txtpos <= '9') + { + short int a = 0; + do { + a = a*10 + *txtpos - '0'; + txtpos++; + } + while(*txtpos >= '0' && *txtpos <= '9'); + return a; + } + + // Is it a function or variable reference? + if(txtpos[0] >= 'A' && txtpos[0] <= 'Z') + { + short int a; + // Is it a variable reference (single alpha) + if(txtpos[1] < 'A' || txtpos[1] > 'Z') + { + a = ((short int *)variables_begin)[*txtpos - 'A']; + txtpos++; + return a; + } + + // Is it a function with a single parameter + scantable(func_tab); + if(table_index == FUNC_UNKNOWN) + goto expr4_error; + + unsigned char f = table_index; + + if(*txtpos != '(') + goto expr4_error; + + txtpos++; + a = expression(); + if(*txtpos != ')') + goto expr4_error; + txtpos++; + switch(f) + { + case FUNC_PEEK: +// RAFA return program[a]; + return 0; + + case FUNC_ABS: + if(a < 0) + return -a; + return a; + + + case FUNC_RND: + return( rand() % a ); + } + } + + if(*txtpos == '(') + { + short int a; + txtpos++; + a = expression(); + if(*txtpos != ')') + goto expr4_error; + + txtpos++; + return a; + } + +expr4_error: + expression_error = 1; + return 0; + +} + +/***************************************************************************/ +static short int expr3(void) +{ + short int a,b; + + a = expr4(); + + ignore_blanks(); // fix for eg: 100 a = a + 1 + + while(1) + { + if(*txtpos == '*') + { + txtpos++; + b = expr4(); + a *= b; + } + else if(*txtpos == '/') + { + txtpos++; + b = expr4(); + if(b != 0) + a /= b; + else + expression_error = 1; + } + else + return a; + } +} + +/***************************************************************************/ +static short int expr2(void) +{ + short int a,b; + + if(*txtpos == '-' || *txtpos == '+') + a = 0; + else + a = expr3(); + + while(1) + { + if(*txtpos == '-') + { + txtpos++; + b = expr3(); + a -= b; + } + else if(*txtpos == '+') + { + txtpos++; + b = expr3(); + a += b; + } + else + return a; + } +} +/***************************************************************************/ +static short int expression(void) +{ + short int a,b; + + a = expr2(); + + // Check if we have an error + if(expression_error) return a; + + scantable(relop_tab); + if(table_index == RELOP_UNKNOWN) + return a; + + switch(table_index) + { + case RELOP_GE: + b = expr2(); + if(a >= b) return 1; + break; + case RELOP_NE: + case RELOP_NE_BANG: + b = expr2(); + if(a != b) return 1; + break; + case RELOP_GT: + b = expr2(); + if(a > b) return 1; + break; + case RELOP_EQ: + b = expr2(); + if(a == b) return 1; + break; + case RELOP_LE: + b = expr2(); + if(a <= b) return 1; + break; + case RELOP_LT: + b = expr2(); + if(a < b) return 1; + break; + } + return 0; +} + +/***************************************************************************/ +void loop() +{ + unsigned char *start; + unsigned char *newEnd; + unsigned char linelen; + boolean isDigital; + boolean alsoWait = false; + int val; + + unsigned char program[NLINES*LINE_LEN]; + + program_start = program; + program_end = program_start; + sp = program+sizeof(program); // Needed for printnum +#ifdef ALIGN_MEMORY + // Ensure these memory blocks start on even pages + stack_limit = ALIGN_DOWN(program+sizeof(program)-STACK_SIZE); + variables_begin = ALIGN_DOWN(stack_limit - 27*VAR_SIZE); +#else + stack_limit = program+sizeof(program)-STACK_SIZE; + variables_begin = stack_limit - 27*VAR_SIZE; +#endif + + // memory free + printnum(variables_begin-program_end); + printmsg(memorymsg); + +warmstart: + // this signifies that it is running in 'direct' mode. + current_line = 0; + sp = program+sizeof(program); + printmsg(okmsg); + +prompt: + if( triggerRun ){ + triggerRun = false; + current_line = program_start; + goto execline; + } + + getln( '>' ); + toUppercaseBuffer(); + + txtpos = program_end+sizeof(unsigned short); + + // Find the end of the freshly entered line + while(*txtpos != NL) + txtpos++; + + // Move it to the end of program_memory + { + unsigned char *dest; + dest = variables_begin-1; + while(1) + { + *dest = *txtpos; + if(txtpos == program_end+sizeof(unsigned short)) + break; + dest--; + txtpos--; + } + txtpos = dest; + } + + // Now see if we have a line number + linenum = testnum(); + ignore_blanks(); + if(linenum == 0) + goto direct; + + if(linenum == 0xFFFF) + goto qhow; + + // Find the length of what is left, including the (yet-to-be-populated) line header + linelen = 0; + while(txtpos[linelen] != NL) + linelen++; + linelen++; // Include the NL in the line length + linelen += sizeof(unsigned short)+sizeof(char); // Add space for the line number and line length + + // Now we have the number, add the line header. + txtpos -= 3; + +#ifdef ALIGN_MEMORY + // Line starts should always be on 16-bit pages + if (ALIGN_DOWN(txtpos) != txtpos) + { + txtpos--; + linelen++; + // As the start of the line has moved, the data should move as well + unsigned char *tomove; + tomove = txtpos + 3; + while (tomove < txtpos + linelen - 1) + { + *tomove = *(tomove + 1); + tomove++; + } + } +#endif + + *((unsigned short *)txtpos) = linenum; + txtpos[sizeof(LINENUM)] = linelen; + + + // Merge it into the rest of the program + start = findline(); + + // If a line with that number exists, then remove it + if(start != program_end && *((LINENUM *)start) == linenum) + { + unsigned char *dest, *from; + unsigned tomove; + + from = start + start[sizeof(LINENUM)]; + dest = start; + + tomove = program_end - from; + while( tomove > 0) + { + *dest = *from; + from++; + dest++; + tomove--; + } + program_end = dest; + } + + if(txtpos[sizeof(LINENUM)+sizeof(char)] == NL) // If the line has no txt, it was just a delete + goto prompt; + + + + // Make room for the new line, either all in one hit or lots of little shuffles + while(linelen > 0) + { + unsigned int tomove; + unsigned char *from,*dest; + unsigned int space_to_make; + + space_to_make = txtpos - program_end; + + if(space_to_make > linelen) + space_to_make = linelen; + newEnd = program_end+space_to_make; + tomove = program_end - start; + + + // Source and destination - as these areas may overlap we need to move bottom up + from = program_end; + dest = newEnd; + while(tomove > 0) + { + from--; + dest--; + *dest = *from; + tomove--; + } + + // Copy over the bytes into the new space + for(tomove = 0; tomove < space_to_make; tomove++) + { + *start = *txtpos; + txtpos++; + start++; + linelen--; + } + program_end = newEnd; + } + goto prompt; + +unimplemented: + printmsg(unimplimentedmsg); + goto prompt; + +qhow: + printmsg(howmsg); + goto prompt; + +qwhat: + printmsgNoNL(whatmsg); + if(current_line != NULL) + { + unsigned char tmp = *txtpos; + if(*txtpos != NL) + *txtpos = '^'; + list_line = current_line; + printline(); + *txtpos = tmp; + } + line_terminator(); + goto prompt; + +qsorry: + printmsg(sorrymsg); + goto warmstart; + +run_next_statement: + while(*txtpos == ':') + txtpos++; + ignore_blanks(); + if(*txtpos == NL) + goto execnextline; + goto interperateAtTxtpos; + +direct: + txtpos = program_end+sizeof(LINENUM); + if(*txtpos == NL) + goto prompt; + +interperateAtTxtpos: + if(breakcheck()) + { + printmsg(breakmsg); + goto warmstart; + } + + scantable(keywords); + +// RAFA +// short int val; +// int stk2 = 4; + + switch(table_index) + { + case KW_DELAY: + { + goto unimplemented; + } + + case KW_FILES: + goto files; + case KW_LIST: + goto list; + case KW_CHAIN: + goto chain; + case KW_LOAD: + goto load; + case KW_MEM: + goto mem; + case KW_NEW: + if(txtpos[0] != NL) + goto qwhat; + program_end = program_start; + goto prompt; + case KW_RUN: + current_line = program_start; + goto execline; + case KW_SAVE: + goto save; + case KW_NEXT: + goto next; + case KW_LET: + goto assignment; + case KW_IF: + // short int val; + expression_error = 0; + val = expression(); + if(expression_error || *txtpos == NL) + goto qhow; + if(val != 0) + goto interperateAtTxtpos; + goto execnextline; + + case KW_GOTO: + expression_error = 0; + linenum = expression(); + if(expression_error || *txtpos != NL) + goto qhow; + current_line = findline(); + goto execline; + + case KW_GOSUB: + goto gosub; + case KW_RETURN: + goto gosub_return; + case KW_REM: + case KW_QUOTE: + goto execnextline; // Ignore line completely + case KW_FOR: + goto forloop; + case KW_INPUT: + goto input; + case KW_PRINT: + case KW_QMARK: + goto print; + case KW_POKE: + goto poke; + case KW_END: + case KW_STOP: + // This is the easy way to end - set the current line to the end of program attempt to run it + if(txtpos[0] != NL) + goto qwhat; + current_line = program_end; + goto execline; + case KW_BYE: +// printf("stk2: 0x%08x\n", &stk2); + // Leave the basic interperater + return; + + case KW_AWRITE: // AWRITE , HIGH|LOW + isDigital = false; + goto awrite; + case KW_DWRITE: // DWRITE , HIGH|LOW + isDigital = true; + goto dwrite; + + case KW_RSEED: + goto rseed; + +#ifdef ENABLE_TONES + case KW_TONEW: + alsoWait = true; + case KW_TONE: + goto tonegen; + case KW_NOTONE: + goto tonestop; +#endif + + + case KW_DEFAULT: + goto assignment; + default: + break; + } + +execnextline: + if(current_line == NULL) // Processing direct commands? + goto prompt; + current_line += current_line[sizeof(LINENUM)]; + +execline: + if(current_line == program_end) // Out of lines to run + goto warmstart; + txtpos = current_line+sizeof(LINENUM)+sizeof(char); + goto interperateAtTxtpos; + + +input: + { + unsigned char var; + int value; + ignore_blanks(); + if(*txtpos < 'A' || *txtpos > 'Z') + goto qwhat; + var = *txtpos; + txtpos++; + ignore_blanks(); + if(*txtpos != NL && *txtpos != ':') + goto qwhat; +inputagain: + tmptxtpos = txtpos; + getln( '?' ); + toUppercaseBuffer(); + txtpos = program_end+sizeof(unsigned short); + ignore_blanks(); + expression_error = 0; + value = expression(); + if(expression_error) + goto inputagain; + ((short int *)variables_begin)[var-'A'] = value; + txtpos = tmptxtpos; + + goto run_next_statement; + } + +forloop: + { + unsigned char var; + short int initial, step, terminal; + ignore_blanks(); + if(*txtpos < 'A' || *txtpos > 'Z') + goto qwhat; + var = *txtpos; + txtpos++; + ignore_blanks(); + if(*txtpos != '=') + goto qwhat; + txtpos++; + ignore_blanks(); + + expression_error = 0; + initial = expression(); + if(expression_error) + goto qwhat; + + scantable(to_tab); + if(table_index != 0) + goto qwhat; + + terminal = expression(); + if(expression_error) + goto qwhat; + + scantable(step_tab); + if(table_index == 0) + { + step = expression(); + if(expression_error) + goto qwhat; + } + else + step = 1; + ignore_blanks(); + if(*txtpos != NL && *txtpos != ':') + goto qwhat; + + + if(!expression_error && *txtpos == NL) + { + struct stack_for_frame *f; + if(sp + sizeof(struct stack_for_frame) < stack_limit) + goto qsorry; + + sp -= sizeof(struct stack_for_frame); + f = (struct stack_for_frame *)sp; + ((short int *)variables_begin)[var-'A'] = initial; + f->frame_type = STACK_FOR_FLAG; + f->for_var = var; + f->terminal = terminal; + f->step = step; + f->txtpos = txtpos; + f->current_line = current_line; + goto run_next_statement; + } + } + goto qhow; + +gosub: + expression_error = 0; + linenum = expression(); + if(!expression_error && *txtpos == NL) + { + struct stack_gosub_frame *f; + if(sp + sizeof(struct stack_gosub_frame) < stack_limit) + goto qsorry; + + sp -= sizeof(struct stack_gosub_frame); + f = (struct stack_gosub_frame *)sp; + f->frame_type = STACK_GOSUB_FLAG; + f->txtpos = txtpos; + f->current_line = current_line; + current_line = findline(); + goto execline; + } + goto qhow; + +next: + // Fnd the variable name + ignore_blanks(); + if(*txtpos < 'A' || *txtpos > 'Z') + goto qhow; + txtpos++; + ignore_blanks(); + if(*txtpos != ':' && *txtpos != NL) + goto qwhat; + +gosub_return: + // Now walk up the stack frames and find the frame we want, if present + tempsp = sp; + while(tempsp < program+sizeof(program)-1) + { + switch(tempsp[0]) + { + case STACK_GOSUB_FLAG: + if(table_index == KW_RETURN) + { + struct stack_gosub_frame *f = (struct stack_gosub_frame *)tempsp; + current_line = f->current_line; + txtpos = f->txtpos; + sp += sizeof(struct stack_gosub_frame); + goto run_next_statement; + } + // This is not the loop you are looking for... so Walk back up the stack + tempsp += sizeof(struct stack_gosub_frame); + break; + case STACK_FOR_FLAG: + // Flag, Var, Final, Step + if(table_index == KW_NEXT) + { + struct stack_for_frame *f = (struct stack_for_frame *)tempsp; + // Is the the variable we are looking for? + if(txtpos[-1] == f->for_var) + { + short int *varaddr = ((short int *)variables_begin) + txtpos[-1] - 'A'; + *varaddr = *varaddr + f->step; + // Use a different test depending on the sign of the step increment + if((f->step > 0 && *varaddr <= f->terminal) || (f->step < 0 && *varaddr >= f->terminal)) + { + // We have to loop so don't pop the stack + txtpos = f->txtpos; + current_line = f->current_line; + goto run_next_statement; + } + // We've run to the end of the loop. drop out of the loop, popping the stack + sp = tempsp + sizeof(struct stack_for_frame); + goto run_next_statement; + } + } + // This is not the loop you are looking for... so Walk back up the stack + tempsp += sizeof(struct stack_for_frame); + break; + default: + //printf("Stack is stuffed!\n"); + goto warmstart; + } + } + // Didn't find the variable we've been looking for + goto qhow; + +assignment: + { + short int value; + short int *var; + + if(*txtpos < 'A' || *txtpos > 'Z') + goto qhow; + var = (short int *)variables_begin + *txtpos - 'A'; + txtpos++; + + ignore_blanks(); + + if (*txtpos != '=') + goto qwhat; + txtpos++; + ignore_blanks(); + expression_error = 0; + value = expression(); + if(expression_error) + goto qwhat; + // Check that we are at the end of the statement + if(*txtpos != NL && *txtpos != ':') + goto qwhat; + *var = value; + } + goto run_next_statement; +poke: + { + short int value; + unsigned char *address; + + // Work out where to put it + expression_error = 0; + value = expression(); + if(expression_error) + goto qwhat; + address = (unsigned char *)value; + + // check for a comma + ignore_blanks(); + if (*txtpos != ',') + goto qwhat; + txtpos++; + ignore_blanks(); + + // Now get the value to assign + expression_error = 0; + value = expression(); + if(expression_error) + goto qwhat; + //printf("Poke %p value %i\n",address, (unsigned char)value); + // Check that we are at the end of the statement + if(*txtpos != NL && *txtpos != ':') + goto qwhat; + } + goto run_next_statement; + +list: + linenum = testnum(); // Retuns 0 if no line found. + + // Should be EOL + if(txtpos[0] != NL) + goto qwhat; + + // Find the line + list_line = findline(); + while(list_line != program_end) + printline(); + goto warmstart; + +print: + // If we have an empty list then just put out a NL + if(*txtpos == ':' ) + { + line_terminator(); + txtpos++; + goto run_next_statement; + } + if(*txtpos == NL) + { + goto execnextline; + } + + while(1) + { + ignore_blanks(); + if(print_quoted_string()) + { + ; + } + else if(*txtpos == '"' || *txtpos == '\'') + goto qwhat; + else + { + short int e; + expression_error = 0; + e = expression(); + if(expression_error) + goto qwhat; + printnum(e); + } + + // At this point we have three options, a comma or a new line + if(*txtpos == ',') + txtpos++; // Skip the comma and move onto the next + else if(txtpos[0] == ';' && (txtpos[1] == NL || txtpos[1] == ':')) + { + txtpos++; // This has to be the end of the print - no newline + break; + } + else if(*txtpos == NL || *txtpos == ':') + { + line_terminator(); // The end of the print statement + break; + } + else + goto qwhat; + } + goto run_next_statement; + +mem: + // memory free + printnum(variables_begin-program_end); + printmsg(memorymsg); + goto run_next_statement; + + + /*************************************************/ + +pinmode: // PINMODE , I/O +awrite: // AWRITE ,val +dwrite: + goto unimplemented; + + /*************************************************/ +files: + // display a listing of files on the device. + // version 1: no support for subdirectories + + goto unimplemented; + + +chain: + runAfterLoad = true; + +load: + // clear the program + program_end = program_start; + + // load from a file into memory + goto unimplemented; + + + +save: + // save from memory out to a file + goto unimplemented; + +rseed: + { + short int value; + + //Get the pin number + expression_error = 0; + value = expression(); + if(expression_error) + goto qwhat; + + srand( value ); + goto run_next_statement; + } + +#ifdef ENABLE_TONES +tonestop: + noTone( kPiezoPin ); + goto run_next_statement; + +tonegen: + { + // TONE freq, duration + // if either are 0, tones turned off + short int freq; + short int duration; + + //Get the frequency + expression_error = 0; + freq = expression(); + if(expression_error) + goto qwhat; + + ignore_blanks(); + if (*txtpos != ',') + goto qwhat; + txtpos++; + ignore_blanks(); + + + //Get the duration + expression_error = 0; + duration = expression(); + if(expression_error) + goto qwhat; + + if( freq == 0 || duration == 0 ) + goto tonestop; + + tone( kPiezoPin, freq, duration ); + if( alsoWait ) { + delay( duration ); + alsoWait = false; + } + goto run_next_statement; + } +#endif /* ENABLE_TONES */ +} + +// returns 1 if the character is valid in a filename +static int isValidFnChar( char c ) +{ + if( c >= '0' && c <= '9' ) return 1; // number + if( c >= 'A' && c <= 'Z' ) return 1; // LETTER + if( c >= 'a' && c <= 'z' ) return 1; // letter (for completeness) + if( c == '_' ) return 1; + if( c == '+' ) return 1; + if( c == '.' ) return 1; + if( c == '~' ) return 1; // Window~1.txt + + return 0; +} + +unsigned char * filenameWord(void) +{ + // SDL - I wasn't sure if this functionality existed above, so I figured i'd put it here + unsigned char * ret = txtpos; + expression_error = 0; + + // make sure there are no quotes or spaces, search for valid characters + //while(*txtpos == SPACE || *txtpos == TAB || *txtpos == SQUOTE || *txtpos == DQUOTE ) txtpos++; + while( !isValidFnChar( *txtpos )) txtpos++; + ret = txtpos; + + if( *ret == '\0' ) { + expression_error = 1; + return ret; + } + + // now, find the next nonfnchar + txtpos++; + while( isValidFnChar( *txtpos )) txtpos++; + if( txtpos != ret ) *txtpos = '\0'; + + // set the error code if we've got no string + if( *ret == '\0' ) { + expression_error = 1; + } + + return ret; +} + +/***************************************************************************/ +static void line_terminator(void) +{ + outchar(NL); + outchar(CR); +} + +/***********************************************************/ +void setup() +{ +} + + +/***********************************************************/ +static unsigned char breakcheck(void) +{ +#ifdef __CONIO__ + if(kbhit()) + //return getch() == CTRLC; + return getc(0) == CTRLC; + else +#endif + return 0; +} +/***********************************************************/ +static int inchar() +{ + int v; + // otherwise. desktop! + // int got = getchar(); + int got = getc(0); + + // translation for desktop systems + if( got == LF ) got = CR; + + return got; +} + +/***********************************************************/ +/* +static void outchar(unsigned char c) +{ + if( inhibitOutput ) return; + + putchar(c); +} +*/ + + + + + +/* these are used in the .ino */ + +void outchar( char ch ) +{ + printf( "%c", ch ); +} + + +/* other helpers */ + +/* +int cmd_Files( void ) +{ + DIR * theDir; + + theDir = opendir( "." ); + if( !theDir ) return -2; + + struct dirent *theDirEnt = readdir( theDir ); + while( theDirEnt ) { + printf( " %s\n", theDirEnt->d_name ); + theDirEnt = readdir( theDir ); + } + closedir( theDir ); + + return 0; +} +*/ + + diff --git a/shell/xsh_editor.c b/shell/xsh_editor.c new file mode 100644 index 0000000..c6b5184 --- /dev/null +++ b/shell/xsh_editor.c @@ -0,0 +1,101 @@ +/* xsh_editor.c - xsh_editor */ + +#include +#include + +// #include "text_buffer.h" +#define NLINES 3 +#define LINE_LEN 24 + +//extern unsigned char program[NLINES*LINE_LEN]; + +/*------------------------------------------------------------------------ + * xhs_editor - text editor + *------------------------------------------------------------------------ + */ +shellcmd xsh_editor(int nargs, char *args[]) +{ + +/* + int32 i; + + if (nargs > 1) { + printf("%s", args[1]); + + for (i = 2; i < nargs; i++) { + printf(" %s", args[i]); + } + } + printf("\n"); +*/ + char buffer[NLINES*LINE_LEN]; + int page = 0; + int i = 0; + int j = 0; + int dev = 0; + int c; + int cursor = 0; + int line = 0; + + fprintf(dev, "\033[2J"); + fprintf(dev, "\033[H"); + fprintf(dev, "Text editor. page: %i\n", page); + + for (i=0; i LINE_LEN) { + cursor = 0; + line++; + printf("\n\r"); + } + break; + default: + break; + } + } + continue; + } + + printf("%c", c); + buffer[line*LINE_LEN+cursor] = c; + cursor++; + if (cursor > LINE_LEN) { + cursor = 0; + line++; + printf("\n\r"); + if (line > NLINES) { + // pasar_pagina(); + } + } + + } + + + // RAFA + return 0; +} diff --git a/shell/xsh_memstat.c b/shell/xsh_memstat.c index 15fe97d..d94093b 100644 --- a/shell/xsh_memstat.c +++ b/shell/xsh_memstat.c @@ -4,6 +4,10 @@ #include #include +// RAFA +#include + + static void printMemUse(void); static void printFreeList(void); @@ -14,34 +18,11 @@ static void printFreeList(void); shellcmd xsh_memstat(int nargs, char *args[]) { - /* For argument '--help', emit help about the 'memstat' command */ - -/* - if (nargs == 2 && strncmp(args[1], "--help", 7) == 0) { - printf("use: %s \n\n", args[0]); - printf("Description:\n"); - printf("\tDisplays the current memory use and prints the\n"); - printf("\tfree list.\n"); - printf("Options:\n"); - printf("\t--help\t\tdisplay this help and exit\n"); - return 0; - } -*/ - /* Check for valid number of arguments */ - -/* - if (nargs > 1) { - fprintf(stderr, "%s: too many arguments\n", args[0]); - fprintf(stderr, "Try '%s --help' for more information\n", - args[0]); - return 1; - } -*/ - - printMemUse(); +// printMemUse(); printFreeList(); + return 0; } @@ -53,7 +34,7 @@ shellcmd xsh_memstat(int nargs, char *args[]) */ static void printFreeList(void) { - char t[80]; +// char t[80]; struct memblk *block; /* Output a heading for the free list */ @@ -66,6 +47,23 @@ static void printFreeList(void) printf("0x%08x %d\n", block, (uint32) block->mlength); } + long i; + int j=0; + char * c = 0; + for (i=0; i<0x5bd ; i++) { + c = (char *)i; + if (j==0) { + serial_put_char('\n'); + serial_put_char('\r'); + printf ("0x%08x ", c); + } + j++; + if (j==16) j=0; + if (*c < 33) + serial_put_char('-'); + else + serial_put_char(*c); + } } extern void start(void); diff --git a/system/getstk.c b/system/getstk.c index 860416e..0bf0c8d 100644 --- a/system/getstk.c +++ b/system/getstk.c @@ -28,6 +28,8 @@ char *getstk( fitsprev = NULL; /* Just to avoid a compiler warning */ while (curr != NULL) { /* Scan entire list */ + // RAFA kprintf("c:%d ",curr->mlength); + // RAFA kprintf("n:%d ",nbytes); if (curr->mlength >= nbytes) { /* Record block address */ fits = curr; /* when request fits */ fitsprev = prev; diff --git a/system/initialize.c b/system/initialize.c index 402451d..11095a1 100644 --- a/system/initialize.c +++ b/system/initialize.c @@ -59,16 +59,15 @@ pid32 currpid; /* ID of currently executing process */ void nullprocess(void) { - kprintf("nullp\n"); +// kprintf("nullp\n"); // resume(create((void *)main, INITSTK, INITPRIO, "Main Process", 0, NULL)); // 200 ok and 400 ok // resume(create((void *)shell, 200, INITPRIO, "shell", 0, NULL)); - //resume(create((void *)shell, 256, INITPRIO, "shell", 0, NULL)); + resume(create((void *)shell, 360, INITPRIO, "shell", 0, NULL)); - resume(create((void *)test, 256, INITPRIO, "test", 0, NULL)); - //resume(create((void *)test, 400, INITPRIO, "test", 0, NULL)); +// resume(create((void *)test, 256, INITPRIO, "test", 0, NULL)); for(;;); } @@ -116,7 +115,13 @@ void nulluser() memptr = memptr->mnext) { free_mem += memptr->mlength; } - kprintf("\n\rFreeMEM:%d\n", free_mem); + kprintf("\nFreeMEM:%d\n", free_mem); + +/* + long * b = (long *) memlist.mnext; + *(b+32) = STACKMAGIC; + kprintf("S2:%X\n", *(b+32)); +*/ /* Initialize the Null process entry */ int pid = create((void *)nullprocess, INITSTK, 10, "Null process", 0, NULL); @@ -127,10 +132,9 @@ void nulluser() /* Enable interrupts */ enable(); - /* Initialize the real time clock */ - clkinit(); +// /* Initialize the real time clock */ +// clkinit(); - /* Start of nullprocess */ startup(0, prptr); @@ -147,6 +151,7 @@ void startup(int INIT, struct procent *p) { /* Should not be here, panic */ // resume(INIT); nullprocess(); + //resume(INIT); avr_kprintf(m6); panic(""); @@ -171,7 +176,7 @@ static void sysinit() platinit(); kprintf(CONSOLE_RESET); - kprintf("\n\r%s\n", VERSION); + avr_kprintf(m0); /* Initialize free memory list */ @@ -225,7 +230,6 @@ static void sysinit() clkinit(); - return; } diff --git a/system/kprintf.c b/system/kprintf.c index 63c3abf..ea9d3e6 100644 --- a/system/kprintf.c +++ b/system/kprintf.c @@ -50,9 +50,9 @@ extern void _doprnt(char *, va_list, int (*)(int)); syscall kprintf(char *fmt, ...) { va_list ap; - intmask mask; + //intmask mask; - mask = disable(); + //mask = disable(); char output[81]; char *c; @@ -68,6 +68,6 @@ syscall kprintf(char *fmt, ...) c++; }; - restore(mask); + //restore(mask); return OK; } diff --git a/system/platinit.c b/system/platinit.c index f678162..16c5c1f 100644 --- a/system/platinit.c +++ b/system/platinit.c @@ -26,7 +26,6 @@ void platinit(void) /* avr uart init */ serial_init(); - char f = serial_get_char(); /* Initialize the Interrupt Controller (evec.c) */ initintc(); diff --git a/system/serial_avr.c b/system/serial_avr.c index 471ed26..f0d7217 100644 --- a/system/serial_avr.c +++ b/system/serial_avr.c @@ -49,8 +49,8 @@ void serial_init() { puerto_serial->status_control_b = (unsigned char)(EN_RX_TX | (1<status_control_a) & (EN_TX))); - puerto_serial->data_es = 'R'; +// while(!((puerto_serial->status_control_a) & (EN_TX))); +// puerto_serial->data_es = 'R'; } @@ -58,8 +58,7 @@ void serial_put_char (char outputChar) { while(!((puerto_serial->status_control_a) & (EN_TX))); - - puerto_serial->data_es = outputChar; + puerto_serial->data_es = outputChar; } char value; @@ -79,7 +78,7 @@ char serial_get_char(void) { /* Wait for the next character to arrive. */ while(!((puerto_serial->status_control_a) & (EN_RX))); - return (puerto_serial->data_es); + return (puerto_serial->data_es); } void serial_put_str (char * mensaje) diff --git a/xinu-avr-port.txt b/xinu-avr-port.txt index 37c03cf..86c53ef 100644 --- a/xinu-avr-port.txt +++ b/xinu-avr-port.txt @@ -91,3 +91,8 @@ En el resched.c nuevo hay que poner la llamada a ctxswitch. BASIC: https://github.com/robinhedwards/ArduinoBASIC/blob/master/arduino_BASIC.ino +En +#define STACK_SIZE (sizeof(struct stack_for_frame)*2) +estaba en *5 en vez de *2 +Pero pisaba memoria de datos. Y con 2 no anda bien. +