Jump to content
IGNORED

RAM under OS in XL/XE machines


RobS

Recommended Posts

After my last postings on the Mystery of Ultima V for the Atari 8-bit a few years ago (http://atariage.com/forums/topic/198752-the-mystery-of-ultima-v-for-the-atari-8-bit/page-4?hl=%2Bmystery+%2Bof+%2Bultima&do=findComment&comment=3970279) I got to thinking about an Ultima-style game (which I had started years ago, but never finished) using character graphics. I managed to work out a system for that (which I will post more on later) but have started to run into the usual memory limit issues.

 

There are many articles on how to use the extra 64k in a 130xe, but my target platform is a 64K XL/XE machine. The only real examples of code is the "OS to RAM" copy routine that moves the entire OS to RAM and runs it there. I want to use the RAM space under the OS, but info for how to do that is really scarce. I came up with a routine that does work, but every few times I run it, it locks the machine. Note I am only swapping out the 16k block above Basic ROM (49152), so that *should* be unaffected. Also my tests were all with small amounts of memory, less than 1k and run from a basic call.

 

I was hoping someone out there with more experience (or ANY experience) with manipulating the RAM under the OS could possibly help me find out how to make this work all the time.

 

Here is the code, which is a simple memory copy routine. Note the OS switches are REM'd out right now and a few other things aren't used. Also this is not a bid to make the fastest/most efficient copy routine, just the most bulletproof and reliable.

 

I have also tried this routine with switching the OS off on every byte read and written. The code below just does it once at the start (off) then back on again after the entire move has been accomplished. Either way does the same thing: if I run it several times, at some point it locks the computer.

 

Many thanks to you all for the help and the great articles that have gotten me this far!

 

MEMMOVEFROM = $70
MEMMOVETO = $72
MEMMOVELEN = $74
PORTB = $D301
PORTBSAVE = $76
; turns on/off OS area once - at beginning then at end
; reverse direction ie high to low addresses (from end to start going down memory)
org 36000
OPT h-f+ ; not bootable, one segment
;OPT h+f+ ; bootable, one segment
;Passed Params Below
PLA
PLA
STA MEMMOVEFROM+1
PLA
STA MEMMOVEFROM
PLA
STA MEMMOVETO+1
PLA
STA MEMMOVETO
PLA
STA MEMMOVELEN+1
PLA
STA MEMMOVELEN
; LDA #$FE
; AND $D301 ; CLR BIT 0 TO
; STA $D301 ; BANK TO OS RAM
;Start here for stand-alone routine
X4
LDY #$00
LDX MEMMOVELEN ; use X-reg as counter
CPX #0 ; if low byte of length=0 then exit, we had exactly a multiple of 256 bytes in that case and no leftovers
BEQ EXIT
X3
LDA (MEMMOVEFROM),Y
STA (MEMMOVETO),Y
INY
DEX ; we use X and count down so we can not do a CPX and because we need to use Y to go from byte #0 up
; if we use Y as the counter also, more logic would be needed because we LDA/STA from Y at the top of the loop
; then we inc or dec the counter, and so we be off 1 byte doing it that way
; since the counter (X) is the total # (lets say 4 bytes as an example) of bytes to move
; but we need to move bytes #0-3 actual, not #1-4
BNE X3
LDY #$00
LDX MEMMOVELEN+1 ; use X-reg as counter for total # of 256-byte pages to do
CPX #00 ; is high byte zero (ie we have less than 256 bytes to move)?
BEQ X4 ; go to do just the <256 bytes
X2
LDA (MEMMOVEFROM),Y
STA (MEMMOVETO),Y
INY
BNE X2 ; in this case, we use Y as the "inner" loop counter, since we completely wrap a full 256 bytes
; around, thus why we start with Y at 0. When it goes from 255 back to 0, that triggers the BNE fail
; and we have done bytes #0-255
INC MEMMOVEFROM+1
INC MEMMOVETO+1
DEX
BNE X2
; LDA #$01
; ORA $D301
; STA $D301 ; BACK TO ROM
EXIT
RTS
Link to comment
Share on other sites

You need to account for interrupts firing while the OS ROM is switched out and replaced with RAM. You can either turn all interrupts off while accessing the RAM, or have 'wrapper' code which re-enables the OS interrupt handlers for the duration of the interrupt and then enables the RAM again.

 

This stuff has been discussed quite a few times, so maybe have a read through some of the existing topics:

 

The first one is a question I posted when I knew basically as much as you did on the subject, and it touches on the interrupt handler code.
  • Like 2
Link to comment
Share on other sites

FlashJazzCat, thank you, I had a feeling it would be something like that. I can get it to work with the following:

 

RPT1
LDA #0
STA $022F ;TURN OFF ANTIC
STA $D40E
STA $D20E ;DISABLE INTRPTS
SEI ;MAKE SURE NO
INC PORTB
......(memcopy code loop here)...
DEC PORTB
CLC
LDA #$FF
STA $D40E
LDA #$F7
STA $D20E ; TURN ON NMI,IRQ
LDA #$22
STA $022F
CLI
Which is as much as I can find on the subject. It works, but the screen freaks out during it. The good news is, I ran it in a loop 55 consecutive times (moving about 200 bytes from OSRAM to screenmem) without crashing, so it seems to "work" but I would love to know how (or even if its possible) to perform this without the screen going to a jumble every time it is invoked. Maybe the code above isnt quite right yet? And I suppose its impossible to do it with the screen staying on in any way.

 

Also it's an honor to meet you. Your work on the GUI is impressive and inspiring. I'm afraid this might be at the limit of my capabilities. I am just getting to the level of being able to handle and understand DLI and VBIs, and managed to get some file handling routines working in pure ASM (open, file get/put, input string). I wrote a VBI "processor" to handle animating the tiles on an automatic basis, and thats about as sophisticated as I am right now.

Link to comment
Share on other sites

$022F (SDMCTL) is an OS shadow variable for the hardware register $D400 (DMACTL). It doesn't take effect until the OS vertical blank handler runs, which you're disabling immediately. This means that the majority of the time DMACTL is not getting updated and thus playfield and display list DMA are not actually getting turned off.

 

The character set is also at $E000 in the OS ROM, so if a text screen is currently being displayed its font will be garbled while the OS is swapped out. This is only a visual glitch, but if you want to avoid it you need to copy $E000-E3FF to RAM and temporarily switch the character set over to that copy while banking out the OS ROM. If you do this, it isn't necessary to disable the display as everything that ANTIC will need to run it will still be valid during the copy.

  • Like 5
Link to comment
Share on other sites

It works, but the screen freaks out during it. The good news is, I ran it in a loop 55 consecutive times (moving about 200 bytes from OSRAM to screenmem) without crashing, so it seems to "work" but I would love to know how (or even if its possible) to perform this without the screen going to a jumble every time it is invoked. Maybe the code above isnt quite right yet? And I suppose its impossible to do it with the screen staying on in any way.

If you just want to use the RAM under the OS to store data and/or code and have easy access to it without worrying about the display, you should probably consider the interrupt and OS call 'wrappers' I mentioned before. It's the technique used by programs like Turbo BASIC XL, The Last Word, and SpartaDOS X (when running in 'OSRAM'). Basically, you leave the ROM turned off but point the IRQ and NMI vectors at the top of memory to code which enables the OS ROM, services the interrupt, then turns the OS back off again. Likewise - if you wanted to call the CIO, for example - you'd call code which turns on the OS, calls CIOV, then turns the ROM off again. Your mainline code then doesn't really have to concern itself at all with the mechanics of the OS being turned off most of the time, and you can just treat the RAM under the OS as regular memory. If you need some skeleton code which sets this up, let me know, since I have ready-to-run library code here.

 

Also it's an honor to meet you. Your work on the GUI is impressive and inspiring. I'm afraid this might be at the limit of my capabilities. I am just getting to the level of being able to handle and understand DLI and VBIs, and managed to get some file handling routines working in pure ASM (open, file get/put, input string). I wrote a VBI "processor" to handle animating the tiles on an automatic basis, and thats about as sophisticated as I am right now.

Thanks for the kind comments. :) One area in which the GOS project is less impressive is that of project management, since the original concept (a GUI shell) was subject to so much feature creep (read: multitasking graphical OS) that it's now barely manageable, but I'm glad it proved motivational in some way. :)

 

As for one's 'limits': I still remember the time when a sequence of a dozen assembly language instructions called from BASIC via USR seemed a major achievement, and you can see from the post I linked earlier that a decade ago (some ten years after I wrote my first large machine code application) I still had no idea how to go about using the Shadow RAM. And six or seven years later, I felt I learned so much from the GOS and various firmware projects that my earlier stuff seems in desperate need of revision. So - as with most things - everyone has to start from the initial point of knowing very little, learning can take a long time, and there is no arbitrary limit to what can be achieved. :)

 

Not really good practice to use INC/DEC PORTB - you can't be guaranteed the state on entry and you could inadvertantly change the state of 130XE type banks at $4000.

True, unless you already know the state on entry. I think TBXL uses INC/DEC PORTB either side of the NMI/IRQ and CIO handlers.

Edited by flashjazzcat
  • Like 4
Link to comment
Share on other sites

If you just want to use the RAM under the OS to store data and/or code and have easy access to it without worrying about the display, you should probably consider the interrupt and OS call 'wrappers' I mentioned before. It's the technique used by programs like Turbo BASIC XL, The Last Word, and SpartaDOS X (when running in 'OSRAM'). Basically, you leave the ROM turned off but point the IRQ and NMI vectors at the top of memory to code which enables the OS ROM, services the interrupt, then turns the OS back off again. Likewise - if you wanted to call the CIO, for example - you'd call code which turns on the OS, calls CIOV, then turns the ROM off again. Your mainline code then doesn't really have to concern itself at all with the mechanics of the OS being turned off most of the time, and you can just treat the RAM under the OS as regular memory. If you need some skeleton code which sets this up, let me know, since I have ready-to-run library code here.

 

 

Thanks for the kind comments. :) One area in which the GOS project is less impressive is that of project management, since the original concept (a GUI shell) was subject to so much feature creep (read: multitasking graphical OS) that it's now barely manageable, but I'm glad it proved motivational in some way. :)

 

As for one's 'limits': I still remember the time when a sequence of a dozen assembly language instructions called from BASIC via USR seemed a major achievement, and you can see from the post I linked earlier that a decade ago (some ten years after I wrote my first large machine code application) I still had no idea how to go about using the Shadow RAM. And six or seven years later, I felt I learned so much from the GOS and various firmware projects that my earlier stuff seems in desperate need of revision. So - as with most things - everyone has to start from the initial point of knowing very little, learning can take a long time, and there is no arbitrary limit to what can be achieved. :)

 

 

True, unless you already know the state on entry. I think TBXL uses INC/DEC PORTB either side of the NMI/IRQ and CIO handlers.

 

Well I have made progress and it *almost* works in all cases, but still fails in certain circumstances. I will report in more detail later, but it appears that it will not work under TBXL, and I think there were some articles on that about TBXL co-opting some interrupts and such. Don't know if that can be made to work under TBXL, but it works perfectly under Atari Basic and in direct ML programs, so it's usable. Trying some combos and permutations now (compiled basic, etc). At least I got ML routines for file read/write working, and the VBI that animates everything works too. I am hoping to use TBXL or ABAS to run the "loader" program that sets up the memory spaces and does all the intro stuff for the game (splash screen, intro, menu/option selections, etc) then BRUN the final assembly main program. If I am good enough to be able to make all this work that is.

 

I was able to successfully write to the entire 16k block (minus the D000-D7FF area) of the shadow ram and read it back out to screen memory (so I could easily visually verify), so that is a BIG plus already. 14k or so of extra ram is always a good thing. I will post code samples for everyone to critique or use when I have things more refined and verified and comments put in.

Link to comment
Share on other sites

Errrmmm, TB XL itself uses RAM under the OS ROM, almost all available RAM under the OS. So if your program requires RAM under the OS it will not work with TB XL (that's why it is named XL, since XL's do have RAM under the OS). There are however versions named TB 400/800 or Frost Basic, but afaik, these versions of TB are merged/appended to DOS 2.0...

 

Afair, the TB 400/800 versions do not include all TB statements, think BRUN or BLOAD or similar are missing...

  • Like 1
Link to comment
Share on other sites

Errrmmm, TB XL itself uses RAM under the OS ROM, almost all available RAM under the OS. So if your program requires RAM under the OS it will not work with TB XL (that's why it is named XL, since XL's do have RAM under the OS). There are however versions named TB 400/800 or Frost Basic, but afaik, these versions of TB are merged/appended to DOS 2.0...

 

Afair, the TB 400/800 versions do not include all TB statements, think BRUN or BLOAD or similar are missing...

Thank you, yes I think I recall that now. I am very very close now to having this working. In fact, it does work except when I put it into my game, and I think I know why but I dont know enough about the ins and outs of enabling and disabling the OS (interrupts, Antic, etc) to know what is the best way to fix it. Here is what I have so far:

 

1. I reverted my main game from TBXL to Atari Basic (ie converted back any TBXL specific commands). This would eventually become the "loader" program

2. made an ASM pure ML program to be run from the "loader"

3. upon executing the test ML game, it waits for a keypress, then copies some mem to $e000 under the ROM. press another key and it copies that data back to screen mem (so we can visually verify it)

 

this works perfectly so far to this point, however I am running a custom DL with a DLI that changes the char set and colors twice on screen, using the "chain" DLI method (or whatever it is called where one DLI sets up the address for the subsequent one)

 

What I get is the mem move working fine, but my display goes wonky. the DL/DLI is fine in the handoff from the compiled basic loader, but hitting the first key press it loses the DLI function (so the fonts and colors dont change out), then with the next key press it comes back, then the final it goes out again.

 

I'm thinking it is something like when I disable the OS and interrupts/antic, it stops somewhere in the middle (potentially) of the DLI then when it is turned back on, its out of sync, or something like that? Or maybe since I am using a DLI, I have to forcibly re-establish the DLI vector each time I turn the OS back on.

 

Trying to avoid as much screen flicker/flashing as possible in the OS/interrupts switch, but it might not be possible if the above is true.

 

I thought I had it for a minute. I was looking over the sample code I had used (which was from the "run your OS from RAM" program) and it set the NIMEN a certain way when turning the OS back on, so I instead set it to the same value that I used to set up my DLI ($c0) but that didnt fix it. The display list itself stays put, so the actual format of the screen doesnt change throughout.

 

How would one preserve a DLI when disabling the OS and interrupts and then re-enabling them? Thanks for all the help and suggestions, I have learned a lot even in the last couple of weeks about this stuff.

Link to comment
Share on other sites

Second paragraph, post #4 outlines why your screen is

garbled but instead you are still using 0xE000-0xE3FF

for your own data instead of the copied to that ram under

rom region character set. Correct?

 

Copy the character set under ram first with all interrupts

off. Before anything else has started. Then avoid using

that region for your data.

 

Alternate is to move that rom data to somewhere else and

point the machine to use it there if you need those four

pages of 0xE000 region ram under rom for your data. Read

756 in Mapping the Atari please.

 

Confusion exists only because you are not telling the

whole story so type liberally and get the concepts across

in order. New character set is where? You are pointing the

machine at it? In VBI or DLI?

 

You need to display the code you are using if you want

real help as to what is wrong with it. Much advice has

possibly been ignored since we last saw what you are

actually running for code NOW. Reading the code would

answer all the questions so far...

 

Don't worry so much about not getting it right first

time out. None of us are bragging about ours because it

just doesn't happen until you know this stuff solid.

And that only happens with many stubbed toes and

humbling face first pratfalls.

Link to comment
Share on other sites

  • 2 months later...

Second paragraph, post #4 outlines why your screen is

garbled but instead you are still using 0xE000-0xE3FF

for your own data instead of the copied to that ram under

rom region character set. Correct?

 

Copy the character set under ram first with all interrupts

off. Before anything else has started. Then avoid using

that region for your data.

 

Alternate is to move that rom data to somewhere else and

point the machine to use it there if you need those four

pages of 0xE000 region ram under rom for your data. Read

756 in Mapping the Atari please.

 

Confusion exists only because you are not telling the

whole story so type liberally and get the concepts across

in order. New character set is where? You are pointing the

machine at it? In VBI or DLI?

 

You need to display the code you are using if you want

real help as to what is wrong with it. Much advice has

possibly been ignored since we last saw what you are

actually running for code NOW. Reading the code would

answer all the questions so far...

 

Don't worry so much about not getting it right first

time out. None of us are bragging about ours because it

just doesn't happen until you know this stuff solid.

And that only happens with many stubbed toes and

humbling face first pratfalls.

I think I got it! I have to do more testing, and validate various blocks in upper mem ($c0, $c1, etc) but a quick test so far seems to work. What I didnt know I had to do was to re-establish the initial vector for the DLI before turning everything back on. I have a "chained" DLI that changes the character set twice - so it flips from a 0 screen to a mode 4, then back to 0 for the bottom part of the screen. This is what was getting messed up when I tried to access the ram under the rom. For my test, I loaded an alternate character set (that represents the game tiles for Towns) into mem, then copied it to $c0 under the rom. then, after I press a key, it copies it back from $c0 to the location of the tiles character set and bam! the tiles on screen changed, the DL and DLI are still intact, and it seems to be working. Thank you all for the suggestions and advice, it helped me think around the problem a bit and suss out what I needed to do. If anyone is interested, I could post my code, since it should work generically enough to drop in to most any program and work.

  • Like 2
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...