6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat May 11, 2024 4:12 pm

All times are UTC




Post new topic Reply to topic  [ 7 posts ] 
Author Message
PostPosted: Mon Oct 04, 2010 5:24 am 
Offline

Joined: Sat Aug 21, 2010 7:52 am
Posts: 231
Location: Arlington VA
Lacking the actual hardware for implementing virtual memory on diskette, I'm going with cassette tape. This leaves the choice of blocks or files. I'd prefer blocks. To me it feels more "Forth-like"

Screen code data is almost always in the $00-$3F (0-63) 6-bit range (normal printable text), except when it isn't.

PETTIL screen editor/cassette based virtual memory design objectives:
capture raw screen codes directly from screen memory
leverage the ROM screen editor as the block editor
Use the STOP key as the editor escape key
e.g. STOP-DOWN would flip to the next screen of source,
STOP-UP would go to the previous screen, etc...
($009B becomes $EF when STOP is pressed, is $FF otherwise)
Turning the editor on (edit mode) would be a matter of trapping the IRQ vector at $0090 to read location $009B (stop key pressed) and wait in a GET loop for the second key of the STOP-key sequence.
STOP key "flashes" the screen or maybe turns the bottom line into a menu

give consideration to the 80/40 logical line wrap table at 00E0-00F8
use LOAD and SAVE routines to move packed data to and from tape
pack and unpack the screens into 256-byte blocks
store packed screens in RAM growing downward from top
use run-length encoding and 6-bit compression
use $00 (@) and/or $1F (left arrow) as escape characters within packed blocks
- to signal values outside the range $00-$3f
e.g. reverse-shifted A (reverse-spade screen code $C1) would become
Code:
011111 1010 11 000001
esc    1shft3  spade

Here "1shft" is an arbitrarily chosen 4-bit value "1010" which means "shift the next single screen code so that the two uppermost bits are..." followed by 11 for reverse and shift (group 3). Other 4-bit codes could set the upper bitmask from 00 to something else until it's changed back or ... what?
- to signal repeated characters e.g. 37 spaces would become
Code:
000000 100000 111111 000000 100000 000110
esc      $20     31   flag    $20     6


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Mon Oct 04, 2010 6:19 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8433
Location: Southern California
I made a cassette modem in the 1980's for a couple of bucks in parts, and it worked well. In a project at work we had cassette transports with electronic control (through solenoids) so a computer could control all the transport functions, and they had stereo heads so we could put data (including location info) on one channel and audio on the other. There was also a 2-bit gray-code optical sensor on one of the reels so you could get an idea of your location when you were fast-forwarding or rewinding much too fast to read the data from the head. I also designed the record and play electronics. The project was canceled before it made it to market, but it did work fine and was very inexpensive.

Unfortunately, compared to modern serial EEPROMs and flash memories, it was big and slow, and even if you have a lifetime supply of cassettes, the transports usually have rubber belts and wheels that don't last a lifetime and they are becoming unavailable. I like the 24C512 64Kx8 I²C EEPROMs (and related ones) in 8-pin DIP or SOIC, and now the 25VF032 4Mx8 SPI flash in SO-8 which I got from Mouser for $2.56/ea. I made half-postage-stamp-sized modules with the I²C ones like this:

Image

At the right in the picture is the 2x2 socket that plugs into the I²C port pin header on my workbench computer. The jumper block at the back is for write-protect, and of course only takes a second to remove or re-install on the 2-pin header by hand. After the first unit, I quit putting the LED on it and put LEDs on the workbench computer to show when the power or clock pins were high. The power LED was for knowing if it's safe to plug in or unplug the module. Obviously it doesn't help for knowing if it's ok to plug in if the LED is on the module-- which is why I put it on the computer after this.

There's a trick or two to operating especially the I²C one, and I can send you my Forth code if you need it. The main thing there is that after you send it an address, you should not do a "busy check" before doing the read or write at that address, since the busy check clears the address again (if I'm remembering it correctly off the top of my head-- I'm not looking at it at the moment). My code for making the 4Mx8 flash work is also in Forth.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu Oct 07, 2010 6:31 pm 
Offline

Joined: Sat Aug 21, 2010 7:52 am
Posts: 231
Location: Arlington VA
Garth: That looks like something I might try (cassette audio <-> PC soundcard) if I'm understanding your design properly. Vice doesn't allow writing to the simulated tape drive.

I'm still proceeding with the strategy of compressing source code into pages and saving it from top of RAM building downward, then dumping large chunks of that out to tape with the SAVE and LOAD routines.

Here's my RLE encoder/decoder code, and another compressor I've been playing with (just the packer, not the unpacker yet). It crams four 6-bit characters into three bytes which probably isn't new art but I've been calling it "shamrock compression" because of the 3 bytes::4 characters thing, in an attempt to reduce memory required by up to 25% (by not storing repetition in the upper two bits.)

There is a table of screen wrap from $E0-$F8 that tells the screen editor which lines are 40 column and which are 80-character continuation lines (bit 7 off). Otherwise they point to the page of memory where the line of video is located. Low bytes of these addresses are stored elsewhere (in a ROM table)

>C:00e0 80 00 80 80 80 80 80 81 81 81 81 81 81 82 82 82 ................
>C:00f0 82 82 82 82 83 83 83 83 83 00 00 00 00 00 00 00 ...............

There is a BASIC trick of forcing a bunch of return characters into the keyboard buffer and then printing commands on the screen spaced appropriately, then letting the screen editor take over. Self-modifying BASIC code without the use of POKE is possible. I'm wondering if I were to change these high-order bytes from $80xx-$83xx to the $7Cxx-$7Fxx range what would the screen editor do? Would continuation lines work?

So, having 1000 characters on the 40x25 screen and 25 bytes in the line wrap table, that's 1025 bytes per screen. Perfect! Not! Commodore 64s had this annoying "one extra byte" too, with Koala images being 10,001 bytes long (background color).

As it turns out (apparently from my experimenting in the screen editor) it's impossible for the top line ($E0) to be a continuation line. The PET double-scrolls the screen. So I only have to stash $E1-F8 (24 bytes) along with the text/graphics on the screen for a neat 1024 bytes.

Not that it matters much. I'm compressing it all. But it's nice to be able to compress a contiguous region of memory ($8000-$83FF) instead of the 1000-byte chunk and the 25-byte (turns out really 24-byte) chunk

As for performance of these two compression algorithms, it goes:
1000 bytes -> RLE -> 490 bytes (51%)
490 bytes -> shamrock -> 405 bytes (59%)

The data used for testing was a typical-looking-enough block of volksForth source.

Code:
;--------------------------------------------------------------
;
;       SHAMPACK   ( from to size -- size2 )
;
; pack four 8-bit bytes into four 6-bit codes until "size" bytes
; have been packed from the input stream starting at "from".
; return "size2" as the number of bytes in the packed buffer at "to"
;
;       set quad for 1 character (octal)
;       00 00
;       00 01
;       00 02
;       00 03
;
;       set quad for multiple characters
;       00 04
;       00 05
;       00 06
;       00 07
;
;       an '@' sign within this quad
;       00 10
;
;       A = byte to pack
shamrockshift   ldy #6
shamrockshift01 lsr
                ror n+5
                ror n+6
                ror n+7
                dey
                bne shamrockshift01
                dex
                bne shamrockshift05
                ldx #2
shamrockshift02 lda n+5,x               ; write bytes to output stream
                jsr rle_write
                dex
                bpl shamrockshift02
                ldx #4                  ; make a new shamrock
shamrockshift05 rts

;       A = byte to pack
shamrockshake   bcc shamrockshake02     ; read?
                lda zi                  ; original byte
                eor n+4
                and #$c0
                beq shamrockshake03
                lda #0                  ; new quad here
                jsr shamrockshift       ; escape character
                lda zi
                eor (n+2),y             ; quad of byte after current byte
                and #$c0                ; just the quad bits, please
                php
                pla
                lsr
                lsr                     ; C is a copy of Z flag (from and #c0)
                lda zi
                and #$c0
                bcc shamrockshake02
                sta n+4                 ; set quad as permanent
shamrockshake02 rol                     ; carry bit
                rol                     ; quad
                rol                     ; bits
                jsr shamrockshift       ; send command
shamrockshake03 lda zi
                and #$3f
                bne shamrockshake04     ; handle "@" sign
                jsr shamrockshift
                lda #$10
shamrockshake04 jmp shamrockshift       ; send character & exit

shampacklfa     .word $adde
                .byt (shampack-*-1)|bit7
                .asc "SHAMPAC","K"|bit7
xyzzy
shampack        ldy #2
                jsr setup               ; 4 bytes in tos tos+1 n n+1
                stx storex
                lda n+1
                eor #$ff
                pha
                lda n
                eor #$ff
                pha                     ; preserve original "to" address
                lda zi
                pha                     ; elbow room
                ldx #4                  ; bytes per shamrock
                inc tos+1               ; bias +$0100 for bne loop
                jsr rle_read            ; get first byte
                sta zi
                and #$c0                ; mask off hi two bits ( quad )
                eor #$c0                ; make it the wrong quad
                sta n+4                 ; current quad
                lda zi
shampack01      sec                     ; write
                jsr shamrockshake
                jsr rle_read
                sta zi
                bne shampack01          ; ~ might be missing the last byte
shampack02      cpx #4                  ; ~ find out when I write unpack
                beq shampack03
                lda #$3f                ; pad last shamrock with 1 bits
                ora n+4                 ; use current quad to avoid spillover
                sec                     ; write
                jsr shamrockshake
                bne shampack02          ; bra
shampack03      ldx storex
                pla
                sta zi
                sec
                pla
                adc n                   ; this is really subtraction
                sta tos
                pla
                adc n+1
                sta tos+1
                jmp next

;--------------------------------------------------------------
;
;       RLDECODE   ( from to size -- )
;
; run-length decodes beginning at "from" to address "to" until
; "size" bytes have been decoded
rld_read        lda (n+2),y
                inc n+2
                bne rldecode01
                inc n+3
rldecode01      rts

rld_write       sta (n),y
                inc n
                bne rldecode02
                inc n+1
rldecode02      dec tos
                bne rldecode03
                dec tos+1
rldecode03      rts

rldecodelfa     .word $adde
                .byt (rldecode-*-1)|bit7
                .asc "RLDECOD","E"|bit7
rldecode        ldy #2
                jsr setup       ; n = to; n+2 = from; tos = howmany
                stx storex
                inc tos+1       ; bias $0100 for bne loop
rldecode04      jsr rld_read
rldecode05      sta n+4         ; lastbyte
                jsr rld_write
                beq rldecode09
                jsr rld_read
                cmp n+4
                bne rldecode05
                jsr rld_write
                beq rldecode09
                jsr rld_read
                tax
                beq rldecode04
                lda n+4
rldecode07      jsr rld_write
                beq rldecode09
                dex
                bne rldecode07
                beq rldecode04
rldecode09      ldx storex
                jmp pops

;--------------------------------------------------------------
;
;       RLENCODE   ( from to size -- size2 )
;
; run-length encodes beginning at "from" for "size" bytes to address "to"
; returns "size2" as the number of compressed bytes at "to"
;
rle_read        lda (n+2),y
                inc n+2
                bne rlencode01
                inc n+3
rlencode01      dec tos
                bne rlencode02
                dec tos+1
rlencode02      rts

rle_write       sta (n),y
                inc n
                bne rlencode03
                inc n+1
rlencode03      rts

rlencodelfa     .word $adde
                .byt (rlencode-*-1)|bit7
                .asc "RLENCOD","E"|bit7
rlencode        ldy #2
                jsr setup               ; n = to; n+2 = from; tos = howmany
                lda n
                sta n+6
                lda n+1
                sta n+7                 ; copy original to address
                stx storex
                inc tos+1               ; bias $0100 for bne loop
rlencode04      jsr rle_read
                sta n+4                 ; lastbyte
                beq rlencode10
                jsr rle_write
rlencode05      jsr rle_read
                beq rlencode10          ; done
                jsr rle_write
                tax
                eor n+4
                bne rlencode08          ; newchar
                ldx #1
rlencode06      jsr rle_read
                pha
                beq rlencode09          ; done rle
                eor n+4
                bne rlencode07          ; endrle
                pla
                inx
                bne rlencode06          ; rleloop
rlencode07      dex
                txa                     ; overflow
                jsr rle_write
                inx
                beq rlencode04          ; handle overflow - restart
                pla
                tax
                jsr rle_write
rlencode08      stx n+4
                jmp rlencode05          ; next
rlencode09      txa
                jsr rle_write
                pla
rlencode10      jsr rle_write
                ldx storex
                sec
                lda n
                sbc n+6
                sta tos
                lda n+1
                sbc n+7
                sta tos+1
                jmp next

; hex 8000 7c00 decimal 1000 rlencode
; hex 7c00 8000 decimal 1000 rldecode


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu Oct 07, 2010 8:48 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8433
Location: Southern California
Quote:
Garth: That looks like something I might try (cassette audio <-> PC soundcard) if I'm understanding your design properly.

No, actually it was an embedded system with a 6502 controlling it, and no PC. I don't know what the state of PC sound cards was in 1986 anyway-- probably not very impressive, and PCs were also prohibitively large for the application.

Anyway, the 6502 computer had a 65c51 ACIA which did RS-232 (but without the line drivers and receivers). The modulator was just a Schmitt-trigger oscillator (probably with an eighteen-cent op amp-- I'd have to look it up) and the RS-232 state turned a transistor on and off to connect and disconnect an extra shunt resistor in the feedback circuit of the oscillator to toggle between two frequencies without any transients. The resulting triangle wave was recorded on the tape. DC tape bias was plenty good, so I didn't even have to design a quiet bias oscillator, bias trap, etc..

For playback, in the demodulator, each zero crossing discharged a capacitor. If the next one arrived before the capacitor had time to charge up to a certain level, a '1' was locked into a flip-flop, otherwise a '0', and the output of the flip-flop was the recovered RS-232 signal to bring back into the 65c51 ACIA. The low frequency gave a minimum of four cycles in one bit time at 300bps and it was completely reliable there. Even at 600bps it was surprisingly rare that there was an error. The high frequency gave at least 8 cycles in one bit time at 300bps. That data rate was plenty for the application.

I'll try to post a diagram if I can remember where I have it without taking too much time.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu Oct 07, 2010 10:19 pm 
Offline

Joined: Sat Aug 21, 2010 7:52 am
Posts: 231
Location: Arlington VA
GARTHWILSON wrote:
No, actually it was an embedded system with a 6502 controlling it, and no PC. I don't know what the state of PC sound cards was in 1986 anyway-- probably not very impressive, and PCs were also prohibitively large for the application.

Anyway, the 6502 computer had a 65c51 ACIA which did RS-232 (but without the line drivers and receivers). The modulator was just a Schmitt-trigger oscillator (probably with an eighteen-cent op amp-- I'd have to look it up) and the RS-232 state turned a transistor on and off to connect and disconnect an extra shunt resistor in the feedback circuit of the oscillator to toggle between two frequencies without any transients. The resulting triangle wave was recorded on the tape. DC tape bias was plenty good, so I didn't even have to design a quiet bias oscillator, bias trap, etc..

I'm pretty sure I can't use your solution here, because I'd have to somehow bring up the driver software first. Besides, the PET already has tape I/O routines in ROM

The objective here is mass storage for the PET so I can load Forth without going into the monitor and entering it all in hex. Some options:
1) locate my actual C2N datasette and some tapes
2) hardware that simulates a C2N datasette via an audio patch cable to a PC (so-called ".tap" format) and some switches for stop/play/record/ff/rew
3) buy a diskette drive on Ebay
4) Make PETTIL rommable and burn a set of ROM chips (8K available)
5) hardware that simulates a Commodore disk drive

I'll probably go with a combination of solutions #1 and #4, but #2 looks pretty good (no moving parts, no cracked rubber bands, no obsolete media formats)


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu Oct 07, 2010 10:49 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8433
Location: Southern California
Quote:
because I'd have to somehow bring up the driver software first.

The source code to set up and run the 6551 might come to half a page-- very simple. It sounds like your PETIL doesn't have or need a 6551 for this job though.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Fri Oct 08, 2010 2:24 pm 
Offline

Joined: Tue Jul 05, 2005 7:08 pm
Posts: 993
Location: near Heidelberg, Germany
chitselb wrote:
The objective here is mass storage for the PET so I can load Forth without going into the monitor and entering it all in hex.


Ah, now I get the meaning of this thread...

Maybe you want to have a look here, "cbmlink" seems to be an easy to use solution. Personally I am using c2n232 currently, although I have an xs1541 sitting here waiting for me to write a new firmware...

http://www.6502.org/users/andre/petindex/transfer.html

André


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 7 posts ] 

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: