Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

C128 version? #95

Open
GoogleCodeExporter opened this issue Mar 14, 2015 · 43 comments
Open

C128 version? #95

GoogleCodeExporter opened this issue Mar 14, 2015 · 43 comments

Comments

@GoogleCodeExporter
Copy link

80 columns would be nice..?

Original issue reported on code.google.com by [email protected] on 27 Oct 2012 at 11:59

@GoogleCodeExporter
Copy link
Author

Original comment by [email protected] on 3 Nov 2012 at 1:42

  • Added labels: Priority-Low
  • Removed labels: Priority-Medium

@GoogleCodeExporter
Copy link
Author

Original comment by [email protected] on 10 Nov 2012 at 9:41

  • Changed state: Duplicate

@GoogleCodeExporter
Copy link
Author

Original comment by [email protected] on 4 Feb 2013 at 2:17

  • Changed state: Accepted
  • Added labels: Priority-Medium
  • Removed labels: Priority-Low

@GoogleCodeExporter
Copy link
Author

Original comment by [email protected] on 22 Jun 2013 at 10:27

  • Added labels: Priority-Low
  • Removed labels: Priority-Medium

@GoogleCodeExporter
Copy link
Author

Probably I will not do it - due to personal lack of interest

Original comment by [email protected] on 22 Jun 2013 at 10:51

  • Changed state: WontFix

@GoogleCodeExporter
Copy link
Author

A quick solution

Original comment by [email protected] on 22 Jul 2013 at 9:59

Attachments:

@GoogleCodeExporter
Copy link
Author

Original comment by [email protected] on 22 Jul 2013 at 10:16

  • Changed title: C128 version?
  • Changed state: New

@GoogleCodeExporter
Copy link
Author

ok... that is not a 100% solution, or? I tried quickly to use it, got the "OK", 
but the Forth source files are not loading for me.

Original comment by [email protected] on 22 Jul 2013 at 10:44

@GoogleCodeExporter
Copy link
Author

Hm, a C128 solution would be cool!
- 128 KB RAM
- 80 characters

I plan to create a retro 8bit roguelike game and 80 characters would help a lot.


Original comment by [email protected] on 2 Aug 2014 at 1:29

@jkotlinski
Copy link
Owner

Seems to be one at http://forth128.blogspot.se/

@polluks
Copy link
Contributor

polluks commented Jan 25, 2016

Pretty cool! Of course there are some changes since August. Is there any download?

@rhalkyard
Copy link
Contributor

rhalkyard commented Dec 5, 2020

I had the same idea, and got it sort-of working fairly without too many changes; I've put a work-in-progress branch up at https://github.com/rhalkyard/durexforth/tree/c128-port.

So far, both 80 column and 40 column text modes work (including switching between them with escape-X), and it can load and compile source and operate interactively. I've added fast and slow words that work like their BASIC 7.0 counterparts, and a fast? word to return the current fast/slow state. v and graphics do not work yet, since they have some C64-specific assumptions in them, but those should be fairly easy to overcome. ls doesn't seem to work either, haven't quite worked out why yet.

Eventually it would be nice to support both the C64 and 128 in a single codebase. Would it be reasonable to add a built-in word to determine the platform that we are running on, so that the same code can do the right thing on both systems?

I also have a Plus/4 sitting around. If I get bored this winter I might try porting to that too ;)

@jkotlinski
Copy link
Owner

Hi!
Wow, that's very exciting and impressive!
I had a glance, and at least so far, it looks like not many changes were needed?
If it's not more, it would be enough to add an Acme define (if there is none already) to conditionally apply the changes.
For $801/$1c01, I think it would be appropriate to add a CONSTANT for that.
If more changes are needed, certainly it would not hurt to add a word that identifies the target.

@rhalkyard
Copy link
Contributor

Thank you! I'm impressed with how easy it was to get it working - it's a very easy-to-understand codebase.

v.fs and gfx.fs will need to handle RAM/ROM switching differently on the 128, and it might be nice to selectively call fast in a few places (e.g. when compiling), so it probably would be worthwhile to have a word. Any objections to calling it c128??

@jkotlinski
Copy link
Owner

jkotlinski commented Dec 5, 2020

I'm not fully aware what fast/slow does? I mean... "fast" sounds nicer than "slow" but I suspect there are circumstances when it cannot be used? :-) I read up on "FAST" mode now. Maybe it would be good to have it always on, except when graphics are enabled? Or are there other circumstances where it will not work?

For your question, c128 should be avoided, since there is a naming conflict with the hexadecimal number with the same name. Maybe there is some other way to do it.

@polluks
Copy link
Contributor

polluks commented Dec 6, 2020

It also works in C64 mode, how about "?vdc"?

@rhalkyard
Copy link
Contributor

rhalkyard commented Dec 7, 2020

Pushed a few more changes that got ls and v working (though v only works correctly in 40 column mode).

It also works in C64 mode, how about "?vdc"?

That might be useful to have too, but we will also need to be able to identify a C128 running in native mode. Hopefully most of those checks can be done in fairly low-level code, but, e.g. graphics routines will need to know about the different memory layout and bank controls on the native 128.

The 128's memory layout is kind of awkward for hi-res graphics; you can't use the $C000-$FFFF VIC bank because $FF00 is a 'magic' address that controls the MMU. Instead, I might try and run the graphics in high RAM; it won't be quite as performant, but it's less awkward than trying to put the bitmap in the middle of everything.

The VDC also has its own unofficial graphics mode that's even higher resolution (640x200 or 640x480 interlaced); might be fun to add support for that sometime too!

EDIT: never mind about my memory layout comment; it is indeed possible to use $C000-$FFFF for graphics, you just can't have the bitmap at $D000-$FFFF. gfx.fs is working with only minor changes, see rhalkyard@008477a. VDC graphics would be nice to have as well though.

@rhalkyard
Copy link
Contributor

rhalkyard commented Dec 8, 2020

In the process of this, I have added some new words [IF] [ELSE] and [THEN] (see https://forth-standard.org/standard/tools/BracketIF) that work like normal if-else-then, but are immediate, so can be used for conditional compilation (like #if/#ifdef in C etc.)

This lets us handle the differences between the C64 and C128 at compile time - only the code appropriate to the machine gets compiled, so (aside from the extra dictionary space these words take up) there will be no runtime cost in speed or code size to supporting both systems.

The implementation and some examples in more and v are in the following commit, if you would like to take a look:
rhalkyard@6759f4c

I realise that adding these words to the standard environment consumes almost all the remaining cartridge space, but it will make supporting both systems (or potentially, having full-featured and "lite" variants of libraries) much easier.

@jkotlinski
Copy link
Owner

jkotlinski commented Dec 11, 2020

Humm, yeah I must admit I'm not really a fan of adding [if] [else] [then] words. Most of the times, those words are not really needed and take up space that maybe could be used for something more fun.

Maybe the differing words could be moved out to their own files? Then the problem could even be solved in the Makefile, by having two separate builds for c64 and c128?

@rhalkyard
Copy link
Contributor

That's reasonable; it was fun implementing them anyway, and I think that with how few changes were actually required, your idea is a better one. If you don't mind me doing so, I'll do some refactoring of the makefile to support it.

On the topic of fun things, the 128 version makes playing with graphics a delight - since the VIC and VDC are completely independent, you can leave the VIC in hi-res mode while the interpreter runs on the VDC, so you can interactively play with graphics words and see their effects immediately. It's one thing to do it in an emulator, but there's a certain magic to seeing it on a pair of CRTs connected to a real machine :)

image

@rhalkyard
Copy link
Contributor

rhalkyard commented Dec 12, 2020

Code-wise, I see only two roadblocks to considering 128 support fully functional.

On the simple side, float.fs still needs to be modified to work with the 128's BASIC routines. I haven't touched it yet because I don't entirely understand how it avoids corrupting the stack - the floating-point accumulators in 128 BASIC are slightly closer to the start of the stack than on the 64, so there would be greater risk of overwriting valid stack values. Some advice on how it works on the 64 would be appreciated.

And then there's a bug that stopped me from sleeping last night. I don't expect you to have an answer for me or anything, but I figure that if I write it all down, it'll at least help me organise my thoughts, and if I'm really lucky, someone smarter than me will see it and have an idea.

On the 128, the first character of the line following an INCLUDE or REQUIRE will sometimes get dropped or garbled. It doesn't happen all the time, but it is repeatable and appears to be affected by file size (with the same set of files, it happens at the same place each time, but when file sizes change, it will happen in different places).

The strange thing is, I've spent hours examining the code path where this happens (INCLUDED-REFILL-interpret_tib) and it appears to be making all the right Kernal calls through the official jump table entries, and (aside from needing to call SETBNK before OPEN on the 128), should work fine on both the 128 and 64.

If we have some source that looks like this,

...
.( compiling foo...) include foo .( done)
cr here .
...

as far as I can understand it, the sequence of events are as follows:

  1. INCLUDED saves TIB state and adjusts TIB pointer to preserve any trailing characters, increments file number, and does a standard SETBNK - SETNAM - SETLFS - OPEN - CHKIN sequence, consumes the first two characters because we are using the PRG filetype, and then goes into REFILL - interpret_tib loop.

  2. REFILL reads the last line of foo into the TIB and sets READ_EOF.

  3. INCLUDED tail-calls interpret_tib to interpret the last line of foo, then returns to the parent's interpret_tib.

  4. The parent interpret_tib sees an empty TIB and returns to the REFILL - interpret_tib loop.

  5. REFILL closes foo, decrements the file number, calls CHKIN to get input from the parent file, and tail-calls RESTORE_INPUT to restore the TIB and EOF state.

  6. interpret_tib interprets the remaining characters (.( done)) successfully.

  7. REFILL attempts to read the next line from the parent file into the TIB, but sometimes, instead of cr here ., it will read something like r here . or %r here . ('%' is just a stand-in for some garbage character).

It gets even stranger when testing with different drives - with a 1571 the problem is sporadic and almost always manifests as a dropped character rather than a garbled one, but a 1541 will always return a garbage character in this case. I first noticed this running in VICE and wondered if it was an emulator issue, but when I tried it on my real 128 with real drives, the issue manifested in the exact same way.

Until I can get to the bottom of it, this bug is a bit of a showstopper, but it is possible to work around the issue by following each INCLUDE with a multi-line comment so that a dropped or garbage character won't affect interpretation, like so:

...
include foo (
guard comment )
...

@burnsauce
Copy link
Contributor

Stepping through with the Vice monitor might be illuminating. Just trying to help you sleep ;)

@Whammo
Copy link
Collaborator

Whammo commented Dec 13, 2020

@jkotlinski
Copy link
Owner

About float.fs: It does not really work on C64 either, so don't worry about it! It's just a fun, undocumented hack. I added a comment to underline that further.

About included et.c.: Ouch! I've struggled with those kind of problems one a lot myself. It's real tricky. Let me know if I can help somehow.

@jkotlinski
Copy link
Owner

By the way, what is the exact repro?

@rhalkyard
Copy link
Contributor

About float.fs: It does not really work on C64 either, so don't worry about it! It's just a fun, undocumented hack. I added a comment to underline that further.

Ah, that's good to know. funnily enough, the C128's ability to remap the zero page might make that kind of thing easier to work with - with some clever memory-map juggling we could have almost the whole zero page dedicated to the Forth stack.

About included et.c.: Ouch! I've struggled with those kind of problems one a lot myself. It's real tricky. Let me know if I can help somehow.

By the way, what is the exact repro?

I've managed to reproduce the issue with a simple program that alternates reading from two different files. The code and a brief writeup are at https://github.com/rhalkyard/c128-chkin-bug. I'll update that repo as I continue to dig into it.

@Whammo
Copy link
Collaborator

Whammo commented Dec 14, 2020

Try using $00 as the secondary address for both files, look for the ASCII value of the byte read in location 512 ($200)
after the GET#

@jkotlinski
Copy link
Owner

jkotlinski commented Dec 14, 2020 via email

@jkotlinski
Copy link
Owner

@rhalkyard I think I got it working by calling CLRCHN before each file switch!

@jkotlinski
Copy link
Owner

Calling UNTALK before file switch seems to work equally well. Maybe it's preferable? I have no idea why it is needed at all.

@Whammo
Copy link
Collaborator

Whammo commented Dec 14, 2020

clrchn calls untalk

@rhalkyard
Copy link
Contributor

rhalkyard commented Dec 15, 2020

Ha, I just got there too, and with some messing about with a logic analyzer, I think I've figured out why - sending a new command to the drive is supposed to implicitly UNTALK it, but because of the way the Fast Serial handshake works on the 128, the drive thinks that the computer is ready for another byte, and then gets interrupted partway through when the computer asserts ATN.

Here's a trace of a CHKIN without CLRCHN on a C64 and 1541:
image

And here's the same thing on a 128 with a 1541 - see how the drive tries to transmit another byte when we release DATA to start the fast-serial handshake:
image

It doesn't happen as often with the 1571, but it does still occur (unfortunately PulseView doesn't know how to decode fast serial properly, but you can see the drive sending a byte immediately before we assert ATN):
image

Explicitly UNTALKing the drive before calling OPEN or CHKIN gets around the issue because UNTALK doesn't attempt the fast-serial handshake:
image

Calling UNTALK seems preferable to me in case CLRCHN messes with any output redirection the user might be doing, though I don't know if it really matters.

Thanks so much for your help!

@rhalkyard
Copy link
Contributor

UNTALK fix pushed as rhalkyard@0e495ef

@Whammo
Copy link
Collaborator

Whammo commented Dec 15, 2020

Simply amazing! Soon, the best programming language implementation for the C64 will be the best programming language implementation for the c128! Thank you all!

@greg-king5
Copy link

Sending a new command to the drive is supposed to implicitly UNTALK it.

NO!
I don't know where people got that idea -- it never has been true. It isn't implied, it isn't automatic. A program always must call CLRCHN explicitly. You must disconnect -- explicitly -- from an active file-channel before you do anything with another file.

AND, you must disconnect -- explicitly -- from an active file-channel before you close that file.

That's true for all models of Commodore 8-bit computers and all models of drive units.

If it had happened to work without CLRCHN, then it was an accident. Don't rely on accidents -- they will bite you in the rear end!

@rhalkyard
Copy link
Contributor

I stand corrected! I can't remember where I picked up that bit of misinformation, but I'd seen it done that way so often, I'd never thought to question it.

rhalkyard added a commit to rhalkyard/durexforth that referenced this issue Dec 17, 2020
Per Greg King's comment on issue jkotlinski#95, this is not a bug, and CLRCHN
should be used on both C64 and C128.
@jkotlinski
Copy link
Owner

Thank you @greg-king5 for sharing knowledge! Much appreciated!

@Whammo
Copy link
Collaborator

Whammo commented Dec 17, 2020

!

@rhalkyard rhalkyard mentioned this issue Dec 17, 2020
@jkotlinski
Copy link
Owner

jkotlinski commented Dec 18, 2020

@greg-king5 a question about this

"AND, you must disconnect -- explicitly -- from an active file-channel before you close that file."

Just to clarify. First call CLOSE, then CLRCHN, is that correct? Like here? https://codebase64.org/doku.php?id=base:reading_a_file_byte-by-byte

@Whammo
Copy link
Collaborator

Whammo commented Dec 18, 2020

@greg-king5
Copy link

"AND, you must disconnect -- explicitly -- from an active file-channel before you close that file."

Just to clarify. First call CLOSE, then CLRCHN, is that correct? Like here? https://codebase64.org/doku.php?id=base:reading_a_file_byte-by-byte

It's the other way around. You can think of the actions in terms of functional blocks. "Openning a file", "connecting to a file", and "getting/sending bytes" are three blocks. The later blocks should be nested completely inside the earlier blocks. It's similar to nested code blocks in a lot of programming languages, such as C, Python, Java, Ruby.

OPEN ---------------------+
  CHKIN/CHKOUT ---------+ |
    begin a loop -----+ | |
      input or output | | |
    end a loop -------+ | |
  CLRCHN ---------------+ |
CLOSE --------------------+

@greg-king5
Copy link

Another thing to consider is that people will want to use DurexForth on devices other than Commodore's floppy drives.

There are hard drives and solid state drives. There are devices that plug into an expansion connector, such as IEEE adapters, the Lt. Kernel hard drive, RAM drives, the IDE64 hard drive adapter, and 80-column display adapters. There were switching hubs that allowed a kind of "Network-Attached Storage" (used in business offices and classrooms).

We can't know how those devices will react to a program that takes shortcuts (leaves out a function call), or calls functions in a wrong order. It's best not to take chances.

@jkotlinski
Copy link
Owner

Further work here: #478

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants