6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sun Nov 24, 2024 10:01 am

All times are UTC




Post new topic Reply to topic  [ 110 posts ]  Go to page Previous  1, 2, 3, 4, 5 ... 8  Next
Author Message
 Post subject: Re: screen editor design
PostPosted: Tue May 06, 2014 8:00 am 
Offline

Joined: Sat Aug 21, 2010 7:52 am
Posts: 231
Location: Arlington VA
EDITDEL (STOP-D) works, almost. There's a bug in the screen wrap logic when I delete the very top line, but otherwise it handles 40 and 80 columns well. Code is here. Update: The most annoying fencepost condition in the world has been fixed. EDITPASTE is still a disaster.
Update: It's all good! Line copy/cut/paste is working as designed. woot!!


Top
 Profile  
Reply with quote  
 Post subject: Re: screen editor design
PostPosted: Wed May 07, 2014 4:08 am 
Offline

Joined: Sat Aug 21, 2010 7:52 am
Posts: 231
Location: Arlington VA
With the line editing working, I'm moving on to the paging up and down through screens. Moving to a screen that doesn't exist automagically creates it. Navigating away from a screen (or quitting the editor) automagically saves it to the buffer. Screens/Blocks are numbered sequentially, starting with 1. The block number is not stored anywhere, but is the number of blocksize hops down from the top of memory.

  • STOP-HOME screen 1 (top)
  • STOP-UP previous screen
  • STOP-DOWN next screen
  • STOP-INS insert a screen before current screen
  • STOP-DEL delete current screen
  • STOP-I index screen composed of the first 40 characters of block 1...block 25
  • STOP-R restore current screen from last time we exited it


Here's the memory scheme for my "virtual memory with cassette tape" design. Sets of blocks are loaded, saved and verifed (STOP-L, STOP-S, STOP-V) to either disk or tape as standard Commodore PRG files. The load address of the PRG file would be the first byte used, and the end address will always be $7C00 (MEMSIZ minus 1K), or whatever the top of memory is on your PET. Each compressed screen in the buffer will be a packet, with the last two bytes being the size of the packet. Here's some bad ASCII art to illustrate what this area at the top of RAM will look like

Editor buffers build downward in RAM from the top, indicated by MEMSIZ (stored at $34-$35 after RESET)
Code:
|        video ram $8000        | <--- MEMSIZ         (e.g. $8000 on 32K PET)
+===============================+
| static 1K block buffer        | MEMSIZ-1024...MEMSIZ-1   ($7C00 on 32K)
| used by compression words ... |
+-------------------------------+
| current screen (editor start) | MEMSIZ-1024-2            ($7BFE)
+-------------------------------+
| block 1 size                  | MEMSIZ-1024-4            ($7BFC)
+-------------------------------+
|f e d c b a 9 8|7 6 5 4 3 2 1 0| linewrap table of 24 high bits $E1-$F8
+---------------+---------------+ bit 0 = line24, bit n = line1,
| RLE encoded   |n m l k j i h g| line0 $E0 is always "1"  ($7BF9)
| screen image  +---------------+
| stored as screen codes        |
| BLOCK 1                   ... | MEMSIZE-1024-2-{block 1 size}
+-------------------------------+
| block 2 size                  | size of block 2
|              .                |
|              .                |
|              .                |
| BLOCK N                 ...   |
+-------------------------------+
| 0                             | a zero-sized block marks the bottom of the block buffer
+-------------------------------+ the address of this word is the load/save address

I'm adding new words to the USERAREA. Are these stupid names?
MEMSIZ = $8000
EDITBLK = $7BFE

Behavior question: I COLD start PETTIL. This puts a zero in EDITBLK (no blocks are loaded or created). I immediately enter the editor by typing EDIT. Since I came in cold, whatever is on the screen will remain, but I'll be in edit mode. I type a few lines, and then... STOP-HOME. Does the editor save the current screen as block 1, and then navigate to block 1? This would turn STOP-HOME into a handy place to anchor something for future STOP-R (restore) operations. I'm also not entirely confident about requiring the user to manually and explicitly clear the paste buffer with STOP-Z (zilch), because the other commands append to it.


Last edited by chitselb on Wed May 07, 2014 7:29 pm, edited 2 times in total.

Top
 Profile  
Reply with quote  
 Post subject: Re: screen editor design
PostPosted: Wed May 07, 2014 7:26 pm 
Offline

Joined: Sat Aug 21, 2010 7:52 am
Posts: 231
Location: Arlington VA
I present RLENCODE and RLDECODE, in 22 bytes of header + a measly 88 bytes of code!


Top
 Profile  
Reply with quote  
 Post subject: Re: screen editor design
PostPosted: Thu May 08, 2014 2:39 am 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1950
Location: Sacramento, CA, USA
I'm really enjoying your tumblr blog. I find it entertaining to be able to read about all of the little details on the bumpy road to a finished project, and I like the way that your 'voice' comes through in your posts ... it's an elusive quality that some of us struggle to maintain, with mixed success. I enjoy it more than github, which is still a confusing and awkward browsing experience for me.

Mike


Top
 Profile  
Reply with quote  
 Post subject: Re: screen editor design
PostPosted: Thu May 08, 2014 5:03 pm 
Offline

Joined: Tue Jul 24, 2012 2:27 am
Posts: 679
It might save you a few bytes of code footprint, and probably much more in your compressed buffers, to not do "full" RLE, but just record spans of spaces vs non-spaces. That's really where your compression ratio is going to come from anyway, unless somebody likes making horizontal lines of dashes and such. It saves a byte from each compressed tag, because the byte that's being repeated is implied to be a space character and no longer needs to be included.

However, reading from your code, do you RLE tag everything? As in a line of "abcde " would be .byt 'a',1,'b',1,'c',1,'d',1,'e',1,' ',35 ?

Usually, RLE compression will use 1 bit of the length byte to flag if the next bytes are repeated or not. Thus, the above example would be .byte 5,"abcde",35|128,' '. This assumes that if the high bit is clear, then that many raw bytes follow. If it is set, the lower 7 bits say how many times to repeat the following byte. A repeated byte is only used when at least 2 are in succession, so "2 3 +" would end up as a span of 5 bytes, followed by a repeated span of 35 spaces, even if you're only RLE-ing spaces.

Code:
Encoding "   3 2 +": (3 leading spaces, some text, then the rest of the line empty)

;; Always using RLE tags, even for single bytes
.byte " ",3, "3",1, " ",1, "2",1, " ",1, "+",1, " ",32
; = 14 bytes

;; Using a bit flag for compressed vs uncompressed
.byte 3|128," ", 5,"3 2 +", 32|128," "
; = 10 bytes

;; Implied spaces as the compressed character
.byte 3|128, 5,"3 2 +", 32|128
; = 8 bytes

_________________
WFDis Interactive 6502 Disassembler
AcheronVM: A Reconfigurable 16-bit Virtual CPU for the 6502 Microprocessor


Top
 Profile  
Reply with quote  
 Post subject: Re: screen editor design
PostPosted: Fri May 09, 2014 4:43 am 
Offline

Joined: Sat Aug 21, 2010 7:52 am
Posts: 231
Location: Arlington VA
Here's what I came up with during the 8 hour car ride between Washington DC and Syracuse NY:

When decompressing blocks, RLDECODE decompresses until {compressed size} bytes of source buffer are exhausted.
Before decompressing, target buffer will be initialized to 1024 spaces
The corollary to this is, compressed buffers never need to store any trailing spaces at the end of the buffer, RLE-encoded or otherwise
When RLENCODE does its thing, it will fail (and store the block uncompressed) if the compressed size exceeds 1024 bytes. This prevents the pessimal case "AABBAABBAABBAABBAABBAABB..." repeated to fill the block from being expanded to "AA",2,"BB",2,"AA",2,"BB",2,"AA",2,"BB",2... (a 50% expansion in the worst-case scenario)
BLOCKs are numbered starting at zero, as per the Forth-83 standard
The number of compressed blocks currently stored in high memory will be kept in the uservariabe VIRTSIZ
VIRTSIZ can expand and contract during the editing session
From a command line, saying "50 BLOCK" after cold start would create empty blocks 0..50
Each empty block so created will contain the word $0002. The length is 2. There are no spaces stored. There are no linewrap bits stored because it's a data block until the screen editor updates it.
I haven't really worked out how and when the three $FFFFFF bytes (representing lines 1..24 are each 40 characters) gets connected to the stored blocks, other than "the editor does it if it tries to edit a block that doesn't have them, and the editor always stores the linewrap table as three bytes after the RLE encoded screen codes
The buffer returned would contain 1024 spaces
EDIT will now require a block number at TOS as an argument
The 2-bytes of current screen currently stored at $7BFE will no longer be stored in the virtual memory buffer. Instead it will become the new uservariable SCR
SCR will be initialized to 0 on CASSLOAD
CASSLOAD is a word which loads the next file named "PETTIL BLOCKS" from cassette tape, or the file named "PETTIL BLOCKS" from disk
the new uservariable DRV will determine the device used for mass storage (initialiized at COLD to 1 for tape #1)
If DRV contains device #>3, the filename saved by SAVE-BUFFERS will be prepended with "@0:" becoming e.g. "@0:PETTIL BLOCKS",8 . Otherwise SAVE-BUFFERS will save to e.g. "PETTIL BLOCKS",1
The start address of SAVE-BUFFERS is calculated by hopscotching backward through block sizes (first one, 0 BLOCK, now has its length word stored at $7BFE) until a zero-sized block (end of virtual memory) is encountered at the bottom address
: EMPTY-BUFFERS VIRTSIZ OFF ;

I hope this is clear. This is scheme "a" Eventually two more virtual memory schemes will be implemented
a) virtual memory on cassette -- groups of blocks loaded/saved to high memory
b) virtual memory on floppy -- like Blazin' Forth does on the C=64. Multiple drives concatenated to increase VIRTSIZ, which is static (the total number of 1K blocks on all drives)
c) virtual memory on PETdisk -- bitfixer.com device which makes a microSD card pretend to be a disk. This will require some atmel coding on the PETdisk and some way of interfacing raw block storage between PET and PETdisk

when LOAD happens, I am very strongly considering treating the end-of-logical-line as a space. I can probably manipulate the beginning of line pointer at $C4-C5 and the line size, (I am pretty sure it's $D8, holding a 39 or 79) to trick the screen editor and kernel CHRIN routine to input from a fake screen at $7C00. How big a party foul is that?
I am also pretty sure I can get away with having only one 1K block buffer at $7C00-$7FFF to make all of this work.


Top
 Profile  
Reply with quote  
 Post subject: Re: screen editor design
PostPosted: Sun May 11, 2014 4:40 pm 
Offline

Joined: Sat Aug 21, 2010 7:52 am
Posts: 231
Location: Arlington VA
barrym95838 wrote:
I'm really enjoying your tumblr blog...
Mike


Mike,

I appreciate that more than you know. Some days it feels like I'm the only guy in the world who wants to do the most kickass Forth ever for the Commodore PET. I'll try to keep the quality and quantity of my efforts up, at least until the job is done and I move on to some new curious obsession of the week. Here's a new one I'm calling Virtual Memory on Cassette Tape


Top
 Profile  
Reply with quote  
 Post subject: Re: screen editor design
PostPosted: Sun May 18, 2014 3:49 pm 
Offline

Joined: Sat Aug 21, 2010 7:52 am
Posts: 231
Location: Arlington VA
If the user types, e.g.
Code:
3 EDIT
they're in the editor, editing away on block 3, which was retrieved from a ramdisk and created if necessary.

Wouldn't it be pretty useful to say
Code:
-1 EDIT
(or any negative value) and have that just start the editor, without fetching a screen, so the current contents of the screen could be captured?

Okay so let's say that's how it works. When the user UPDATEs that captured screen, e.g. by going to another screen, where is it written in the ramdisk? Appended as the last block?? As the new block 0?? Something else?


Top
 Profile  
Reply with quote  
 Post subject: Re: screen editor design
PostPosted: Sun May 18, 2014 4:02 pm 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1950
Location: Sacramento, CA, USA
Could you add 'virgin' flags to your screens? If so, another word, like CAPTURE (or maybe even a hot-key), could find the first virgin (or maybe just blank) screen and copy the current contents there before launching into EDIT.

I confess that I don't know how your interactive console 'screen' is implemented. Could it be morphed into an actual storage-class 'screen'? Or am I just spouting nonsense?

Mike


Top
 Profile  
Reply with quote  
 Post subject: Re: screen editor design
PostPosted: Mon May 19, 2014 1:13 am 
Offline

Joined: Sat Aug 21, 2010 7:52 am
Posts: 231
Location: Arlington VA
Here's the Forth-javadoc for it:

EDIT ( scr -- )

Sets the SCR user variable and launches the full screen block editor. If {scr} is negative, a new packet is appended to the virtual memory buffer and becomes the current SCR.

Hot keys aren't trivial on the PET, and are very un-Forth-like. I came across another Forth (Durex Forth) for the C=64 which I haven't really analyzed yet, but I was a little squicked when I learned that their screen editor is a vi clone.


Top
 Profile  
Reply with quote  
 Post subject: Re: screen editor design
PostPosted: Wed May 21, 2014 4:25 am 
Offline

Joined: Sat Aug 21, 2010 7:52 am
Posts: 231
Location: Arlington VA
top of dictionary now at 26c7 no headers, 2f8f with headers
difference = 8C8 or 2248 decimal bytes

As an experiment, I surrounded all the Link and Name fields in my Forth with "#ifdef HEADERS / #endif" and did a build. On a 32K machine, that's probably a big deal, because I'm going to need every byte I can get for this videogame application. I expected more, but it's still worth going after. If I detach the symbol table from the dictionary, and it looks like reserving 4K of symbol table space for "development" mode will more than suffice. I can also move all of the outer interpreter and compiler into a second dictionary, because that code becomes worthless once the name fields vanish and so won't be used in the target compiled environment. That might be another 2K of code for IF THEN ELSE BEGIN WHILE REPEAT UNTIL AGAIN DO LOOP +LOOP : ; CREATE VARIABLE CONSTANT QUIT ... I wonder if there's any other big chunks of low hanging fruit like that, before I start to go after individual words that aren't required?


Top
 Profile  
Reply with quote  
 Post subject: Re: screen editor design
PostPosted: Wed May 28, 2014 9:12 pm 
Offline

Joined: Sat Aug 21, 2010 7:52 am
Posts: 231
Location: Arlington VA
I feel bad about kicking vocabularies to the curb. If I were to split the headers off from the code, with the headers constructed like in the diagram below, is there enough information to put vocabulary back? Assume it's possible to slide words around at will. Perhaps the unused flag bit could be used to tag the tail end of a vocabulary?

for our example, here's ALLOT :
Code:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         $1467                 | +0 code field
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
[0]             | immediate bit   +2 name field length/flags byte
| [0]           | smudge bit
|   [0]_________| unused, always a 0
|     [    5    ] name length 0..31
+-+-+-+-+-+-+-+-+
|      A        |                 +3 name field first letter
+-+-+-+-+-+-+-+-+
|      L        |
+-+-+-+-+-+-+-+-+
|      L        |
+-+-+-+-+-+-+-+-+
|      O        |
+-+-+-+-+-+-+-+-+
|      T        |                 +n name field last letter
+-+-+-+-+-+-+-+-+


Top
 Profile  
Reply with quote  
 Post subject: Re: screen editor design
PostPosted: Thu May 29, 2014 10:30 am 
Offline

Joined: Tue Jan 07, 2014 8:40 am
Posts: 91
I'd say it depends on what you want to use vocabularies for. There's no rule that says vocabularies have to be kept in multiple linked lists. You could, for example, add a single byte to the header of each word, indicating what vocabulary that word belongs to. (If you make that byte part of the name, the vocabulary match is done as part of the name comparison.) That would let you have 256 vocabularies, which is enough for any Forth application I've ever seen.

Of course, implementing it that way does not speed compilation in the slightest. I do know of people who have broken their dictionary into multiple vocabularies in order to speed dictionary search. But I tend to think of that as an incidental benefit of certain implementations. The purpose of vocabularies (IMHO) is to give you multiple, independent namespaces.

_________________
Because there are never enough Forth implementations: http://www.camelforth.com


Top
 Profile  
Reply with quote  
 Post subject: Re: screen editor design
PostPosted: Thu May 29, 2014 9:00 pm 
Offline

Joined: Sat Aug 21, 2010 7:52 am
Posts: 231
Location: Arlington VA
new blog post, hopefully solving the riddles.


Top
 Profile  
Reply with quote  
 Post subject: Re: screen editor design
PostPosted: Fri May 30, 2014 7:21 pm 
Offline

Joined: Sat Aug 21, 2010 7:52 am
Posts: 231
Location: Arlington VA
Where I'm running into a snag is redefining an existing word. In the headless model, the new CFA replaces the existing CFA in the symbol table.

What FIG Forth CREATE does
  • copy the name to HERE+1
  • store the length at HERE
  • set the smudge bit on the length byte
  • FIND still locates the pre-existing word, because smudge hides the new one
  • when closing the definition later, either ; ;CODE or END-CODE turns off smudge

Here's my not-really-sure-if-it-will-workaround in PETTIL CREATE. Make a new user variable (ugh) called REDEFINE. During the time between CREATE and sealing the vault, REDEFINE is either off ($0000) for new words or it's a copy of the old definition's CFA. Smudge will also be set on the header during this time.
  • FIND the address of a pre-existing head, or add a new one. Duplicates (same name) are never created.
  • if it's new, turn REDEFINE off ($0000), otherwise set REDEFINE = the CFA of the found word (found at 2- from the length byte)
  • set the smudge bit
  • during execution token compilation, FIND will check REDEFINE if the smudge bit is on
  • - REDEFINE @ if REDEFINE is nonzero
  • - HERE if REDEFINE is zero
  • turn off SMUDGE (and maybe clear REDEFINE) when closing the definition

It feels inelegant and un-Forth-like. How do Forth optimizers sleep at night?


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 110 posts ]  Go to page Previous  1, 2, 3, 4, 5 ... 8  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 5 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:  
cron