A project to implement a console using the Mbed using VGA for video output and a PS/2 keyboard for the input. The eventual goal is to also include tools for managing SD cards, and a semi-self-hosting programming environment.
Dependencies: PS2_MbedConsole fastlib SDFileSystem vga640x480g_mbedconsole lightvm mbed
MbedConsole is a cool little project to have a self-contained computer all on an Mbed. So far it has VGA and PS/2 support and can stand alone without a computer powering it. Next planned features are SD card support and a lightweight programmable VM complete with a file editor and self-hosted assembler.
You can view additional details about it at http://earlz.net/tags/mbedconsole
plEarlz.cpp@6:a4dff59ef214, 2012-09-21 (annotated)
- Committer:
- earlz
- Date:
- Fri Sep 21 04:53:45 2012 +0000
- Revision:
- 6:a4dff59ef214
- Parent:
- 5:367397a82ddc
- Child:
- 7:2ac6752d47d2
Switched a virtual machine instead of trying to interpret directly. This is much easier for development, and should amazingly make it both faster and use less memory :D
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
earlz | 6:a4dff59ef214 | 1 | #include "mbedconsole.h" |
earlz | 6:a4dff59ef214 | 2 | #include "plEarlz.h" |
earlz | 6:a4dff59ef214 | 3 | #include <stdarg.h> |
earlz | 6:a4dff59ef214 | 4 | #include <stdint.h> |
earlz | 6:a4dff59ef214 | 5 | //Basically a non-conforming take on Forth, btw. |
earlz | 6:a4dff59ef214 | 6 | |
earlz | 6:a4dff59ef214 | 7 | inline int internal_captureline(void* pBuffer, char const* pFormatString, ...) |
earlz | 6:a4dff59ef214 | 8 | { |
earlz | 6:a4dff59ef214 | 9 | char* pStringEnd = (char*)pBuffer + strlen((char*)pBuffer); |
earlz | 6:a4dff59ef214 | 10 | va_list valist; |
earlz | 6:a4dff59ef214 | 11 | |
earlz | 6:a4dff59ef214 | 12 | va_start(valist, pFormatString); |
earlz | 6:a4dff59ef214 | 13 | |
earlz | 6:a4dff59ef214 | 14 | return vsprintf(pStringEnd, pFormatString, valist); |
earlz | 6:a4dff59ef214 | 15 | } |
earlz | 6:a4dff59ef214 | 16 | void printheapstats() |
earlz | 6:a4dff59ef214 | 17 | { |
earlz | 6:a4dff59ef214 | 18 | char buffer[256]; |
earlz | 6:a4dff59ef214 | 19 | __heapstats(internal_captureline, buffer); |
earlz | 6:a4dff59ef214 | 20 | vputs("Memory info: "); |
earlz | 6:a4dff59ef214 | 21 | vputs(buffer); |
earlz | 6:a4dff59ef214 | 22 | } |
earlz | 6:a4dff59ef214 | 23 | |
earlz | 6:a4dff59ef214 | 24 | |
earlz | 6:a4dff59ef214 | 25 | |
earlz | 6:a4dff59ef214 | 26 | |
earlz | 6:a4dff59ef214 | 27 | |
earlz | 6:a4dff59ef214 | 28 | ErrorType pl_error=None; |
earlz | 6:a4dff59ef214 | 29 | |
earlz | 6:a4dff59ef214 | 30 | |
earlz | 6:a4dff59ef214 | 31 | enum WordType |
earlz | 6:a4dff59ef214 | 32 | { |
earlz | 6:a4dff59ef214 | 33 | Unknown, |
earlz | 6:a4dff59ef214 | 34 | Number, |
earlz | 6:a4dff59ef214 | 35 | Word, |
earlz | 6:a4dff59ef214 | 36 | Quote |
earlz | 6:a4dff59ef214 | 37 | }; |
earlz | 6:a4dff59ef214 | 38 | |
earlz | 6:a4dff59ef214 | 39 | |
earlz | 6:a4dff59ef214 | 40 | uint8_t *pl_codeblock; |
earlz | 6:a4dff59ef214 | 41 | int pl_blockpos; |
earlz | 6:a4dff59ef214 | 42 | int pl_blocksize; |
earlz | 6:a4dff59ef214 | 43 | |
earlz | 6:a4dff59ef214 | 44 | void push_opcode_byte(uint8_t val) |
earlz | 6:a4dff59ef214 | 45 | { |
earlz | 6:a4dff59ef214 | 46 | if(pl_blockpos>=pl_blocksize) |
earlz | 6:a4dff59ef214 | 47 | { |
earlz | 6:a4dff59ef214 | 48 | void* tmp=realloc(pl_codeblock, pl_blocksize+CODEBLOCKSTEP); |
earlz | 6:a4dff59ef214 | 49 | if(tmp==NULL) |
earlz | 6:a4dff59ef214 | 50 | { |
earlz | 6:a4dff59ef214 | 51 | vputs("Out of memory!!"); |
earlz | 6:a4dff59ef214 | 52 | return; |
earlz | 6:a4dff59ef214 | 53 | } |
earlz | 6:a4dff59ef214 | 54 | pl_codeblock=(uint8_t*)tmp; |
earlz | 6:a4dff59ef214 | 55 | pl_blocksize+=CODEBLOCKSTEP; |
earlz | 6:a4dff59ef214 | 56 | } |
earlz | 6:a4dff59ef214 | 57 | pl_codeblock[pl_blockpos]=val; |
earlz | 6:a4dff59ef214 | 58 | pl_blockpos++; |
earlz | 6:a4dff59ef214 | 59 | } |
earlz | 6:a4dff59ef214 | 60 | void push_opcode(Opcode val) |
earlz | 6:a4dff59ef214 | 61 | { |
earlz | 6:a4dff59ef214 | 62 | if(pl_blockpos>=pl_blocksize) |
earlz | 6:a4dff59ef214 | 63 | { |
earlz | 6:a4dff59ef214 | 64 | void* tmp=realloc(pl_codeblock, pl_blocksize+CODEBLOCKSTEP); |
earlz | 6:a4dff59ef214 | 65 | if(tmp==NULL) |
earlz | 6:a4dff59ef214 | 66 | { |
earlz | 6:a4dff59ef214 | 67 | vputs("Out of memory!!"); |
earlz | 6:a4dff59ef214 | 68 | return; |
earlz | 6:a4dff59ef214 | 69 | } |
earlz | 6:a4dff59ef214 | 70 | pl_codeblock=(uint8_t*)tmp; |
earlz | 6:a4dff59ef214 | 71 | pl_blocksize+=CODEBLOCKSTEP; |
earlz | 6:a4dff59ef214 | 72 | } |
earlz | 6:a4dff59ef214 | 73 | pl_codeblock[pl_blockpos]=(uint8_t)val; |
earlz | 6:a4dff59ef214 | 74 | pl_blockpos++; |
earlz | 6:a4dff59ef214 | 75 | } |
earlz | 6:a4dff59ef214 | 76 | void push_opcode_word(uint16_t val) |
earlz | 6:a4dff59ef214 | 77 | { |
earlz | 6:a4dff59ef214 | 78 | if(pl_blockpos>=pl_blocksize) |
earlz | 6:a4dff59ef214 | 79 | { |
earlz | 6:a4dff59ef214 | 80 | void* tmp=realloc(pl_codeblock, pl_blocksize+CODEBLOCKSTEP); |
earlz | 6:a4dff59ef214 | 81 | if(tmp==NULL) |
earlz | 6:a4dff59ef214 | 82 | { |
earlz | 6:a4dff59ef214 | 83 | vputs("Out of memory!!"); |
earlz | 6:a4dff59ef214 | 84 | return; |
earlz | 6:a4dff59ef214 | 85 | } |
earlz | 6:a4dff59ef214 | 86 | pl_codeblock=(uint8_t*)tmp; |
earlz | 6:a4dff59ef214 | 87 | pl_blocksize+=CODEBLOCKSTEP; |
earlz | 6:a4dff59ef214 | 88 | } |
earlz | 6:a4dff59ef214 | 89 | *(uint16_t*)&pl_codeblock[pl_blockpos]=val; |
earlz | 6:a4dff59ef214 | 90 | pl_blockpos+=2; |
earlz | 6:a4dff59ef214 | 91 | } |
earlz | 6:a4dff59ef214 | 92 | void push_opcode_dword(uint32_t val) |
earlz | 6:a4dff59ef214 | 93 | { |
earlz | 6:a4dff59ef214 | 94 | if(pl_blockpos>=pl_blocksize) |
earlz | 6:a4dff59ef214 | 95 | { |
earlz | 6:a4dff59ef214 | 96 | void* tmp=realloc(pl_codeblock, pl_blocksize+CODEBLOCKSTEP); |
earlz | 6:a4dff59ef214 | 97 | if(tmp==NULL) |
earlz | 6:a4dff59ef214 | 98 | { |
earlz | 6:a4dff59ef214 | 99 | vputs("Out of memory!!"); |
earlz | 6:a4dff59ef214 | 100 | return; |
earlz | 6:a4dff59ef214 | 101 | } |
earlz | 6:a4dff59ef214 | 102 | pl_codeblock=(uint8_t*)tmp; |
earlz | 6:a4dff59ef214 | 103 | pl_blocksize+=CODEBLOCKSTEP; |
earlz | 6:a4dff59ef214 | 104 | } |
earlz | 6:a4dff59ef214 | 105 | *(uint32_t*)&pl_codeblock[pl_blockpos]=val; |
earlz | 6:a4dff59ef214 | 106 | pl_blockpos+=4; |
earlz | 6:a4dff59ef214 | 107 | } |
earlz | 6:a4dff59ef214 | 108 | void new_codeblock(bool freeit) |
earlz | 6:a4dff59ef214 | 109 | { |
earlz | 6:a4dff59ef214 | 110 | if(freeit) |
earlz | 6:a4dff59ef214 | 111 | { |
earlz | 6:a4dff59ef214 | 112 | free(pl_codeblock); |
earlz | 6:a4dff59ef214 | 113 | } |
earlz | 6:a4dff59ef214 | 114 | pl_codeblock=(uint8_t*)malloc(CODEBLOCKSTEP); |
earlz | 6:a4dff59ef214 | 115 | pl_blockpos=0; |
earlz | 6:a4dff59ef214 | 116 | pl_blocksize=CODEBLOCKSTEP; |
earlz | 6:a4dff59ef214 | 117 | } |
earlz | 6:a4dff59ef214 | 118 | int execute_codeblock() |
earlz | 6:a4dff59ef214 | 119 | { |
earlz | 6:a4dff59ef214 | 120 | return forth_execute(pl_codeblock, pl_blockpos); |
earlz | 6:a4dff59ef214 | 121 | } |
earlz | 6:a4dff59ef214 | 122 | |
earlz | 6:a4dff59ef214 | 123 | int compile_word(char *word, WordType type) //returns 0 for success, 1 for ending word found, -1 for error |
earlz | 6:a4dff59ef214 | 124 | { |
earlz | 6:a4dff59ef214 | 125 | if(type==Number){ |
earlz | 6:a4dff59ef214 | 126 | push_opcode(Push); |
earlz | 6:a4dff59ef214 | 127 | push_opcode_dword(atoi(word)); |
earlz | 6:a4dff59ef214 | 128 | }else{ |
earlz | 6:a4dff59ef214 | 129 | if(word[1]==0) //check the quick builtins first |
earlz | 6:a4dff59ef214 | 130 | { |
earlz | 6:a4dff59ef214 | 131 | if(word[0]=='.'){ |
earlz | 6:a4dff59ef214 | 132 | push_opcode(CallInt); |
earlz | 6:a4dff59ef214 | 133 | push_opcode_dword((uint32_t)&bi_print); |
earlz | 6:a4dff59ef214 | 134 | }else if(word[0]==';') |
earlz | 6:a4dff59ef214 | 135 | { |
earlz | 6:a4dff59ef214 | 136 | //execute! |
earlz | 6:a4dff59ef214 | 137 | return 1; |
earlz | 6:a4dff59ef214 | 138 | }else if(word[0]=='+'){ |
earlz | 6:a4dff59ef214 | 139 | push_opcode(Add); |
earlz | 6:a4dff59ef214 | 140 | }else if(word[0]=='/'){ |
earlz | 6:a4dff59ef214 | 141 | push_opcode(Div); |
earlz | 6:a4dff59ef214 | 142 | }else if(word[0]=='-'){ |
earlz | 6:a4dff59ef214 | 143 | push_opcode(Sub); |
earlz | 6:a4dff59ef214 | 144 | }else if(word[0]=='!'){ |
earlz | 6:a4dff59ef214 | 145 | //pl_push(pl_pop()-pl_pop()); |
earlz | 6:a4dff59ef214 | 146 | }else if(word[0]=='%'){ |
earlz | 6:a4dff59ef214 | 147 | push_opcode(Mod); |
earlz | 6:a4dff59ef214 | 148 | }else if(word[0]=='*'){ |
earlz | 6:a4dff59ef214 | 149 | push_opcode(Mul); |
earlz | 6:a4dff59ef214 | 150 | }else if(word[0]=='!'){ |
earlz | 6:a4dff59ef214 | 151 | int tmp=pl_pop(); |
earlz | 6:a4dff59ef214 | 152 | int* tmp2=(int*)pl_pop(); |
earlz | 6:a4dff59ef214 | 153 | *tmp2=tmp; |
earlz | 6:a4dff59ef214 | 154 | }else if(word[0]=='?'){ |
earlz | 6:a4dff59ef214 | 155 | pl_push(*(int*)pl_pop()); |
earlz | 6:a4dff59ef214 | 156 | }else if(word[0]=='='){ |
earlz | 6:a4dff59ef214 | 157 | pl_push(pl_pop() == pl_pop()); |
earlz | 6:a4dff59ef214 | 158 | }else if(word[0]=='`'){ |
earlz | 6:a4dff59ef214 | 159 | pl_push(pl_pop()>0); |
earlz | 6:a4dff59ef214 | 160 | }else if(word[0]=='$'){ |
earlz | 6:a4dff59ef214 | 161 | //print string (address on stack |
earlz | 6:a4dff59ef214 | 162 | } |
earlz | 6:a4dff59ef214 | 163 | |
earlz | 6:a4dff59ef214 | 164 | }else if(strlcmp("if", word, 3)==0){ |
earlz | 6:a4dff59ef214 | 165 | |
earlz | 6:a4dff59ef214 | 166 | |
earlz | 6:a4dff59ef214 | 167 | }else{ |
earlz | 6:a4dff59ef214 | 168 | vputs("I don't know the word "); |
earlz | 6:a4dff59ef214 | 169 | vputs(word); |
earlz | 6:a4dff59ef214 | 170 | vputs("\n"); |
earlz | 6:a4dff59ef214 | 171 | } |
earlz | 6:a4dff59ef214 | 172 | } |
earlz | 6:a4dff59ef214 | 173 | return 0; |
earlz | 6:a4dff59ef214 | 174 | } |
earlz | 6:a4dff59ef214 | 175 | |
earlz | 6:a4dff59ef214 | 176 | |
earlz | 6:a4dff59ef214 | 177 | |
earlz | 6:a4dff59ef214 | 178 | void parse_line(char *line) |
earlz | 6:a4dff59ef214 | 179 | { |
earlz | 6:a4dff59ef214 | 180 | int len=strlen(line); |
earlz | 6:a4dff59ef214 | 181 | char word[16]; |
earlz | 6:a4dff59ef214 | 182 | word[0]=0; |
earlz | 6:a4dff59ef214 | 183 | int wordpos=0; |
earlz | 6:a4dff59ef214 | 184 | WordType type=Unknown; |
earlz | 6:a4dff59ef214 | 185 | for(int i=0;i<len;i++) |
earlz | 6:a4dff59ef214 | 186 | { |
earlz | 6:a4dff59ef214 | 187 | char c=line[i]; |
earlz | 6:a4dff59ef214 | 188 | if(is_whitespace(c) || c=='\\') |
earlz | 6:a4dff59ef214 | 189 | { |
earlz | 6:a4dff59ef214 | 190 | if(word[0]!=0) |
earlz | 6:a4dff59ef214 | 191 | { |
earlz | 6:a4dff59ef214 | 192 | word[wordpos]=0; |
earlz | 6:a4dff59ef214 | 193 | |
earlz | 6:a4dff59ef214 | 194 | int tmp=compile_word(word,type); |
earlz | 6:a4dff59ef214 | 195 | if(tmp==1) |
earlz | 6:a4dff59ef214 | 196 | { |
earlz | 6:a4dff59ef214 | 197 | execute_codeblock(); |
earlz | 6:a4dff59ef214 | 198 | new_codeblock(true); |
earlz | 6:a4dff59ef214 | 199 | } |
earlz | 6:a4dff59ef214 | 200 | word[0]=0; |
earlz | 6:a4dff59ef214 | 201 | } |
earlz | 6:a4dff59ef214 | 202 | wordpos=0; |
earlz | 6:a4dff59ef214 | 203 | type=Unknown; |
earlz | 6:a4dff59ef214 | 204 | if(c=='\\'){ |
earlz | 6:a4dff59ef214 | 205 | return; //rest is a comment |
earlz | 6:a4dff59ef214 | 206 | } |
earlz | 6:a4dff59ef214 | 207 | }else if(is_numeric(c)){ |
earlz | 6:a4dff59ef214 | 208 | if(type==Unknown){ |
earlz | 6:a4dff59ef214 | 209 | type=Number; |
earlz | 6:a4dff59ef214 | 210 | } |
earlz | 6:a4dff59ef214 | 211 | word[wordpos]=c; |
earlz | 6:a4dff59ef214 | 212 | wordpos++; |
earlz | 6:a4dff59ef214 | 213 | }else if(is_quote(c)){ |
earlz | 6:a4dff59ef214 | 214 | vputs("This isn't supported yet foo!"); |
earlz | 6:a4dff59ef214 | 215 | return; |
earlz | 6:a4dff59ef214 | 216 | }else{ |
earlz | 6:a4dff59ef214 | 217 | if(type==Number){ |
earlz | 6:a4dff59ef214 | 218 | vputs("Syntax Error! Unexpected symbol in the middle of a number"); |
earlz | 6:a4dff59ef214 | 219 | return; |
earlz | 6:a4dff59ef214 | 220 | } |
earlz | 6:a4dff59ef214 | 221 | type=Word; |
earlz | 6:a4dff59ef214 | 222 | word[wordpos]=c; |
earlz | 6:a4dff59ef214 | 223 | wordpos++; |
earlz | 6:a4dff59ef214 | 224 | } |
earlz | 6:a4dff59ef214 | 225 | } |
earlz | 6:a4dff59ef214 | 226 | } |
earlz | 6:a4dff59ef214 | 227 | |
earlz | 6:a4dff59ef214 | 228 | |
earlz | 6:a4dff59ef214 | 229 | void tester() |
earlz | 6:a4dff59ef214 | 230 | { |
earlz | 6:a4dff59ef214 | 231 | printf("foo!"); |
earlz | 6:a4dff59ef214 | 232 | } |
earlz | 6:a4dff59ef214 | 233 | |
earlz | 6:a4dff59ef214 | 234 | int pl_shell() |
earlz | 6:a4dff59ef214 | 235 | { |
earlz | 6:a4dff59ef214 | 236 | vputs(">>plEarlz -- A forth-ish shell<<\n"); |
earlz | 6:a4dff59ef214 | 237 | printheapstats(); |
earlz | 6:a4dff59ef214 | 238 | vputs("\n"); |
earlz | 6:a4dff59ef214 | 239 | char *line=(char*)malloc(MAXLINELENGTH); |
earlz | 6:a4dff59ef214 | 240 | sprintf(line, "Stack Size: %i; Max Recursion Level %i; Loaded WORDs: %i", MAXSTACK, MAXCALLS, 0); |
earlz | 6:a4dff59ef214 | 241 | vputs(line); |
earlz | 6:a4dff59ef214 | 242 | sprintf(line, "Max line length: %i\n", MAXLINELENGTH); |
earlz | 6:a4dff59ef214 | 243 | vputs(line); |
earlz | 6:a4dff59ef214 | 244 | new_codeblock(false); |
earlz | 6:a4dff59ef214 | 245 | char *tmp=(char*)malloc(32); //for constructing words/elements |
earlz | 6:a4dff59ef214 | 246 | while(1) |
earlz | 6:a4dff59ef214 | 247 | { |
earlz | 6:a4dff59ef214 | 248 | vputs("cmd> "); |
earlz | 6:a4dff59ef214 | 249 | vgetsl(line, MAXLINELENGTH); |
earlz | 6:a4dff59ef214 | 250 | line[MAXLINELENGTH-1]=0; |
earlz | 6:a4dff59ef214 | 251 | int len=strlen(line); |
earlz | 6:a4dff59ef214 | 252 | line[len]='\n'; |
earlz | 6:a4dff59ef214 | 253 | line[len+1]=0; |
earlz | 6:a4dff59ef214 | 254 | parse_line(line); |
earlz | 6:a4dff59ef214 | 255 | |
earlz | 6:a4dff59ef214 | 256 | } |
earlz | 6:a4dff59ef214 | 257 | free(line); |
earlz | 6:a4dff59ef214 | 258 | free(tmp); |
earlz | 6:a4dff59ef214 | 259 | return 0; |
earlz | 6:a4dff59ef214 | 260 | } |
earlz | 6:a4dff59ef214 | 261 | |
earlz | 6:a4dff59ef214 | 262 |