scotws / taliforth2 Goto Github PK
View Code? Open in Web Editor NEWA Subroutine Threaded Code (STC) ANS-like Forth for the 65c02
License: Other
A Subroutine Threaded Code (STC) ANS-like Forth for the 65c02
License: Other
They're sort of a mess, and we're not using all of them anyway.
... at least it's failing the test suite there.
Also consider REPLACE, UNESCAPE, and SUBSTITUTE, though they all are monsters in size.
Exampe: WITHIN. Note we want to make sure we have test cases for these words before we code them in assembler. TO is another candidate.
:NONAME
is a core word that seems to be missing from Tali Forth 2 for some strange reason, see https://forth-standard.org/standard/core/ColonNONAME . It is used as part of their test suite.
The test for MOVE is failing because it is based on CMOVE and CMOVE>, which both propagate ("clobber") bytes depending on the direction of the move, whereas MOVE does not. See https://www.forth.com/starting-forth/10-input-output-operators/ for background on this. -- The code for MOVE must be completely rewritten.
There is a problem with constant/variable access when nc-limit is not 0. See http://forum.6502.org/viewtopic.php?f=9&t=2926&p=59192#p59178 for details.
: ggg 11 1 do i dup 8 = if leave then . loop ." Done" drop ;
`: hhh ( a b -- gcd ) ?dup if tuck mod recurse then ;
Which should produce 16
for 784 48 hhh
.
The test suite shows that u< is missing, and it is used in 15 of the tests. Implementing this would get the Undefined word errors down to just a handful.
{ 0 1 u< -> <true> } >u<< Undefined word
Tali Forth needs a built-in editor, but not one of the screen-based ones that uses too much space. The Unix editor ed should be the model for a line-based editor.
Currently, Tali Forth words are tested by typing or copy & pasting commands from the documentation into the terminal and comparing this to the output. This is time consuming and error-prone. What is needed is some script or program that will start Tali (through py65mon at least, through other programs like minicom if possible) and then send tests and automatically test responses.
It's easy and intuitive to take the TICK for a word, and at the moment we're converting everything with an extra INT>NAME, which is silly.
CMOVE> should propagate characters the same way CMOVE does (where it works). However, it currently fails. Consider reverting to Tali Forth 1 code, which is based more directly on Leventhal.
After doing a "git pull upstream master" I can't run Tali in py65mon:
$ py65mon -m 65c02 -r taliforth-py65mon.bin
Reset with new MPU 65C02
PC AC XR YR SP NV-BDIZC
65C02: 0000 00 00 00 ff 00110000
Wrote +32768 bytes from $8000 to $ffff
PC AC XR YR SP NV-BDIZC
65C02: 0000 00 00 00 ff 00110000
Tali Forth 2 default kernel for py65mon (18. Feb 2018)
PC AC XR YR SP NV-BDIZC
65C02: 75e1 78 78 00 ef 00110100
Py65 Monitor
PC AC XR YR SP NV-BDIZC
6502: 0000 00 00 00 ff 00110000
.
0BRANCH and BRANCH are holdovers from Tali Forth 1's basis on FIG Forth, most modern ANSI Forths use CS-PICK and CS-ROLL. It would probably make more sense to switch as well.
In working towards the goal of an automated test suite, I'm trying to get John Hayes' test software working. It uses your forth to test your forth. I'm off to a good start, but noticed that 2/ appears to be missing. Here is a bit from the automated test showing 2* passing and then 2/ failing:
0 constant 0s ok
0 invert constant 1s ok
{ 0s 2* -> 0s } ok
{ 1 2* -> 2 } ok
{ 4000 2* -> 8000 } ok
{ 1s 2* 1 xor -> 1s } ok
{ msb 2* -> 0s } ok
ok
{ 0s 2/ -> 0s } >/< Undefined word
{ 1 2/ -> 0 } >/< Undefined word
{ 4000 2/ -> 2000 } >/< Undefined word
{ 1s 2/ -> 1s } \ msb propogated >/< Undefined word
{ 1s 1 xor 2/ -> 1s } >/< Undefined word
{ msb 2/ msb and -> msb } >/< Undefined word
For reference, the word {
doesn't do anything (just looks nice), the word ->
saves a snapshot of the stack, and the word }
compares the current stack to the snapshot. You essentially just put {
, your test, then ->
and then the expected answer and then }
and if all is well you get ok
, but if there are problems you get an error message.
It's interesting that only the / part is undefined (eg. the 2 is missing), according to the error message.
Follow practice of Gforth to point out when an existing word was redefined
Possibly based on the code for testing -- send word / line of input with word to py65, starting the timer, and then stop it when we receive a result. Repeat x times and average. Would be very crude, but might enable at least comparisons of various code variants.
The size of the native words for the docs/WORDLIST.md
is currently taken from the header comments in native_words.asm
, which is asking for trouble. Instead, they should be automatically generated on the basis of the xt_word
and z_word
labels in docs/ophis_labelmap.txt
.
While poking around forth-standard.org looking at the whitespace issue, I noticed the last line of section 3.4.2 (Finding definition names) at http://forth-standard.org/standard/usage
After saying that forths can be case sensitive, it says:
A system shall be capable of finding the definition names defined by this standard when they are spelled with upper-case letters.
I see you already have a note on the fact that all of Tali's built-in words are lowercase in 4.2 of manual.pdf, and perhaps that is enough. I don't really have a preference, although I have had to lowercase a lot of existing forth code to get it to work on Tali.
See discussion at #46 -- this could be done as a make
file or as part of the Python testing script (preference). Other options to the test program should include a way to silence the output, rename the output file, add an acoustic single like a beep when testing is done.
See http://lars.nocrew.org/dpans/dpans6.htm#6.1.1345 for details on ENVIRONMENT? and http://lars.nocrew.org/dpans/dpans3.htm#3.2.6 for a list of what the results should be. This is a required ANSI core word. The Forth Programmer's Handbook, 3rd edition by Conklin and Rather discusses this on p. 120. -- This doesn't make much sense to add until the rest of the code is stable.
Use CTRL-P and CTRL-N (which should be the traditional Unix shell codes) to bring up at least the last input. This probably requires the ability to get multi-byte input(?)
If the number of bytes to disassemble doesn't exactly land at the end of an instruction (eg. it lands in the middle of a multi-byte instruction) then the disassembler doesn't stop.
( working correctly - your address might be different )
' disasm 2 disasm
86BB cpx.# 75
ok
( not stopping )
' disasm 3 disasm
86BB cpx.# 75
86BD bmi 03
86BF jmp B421
86C2 jsr 995B
86C5 rts
86C6 cpx.# 75
86C8 bmi 03
86CA jmp B421
86CD ldy.# 00
86CF sec
86D0 tya
86D1 sbc.zx 02
...
I have to reset my SBC hardware to get it to stop. I didn't wait to see if it would stop on wraparound.
We already have a disassembler, so we should go all the way.
While watching the test program run, I noticed a line reporting a stack underflow, but the test program didn't print one of the tester errors. The part of the python tester program that reports the results at the end should look for these lines as well.
Also, add test cases.
The \ word doesn't work when compiling a new word.
Perhaps it is being compiled? eg. not an immediate word?
A simple example:
: a \ ignore this
gives the result
>ignore< Undefined word
WITHIN currently has no test cases, and there are none included in the standard (see https://forth-standard.org/standard/core/WITHIN) -- it just states that their implementation : WITHIN ( test low high -- flag ) OVER - >R - R> U< ;
"works in all cases". Gforth (mirror at https://github.com/forthy42/gforth/blob/master/test/core.fs) also doesn't seem to test this. The problem is that the word gets tricky for signed and unsigned numbers, and it would be nice to do WITHIN in assembler because the JSR use lots of cycles for simple moves to and from the Return Stack.
The code
: aaa 100 10 do i dup 20 = if ." twenty " then . loop ; ok
aaa 10 11 12 13 14 15 16 17 18 19 IM
size (decimal): -10
000A 03 00 03 00 9C 07 1C F0 16 F0 00 00 00 00 10 00
001A 00 00 2A 07 2C 09 03 02 18 00 76 00 00 00 2C 09
(...)
fails horribly, though simpler variants are fine:
: aaa 100 10 do i 20 = if ." twenty " then loop ; ok
aaa twenty ok
This is only used in the few tests that test it.
{ 123 456 a-addr 2! a-addr 2@ -> 123 456 } >!< Undefined word
Bug found by testing suite, see line 841 pp: ge1 evaluate
does not produce "123" but "6038", and ge2 evaluate
produces "6063" instead of "124". ge3 evaluate
works, as do the compile-state words.
Note that 6038 is $1796, the location where the string from ge1 is saved, and 6063 is the location of the ge2 string. Testing the test code with Gforth gives the behavior expected in the test.
This bug seems to be messing up other parts of the test suite.
In docs/ch_developing.tex, starting on line 37 are instructions for cloning and installing Ophis. I believe the cd command on line 38 is incorrect. It currently says:
git clone https://github.com/michaelcmartin/Ophis
cd src
sudo python setup.py install
but on my Fedora system it needed to be:
git clone https://github.com/michaelcmartin/Ophis
cd Ophis/src
sudo python setup.py install
as the git clone command created an Ophis directory with the src directory inside of that.
Starting on line 42 are instructions for assembling Tali, however they reference an assemble.sh script that doesn't seem to be in the repository. I did find a Makefile, which seems to work fine. I believe this is just out of date, as I have seen you mention a Makefile somewhere else (might have been on 6502.org)
I'm going to try to get Tali running on my homebrew 65C02 SBC, so I'll let you know if I find anything else. So far, everything has been documented very well.
This causes it to "get behind" when collecting responses that have CR in them. Because it collects the echoed commands as well as the responses, this behaviour isn't immediately obvious unless you watch very carefully near the end of the tests. I believe this previously caused the last test or two to not be collected into the results. I do wonder if this might be part of the issue where you seem to be dropped to the debugger all of a sudden near the end of the tests - where you have all of the CRs in a single test word.
Some solutions might include:
Add enough blank lines at the end of the test program to allow it to catch up (one per CR used in the tests).
Have pexpect attempt to collect multiple lines, but it will have to time out to know there aren't any more. This may slow down testing significantly, but I need to do some more research on what the possibilities are here.
Please note that I'm redefining the word "testing" in a couple of these examples on purpose.
If I don't put CR into a word, I can put multiple strings into a work like so:
Type 'bye' to exit
: testing compiled
." string1:" compiled
." string2 :" compiled
." string3 :" compiled
; ok
ok
: testing2 compiled
." string3:" compiled
." string4: :" compiled
." string5 :" compiled
; ok
ok
: testing compiled
." string1:" compiled
." string2 :" compiled
." string3 :" compiled
; ok
ok
testing string1:string2 :string3 : ok
If I add some "CR"s in between each string, some weird things happen:
Type 'bye' to exit
: testing compiled
." string1:" cr compiled
." string2 :" cr compiled
." string3 :" cr compiled
; ok
ok
: testing2 compiled
." string3:" cr compiled
." string4: :" cr compiled
." string5 :" cr compiled
; ok
ok
: testing compiled
." string1:" cr compiled
." string2 :" cr compiled
." string3 :" cr compiled
; ok
ok
testing string1:
string2 :
string3:
string4: :
string5 :
ok
and if I fiddle with the lengths of the strings (with CRs), it has very odd behavior and sometimes crashes. I think this is the cause of the crashes you were seeing. Exactly how it crashes depends on the length of the string (I'm playing with the second string). Sometimes it does some weird things and then gives a Stack underflow - other times it crashes the simulator.
Type 'bye' to exit
: testing compiled
." string1:" cr compiled
." string2 :" cr compiled
." string3 :" cr compiled
; ok
testing string1:
string2 :
0156 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Stack underflow
After some playing around, I think I have a rather simple example, and it doesn't even have any CRs in it:
Type 'bye' to exit
: testing compiled
." string1string1string1string1string1string1string1string1" compiled
." string2string2string2string2string2string2string2" compiled
; ok
testing string1string1string1string1string1string1string1string10000
Stack underflow
: fff 11 1 do i dup 8 = if drop unloop exit then . loop ." Done" ;
Crashes after number print numbers 1-7
In the following code, when actual-depth has a value of 0, I'm expecting to see ACTUAL RESULT: { }
but instead I get only ACTUAL RESULT: {
and the closing curly brace doesn't print. The closing curly brace does print for actual-depth values 1 or more.
\ Added by SamCo 2018-05 to show actual results of previous test.
: show-results \ ( -- ) Print the previous test's actual results.
s" ACTUAL RESULT: { " type
actual-depth @ 0 ?do
actual-results
actual-depth @ i - 1- \ Print them in reverse order to match test.
cells + @ .
loop
s" }" type ;
Example output (when run with a test program that calls this word upon encountering an error):
{ 1 2 -> 3 4 } INCORRECT RESULT: { 1 2 -> 3 4 } ACTUAL RESULT: { 1 2 } ok
{ -> 3 4 } WRONG NUMBER OF RESULTS: { -> 3 4 } ACTUAL RESULT: { ok
A simple stand-alone test that can be run without the test program:
: stuff 0 ?do i . loop 12345 . ; ok
1 stuff 0 12345 ok
0 stuff ok
It's possible I'm making a Forth mistake or not fully understanding all of the words I am using, so if a correction is needed, it will also need to be applied to the pull request I recently made adding this code to the tester.
Found during a test for 2@, which doesn't appear to be in your set of words. When entering a number, an @ in the number is treated as the digit 9:
1@@f ok
. 199F ok
1@2@3 ok
. 19293 ok
@ by itself works as expected, but @2 becomes 92.
I've tested the following words (using the NAME from WORDLIST.md):
COUNT
D_MINUS
D_PLUS
D_TO_S
DABS
DEFER
DIGIT_QUESTION
Should I update the magical comment line in native_words.asm and then generate a pull request?
I've also been keeping a lot of expected responses vs actual responses. Would you like those put somewhere? I saw you had some of your test cases in docs/ch_tests.tex - should I add the test cases to that? My text file of tests/results is currently 160 lines long for testing just the above words. I'm currently copying/pasting directly into a minicom session to have my hardware run the test and then copying the results back into my file for a record.
Here's an example for COUNT. I tried not use use any words that weren't tested already, so some of this is a little brutish (eg. poking bytes directly into memory):
( COUNT )
( Helper definitions )
: makebuffer ( n -- ) ( -- a ) create allot ;
: addchar ( addr ch -- [addr+1] )
over c! 1+ ;
( Create a buffer to make a counted string in. )
256 makebuffer my_counted_string
( Put a small string there. )
my_counted_string
5 addchar ( Length of 5 )
72 addchar ( H )
101 addchar ( e )
108 addchar ( l )
108 addchar ( l )
111 addchar ( o )
drop ( drop the address )
( Testing COUNT )
my_counted_string count . my_counted_string - .
( expecting 5 1 )
( RESULTS: 5 1 )
( Put a pretend large string there )
255 my_counted_string c! ( adjust size of string )
my_counted_string count . my_counted_string - .
( expecting 255 1 )
( RESULTS: 255 1 )
( Put an empty string there )
0 my_counted_string c! ( adjust size of string )
my_counted_string count . my_counted_string - .
( expecting 0 1 )
( RESULTS: 0 1 )
UD/MOD is a non-standard word that has been sort of left over from FIG Forth days. Currently, it is only used in only one place, # (NUMBER_SIGN). Since it is non-standard, there are no tests available. The funny thing is that everybody seems to use UD/MOD though - Gforth, pForth, and AMForth have it internally.
... to distinguish them from the hand-tested ones: coded
is written, but not tested at all; tested
is tested by hand; auto
is tested by the test suite.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.