6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sun Nov 24, 2024 9:30 pm

All times are UTC




Post new topic Reply to topic  [ 24 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: eForth
PostPosted: Sun Dec 18, 2011 9:20 pm 
Offline
User avatar

Joined: Thu Mar 11, 2004 7:42 am
Posts: 362
As a side project, I've been experimenting with porting eForth to the 6502 family, including the 65org16. (eForth is designed to be easily ported to different processors.) I've got versions working for the 6502, 65C02, 65C816 as well as a 65C816/65org16 hybrid (i.e. it runs on the 65C816 but can be quickly ported to the 65org16 -- I've only tried this one on the 65C816; the non-hybrid 65C816 version takes advantage of 65C816-specific instructions and addressing modes.) I also have STC versions of all the above working as well.

Bill Muench (note Bill Muench, not Bill Mensch), author of eForth, has graciously given his blessing to put these versions on the web. There's still a couple of things left to fix, test, and clean up, but I'm planning to have the two hybrid versions up in a couple of days.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Sun Dec 18, 2011 9:58 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
Excellent! Should be relatively straightforward to try that porting using the py65-based 65Org16 emulator - I'll give it a go if no-one else gets there first, but it would be great Bruce if we could recruit you into the active set of 65Org16 interested parties!

Cheers
Ed


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Fri Dec 23, 2011 9:26 pm 
Offline
User avatar

Joined: Thu Mar 11, 2004 7:42 am
Posts: 362
The 65C816-65org16 hybrid version can be found here:

http://www.lowkey.comuf.com/

The only version that links (for me, anyway) was the 65C816 ITC version. There's nothing really to link (there's only one section), so I got around this by whipping up a short but fake XML parser which turns the .obj file into an output format.

It's something you can experiment with, though the 65xx-specific documentation is pretty sparse at this point (most of the eForth words are described in the ANS spec). But feel free to ask questions or make suggestions for things you'd like to see documented (or clarified).

I originally intended to keep the assembly as generic as possible so as not to restrict it to a single assembler, but right now it's dev65 only with a bunch of macros. I'd like to move towards generic assembly in the future though.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed Dec 28, 2011 8:18 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
Hi Bruce
great - got it built and loaded in the emulator. It writes the banner but then goes off into the wilds. Any ideas about how to debug? It appears to be indulging in self-modifying code, which makes it a bit harder.

(Edit: removed unnecessary change to .byte $AC )

(Edit: Bruce's site presently offline, so see here for an archive.)

Here's the result of running:
Code:
$ PYTHONPATH=. python ./py65/monitor.py -m 65Org16 -l efhybi01.bin
Reset with new MPU 65Org16
Wrote +8930 bytes from $00000000 to $000022e1

Py65 Monitor

          PC      AC   XR   YR   SP   NV---------BDIZC
65Org16: 00000000 0000 0000 0000 ffff 0000000000110000
.goto 1000

eForth 65org16 ITC 0.1
Copyright 1989-1999 Bill Muench All rights reserved.
Run terminated at stopcode, last two instructions were:
$0000feb9  feb0            ???
$0000febb  0000            BRK

          PC      AC   XR   YR   SP   NV---------BDIZC
65Org16: 0000febb feb7 feb6 feb6 0001 1000000000110000
.


I wonder if in fact it's interpreting some data as program, instead of interpreting an empty program and giving me a prompt? There are nearly 180 JMPs following the last character written. Here are the first and last few:
Code:
$00001003  0085 f001       STA $f001
$000012a0  004c 1068 0000  JMP $NEXT1
$00001072  004c 1065 0000  JMP $EXIT1
$00001072  004c 1065 0000  JMP $EXIT1
$00001072  004c 1075 0000  JMP $LIST1
$0000107b  004c 1068 0000  JMP $NEXT1
$00001072  004c 1075 0000  JMP $LIST1
$0000107b  004c 1068 0000  JMP $NEXT1
[snip]
$00001072  004c 110e 0000  JMP $0000110e
$00001115  004c 1068 0000  JMP $NEXT1
$00001072  004c 117d 0000  JMP $0000117d
$00001180  004c 1068 0000  JMP $NEXT1
$00001072  004c 1133 0000  JMP $00001133
$0000113d  004c 1068 0000  JMP $NEXT1
$00001072  004c 1065 0000  JMP $EXIT1
$00001072  004c feb5 0000  JMP $0000feb5
$0000feb7  ff00            ???

(These are not consecutive instructions, just the JMPs, as an indication that the interpreter is busy doing something complicated. In fact about 900 instructions go by between the last writechar and the last JMP.)

(This could be a good case study for adding some tracing and debug capability to the py65 emulator.)

Any tips appreciated. I've built the 65816 version, so I might be able to run that up in an emulator and compare traces.

Cheers
Ed


Last edited by BigEd on Tue Nov 03, 2015 3:56 pm, edited 1 time in total.

Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Fri Dec 30, 2011 8:54 pm 
Offline
User avatar

Joined: Thu Mar 11, 2004 7:42 am
Posts: 362
There is one thing I forgot about: RP@ (RPAT) and RP! (RPSTO) push the (lower 16 bits) of the actual address on the return stack pointer (the S register). Hence the TSX-INX in the former, and the DEX-TXS in the latter (since the top of the 65xx stack is 1,S rather than 0,S). However, on the 65org16, the stack is on "page" 1 rather than page 0. Thus the first ! in ACTIVATE (which activates a new task and stores on the return stack in preparation) should be 1 L! instead. I have corrected this and uploaded it at the link above. However, there's probably still something else wrong as well, since ACTIVATE isn't used unless you type it yourself, and obviously it's crashing before you can type things.

Most likely, the (cooperative) multitasker isn't quite right. That's the part I modified (in ITC) and hence the most likely thing to fail. PAUSE is the word which switches tasks. Until you create and activate more tasks (and of course you can't do that until you can start typing) there's only one task, so it will switch back to itself and keep going. The switching part is a bit tricky and I screwed this up more than once trying to get it to work.

To test this, in PAUSE (PAUS), insert .byte EXITT after JLIST. This, in effect, disables the multitasker since it will never switch. Then, you can see if you're able to type things like

Code:
1 2 + .


and get the expected result (3 and an ok prompt). You could also put a breakpoint (or output something) in your INPUT routine to see if you got there.

The fact that you got the startup message is good news since a lot of things have to work right for that to happen.

Forth doesn't interpret an "empty program". The code that waits for a keypress, displays it, acts on it, and so on is itself a Forth program.

Assuming the $FF00 (end of memory address) in the ETIB .equ is unchanged

  • $FEB0-$FEFF is the input buffer (i.e. >= ETIB )
  • $FE70-$FEAF is the forth data stack (i.e. < ESP)
  • $FE30-$FE6F is the forth return stack (i.e. < ERP)
  • $FE2A-$FE2F is the user area (i.e. < EUP)

The input buffer is where characters are stored, like pretty much every other line-oriented input buffer ever.

The X register is used to index the forth data stack; it should always be between $FE71 and $FEB0 inclusive (and will usually be closer the $FEB0, since the stack builds downward in memory)

The S register (65org16 stack pointer) is used to index the forth return stack and should always be between $FE30 and $FE6F (remember 1,S is the top of the stack), and usually near $FE6F since the the 65xx hardware stack builds downward.

The user area is:

  • $FE2F ($FE30-1) FOLLOWER should be the address of STATUS ($FE2E)
  • $FE2E ($FE30-2) STATUS should be the address of UWAKE
  • $FE2D ($FE30-3) TOS is the saved value of data stack pointer, not written until you switch tasks with PAUSE
  • $FE2C ($FE30-4) TID should be the value of address of SUP1
  • $FE2B ($FE30-5) TF is not written until an exception is thrown (e.g. trying to execute a non-existent word)
  • $FE2A ($FE30-6) U1 is unused

The self-modifiying code isn't as bad as it looks (it's unlikely the problem is there). A self-modifying LDY abs is being used as a replacement for the non-existent LDY (zp) instruction. The self-modifying JMP is a replacement for the common 65xx PHA-RTS trick, but with JMP we don't have to adjust the address by 1. BYE exits forth (and thus restores the stack pointer) so the immediate data of LDX is self-modified.

Cells on the forth data stack (and the forth return stack) are 16 bits wide. Traditionally, ITC forth looks like this:

Code:
      .word OVER
      .word PLUS
      .word SWAP


I went down a little more unorthodox path. Most forth programs/applications will easily fit in 64k, so the upper 16 bits will be the same. Hence we can use:

Code:
      .byte OVER
      .byte PLUS
      .byte SWAP


since "bytes" are 16 bits wide. This is why indirect addressing isn't used anywhere -- addresses are 16 bits wide, rather than 32 bits wide (except L! and L@ which access the entire 32-bit address space, and hence use 32-bit addresses).

IMO, the most helpful things to output for debugging are the data stack pointer (the X register), the top of the data stack, the return stack pointer (the S register), the top of the return stack, the IP variable, and the user area.

Code:
DEBUG .byte DBUG1
DBUG1 jsr outcrlf

      txa          ;data stack pointer
      jsr outhex
      jsr outspace

      lda 0,x      ;top of data stack
      jsr outhex
      jsr outspace

      txa
      tsx          ;return stack pointer
      pha
      txa
      jsr outhex
      jsr outspace
      pla          ;restore x reg
      tax

      pla          ;top of return stack
      pha          ;put it back
      jsr outhex
      jsr outspace

      lda IP       ;IP
      jsr outhex
      jsr outspace

      ldy #5       ;user area
DBUG2 lda EUP-6,Y
      jsr outhex
      dey
      bpl DBUG2

      brk          ;or use JMP NEXT1


where outhex outputs the 16-bit value in the accumulator, and outcrlf and outspace are obvious.

If you insert

Code:
      .byte DEBUG


before the J 1,QUIT (in COLD) you should see that the X register is $FEB0, the S register is $FE6F (both data and return stacks should be empty) IP is the address of J 1,QUIT and the top of the data and return stacks are "don't care". If you move the .byte DEBUG into PAUSE so I can see each step (i.e. after the JLIST then after J 0,RPAT, etc.) that should give me enough information to determine where things are going wrong.

You could also move the output stuff into the NEXT routine. That will spew a lot of data (probably way too much), so you might want the ability to turn it on and off, e.g.

Code:
DEBUG_FLAG:
      .byte $FFFF
DEBUG_OUT_ON:
      .byte DOO1
DOO1  LSR DEBUG_FLAG
      JMP NEXT1
NEXT1:
      BIT DEBUG_FLAG
      BMI NEXTSKIP
      ; output debug info here (you could JSR to a routine which outputs
      ; debug info but remember that the S register will be off by 2 then)
NEXTSKIP:
      ; the real NEXT1 work continues here


Then you'd just insert .byte DEBUG_OUT_ON after, say the JLIST in PAUSE and you get the startup message (without a bunch of debug info for something that already works), then it will start spewing debug info at what is most likely the problem spot.

Also, one thing I did was put the debugging code at $0800 to keep the addresses from moving around much. You might want to do this with any extra initialization code rather than putting it at the beginning (and thus shifting all the addresses around). Alternatively, you could insert it after HERE0. One nice thing about having debug code at $800 is that its location was the same no matter what I changed or corrected.

Note: all the code snippets in this post are untested.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Fri Dec 30, 2011 9:06 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
Thanks for all the extra info!

I got the 816 version running - or at least, started - in Samuel's kestrel emulator. It prints the banner and accepts input, but does nothing with it other than echoing it back. I think there's a line-ending problem, because if I feed in a carriage return
echo -e '1 2 + .\r' | ./run65816 ...
then I get a bunch of NUL characters out - which is to say, I get a response, although still not the expected one.

So, the 816 version isn't yet working either, for me, but I may get somewhere by comparing the two and by using the information you've given.

Cheers
Ed


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed Jan 04, 2012 2:56 am 
Offline
User avatar

Joined: Thu Mar 11, 2004 7:42 am
Posts: 362
I found a couple of bugs that pertain to the 65org16 versions (.word instead of the W macro, and ! had a pair of INXs instead of the INXX macro). The INX vs. INXX could explain the issue you're seeing with the 65org16 version. As usual, uploaded at the link above.

The 65C816 troubles puzzle me. Do your INPUT, OUTPT, and INIIO routines clobber the X register? The OUTPT routine may be returning characters correctly (so echoing would work), but if X gets overwritten they won't be stored in the buffer correctly (so executing commands won't work). It shouldn't be necessary to preserve Y, but it wouldn't hurt to do so. Other possibilities off the top of my head:

  • It should enter with the m and x flags clear; you should return with them clear also.
  • Likewise for the d flag.
  • Are the Direct, DBR, and PBR registers all $0000 (i.e. is it running entirely in bank 0)?
  • Are you getting into emulation mode inadvertently?


You might also consider outputing the full 16-bit accumulator value in hex rather than (or in addition to) a character. Obviously this will spew a lot for the welcome message and when you're typing. The upper 8 bits can be disregarded when outputting characters, of course, but see the full 16-bits is sometimes helpful.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed Jan 04, 2012 4:39 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 9:02 pm
Posts: 1748
Location: Sacramento, CA
Thanks for posting this!! I will try to get it running on my 65816 SBC-4P, once I finish a few other projects.

Daryl


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed Jan 04, 2012 7:28 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
Bruce
Again, thanks for the tips (and thanks for the update). In fact all the I/O is at present emulated, so no register effects - each routine looks like an RTS. Any added-value I'm doing in the emulator (or in gdb) rather than in '816 code. I believe it's all in bank 0.

But something is up! I'll get back to this on Friday, with your latest code, and check that I start with the machine in the right state!

Cheers
Ed


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu Jan 05, 2012 3:35 am 
Offline
User avatar

Joined: Thu Mar 11, 2004 7:42 am
Posts: 362
One other thing that occured to me. Remember that INPUT must return a value in the carry as well as the accumulator. The INPUT routine I've used looks like this:

Code:
JSR WAIT_FOR_KEYPRESS
CLC
RTS


(Hence the ability to disable the NUF? word.) I realize these are rather basic tips, but nothing else comes to mind.

Also, I found a couple of bugs in the STC versions. I have NOT YET uploaded an update. I'm hoping to get to that this weekend. But there aren't any known bugs in the ITC versions.

8BIT wrote:
I will try to get it running on my 65816 SBC-4P, once I finish a few other projects.


If you're interested in a 65C816 version, I should reiterate that there are two versions for the 65C816. The one at the link above runs on 65C816 but is intended to be 90% of the way to a 65org16 version (which is why I'm calling it the hybrid version for lack of a better term). The idea being that most of the silly bugs are caught, and it shouldn't take too long to get it going on the 65org16. One it's working on the 65org16, then the 65C816 portions are going to get pitched, since they were never intended as anything more than a starting point.

In fact, I've forked my crude 65C816 simulator (mentioned elsewhere) to simulate the 65org16, but I've not tested it yet. (It builds! It must work! :)) So the 65C816 half of the hybrid version is not long for this world.

The other 65C816 version, which is working, but not yet at the link above, takes advantage of the 65C816-specific instructions and addressing modes. I can add this version at the link above, if/when there's interest. A 65org16 port was what got this whole eForth side project going, so I figured I'd that part out first so that others can try it and experiment. Once I got started with eForth, I pretty much went overboard with eForth and made versions for the entire 6502 family as well as versions with subroutine threading. It's not a problem to put part or all of the rest of it up; I was planning on doing that eventually anyway.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu Jan 05, 2012 4:08 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 9:02 pm
Posts: 1748
Location: Sacramento, CA
I understand. I'm looking at three to four weeks before I can even start looking at the code. Still ironing out some bugs in my cc65 target drivers.

I've been looking at making a hardware driver for some cheap 640x480 LCD's also. I don't want for things to do... just time to do them!

Daryl


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Sat Jan 07, 2012 9:24 pm 
Offline
User avatar

Joined: Thu Mar 11, 2004 7:42 am
Posts: 362
I've got both the 65org16 versions (ITC & STC) working on the simulator now. As usual, they are available at the link above. The 65C816-hybrid versions are now obsolete. They're still there, but won't be once I release the real 65C816 versions.

I've also made source code for both dev65 and HXA, rather than the mess of macros I started with. (I couldn't get strings to come out quite right in HXA, so I'm currently working around it with .byte directives and hex values. It's likely that I haven't got the .assume/.cpu directives quite right.)

I'm still trying to work out a way to provide some sort of debug info from my testing for comparison. I put a routine like the above (but always on) in NEXT with a couple of simple examples like 1 2 + . and it spit out 1.7M of info, which is way too much to wade through.

Quote:
Alternatively, you could insert it after HERE0.


I meant to say BEFORE HERE0 not after HERE0.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Sat Jan 07, 2012 9:50 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
That's great progress - I've downloaded, and will have a look when my brain's in a fit state to concentrate.

I'd be happy to receive that 1.7MB trace in my inbox - I can extract fields and adjust hex values if needed, and compare with what I see. I'm wondering if (in the 816 case) there's an emulator bug to find - but I should first spin up the latest code.

Cheers
Ed


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Mon Jan 09, 2012 5:01 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
Hi Bruce
I'm delighted to say that your latest revision (dev65 version, 65org16 version) now works fine in the emulator py65!

I used Mike's latest version of py65, which now includes a model of the 65Org16

I'm running on linux, so I had to make a small change to recognise the line-end character in the interpreter - I think another change is needed somewhere to print a newline in the output:

Code:
$ make -B
java -cp ./65016.jar org.x6502.x65016.As65016  EFO16I01.ASM
java -cp ./65016.jar org.x6502.x65016.Lk65016 -bss \$00010000-\$EFFFFFFF -code \$00000000-\$00002300 -bin -output EFO16I01.bin EFO16I01.obj
$ env PYTHONPATH=mnaberez-py65-ee39c0c/src python ./mnaberez-py65-ee39c0c/src/py65/monitor.py -m 65Org16 -l EFO16I01.bin -g 1000
Reset with new MPU 65Org16
Wrote +8961 bytes from $00000000 to $00002300

eForth 65org16 ITC 0.1
Copyright 1989-1999 Bill Muench All rights reserved.
 
ok .( Hello, world) Hello, world
ok : HELLO-WORLD ." Hello, world." ;
ok 
ok HELLO-WORLD Hello, world.
ok 
ok 1 2 + . 3
ok 
ok 


Here are my changes:
Code:
*** EFO16I01.ASM.bruce  2012-01-07 12:02:40.000000000 +0000
--- EFO16I01.ASM        2012-01-09 16:55:14.000000000 +0000
***************
*** 4,12 ****
  MEMB  .equ $1000
  MEME  .equ $7F00
 
! INIIO .equ $7F80
! OUTPT .equ $7F83
! INPUT .equ $7F86
 
  CHAR1 .equ 1
  CELL1 .equ 1
--- 4,26 ----
  MEMB  .equ $1000
  MEME  .equ $7F00
 
! ; i/o routines for Bruce's emulator
! ;INIIO .equ $7F80
! ;OUTPT .equ $7F83
! ;INPUT .equ $7F86
!
! ;; all extra code to go in some lower memory to avoid perturbing addresses
!       .org $800
!
! INPUT:
!       LDA $F005 ;; for py65
!       CLC
! INIIO:          ;; just a stub
!       RTS
!
! OUTPT:
!       STA $F001 ;; for py65
!       RTS
 
  CHAR1 .equ 1
  CELL1 .equ 1
***************
*** 1959,1965 ****
        .byte OVER
  ACCE1 .byte KEY
        .byte DUP
!       .byte ULIT,ECR
        .byte XORR
        .byte UIF,ACCE6
        .byte DUP
--- 1973,1979 ----
        .byte OVER
  ACCE1 .byte KEY
        .byte DUP
!       .byte ULIT,ELF ;; changed for linux from ECR
        .byte XORR
        .byte UIF,ACCE6
        .byte DUP


Cheers
Ed


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Mon Jan 09, 2012 10:07 pm 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
A high-level language for the 65Org16? Awesome!! -- that's quite a milestone! Congratulations, Ed and Bruce!

Jeff


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 24 posts ]  Go to page 1, 2  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: