Small device with a pre-programmed microcontroller like a z8 programmed with code to drive a small LCD panel, scan some key switches, communicate on a serial port and read or write to an EEPROM. Any left over pins are available for general purpose IO. On power up, it tries to read and execute a byte code language like the CUMP Byte Code or BitScope Command Set from the serial port, if a device is connected or from the EEPROM if not.
Registers: 8 bit unless indicated
FLAGS
NUM stores numbers from the command text
SRC and DST reference one of the 125 8 bit registers or (high bit set) one of the available devices (LCD/Keys, Serial, EEPROM, IO). The default setting is LCD/Keys. The DST is set first, and the SRC/DST flag toggled so that SRC is loaded next at which point the current operation and comparison are performed. If SRC is not loaded (zero), NUM is the SRC. After each operation SRC is cleared. At the end of each line, SRC/DST and DST is cleared.
OP stores the operation to perform once we have a SRC (we should already have a DST) or when the line ends. Since there is only one SRC at a time, binary operations like addition always accumulate into DST. i.e. DST is the implied second source in binary operations. The default operation, when no other is specified, is copy. i.e. if only a DST, then a SRC are specified, the value of the SRC is simply written to the DST. OP is not cleared so that " can escape ".
The goal here is to get as close to a high level language, or at least a very understandable syntax, without including a compiler, and using the minimum resources possible to interpret the bytecodes. How little code can interpret something that at least looks like a HLL?
0-9 A-F nibble swap NUM, load hex digit into low nibble of NUM. Conversion from/to decimal is too much. : Copy operation, effectivly a noop. Not really needed, included only for readability. a-z set SRC or DST to register. a is register 0. b is register 4. z is 100. a:5 sets register 0 to 5. a:b copies register 4 to register 0. NUM is added to the register address first. 3a is the third byte after the start of a. Register 125 is 7Da or 19z (19h=25d, z=100, +25=125) SRC, DST, etc start at 5z. After SRC is loaded, SRC/DST is set and the next address is loaded to DST. @ Set operation to index. When SRC is loaded, replace with the value at that address and clear op. This sets the stage for another op and SRC. e.g. b@a sets the DST to the address of b plus the value of a. " (Quote) Text. Each following char is copied to the DST until the ending quote. If the operation was already " when a new starting " is seen, put a " to the dest then enter text mode. "Push ""START""" prints Push "START" + set operation to add. a+b adds b to a. a:b+5 sets a to b then adds 5. if there is no SRC, the NUM is used as the SRC. a+1 increments a. maybe if last op was +, load 1 into NUM. a++ increments a. - set operation to add, pre operation to negate or not, and set carry & set operation to bitwise AND. a-&b ANDs a with NOT b. a&-b subtracts b from a (& is ignored) | set operation to bitwise OR = set compare type to equal < set compare type to less than > set compare type to greater than ~ Not. Toggle true/false flag. Use with greater less and equal. ; e.g. a<b~ will set the true flag if a is greater than or equal to b. ; >~ is less than or equal too. <~ is greater than or equal too. =~ is not equal ? skip to the next line if the comparison fails (not TRUE) K (Local) set SRC or DST to the LCD/Keys. The actual value stored is 0x88 NUM is used to select the position? T (Terminal) set SRC or DST to the Serial port. 0x89 P (Port) set SRC or DST to IO pins. The value stored will be 0x80-0x87 NUM before P selects the port if more than 1 available. stored in the lower 3 bits of the value. NUM after P selects the pin. These are 1 to 8, not 0 to 7 so that 0 can indicate the entire port. I (In) set the Port or Port pin in DST to an Input O (Out) set the Port or Port pin in DST to an Output H (High) set the Port pin(s) in DST to high. e.g. P1H sets port 0, pin 1 (the second pin) high. L (Low) set the Port pin(s) in DST to low. e.g. 2PL sets all pins on port 2 low. When the pin is an input, H and L set or clear TRUE based on the pins value. J (Jump) move NUM lines
Case '"' //Start putting out text while temp = SerialGet // after the '"' temp=='"'? // but two quotes LCDPutChr temp // puts out a quote chr temp = SerialGet // after the '"' - - - - Until temp '"' //Until the next quote
"Push ""START"""
While true
- CMD = GetCMD
- Select CMD
- - Case '"' //A After a '"'
- - - temp = GetCMD //B start reading text
- - - temp=='"'? //C but two quotes
- - - - PutDST temp //D puts out a quote chr
- - - While temp NOT '"' //E Until the next quote
- - - - PutDST temp //F put out chrs
- - - - temp = GetCMD //G and read more text
Notice how something like "Push ""START""" gets executed: The first quote gets us to line //B above where temp gets loaded with "P". //C fails and //D is skipped. Since temp is no longer a quote, we are now inside the While that started at //E and we put the character out at //F and get another at //G repeatedly until we reach the second quote. At that point, we fall out of the loop, all the way back to the outer loop where we get another command
Comments:
Let's think about the indexing of one array by another and how that can be supported with minimal effort. Lower case letters cause their address to be loaded to DST or SRC, not their value. If you want to addr an element of 'a' by an offset in 'i' then the value in 'i' must be added to the addr of 'a' . There are two ways to do this: Make the var code translate any existing value in SRC or DST from address to value before adding in the next var addr. Or: xlate the new var adr to a value before adding it to DST or SRC only when they are not empty.
Make lower case letters add their base address to what ever is in NUM before loading SRC or DST. This moves the offset before the variable so 5a is the same as b.
One of the goals of this design is to have a syntax that is as close to a high level language as possible without a compiler. To that end, should we add a character for the default copy operation? e.g. a=b+1 is totally clear, but = is also needed for comparisons and really, no operation needs to be specified there at all: ab+1 does the same thing. a:b+1 is a possibility.
Is it useful to detect and use the case of more than one operation being specified without a SRC between them? E.g. ++ for increment. &- for AND NOT (rather than -&). In some cases, the change requires a lot of work: a<=b is not as easy as it looks since a>b~ does the same job without requiring a new, combined operator. We can "fake" ++ by loading NUM with 1 when we see + and the last op was + as well. Is it worth it?
If NUM is not zero when performing an operation, repeat the operation, after incrementing SRC and DST, then decrement NUM and loop until NUM is zero. So a:b3 copies register 4,5,6, and 7 to registers 0,1,2, and 3. If multibyte values are taken in LSB first (little endian) order, then a:b3+c3 actually moves a LONG at b to a then adds c as a LONG.
Something needs to address the EEPROM when instructions are being pulled from there. That is our program counter (PC). If we used one of the registers, we could affect the flow of the program with more than the skips. Use "p"?
It would be nice to come up with a clever way to save the current PC when jumping to a new location in the program. This would allow more complex flow control like call, parameter passing, and return to be written in the language itself. One possibility is to follow the 1802 model.
In an 1802, there is no specific program counter register. Instead, there are a set of general purpose registers R(x), any one of which can be used as the program counter called R(P). Another register (P) pointed to the register that would be used as the PC. There are also no call instruction. To call, you load another general purpose register wth the address of the subroutine, then set P (the PC pointer) to that register. The subroutine then executes and returns by setting P back to the original R.
For commonly used routines, you dedicate a register to the subroutine, and initiallize it to start, not at the beginning, but a few instructions into the sub. The sub, when it is ready to return, jumps back to it's very start, where P (the PC Pointer) is set back to the main PC, leaving the PC of the subroutine back at the entry point, ready for the next call.
Although the 1802 had a dedicated stack and jump instruction, I see no reason why these are really necessary: To jump, you just load the register being used as the PC with a new address. To form a call/return stack, you can use the next GP register to point to the subroutine and the subroutine returns by decrementing P. (the real 1802 didn't have an inc or dec P instruction!).
The real trick is making that work in a way that looks more like standard subroutine and function calls in a higher level language.
LCD: Try to include space for a 15 pin header with an extra IO line on pin 15 to support e.g. 4x16 displays with a second Enable line.
Ports
P0.0 P0.1 P0.2 P2.0 P2.1 P2.2 P2.3 P2.4 LCD.D4 P2.5 LCD.D5 P2.6 LCD.D6 P2.7 LCD.D7 P3.0 AN1 P3.1 AN2 P3.2 AO1
There is a case that is currently unused: When DST has not be set (zero) and an operation or number is found in the command text. Can we think of a use for that? 9=a? is better programming practice than a=9? so maybe NUM should be the dest when DST is not loaded?
See also:
| file: /techref/idea/minimalcontroller.htm, 11KB, , updated: 2008/7/26 14:37, local time: 2008/11/20 15:02,
38.103.63.59:LOG IN
|
| ©2008 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? Please DO link to this page! Digg it! <A HREF="http://piclist.org/techref/idea/minimalcontroller.htm"> Minimal Controller Idea</A> |
| Did you find what you needed? |
|
o List host: MIT, Site host massmind.org, Top posters @20081120 Apptech, Jinx, Xiaofan Chen, olin piclist, Vitaliy, William \Chops\ Westfield, Tamas Rudnai, Alan B. Pearce, JonnyMac, Gerhard Fiedler, * Page Editors: James Newton, David Cary, and YOU! * Roman Black of Black Robotics donates from sales of Linistep stepper controller kits. * Ashley Roll of Digital Nemesis donates from sales of RCL-1 RS232 to TTL converters. * Monthly Subscribers: Shultz Electronics, Timothy Weber, on-going support is MOST appreciated! * Contributors: Richard Seriani, Sr. |
|
.