I just checked in a new version of newterm. I took me longer then I first expected. i had some (major) trouble with the editor, but I think it is working now (and a bit more error free :). The changes are:
- Added basic support for: PWM and setting AUXPIN mode
- global command enters basic mode (s)
- remove global command (S) (superseded with list in basicmode)
- added list, run, new, load, save, format, exit to new basicmode.
- added eeprom support to basicmode (needs an i2c eeprom on the icsp interface)
(enables run, save and format commands)
- simple edditing of basicprogram
- fixed liveIO mode
- fixed bug in raw2wire interface (clkl and clkh)
- left out jtag to save some bytes
to enter basic mode:
HiZ> i
Bus Pirate v3
Firmware v4.2 (newterm-basic) Bootloader v4.1
DEVID:0x0447 REVID:0x3043 (B5)
http://dangerousprototypes.com
HiZ> s
HiZ(BASIC)>
the following commands can be used:
run runs current program
list list current program
new clear current program
format format eeprom
save x save current program to slot x
load x load slot x into program memory
debug hexdump program memory
debug is only present to debug the editor, because i still suspect there are errors in it.. To demonstrate the editor:
HiZ(BASIC)> new
Ready.
HiZ(BASIC)> 100 let c=10
Ready.
HiZ(BASIC)> 110 print c
Ready.
HiZ(BASIC)> 120 end
Ready.
HiZ(BASIC)> list
100 LET C=10
110 PRINT C
120 END
65535 END
20 bytes.
Ready.
HiZ(BASIC)> 110 print "C=";c
Ready.
HiZ(BASIC)> list
100 LET C=10
110 PRINT "C=";C
120 END
65535 END
25 bytes.
Ready.
HiZ(BASIC)>
Note that the new command adds the line 65535 END (by design). Also everyhting is converted to uppercase by design.
The current tokens (should be) recognized by both the editor and interpretter:
#define STAT_LET "LET"
#define STAT_IF "IF"
#define STAT_THEN "THEN"
#define STAT_ELSE "ELSE"
#define STAT_GOTO "GOTO"
#define STAT_GOSUB "GOSUB"
#define STAT_RETURN "RETURN"
#define STAT_REM "REM"
#define STAT_PRINT "PRINT"
#define STAT_INPUT "INPUT"
#define STAT_FOR "FOR"
#define STAT_TO "TO"
#define STAT_NEXT "NEXT"
#define STAT_END "END"
#define STAT_READ "READ"
#define STAT_DATA "DATA"
#define STAT_START "START"
#define STAT_STARTR "STARTR"
#define STAT_STOP "STOP"
#define STAT_STOPR "STOPR"
#define STAT_SEND "SEND"
#define STAT_RECEIVE "RECEIVE"
#define STAT_CLK "CLK"
#define STAT_DAT "DAT"
#define STAT_BITREAD "BITREAD"
#define STAT_ADC "ADC"
#define STAT_AUX "AUX"
#define STAT_PSU "PSU"
#define STAT_PULLUP "PULLUP"
#define STAT_DELAY "DELAY"
#define STAT_AUXPIN "AUXPIN"
#define STAT_FREQ "FREQ"
#define STAT_DUTY "DUTY"
If you want to connect an eeprom use this pinout:
ICSP EEPROM (24xx256)
PGC 4
PGD 5
GND 1,2,3,4
VCC 8
If an eeprom is connected you can FORMAT it and load or save your programs. Currently the eeprom is divided in slots, but i want eventually make a very simple filesystem (not my main concarn atm). Only a 24lc256 is supported, but it's fairly easy to adopt it.
I left out the jtag because i needed the space and I think (!) noone use it.
Liveio should be compatible with the old versions (i misinterpret the way it worked) and also a small error in the glue logic of raw2write is solved.
Please give it a try and provide me with the feedback.
I'm having problems with stack overflows (I believe):
PIC(BASIC)> new
Ready.
PIC(BASIC)> list
65535 END
3 bytes.
Ready.
PIC(BASIC)> 100 REM DUMP PIC16F628a
Ready.
PIC(BASIC)> 110 for A=1 to 0x2000
Ready.
PIC(BASIC)> start
Syntax error
Ready.
PIC(BASIC)> START
Syntax error
Ready.
PIC(BASIC)> 120 START
Ready.
PIC(BASIC)> 130 SEND 4
Ready.
PIC(BASIC)> 140 STOP
Ready.
PIC(BASIC)> 150 PRINT RECEIVE ;",";
Ready.
PIC(BASIC)> START
Syntax error
Ready.
PIC(BASIC)> SEND 6
Syntax error
Ready.
PIC(BASIC)> 160 START
Ready.
PIC(BASIC)> 170 SEND 6
Ready.
PIC(BASIC)> 180 STOP
Ready.
PIC(BASIC)> 190 NEXT A
Ready.
PIC(BASIC)> 200 END
Ready.
PIC(BASIC)> RUN
Error(3) @line:110 @pgmspace:29
Ready.
PIC(BASIC)> 110 FOR A=1 TO 0X2000
Ready.
PIC(BASIC)> RUN
Error(3) @line:110 @pgmspace:29
Ready.
PIC(BASIC)> 110 FOR A=1 TO 8192
Bus Pirate v3
Firmware v4.2 (newterm-basic) Bootloader v4.4
DEVID:0x0447 REVID:0x3042 (B4)
http://dangerousprototypes.com
HiZ>
Ok, I will look into it. I believe it has to do with the input ringbuffer, as I noticed it before and it occurs after adding a line of 14. but it is a hard error to debug I'm afraid.
BTW basic only supports decimals.
This bug is fixed. The cullprit was the part that converts the basicline to uppercase (it wrote prolly in the stackspace).
Happy scripting! Please share them in this topic.
It was time for some documentation (the hell of every programmer ;)) This isn't intended as a guide in learning how to program. General programming knowledge is assumed. Be aware that only basic checking is done and there are no warnings printed to the terminal (except those intended by the program with print statements). The editor is very rudimentair and does not check if the syntax is right. The language is loosy based on basic.
You need to take care of entering the correct mode and set it up (things like speed, Hiz, etc.).
Basic is entered by 's' from the buspirate commandline (command is only available on newterm http://dangerousprototypes.com/forum/in ... opic=291.0 (http://dangerousprototypes.com/forum/index.php?topic=291.0)):
HiZ> i
Bus Pirate v3
Firmware v5.0-pre1 (r351) Bootloader v4.1
CFG1:0xF9DF CFG2:0x3F7F
DEVID:0x0447 REVID:0x3043 (B5)
http://dangerousprototypes.com
HiZ> s
HiZ(BASIC)>
First clear the memory with the NEW command (very important!)
HiZ(BASIC)> new
Ready.
HiZ(BASIC)>
From the basic commandline programs can be entered. The basicinterpreter uses linenumbers followed by statements. After this the program can be listed by the command 'LIST'
HiZ(BASIC)> list
100 REM BASICDEMO
110 PRINT "HELLO WORLD!"
120 PRINT "HELLO AGAIN"
65535 END
52 bytes.
Ready.
HiZ(BASIC)>
You can also run it with the command run:
HiZ(BASIC)> run
HELLO WORLD!
HELLO AGAIN
Ready.
HiZ(BASIC)>
VariablesA..Z (26) variables are possible. The variable are internally 16bit signed
General basic commandsLETassigns a variable. Another variable, constants or functions that returns a value (e.g. RECEIVE)
10 LET A=B+1
IF {ifstat} THEN {truestat} ELSE {falsestat}Evaluate the {ifstat} if it evaluate to a value that is not zero {truestat} get executed otherwise {falsestat}.
10 IF A=1 THEN GOTO 100 ELSE PRINT "A IS NOT 1"
GOTO {line}jumps to line {line}, without remembering where it came from (see also GOSUB)
10 GOTO 100
20 PRINT "line 20"
100 PRINT "line 100"
line 20 doesn't get executed
GOSUB {line} and RETURNjumps to line {line}, executes from there till a RETURN and return to the line after the GOSUB.
10 GOSUB 1000
20 PRINT "line 20"
30 END
1000 PRINT "line 1000"
1010 RETURN
Stack is 10 levels deep, so 10 nested gosubs are possible.
REM {text}Puts a remark into the code, but gets skipped.
10 REM A WONDERFULL PROGRAM
Don't use REM between DATA statements!
PRINT {text} Prints {text} to the terminal. Variable and statement can be mixed and are seperated with a ';'. A ';' at the end suppresses a newline.
10 PRINT "A = ";A
20 PRINT "RECEIVED: ";RECEIVE
30 PRINT "B = ";
40 PRINT B
INPUT {question};{var}Ask {question} and put the answer the user gave into {var}
10 INPUT "A = ";A
FOR {var}={minvalue} TO {maxvalue} {stats} NEXTAssigns value {minvalue} to variable {var}, executes statements {stats} until NEXT is encountered. Variable {var} wil be increased by one, {stats} is again executed, until {var} has the value {maxvalue}.
10 FOR A=1 TO 10
20 PRINT "A = ";A
30 NEXT A
for/nexts can be nested 4 deep.
READ {var}DATA {val1}, {val2}, .. {val1}, {val2},Read a value into variable {var}. The values are stored in DATA statements.
10 READ A
20 PRINT "A = ";A
30 READ A
40 PRINT "A = ";A
1000 DATA 10,20
Buspirate specific basic commandsNote: Not all commands are supported with every mode!
STARTSame as the buspirate '[' command
10 START
STOPSame as the buspirate ']' command
10 STOP
STARTRSame as the buspirate '{' command
10 STARTR
STOPRSame as the buspirate '}' command
10 STOPR
SEND {val/var}Sends a value {val} or variable {var} over the bus.
10 SEND 10
20 SEND A
[code]
Some protocols send/receive at the same time. This is also possible:
[code]
10 LET A=SEND 100
20 PRINT "SEND 100 GOT ";A
[/code]
[b]RECEIVE[/b]
Receives data from the bus. With some protocols it returns value >255 to signal busstates (like no data, got ACK, etc), other protocols are 16 bit (like pic).
[code]
10 LET A=RECEIVE
20 PRINT "A = ";A
[/code]
[b]CLK {val}[/b]
Controls the CLK line, its behaviour depends on val; 0=low, 1=high, 2=pulse.
[code]
10 CLK 2
[/code]
[b]DAT {val}[/b]
Controls the DAT line, its behaviour depends on val; 0=low, 1=high.
[code]
10 DAT 0
[/code]
DAT value can also be read:
[code]
10 LET A=DAT
20 PRINT "A = ";A
[/code]
[b]BITREAD[/b]
Same as the buspirate '!' command.
[code]
10 LET A=BITREAD
20 PRINT "A = ";A
[/code]
[b]ADC[/b]
Reads the ADC. Value returned is 10bits (no conversion!).
[code]
10 LET A=ADC
20 PRINT "A = ";A
[/code]
[b]AUX {val}[/b]
Controls the AUX line, its behaviour depends on val; 0=low, 1=high.
[code]
10 AUX 1
[/code]
AUX value can also be read:
[code]
10 LET A=AUX
20 PRINT "A = ";A
[/code]
[b]AUXPIN {val}[/b]
Controls which pin is controlled by the AUX statement; 0=AUX; 1=CS
[code]
10 AUXPIN 1
[/code]
[b]PSU {val}[/b]
Controls the onboard voltage regulators; 0=off, 1=on
[code]
10 PSU 1
[/code]
[b]PULLUP {val}[/b]
Controls the onboard pullup resistors; 0=off, 1=on
[code]
10 PULLUP 0
[/code]
[b]DELAY {var}[/b]
Delays {var} ms
[code]
10 DELAY 100
[/code]
[b]FREQ {var}[/b]
[b]DUTY {var}[/b]
Controls the onboard PWM generator. Frequency of 0 disables it. (same limits apply as regular PWM command ('g'))
[code]
10 freq 100
20 duty 25
Note this i just the first version, so please provide some feedback about error or misspelling.
I really have to say that your coding style is ugly :) (talking about the cosmetics)
I'm glad you have removed that huge table for memory conservation.
More sophisticated expression evaluator is wanted. I hate the idea that A+B*C is in your basic (A+B)*C and not A+(B*C). Also support for parenthesizes () would be nice (If you want i can provide the "evaluator" from my project, that needs very little change to work with your code).
Why aren't you debugging this code on your computer ? I see no HW dependent stuff (other than the peripheral stuff) that would stop you from doing so, it would save you many flash cycles, many hours of flashing, and also other benefits :)
I'm sorry that that my style isn't cosmetic right for you. This is the way I thought it and this is the way for me to see if I forgot a ) or a } (assuming this is what you mean).
It is also my first go to write an interpreter and I know it can use an optimizing here and there. I'd like to integrate your "evaluator" into the scripting engine, parenthesis was something that was lacking.
Is there a syntax for invoking macros from your language? I am doing alot with 1-wire, which auto sets addresses as macros. It would be handy to invoke them in a program. I am used to slightly more powerful macro languages, so I am trying to figure out how to get more power of expression.
Macro's aren't supported in the scripting engine. The idea behind is that the scripting engine can offers the same functionality as the macro systeem. It can be incorperated though (although some macros need one or more argument or wait for user input which makes it cumbersome).
Okay I see, hmm this is difficult with things like 1 wire mode that side-affect the macros. I am not sure how to rationalize the two here. Do you have any ideas?
Another question/confusion on my part how do you read a bit or byte from a bus and assign it to a variable? Also is there a way to invoke built-in functions? C does not have reflection, which is one of the reasons I hate having to go back and work there, but without it you need compile time list of all the functions you want to call. So for example I was thinking about trying to implement 1-wire here, and I don't really see how to do some of the things are are built into the mode and address macros. As far as I can tell the address macros are going to be needed. I guess the question is how to invoke mode specific functions in your language?
I'm sorry I hadn't responded to this post yet. I was away from a normal computer when you posted it and responding with a cellphone is a bit cumbersome (esp. when quoting)
[quote author="rhyde"]
Another question/confusion on my part how do you read a bit or byte from a bus and assign it to a variable?
[/quote]
100 LET A=RECEIVE
[quote author="rhyde"]
Also is there a way to invoke built-in functions? C does not have reflection, which is one of the reasons I hate having to go back and work there, but without it you need compile time list of all the functions you want to call.
[/quote]
100 AUXPIN 1
[quote author="rhyde"]
As far as I can tell the address macros are going to be needed.
[/quote]
I included the macro keyword for you. However it only makes sense with 1wire library. Syntax:
100 MACRO 1
I'll update the newterm topic and svn later tonight.
[quote author="rhyde"]
I guess the question is how to invoke mode specific functions in your language?
[/quote]
I posted a quickreference guide in this topic (about 5 topic up). All the mode specific commands are below the line buspirate specific commands. All you have to do is enter the right mode (and set it up), enter the scripting language with 's' enter your program (use first new!!) and let your imagination go..
NB.: I didn't implement robots evaluator yet, but when I find the time I'll integrate it. (sorry robots!)
Thanks for the updates I willl try them out.
Here is a small patch to extend the expression evaluator:
1. It is now possible to cascade more than one operator: 10 LET A=1+2+3
Up to now you could only use one operator on each expression, e.g.: 10 LET A=1+2
Before:HiZ(BASIC)> 10 LET A=1+2+3
Ready.
HiZ(BASIC)> 20 PRINT A
Ready.
HiZ(BASIC)> run
Error(2) @line:10 @pgmspace:9
NowHiZ(BASIC)> 10 LET A=1+2+3
Ready.
HiZ(BASIC)> 20 PRINT A
Ready.
HiZ(BASIC)> run
6
Ready.
2. It is possible to use + - * / with the normal mult/div precedence over plus/minus.
3. It is now possible to use parenthesis to change operator precedence.
HiZ(BASIC)> 10 LET A=1+2*3*(4+5)
Ready.
HiZ(BASIC)> 20 PRINT A
Ready.
HiZ(BASIC)> run
55
Ready.
Since I have no commit access to the SVN, here is the patch.
Hi udif - great patch, thank you. Would you like commit access? Just PM me a google code registered email address.
thanks. It was on the list for 5.1 but i kept it postphoning.
Please note there are probably 2 more issues not handled yet:
1. I haven't figured yet how you handle error cases in your parser, as it seems there is no way to return an error code from assign() and getnumvar().
2. In my patch, getnumvar() is calling assign() when maybe I should have called evaluate() so that the following can be done:
LET A=(B>C)
I haven't written BASIC in 25 years, so I don't remember if this is legal or not (it certainly legal in C and other languages I'm used to).
One more issue I saw is that you have to type NEW on the first time you go into the script mode, otherwise it locks up on the first command entered.
Why is NEW not done automatically?
[quote author="udif"]
A few other things I noted:
http://code.google.com/p/the-bus-pirate ... areCompile (http://code.google.com/p/the-bus-pirate/wiki/FirmwareCompile)
The Wiki page says you need to export the result into an Intel Hex file, but in reality running Make or Build All with the default bus pirate project file from the trunk does this for you.
In fact, when I tried to follow the instructions above and generated a hex file I got a file starting at 0 that was rejected because it tried to overwrite the boot sector.
One more thing: the current project includes no optimizations, and uses 94% of the code space. Turning size optimization (-Os) reduced this to ~67% !!!.
I haven't tried running the result though.
The major reason I got into the Bus Pirate in the first place is JTAG.
I wanted a cheap and open source platform for JTAG experimenting. It now seems that JTAG is disabled on v5. Why was that done, and how do I enable it again on my builds?
busPirateCode.c now have a structure with member functions for each mode, and I see no wuch table for JTAG.
I want to incorporate the following code, which on a 2nd thought probably needs a new separate mode, and not any existing JTAG:
http://hackaday.com/2007/09/29/automati ... detection/ (http://hackaday.com/2007/09/29/automatic-jtag-pinout-detection/)
thanks,
Udi
[/quote]
This is from a PM, I wanted to answer it here so Sjaak can comment too.
The wiki is really outdated, it refers to the v2 bootloader branch, not the new v4 bootloader. Writing at 0 should be fine, it's the last page and configuration words that aren't allowed by the ds30loader app and bootloader self-protection. You can also do a file->export and change the end range to 0xa7fe and it should work (I still do this for some reason, even though it's not needed).
I believe Sjaak has tried an -O level or two. I haven't even tried because I'm such a sloppy coder that I assume there's no way the compiler is going to optimize things right, Sjaak's code is much cleaner with much more attention paid to variable types, etc, but a huge amount is still written by me :)
The v5 branch is a complete revamp of v4. The JTAG library was not ported to v5 because we didn't know anyone used it, there is new OpenOCD JTAG support, and we are quickly running out of space. It would have to be ported from teh v4 style to v5 style, which means breaking it up into discrete functions and assigning them to a commands in the core.c file. JTAG should also be ported to the central bitbang library to save space, it currently uses it's own software pin routines. We had a brief conversion about it here:
Basically, the JTAG library uses a really ugly state machine to track your way through the JTAG states and do stuff like clock out the last databit of a byte while doing the TMS transition, which is difficult to do in raw3wire or SPI libraries.
I'm not exactly sure how to integrate the statemachine tracker in the JTAG library into the newterm.
The JTAG detector looks interesting. It would be nice to add it to a revamped JTAG library.
Sorry, that JTAG conversation link is here:
http://dangerousprototypes.com/forum/in ... 35#msg5635 (http://dangerousprototypes.com/forum/index.php?topic=617.msg5635#msg5635)
I tried optimize (-o1) but the binary won't work as expected. I'm afraid it will cost a lot of time to get it ok to optimize.
GCC optimize for microncontrollers with seperate code and data memory requires strict use of variables, and I believe gcc can't cope easy with with seperate code and data memory (assumption). You need to keep track of a variable is dirty or reused and use the keyword volatile to avoid being cached. I had in the past (about 5 years ago) lots of problems with turning optimalization on after writing programs for an embedded system. This experience is a bit old so it could be not true (anymore).
We are trying to get a new hw revision with more memory out, so optimizing isn't a very big issue. There are several ways to make it work on the old platform.
Using the .hex directly (from the ouput instead of exporting) will not work on the pirateloader on linux (it can't cope with lowercase (yet?))
Error handling is done by the stop var, which is not global ( more or less assume the evaluate does work always (evaluate() consumes what it understands and leave the pc there, the
evaluate() consumes what it understands and leave the pc there. If there is an error it will be a syntax error.
let a=(b>c) isn;t valid I guess (At least i made it invalid ;) )
NEW isn't automatically done so the program stays in memory after quitting the scripting language, and initialising the array globally would eat another 1k of code space. I struggled a bit how to get it right but it is a bit unpolished ;) Perhaps a proper check in the lineadder function would do the trick.
I commited my changes (r386), plus a new fix that allows relational operators ("<", ">", etc.) to be a part of an expression.
I cross checked this with some BASIC manuals that seems to confirm this is the required behavior.
However, one change I didn't implement yet, was that at least in commodore BASIC, the return value of the relational operators was 0 for false and -1 for true, while BP uses '1' for true.
http://www.devili.iki.fi/Computers/Commodore/C64/Programmers_Reference/Chapter_1/page_012.html (http://http://www.devili.iki.fi/Computers/Commodore/C64/Programmers_Reference/Chapter_1/page_012.html)
Thanks udif, here's a updated nightly with your fix and a few others:
http://the-bus-pirate.googlecode.com/sv ... e-v5.1.hex (http://the-bus-pirate.googlecode.com/svn/trunk/firmware/v5-nightly/BPv3&v2go/BPv3-Firmware-v5.1.hex)
I didn't mean to kill the JTAG discussion :) If you want it, but all means I want to put it back in. Have you used it in the past? Do you have an opinion about how it worked, how it could be improved? What abilities do you want the most?
Commodore BASIC! Still alive. It says Microsoft Corporation during initialization.
I haven't used JTAG before, but I consider it most valuable. That is, if it's able to program and debug ARM uC's (or even a FPGA).
That is, if it's able to program and debug ARM uC's (or even a FPGA).
The terminal JTAG mode is mostly for very low level JTAG debugging - reading the scan chain, pushing a couple bytes in and out of the JTAG interface. The OpenOCD JTAG support is a full-featured JTAG programmer/debugger.
Maybe we can add the low-level JTAG stuff to raw3wire - JTAG scan chain, the JTAG pin detection that udif mentioned?
I have another feature request :) 1-16bit binary entry, or configurable bit-length in the rawwire libraries. For example entering 0p111 would only send a partial byte (3 high bits), and maybe a macro to set the word length to non-8bit words. I'll probably work it a little this week. My newbin port hit a snag because the only way I could figure out how to do it is make a 32 function prototype for all the possible commands and then use it like the newterm, it's unwieldy, this would be a nice break.
Script mode does not work for me :S why ?
HiZ>s
Syntax error at char 1
HiZ>i
Bus Pirate v3.5
Firmware v6.1 r1676 Bootloader v4.4
DEVID:0x0447 REVID:0x3046 (24FJ64GA002 B8)
http://dangerousprototypes.com (http://dangerousprototypes.com)
Hi stdjmax,
script mode was removed in v6.1 due to space issues and would have to be back in v6.2.
Actually it is back in the last firmware release in the SVN, v6.3 r2012.
The latest version is the one that you find here: http://tinyurl.com/p99ktlr (http://tinyurl.com/p99ktlr)
Please pay attention to the fact although the script mode is come back working, there may be other weird things due to bugs.
Regards,
sre71