Using overlay memory: how, tips and possibility for direct save/load

Since we do not have native C compilers on the Oric, this forum will be mostly be used by people using CC65 or the OSDK. But any general C related post will be welcome !
User avatar
xahmol
Flight Lieutenant
Posts: 437
Joined: Sun Jun 28, 2020 7:32 pm
Location: Utrecht, The Netherlands
Contact:

Using overlay memory: how, tips and possibility for direct save/load

Post by xahmol »

Triggered by this article on OSDK.org on using overlay RAM memory I am investigating how to make best use of this overlay RAM memory, as an extra 16KiB of RAM is just to juicy to ignore.

Question 1: Possible to use it by switching on only when needed and then switching off again?

The arcticle describes how to switch off overlay ROM and that looks very clear and easy. However, the downside of not being able to use ROM kernal routines anymore would be an issue for me, as I program in C using CC65 and the CC65 libs most definitely are using those ROM routines.
However, with programming on the Commodore 128 (and to lesser extent the Commodore Plus/4) I have reference on how to do a similar thing there, and that is basically switching the correct bank over overlay area in, do stuff that you want there, and switch back to the original memory layout.

So would a similar think be possible on the Oric as well by doing it like this?
- stop IRQ
- enable overlay RAM
- do the PEEKing, POKEing and memory copying
- disable overlay RAM
- enable IRQ
- return

Or do I miss some other caveat here now?

If possible, it would be fairly easy to create POKE_OVERLAY, PEEK_OVERLAY and MEMCPY_OVERLAY routines in assembly to use with C wrapper functions, which would directly enable to use overlay RAM for data storage, swap storage and even overlay code storage in CC65.

Question 2: Is there any possibility for direct SEDORIC LOADs to and SAVEs from overlay RAM memory?

Ideally, I would like to directly load and save data to and from the overlay memory RAM area. But as the SEDORIC calls to make for those SAVEs and LOADs are residing in that same overlay memory area, my assessment so far is that that alas is not possible, at least not without yourselves completely rewriting own routines to replace the SEDORIC ROM ones, a task I lack the knowledge to do, if even possible.
Am I correct in this? Or are there possibilities to do this?
(on the Commodore machines, this is fairly easy to do as by default ROM kernal calls exits supporting disk load/save, that also fully support overlay and banked memory areas. To begin with, the most important kernal calls on Commodore machines are reachable via jump pointers in the always visible $FFxx memory area).

Background
After doing some Commodore projects I am now preparing to return for some Oric coding. Have my build chain up and running again (on different machine, and now Linux based using WSL2/Ubuntu under Windows 11).
I am investigating the viability of porting my most recent Commodore project, a screen editor. See the original C128 80 column version and the port I just finished for the Commodore Plus/4.
Main premise of this utility is the ability to use rather large screen maps that are a multiple of the visible screen. The C128 version can use up to 30 KiB as screenmap, the Plus/4 version 15 KiB. For the Oric I need half the memory as on the Commodores as characters and attributes are not two seperate memory areas (obviously, the lack of seperate attribute space will complicate the rest of the program and limit some possibilities, but that is how it is on the Oric). But still, it would be nice to have at least 7-8 KiB memory available for screen map data, next to having room for swap memory for my windowing system, swap memory for some screen operation stuff and memory to swap out a redefined character set to be able to return to the default charset and back to the redefined one.
For all this, of course the ablity to use that 16 KiB overlay memory RAM area would be ideal. But especially for that 7-8 KiB screenmap space, only if direct load and save to that area is possible to avoid need to reserve that 7-8 KiB in normal RAM at least as loading temporary buffer area.

Appreciate your ideas and tips!
User avatar
Dbug
Site Admin
Posts: 4444
Joined: Fri Jan 06, 2006 10:00 pm
Location: Oslo, Norway
Contact:

Re: Using overlay memory: how, tips and possibility for direct save/load

Post by Dbug »

xahmol wrote: Tue May 31, 2022 8:36 am Triggered by this article on OSDK.org on using overlay RAM memory I am investigating how to make best use of this overlay RAM memory, as an extra 16KiB of RAM is just to juicy to ignore.

Question 1: Possible to use it by switching on only when needed and then switching off again?
So would a similar think be possible on the Oric as well by doing it like this?
(...)
Or do I miss some other caveat here now?

If possible, it would be fairly easy to create POKE_OVERLAY, PEEK_OVERLAY and MEMCPY_OVERLAY routines in assembly to use with C wrapper functions, which would directly enable to use overlay RAM for data storage, swap storage and even overlay code storage in CC65.
Indeed, switching between ROM and RAM is just one byte to change in page 3, and yes the issues is code that uses the ROM, including IRQs.

Assuming your code does not rely on anything from the C000-FFFF ROM, there are two ways to deal with the IRQ issue:
  1. Manually disable or enable IRQs using combinations of SEI/CLI/PLP/PHP around the code you want to run
  2. Have the IRQ vector in the overlay ram point to some dummy IRQ handler that just does RTI


xahmol wrote: Tue May 31, 2022 8:36 am Question 2: Is there any possibility for direct SEDORIC LOADs to and SAVEs from overlay RAM memory?

Ideally, I would like to directly load and save data to and from the overlay memory RAM area. But as the SEDORIC calls to make for those SAVEs and LOADs are residing in that same overlay memory area, my assessment so far is that that alas is not possible, at least not without yourselves completely rewriting own routines to replace the SEDORIC ROM ones, a task I lack the knowledge to do, if even possible.
Am I correct in this? Or are there possibilities to do this?
That's a complicated question, in theory Sedoric is BANK based, so it's possible to restrict Sedoric to only some parts of the overlay, but I've never done it myself.

This whole thing is why I made the Floppy Builder in first place, to allow us to have a minimalistic loader to get almost full access to the overlay ram, but it's not ideal for tools because the format is not standard which means you would need some additional tool to extract the data to use it somewhere else.
User avatar
xahmol
Flight Lieutenant
Posts: 437
Joined: Sun Jun 28, 2020 7:32 pm
Location: Utrecht, The Netherlands
Contact:

Re: Using overlay memory: how, tips and possibility for direct save/load

Post by xahmol »

Thanks Dbug, confirms what I thought to understand. So will start experimenting with that.

On the Sedoric banking topic: good to know it probably is possible then, but as said would not know where to begin myself (nor do I have any hope of being able any time soon). So unless maybe Iss reworks his SEDORIC routines in his OpenOricLibrary that I use now for SEDORIC stuff to enable banking, I will for now alas consider direct save/load a no go.

Will then have to do some puzzling if I can squeeze a program I started to design using 128 KiB that I squeezed in 64 KiB on the Plus/4 to the 48 KiB of the Atmos, with possibly some use of the overlay RAM area for swapping data and code.
User avatar
Dbug
Site Admin
Posts: 4444
Joined: Fri Jan 06, 2006 10:00 pm
Location: Oslo, Norway
Contact:

Re: Using overlay memory: how, tips and possibility for direct save/load

Post by Dbug »

Technically, an alternative could be to have a Sedoric compatible floppy, with pre-saved "slots" for whatever your tool does (not sure if it's fixed size or not), which if they are stored continuously on the floppy could be then simply accessed by some read/write sectors without requiring Sedoric at all (as long as you know the position of the first sector.
User avatar
xahmol
Flight Lieutenant
Posts: 437
Joined: Sun Jun 28, 2020 7:32 pm
Location: Utrecht, The Netherlands
Contact:

Re: Using overlay memory: how, tips and possibility for direct save/load

Post by xahmol »

Makes sense, and I think would be viable. Would then need to look into what your floppy builder tool is doing. But my first guestimate is that that is a more complex undertaking for me then I am presently prepared to do. But will keep it in mind as potential future improvement, especially as the other approach will really give me lack of memory issues.

Thanks for thinking along!
User avatar
Dbug
Site Admin
Posts: 4444
Joined: Fri Jan 06, 2006 10:00 pm
Location: Oslo, Norway
Contact:

Re: Using overlay memory: how, tips and possibility for direct save/load

Post by Dbug »

I was more thinking of testing with Tap2DSK, like adding a bunch of empty tap files of the right size to reserve spots on the disk.
Should probably check how Tap2DSK allocates the sectors, but they are probably consecutive on disk.
User avatar
Chema
Game master
Posts: 3014
Joined: Tue Jan 17, 2006 10:55 am
Location: Gijón, SPAIN
Contact:

Re: Using overlay memory: how, tips and possibility for direct save/load

Post by Chema »

Well, Dbug already answered and provided most (all?) of the relevant information.

I have used overlay ram several times and you can check the source code. As you are restricted to C, you have the problem with library functions that use the ROM routines.

That is what we faced in pinforic and our solution was to patch the libraries and add code to switch the overlay off and on when necessary: switch_to_ram and switch_to_rom defined in header.s inside the lib16 folder. In the end, I think Fabrice came up with only two patched functions (getchar & putchar, redefined in header.s), and patched only a few library files that used the originals. I am not sure if he did anything else, but that was the general idea.

About using sedoric, that would be indeed trickier. Sedoric basically loads in overlay ram, so I doubt you can do much without becoming mad. What can be done for sure, is loading chunks of data using sector-based reads. I've done that in Space:1999 and 1337. Just create a file with your data and store it the first one when creating the disk. If I recall correctly, its data will start at sector 100 (after Sedoric stuff). I usually assemble everything that is to go there separately, creating a tap file which is added to the final disk by setting OSDKDISK= <tap_with_data> <taps with program>
User avatar
xahmol
Flight Lieutenant
Posts: 437
Joined: Sun Jun 28, 2020 7:32 pm
Location: Utrecht, The Netherlands
Contact:

Re: Using overlay memory: how, tips and possibility for direct save/load

Post by xahmol »

Thanks Chema.
Think I will have more work than you in C as I use CC65 and not the standard OSDK C compiler you probably do. I presently use the CC65 conio.h lib quite extensively and that one almost for certain is making lots of kernal calls.
Of course that is certainly solvable by reverting to more OSDK C like routines for screen handling, but that also sacrifices code portability so comes with a price.

But I think for what I have in mind I probably can manage with just needing to read overlay RAM with a PEEK like function, write to it with a POKE like function and copy memory to and from it with a memcpy like function. I actually already did write similar functions to use banking on the C128, which CC65 also does not support out of the box. Difference only being that on the C128, its MMU (memory management unit) takes care of things like IRQ going to the right place, so no need to disable interrupts there.

So think I will start with a PoC with at least these functions in assembly and avoiding any ROM call or C lib call in those functions. Should be doable, unless I miss something in how the Atmos behaves.
If I have that, at least I can use the memory space for:
- using the CC65 overlay system from memory instead of loading from disk by swapping the CC65 designated code overlay area in and out of that upper 16 KB area. Actually also now do that in my C128 version.
In that way, you have no need to run the code from the C000-FFFF area, you designate some area under the textscreen area as code overlay area and copy the code in from the upper 16KB on demand. CC65 supports the proper linking and addressing for that (sorry for the Wayback Machine link, but although the original is offline, this was still the best tutorial on CC65 overlays I could find),
Price is of course that there is always a part f code that is residing twice in active memory, namely both the CC65 overlay area and the upper 16 KB area, but that is certainly already way better than not using that 16 KiB at all.
- Swap memory for screen manipulation functions, unless it proves to be too slow. Probably fast enough though as I am not building an action game here
- Swap memory for custom character sets
- Maybe (but that is stretching) also the undo/redo implementation I made on the C128 using the 64 KB VDC video RAM memory if available (most machines have 16 KB, so made that part optional)

Sedoric direct sector access routines I still envision as a maybe for later. Think my skills are not mature yet to venture into that.
User avatar
xahmol
Flight Lieutenant
Posts: 437
Joined: Sun Jun 28, 2020 7:32 pm
Location: Utrecht, The Netherlands
Contact:

Re: Using overlay memory: how, tips and possibility for direct save/load

Post by xahmol »

By the way, Chema, your code for doing this confirms what I thought that would work my self, so thanks, very usable:

Code: Select all

_machine_type   .byt 0
 
switch_to_rom
        php
        pha
        bit _machine_type
        bvc jasmin_switch_to_rom
        lda #$86
        sta $0314
        lda #7
        sta $032F
        pla
        plp
        rts
jasmin_switch_to_rom
        lda #0
        sta $03fb
        lda #0
        sta $03fa
        pla
        plp
        rts
 
switch_to_ram
        php
        pha
        bit _machine_type
        bvc jasmin_switch_to_ram
        lda #$84
        sta $0314
        lda #0
        sta $032F
        pla
        plp
        rts
jasmin_switch_to_ram
        lda #1
        sta $03fa
        pla
        plp
        rts
User avatar
xahmol
Flight Lieutenant
Posts: 437
Joined: Sun Jun 28, 2020 7:32 pm
Location: Utrecht, The Netherlands
Contact:

Re: Using overlay memory: how, tips and possibility for direct save/load

Post by xahmol »

OK, seem to have working code now with these routines:

Code: Select all

; ======================================================================
; Overlay memory area routines code
; ======================================================================

switch_to_rom:
    ; Enable bits 1 and 7 of $0314 to enable overlay ROM
    ; Bit 1: Enables the internal BASIC ROM when set to one
    ; Bit 7: Enables the disk controller boot EPROM
    lda #$7F                            ; Load $7F for #011111111 mask to enable bit 1 and disable bit 7
    sta $0314
    rts

    ; Restore state after re-enablling overlay ROM
    cli                                 ; Re-enable IRQ
    rts
 
switch_to_ram:
    ; Set safe state to disable overlay ROM
    sei                                 ; Stop IRQ

    ; Disable bits 1 and 7 of $0314 to disable overlay ROM
    ; Bit 1: Disables the internal BASIC ROM when set to zero
    ; Bit 7: Disables the disk controller boot EPROM
    lda #$FD                            ; Load $FD for #%11111101 mask to disable bit 1 and enable bit 7
    sta $0314
    rts

; Overlay memory areas core routines

; ------------------------------------------------------------------------------------------
_POKEO_core:
; Function to poke to a memory position with upper 16KiB overlay RAM area enabled
; Input:	ORIC_addrh and ORIC_addrl:	high and low byte of address to poke
;			ORIC_value:					value to poke
; ------------------------------------------------------------------------------------------

	jsr switch_to_ram                   ; Enable overlay RAM

	; Set address pointer in zero-page
	lda _ORIC_addrl						; Obtain low byte in A
	sta ZP1								; Store low byte in pointer
	lda _ORIC_addrh						; Obtain high byte in A
	sta ZP2								; Store high byte in pointer

	; Store value in specified address
	ldy #$00							; Clear Y index
	lda _ORIC_value						; Load value in A
	sta (ZP1),y							; Store at destination

	jsr switch_to_rom                   ; Disable overlay RAM
    rts

; ------------------------------------------------------------------------------------------
_PEEKO_core:
; Function to peek a memory position with upper 16KiB overlay RAM area enabled
; Input:	ORIC_addrh and ORIC_addrl:	high and low byte of address to peek
;			ORIC_tmp3:					MMU config for peek
; Output:	ORIC_value:					value peeked at address
; ------------------------------------------------------------------------------------------

	jsr switch_to_ram                   ; Enable overlay RAM

	; Set address pointer in zero-page
	lda _ORIC_addrl						; Obtain low byte in A
	sta ZP1								; Store low byte in pointer
	lda _ORIC_addrh						; Obtain high byte in A
	sta ZP2								; Store high byte in pointer

	; Store value in specified address
	ldy #$00							; Clear Y index
	lda (ZP1),y							; Load value from source address
	sta _ORIC_value						; Store value in variable to return

	jsr switch_to_rom                   ; Disable overlay RAM
    rts
Wrote a small test program that pokes values 0-9 in the area from $C000 and $F000 and reads back from both ROM as RAM:

Code: Select all

    for(x=0;x<10;x++)
    {
        address = 0xC000+x;
        gotoxy(1,x);
        POKEO(address,x);
        cprintf("Nr: %2u %4X ROM: %2X RAM: %2X",x,address,PEEK(address),PEEKO(address));
        address = 0xF000+x;
        gotoxy(1,10+x);
        POKEO(address,x);
        cprintf("Nr: %2u %4X ROM: %2X RAM: %2X",x,address,PEEK(address),PEEKO(address));
    }
This gives the satisfactory output:
Schermafbeelding 2022-06-03 101244.png
So, so far so good.

Only I also want to understand WHY it works (and please forgive my still novice grasp of assembly and the Oric inner workings).
I first tried the Pinforic code Chema pointed me too. Did not work, when trying to read from RAM I get the values from ROM. I also note that that code uses for the Microdisc code this for switch_to_ram:

Code: Select all

lda #$84
sta $0314
Which puzzles me, as $84 sets 1000 0100 as bitmask, which is way different than the bitmask 11111101 that DBug is explaining in his OSDK article. On the other hand, the bits that apparently matter, 1 and 7, are the same (0 and 1 respectively), so for that reason it is strange that the Pinforic one does not seem to work.
Also I see a value been stored in the Pinforic code in $32f (lda #0 sta $032F), what does that do? What is $032F?

The mask from the Dbug artictle does work, but if possible I also want to understand that Pinforic code.

I also found that actually adding php/pha/pla/plp around my code breaks the code, it breaks on execution. Without it it seems to work just fine. Why is this, so I understand why the first breaks and the second seems to work? Also to ensure I do not miss something biting me as bug later?

Is there somewhere a full documentation on the meaning of all bits in $0314, and preferably all extra registers added by the Microdisc controller? Do not see them in the Sedoric manual for example. Neither in Oric Advanced User Guide

And finally, is there a way in the Oricutron monitor to dump the RAM in the overlay memory area instead of the ROM? Do not see any option in the manual to choose which memory area is dumped.
User avatar
Dbug
Site Admin
Posts: 4444
Joined: Fri Jan 06, 2006 10:00 pm
Location: Oslo, Norway
Contact:

Re: Using overlay memory: how, tips and possibility for direct save/load

Post by Dbug »

Don't have time for a full answer now, but you can find some descriptions on Fabrice's page:
http://oric.free.fr/programming.html#disc
User avatar
xahmol
Flight Lieutenant
Posts: 437
Joined: Sun Jun 28, 2020 7:32 pm
Location: Utrecht, The Netherlands
Contact:

Re: Using overlay memory: how, tips and possibility for direct save/load

Post by xahmol »

Dbug wrote: Fri Jun 03, 2022 9:41 am Don't have time for a full answer now, but you can find some descriptions on Fabrice's page:
http://oric.free.fr/programming.html#disc
Thanks for that already!
(but from now knowing what the other bits of $314 do, still not understand why the Pinforic code did not work for me. Maybe did something else wrong as well)
User avatar
xahmol
Flight Lieutenant
Posts: 437
Joined: Sun Jun 28, 2020 7:32 pm
Location: Utrecht, The Netherlands
Contact:

Re: Using overlay memory: how, tips and possibility for direct save/load

Post by xahmol »

xahmol wrote: Fri Jun 03, 2022 9:24 am I also found that actually adding php/pha/pla/plp around my code breaks the code, it breaks on execution. Without it it seems to work just fine. Why is this, so I understand why the first breaks and the second seems to work? Also to ensure I do not miss something biting me as bug later?
Never mind this question: just realised myself what I did wrong there (doing php/pha in the enable_ram routine without doing a pla/plp before returning (did the pla/plp after the enable_rom routine) obviously makes that the program counter does not know where to return. Duh.....). So only question is: is that php/pha/pla/plp really needed as my code so far seems to work without it.
User avatar
xahmol
Flight Lieutenant
Posts: 437
Joined: Sun Jun 28, 2020 7:32 pm
Location: Utrecht, The Netherlands
Contact:

Re: Using overlay memory: how, tips and possibility for direct save/load

Post by xahmol »

Think I have found the reason why the Pinforic code was not working as well, forgot the part of the code that was initialising the machine_type variable:

Code: Select all

*=$500
sta _machine_type
So think that by not initialising this, the code jumped to the Jasmin code, instead of the Microdisc code.
Will now contemplate if I want to support Jasmin or only Microdisc, as the way it is done here might be complicated in what I am doing. As far as I understand from this, on program start it stores whatever is in the accumulator at program start, which apparently is an indication of machine type? But as I am using C in CC65, it is actually complicated to run this little piece of code at program start as first the CC65 initialisation code kicks in. Possible I guess, but have to dive in CC65 initialization code then. So think I will refrain from supporting Jasmin for now. Or is there an alternative to do this?

Checked, and indeed my code is also working with the $84 and $86 bitmasks of the Pinforic code.

Think I will modify my code to just toggle the 1 and 7 bits and remain the rest of $314 intact, as if I see the meaning of those other bits, I suspect that changing them might interfere with disk operations of my program. So will either use logical AND/ORs to toggle bits, or safeguard and restore the original value of $314 on entering/leaving RAM overlay enabled.

Now use this code:

Code: Select all

; ======================================================================
; Overlay memory area routines code
; ======================================================================

switch_to_rom:
    ; Set safe state
    php                                 ; Push program counter
    pha                                 ; Push accumulator

    ; Restore old $0314 value
    lda ORIC_FDCtmp                     ; Get old value of $314
    sta FDC_BUFFER                      ; Restore value

    ; Restore state after re-enablling overlay ROM
    pla                                 ; Pull accumulator
    plp                                 ; Pull program counter
    cli                                 ; Re-enable IRQ
    rts
 
switch_to_ram:
    ; Set safe state to disable overlay ROM
    sei                                 ; Stop IRQ
    php                                 ; Push program counter
    pha                                 ; Push accumulator

    ; Safeguard old value of $314
    lda FDC_BUFFER                      ; Load present value of $314
    sta ORIC_FDCtmp                     ; Safeguard at tempory location

    ; Disable bits 1 and 7 of $0314 to disable overlay ROM
    ; Bit 1: Disables the internal BASIC ROM when set to zero
    ; Bit 7: Disables the disk controller boot EPROM
    lda #$FD                            ; Load $FD for #%11111101 mask to disable bit 1 and enable bit 7
    sta FDC_BUFFER                      ; Store in FDC register at $0314

    ; Pull PC and A
    pla                                 ; Pull accumulator
    plp                                 ; Pull program counter
    rts
    
User avatar
Chema
Game master
Posts: 3014
Joined: Tue Jan 17, 2006 10:55 am
Location: Gijón, SPAIN
Contact:

Re: Using overlay memory: how, tips and possibility for direct save/load

Post by Chema »

Sorry for not being able to answer before...

You only have to save the registers you wish, of course. I use to save those I modify (a and p in this case). I have yet another version which I am using in 1337 and also disables interrupts, just in case. Here is the code:

Code: Select all


diskcntrl .byt $86
_switch_ovl 
    php
    pha
    sei
    lda diskcntrl
    eor #2
    sta diskcntrl
    sta $0314
    lda #0
    sta $032F
    pla
    plp
    rts	
This one is just one routine to switch overlay in and out (by modifying the value of diskcntrl. You don't need to enable interrupts back with cli, as plp gets the original value of the interrupt flag (whatever it was).

EDIT: Oh, and $032f is probably there for compatibility with Telestrat. See https://wiki.defence-force.org/doku.php ... emory_maps, where it says:
0320-032F Second VIA 6522 (Telestrat)
Post Reply