Jump to content
IGNORED

SAMS Support in TurboForth


Willsy

Recommended Posts

This is a cross posting from the TurboForth mailing list. If anyone is interested in joining the mailing list, please go here.

 

Thanks

 

Mark

 

 

As an owner of a SAMS 1MB memory card, I'm very interested in using all that lovely memory in my TI. It would be nice if TurboForth could work with a SAMS card.

 

Well, with a little bit of effort, it can. All it needs is some supporting words to support CRU operations, and we can use them to drive the SAMS board. Perfect.

 

Let's write:

SBO ( cru_base cru_bit -- )
SBZ ( cru_base cru_bit -- )
TB ( cru_base cru_bit -- true|false )

 

Put this code on a block somewhere and you should be good to go:

CODE: SBO
0200 1D00 C054 0644 C314 0644 06C1 D801 8301 0480 020C
8328 ;

CODE: SBZ
0200 1E00 C054 0644 C314 0644 06C1 D801 8301 0480 020C
8328 ;

CODE: TB
0200 1F00 C054 0644 C314 06C1 D801 8301 0480 1302 0714
1001 04D4 020C 8328 ; 

 

Classic99 has SAMS support, so I tried writing a word of memory to standard memory at address >3000, then I paged a bank of SAMS memory in at >3000 - the word was gone, which means the SAMS did "bank the ram in", so the CRU must have worked.

 

Here is the code I used:

$994A $3000 !   - write 994A to >3000
$1E00 0 SBO     - enable SAMS registers
$1400 $4006 !   - map bank 20 of SAMS memory to >3000
$3000 @ $.      - read address >3000 - should be 0, not >994A
$0300 $4006 !   - map bank 3 of SAMS memory to >3400)
$3000 @ $.      - read address >3000 - should be >994A again

 

Notes:

1) In case you are wondering, you can specify any number in hex regardless of BASE by prefixing with a $ symbol

2) $. is similar to U. but prints in hex, regardless of current base.

 

So, with the above words defined, I went ahead and defined a word called SAMS? which returns TRUE if a SAMS card is detected, otherwise it returns FALSE:

: SAMS? ( -- t|f)
$3000 @ $994A $3000 ! $1E00 0 SBO $1400 $4006 !
$3000 @ $994A = IF FALSE ELSE TRUE THEN SWAP $3000 ! ;

This word reads >3000 (so that it can restore it again) then writes >994A to >3000. Then it maps page 20 of SAMS to >3000, so the >994A should vanish. It then does a read of >3000. If we get >994A back, then there was no SAMS card fitted - it's just a standard 32k card, so we push a FALSE, else we push a TRUE.

 

Then we restore the value that we originally read, leaving our boolean on the stack. Neat!

 

Since the entire 8K memory block is free in TurboForth, there is room to map two 4K SAMS blocks into this space. Of course, you can map any of the SAMS' 256 4K banks in. You can even have the same bank at both >2000 and >3000 at the same time!

 

So, all that is really needed is a word to map a bank of SAMS in at >2000, and another bank at >3000. We then have SAMS support:

: @2000 ( bank -- ) $1E00 0 SBO >< $4004 ! $1E00 0 SBZ ;
: @3000 ( bank -- ) $1E00 0 SBO >< $4006 ! $1E00 0 SBZ ;

E.g. 5 @2000 maps SAMS bank 5 into >2000

E.g. 8 @3000 maps SAMS bank 8 into >3000

 

Let's try it: Let's map the standard bank for >2000 (SAMS bank 3) into >2000:

3 @2000

Now, for fun, let's map the *same* bank in at >3000:

3 @3000

Now, write a word of data to >2000:

$FACE $2000 !

Now, let's read >3000. We SHOULD see the data we just wrote to >2000:

$3000 @ $.

 

And voilà! It works!

 

Here is the complete SAMS support code, just place this on an available block:

CODE: SBO
0200 1D00 C054 0644 C314 0644 06C1 D801 8301 0480 020C
8328 ;
CODE: SBZ
0200 1E00 C054 0644 C314 0644 06C1 D801 8301 0480 020C
8328 ;
CODE: TB
0200 1F00 C054 0644 C314 06C1 D801 8301 0480 1302 0714
1001 04D4 020C 8328 ;
: SAMS? ( -- t|f)
$3000 @ $994A $3000 ! $1E00 0 SBO $1400 $4006 !
$3000 @ $994A = IF FALSE ELSE TRUE THEN SWAP $3000 ! ;
: @2000 ( bank -- ) $1E00 0 SBO >< $4004 ! $1E00 0 SBZ ;
: @3000 ( bank -- ) $1E00 0 SBO >< $4006 ! $1E00 0 SBZ ;
.( SAMS support loaded)

If you want this loaded at boot up, just load it from block 1. Instant SAMS support.

 

May the Forth be with you.

 

Mark

Link to comment
Share on other sites

  • 2 years later...
  • 3 weeks later...

This is a cross posting from the TurboForth mailing list. If anyone is interested in joining the mailing list, please go here.

 

Thanks

 

Mark

 

 

As an owner of a SAMS 1MB memory card, I'm very interested in using all that lovely memory in my TI. It would be nice if TurboForth could work with a SAMS card.

 

Well, with a little bit of effort, it can. All it needs is some supporting words to support CRU operations, and we can use them to drive the SAMS board. Perfect.

 

Let's write:

SBO ( cru_base cru_bit -- )
SBZ ( cru_base cru_bit -- )
TB ( cru_base cru_bit -- true|false )
Put this code on a block somewhere and you should be good to go:
CODE: SBO
0200 1D00 C054 0644 C314 0644 06C1 D801 8301 0480 020C
8328 ;

CODE: SBZ
0200 1E00 C054 0644 C314 0644 06C1 D801 8301 0480 020C
8328 ;

CODE: TB
0200 1F00 C054 0644 C314 06C1 D801 8301 0480 1302 0714
1001 04D4 020C 8328 ;
Classic99 has SAMS support, so I tried writing a word of memory to standard memory at address >3000, then I paged a bank of SAMS memory in at >3000 - the word was gone, which means the SAMS did "bank the ram in", so the CRU must have worked.

 

Here is the code I used:

$994A $3000 !   - write 994A to >3000
$1E00 0 SBO     - enable SAMS registers
$1400 $4006 !   - map bank 20 of SAMS memory to >3000
$3000 @ $.      - read address >3000 - should be 0, not >994A
$0300 $4006 !   - map bank 3 of SAMS memory to >3400)
$3000 @ $.      - read address >3000 - should be >994A again
Notes:

1) In case you are wondering, you can specify any number in hex regardless of BASE by prefixing with a $ symbol

2) $. is similar to U. but prints in hex, regardless of current base.

 

So, with the above words defined, I went ahead and defined a word called SAMS? which returns TRUE if a SAMS card is detected, otherwise it returns FALSE:

: SAMS? ( -- t|f)
$3000 @ $994A $3000 ! $1E00 0 SBO $1400 $4006 !
$3000 @ $994A = IF FALSE ELSE TRUE THEN SWAP $3000 ! ;
This word reads >3000 (so that it can restore it again) then writes >994A to >3000. Then it maps page 20 of SAMS to >3000, so the >994A should vanish. It then does a read of >3000. If we get >994A back, then there was no SAMS card fitted - it's just a standard 32k card, so we push a FALSE, else we push a TRUE.

 

Then we restore the value that we originally read, leaving our boolean on the stack. Neat!

 

Since the entire 8K memory block is free in TurboForth, there is room to map two 4K SAMS blocks into this space. Of course, you can map any of the SAMS' 256 4K banks in. You can even have the same bank at both >2000 and >3000 at the same time!

 

So, all that is really needed is a word to map a bank of SAMS in at >2000, and another bank at >3000. We then have SAMS support:

: @2000 ( bank -- ) $1E00 0 SBO >< $4004 ! $1E00 0 SBZ ;
: @3000 ( bank -- ) $1E00 0 SBO >< $4006 ! $1E00 0 SBZ ;
E.g. 5 @2000 maps SAMS bank 5 into >2000

E.g. 8 @3000 maps SAMS bank 8 into >3000

 

Let's try it: Let's map the standard bank for >2000 (SAMS bank 3) into >2000:

3 @2000
Now, for fun, let's map the *same* bank in at >3000:

3 @3000
Now, write a word of data to >2000:

$FACE $2000 !
Now, let's read >3000. We SHOULD see the data we just wrote to >2000:

$3000 @ $.
And voilà! It works!

 

Here is the complete SAMS support code, just place this on an available block:

CODE: SBO
0200 1D00 C054 0644 C314 0644 06C1 D801 8301 0480 020C
8328 ;
CODE: SBZ
0200 1E00 C054 0644 C314 0644 06C1 D801 8301 0480 020C
8328 ;
CODE: TB
0200 1F00 C054 0644 C314 06C1 D801 8301 0480 1302 0714
1001 04D4 020C 8328 ;
: SAMS? ( -- t|f)
$3000 @ $994A $3000 ! $1E00 0 SBO $1400 $4006 !
$3000 @ $994A = IF FALSE ELSE TRUE THEN SWAP $3000 ! ;
: @2000 ( bank -- ) $1E00 0 SBO >< $4004 ! $1E00 0 SBZ ;
: @3000 ( bank -- ) $1E00 0 SBO >< $4006 ! $1E00 0 SBZ ;
.( SAMS support loaded)
If you want this loaded at boot up, just load it from block 1. Instant SAMS support.

 

May the Forth be with you.

 

Mark

 

Hey Willsy -

 

This looks pretty simple and powerful. Can you point me to an explanation of the CRU and banking operations and how you are using them? In Faire spirit, I found my SAMS card and want to do some 'playing' on Saturday ;) In the meantime I'm gonna take your hex code and 'disassemble' it for easier viewing. :)

(sorry for the big quote - this newest AA editor makes it tough to edit anything)

Edited by InsaneMultitasker
Link to comment
Share on other sites

Hi Tim

 

Well version 1.2 (which will be available from Bob at the fair, and is already built into classic 99) had the much more powerful word >MAP ("to mapper") which maps 4k chunks into any area.

 

The code you quoted above is older code for v1.0 - it won't work in v1.2 because the stack directions are reversed in 1.2

 

If you're interested I can post a version that will work in v1.2 that will use the forth assembler. You just type the machine code right in and is ready!

Link to comment
Share on other sites

Okay, here's some code that I just knocked up for TFV1.2. I had to look up the SBO and SBZ instructions - couldn't remember how to use them - I don't use them very often!

 

So, this code:

 

  • Saves the address in R12 (it's used by the TF inner interpreter)
  • gets the bit to set from the stack to r1
  • restricts it to a value from 0 to >FF
  • adds the bit number to $1D00 (SBO) or 1E00 (SBZ)

You then end up with an op-code in R2 in the form of >1Dnn (SBO) or >1Enn (SBZ)

 

Where nn is the bit number.

 

This opcode is then executed using the X instruction.

 

To use this code, all you have to do is make sure the TFV1.2 disk is in drive 1 (you can download it from turboforth.net), start turboforth, and let it do it's thang.

 

When you get the cursor up, type:

 

9 LOAD

 

to load the assembler. (The assembler is compiled live from raw Forth source code).

 

You can then just type in the assembler code. Note that each line of assembler code is compiled as soon as you hit enter, just like Forth.

 

Here's the code:

 

 

ASM: SBO ( cru bit -- )
    r12 r11 mov,    \ save address of NEXT
    *sp+ r1 mov,    \ pop bit from stack to r1
    r1 $FF andi,    \ clip to lower 8 bits
    *sp+ r12 mov,   \ pop cru base to r12
    r2 $1D00 li,    \ opcode of SBO instruction
    r1 r2 a,        \ add bit number to opcode
    r2 x,           \ execute the SBO instruction
    r11 r12 mov,    \ restore address of next
;asm

ASM: SBZ ( cru bit -- )
    r12 r11 mov,    \ save address of NEXT
    *sp+ r1 mov,    \ pop bit from stack to r1
    r1 $FF andi,    \ clip to lower 8 bits
    *sp+ r12 mov,   \ pop cru base to r12
    r2 $1E00 li,    \ opcode of SBZ instruction
    r1 r2 a,        \ add bit number to opcode
    r2 x,           \ execute the SBZ instruction
    r11 r12 mov,    \ restore address of next
;asm

 

To test: (note that TF V1.2 sets up SAMS bank 0 at >2000 and bank 1 at >3000 (IIRC).

 

So, bank 0 is already mapped to >2000, so, lets see what's there: (also: open the classic99 debugger and set it's CPU tab address to >2000)

 

$2000 @ $.

 

(in my system (classic99) I see 7EE4.

 

Now, let's write >994A to >2000:

$994A $2000 !

 

Now we need to enable access to the SAMS memory mapper registers:

 

$1E00 0 SBO

 

Now we can change the bank that is mapped to >2000:

 

1 $4004 !

 

At this point, the memory in the CPU window of the debugger should change.

 

Verify it:

 

$2000 @ $.

 

Now, switch it back:

 

0 $4004 !

 

Et voila.

 

Once you have the above two words defined, you can add a layer of abstraction to work directly with the SAMS and map banks into >2000 and >3000

 

 

: @2000 ( bank -- ) $1E00 0 SBO >< $4004 ! $1E00 0 SBZ ;
: @3000 ( bank -- ) $1E00 0 SBO >< $4006 ! $1E00 0 SBZ ;

 

Have fun ;-)

Link to comment
Share on other sites

Seems I was talking shite about which banks are set up as active in TF:

 

 

;[ initialise SAMS card if fitted
        li r12,>1e00                ; sams CRU base
        sbo 0                       ; enable access to mapper registers
        sbz 1                       ; disable mapping while we set it up
        li r0,>4004                 ; register for >2000
        li r1,>f8f8                 ; map bank >f8 into >2000
        mov r1,*r0+                 ; do it
        li r1,>f9f9                 ; map bank >f9...
        mov r1,*r0+                 ; ...into >3000
    ; now set up the banks for high memory...
        li r0,>4014                 ; register address
        li r1,>fafa                 ; register value
        li r2,6                     ; loop count
sams    mov r1,*r0+                 ; write to the register
        ai r1,>0101                 ; next register value
        dec r2                      ; finished?
        jne sams                    ; loop if not
        sbo 1                       ; enable mapping
        sbz 0                       ; lock the mapper registers

 

So, banks F8 and F9 are mapped to >2000 and >3000, and banks >FA to >FF are mapped to >A000 to >FFFF.

 

I remember now. There was a method to my madness. It means a programmer can use banks 0 to >F9 for whatever he wants, and the "32k" is in banks >FA to >FF.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...