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:

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

Post by xahmol »

iss wrote: Wed Jun 29, 2022 11:53 am.
Good news for Sedoric I/O - at $4FD is the result code from last operation: if it's 0 (zero) - no error.
Saw that, but that does not help much if SEDORIC first throws you to BASiC on e.g. a file not found. C code can not recover from that (or do I miss something?)
Ideal would be to hijack ERRGOTO in a way.

Also, the SEARCH command is interesting before you save a file to see if an existing one exists , so you can ask the user if overwrite is OK.
In BASIC, this returns a 0 or 1 value on the variable EF. Was wondering: will setting that variable be destructive for C code as of course that EF var8able is stored somewhere? But also: would it be possible to read that variable from C code?
Because that would enable a File exists dialogue (that I do have in my Commodore targets).
Looking at the SEDORIC code for SEARCH, I could of course just patch that command again to store it at a memory location instead of EF:

Code: Select all

E608 A9 01 LDA #01 A = #01 (pour "trouvé")
E60A 4C D5 D7 JMP D7D5 et dans les deux cas, continue en D7D5 où la variable EF (Existing File) reçoit A (0 si "non trouvé",1 si "trouvé"). Pour le traitement logique du résultat de la recherche, il faudra donc demander IF -EF THEN... et non IF EF THEN...
and patch the jump to D7D5 with a jump to an own handler.
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 »

Progress: managed to reroute the SEDORIC output to screen by indeed patching.

Started with a small Proof of Concept to reroute output to the $9000 memory area, and that works! Needed that to exactly see the output steam format.
Schermafbeelding 2022-06-29 152435.png
Code used:

Code: Select all

DOSROM				=	$04F2			; Call to function to disable/enable SEDORIC RAM
_DOSERROR			=	$04FD			; Disk error address
SED_PRINTCHAR		=	$D20F			; SEDORIC print character patch address
SED_XROM			=	$D5D8			; SEDORIC default jump address before patch

; Disk directory parser routines

; ------------------------------------------------------------------------------------------
_ORIC_DIRParse_start:
; Function to enable directory parser and reroute screen output while DIR is executed
; Input:	
; ------------------------------------------------------------------------------------------

	; Enable overlay RAM
	jsr	DOSROM							; Call function to toggle overlay RAM

	; Patch SEDORIC print character function
	lda #<ORIC_DIRParse_process			; Get low byte of parsing function
	sta SED_PRINTCHAR					; Store at patch address
	lda #>ORIC_DIRParse_process			; Get low byte of parsing function
	sta SED_PRINTCHAR+1					; Store at patch address
	lda #$60							; Load $60 for oppcode RTS
	sta SED_PRINTCHAR+2					; Store RTS at patch location

	; Disable overlay RAM
	jsr	DOSROM							; Call function to toggle overlay RAM

	lda #$00
	sta dirparse_automodify+1
	lda #$90
	sta dirparse_automodify+2

	rts

; ------------------------------------------------------------------------------------------
_ORIC_DIRParse_end:
; Function to disable directory parser and reroute screen output while DIR is executed
; Input:	
; ------------------------------------------------------------------------------------------

	; Enable overlay RAM
	jsr	DOSROM							; Call function to toggle overlay RAM

	; Patch SEDORIC print character function
	lda #<SED_XROM						; Get low byte of parsing function
	sta SED_PRINTCHAR					; Store at patch address
	lda #>SED_XROM						; Get low byte of parsing function
	sta SED_PRINTCHAR+1					; Store at patch address
	lda #$12							; Load original value
	sta SED_PRINTCHAR+2					; Store RTS at patch location

	; Disable overlay RAM
	jsr	DOSROM							; Call function to toggle overlay RAM

	rts

; ------------------------------------------------------------------------------------------
ORIC_DIRParse_process:
; Function to intercept the system char to screen routine
; Input:	Parses inout character stream via the X register
; ------------------------------------------------------------------------------------------

dirparse_automodify:
	sta $9000
	inc dirparse_automodify+1
	bne dirparseend
	inc dirparse_automodify+2

dirparseend:
	; Jump to XROM routine to return to SEDORIC gracefully
	jsr SED_XROM						; Jump to XROM routine
	.byte $10,$cd,$10,$cd				; Data for XROM

	rts
So, from here, a DIR parser should not be difficult anymore if I take only disks with this specific DIR layout as requirement.

(PS: Quickly noted that in the parser function, the use of zero page variables is to avoided, as the program went completely crazy ;- Apparently SEDORIC uses the same ZP addresses, but safeguards those on entering SEDORIC functions to restore afterwards)
Last edited by xahmol on Wed Jun 29, 2022 2:38 pm, edited 1 time in total.
User avatar
Dbug
Site Admin
Posts: 4437
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: Wed Jun 29, 2022 12:08 pm Saw that, but that does not help much if SEDORIC first throws you to BASiC on e.g. a file not found. C code can not recover from that (or do I miss something?)
Ideal would be to hijack ERRGOTO in a way.
Have you found out how it gets back to BASIC?
Technically you can redirect the "Ready" prompt to call some code, it's often used as a protection in BASIC programs to call the reset routine when going back to the prompt:

DOKE(#1B,DEEK(#FFFC))

Technically you could replace this vector by a way to recover from errors, but I don't know what the status of the stack, etc... would be.

I guess technically the Sedoric/Basic wrapper could do something like having a small function designed to restore the stack pointer value and jmp to the end of the Sedoric function caller, and before calling Sedoric modify #1B-1C to point to this function and set the right stack value to restore to.

If the code does not crash, nothing happen, if it does crash, it would auto-jump to the crash handler, restore the stack, and jump back to continue running the code.
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: Wed Jun 29, 2022 2:38 pm Have you found out how it gets back to BASIC?
Well, see for example here (page 187):

Code: Select all

Affiche le message "DISP_TYPE_MISMATCH"
Puis réinitialise la pile, affiche "_ERROR" et retourne au "Ready"
D16F- A9 A3 LDA #A3 pour le message "DISP_TYPE_MISMATCH_ERROR" (bogue: LDX)
D171- 20 D8 D5 JSR D5D8 XROM exécute à partir de la RAM une routine ROM
D174- 85 C4 7E C4 adresse ROM 1.0 adresse ROM 1.1 (affiche le message)
So, apparently it jumps to C47E, which is indeed the standard Oric Atmos ROM routine to print error messages (apart from skipping the first LDX) and return to BASIC (and indeed seems to clear stack and everything):

Code: Select all

PRINTERROR
$C47C	A2 4D                    	LDX   #$4D                              	PRINT ERROR MESSAGES
$C47E	20 2F C8                 	JSR   $C82F                             	Reset output to screen.
$C481	46 2E                    	LSR   $2E                               	Reset CTRL O.
$C483	20 F0 CB                 	JSR   $CBF0                             	Move to start of next line.
$C486	20 D7 CC                 	JSR   $CCD7                             	Print "?" on screen.
$C489	BD A8 C2                 	LDA   $C2A8,X                           	Print error message on screen
$C48C	48                       	PHA                                     	until last char which has bit
$C48D	29 7F                    	AND   #$7F                              	7 set. X holds initial offset
$C48F	20 D9 CC                 	JSR   $CCD9                             	into error table at start of
$C492	E8                       	INX                                     	routine.
$C493	68                       	PLA
$C494	10 F3                    	BPL   $C489
$C496	20 26 C7                 	JSR   $C726                             	Reset 6502 stack etc.
$C499	A9 A6                    	LDA   #$A6                              	Print "ERROR" after the
$C49B	A0 C3                    	LDY   #$C3                              	message.
$C49D	20 B0 CC                 	JSR   $CCB0
$C4A0	A4 A9                    	LDY   $A9                               	If high byte of line number
$C4A2	C8                       	INY                                     	is #FF then the computer is in
$C4A3	F0 03                    	BEQ   $C4A8                             	immediate mode (not program).
$C4A5	20 BA E0                 	JSR   $E0BA                             	Print "IN (line number>"


BACKTOBASIC
$C4A8	4E 52 02                 	LSR   $0252                             	RESTART BASIC
$C4AB	46 2E                    	LSR   $2E                               	Clear pending ELSE, CTRL O
$C4AD	4E F2 02                 	LSR   $02F2                             	and LIST/EDIT flags.
$C4B0	A9 B2                    	LDA   #$B2
$C4B2	A0 C3                    	LDY   #$C3
$C4B4	20 1A 00                 	JSR   $001A                             	Print "Ready"
See only in the SEDORIC code that it does not use just one single routine or ROM entry point, references to "retourne au Ready" are all over the place, using also different ROM entry points.
For example, here entry point in ROM at C4A0, so few lines further, probably becasue SEDORIC already printed its own error message (p 187):

Code: Select all

Retourne au Ready après affichage d'un message d'erreur
D154- 20 D8 D5 JSR D5D8 XROM exécute à partir de la RAM une routine ROM
D157- AD C4 A0 C4 adresse ROM 1.0 adresse ROM 1.1
D15B- 60 RTS
So have to try, that one on p 187 seems to be the most promising entry point for patching, but there it is already to late to have SEDORIC print its own error message. Think then I have to find wherever it actually prints those error messages and patch already there.

Edit: Apparently, it prints those messages here:

Code: Select all

D391- 20 2A D6 JSR D62A XAFCAR affiche le caractère ASCII contenu dans A
So maybe could patch there to save the error message to a string instead of printing it, and then patch the jump to BASIC one.

(BTW: Following the French of 'SEDORIC 3.0 à NU' is more manageable than I thought)
User avatar
iss
Wing Commander
Posts: 1637
Joined: Sat Apr 03, 2010 5:43 pm
Location: Bulgaria
Contact:

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

Post by iss »

Intercepting $1B,$1C is exactly what libbasic does (stack sanity included) ;).
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 »

Took a while for an update due to COVID (caught an infection last month and limited retro time as I practiced self isolation in home to avoid the rest om my family catching it) and holiday in France (luckily recovered with proper quarantine length in time). So only this week back to my retros since a month.

Also have been struggling to get that dirparser working. But alas gave up for now. Feel I was almost there as I saw things happening, but for some reason I caught most chars right but some not and for me in an unpredictable way. So that broke all my parser attempts.
I am sure it can be done because I feel I was so close, but also do not understand at all what went wrong, so decided to leave it for now.
Copying directly to memory was working fine, so think my routines became either too complex, took too long or I made some error somewhere. Of course copying the dir to memory would also work if only I had enough memory left for it to copy to. But have not that much memory to spare.

As I do want to release some version soon, I proceeded with a dir based file picker purely from the BASIC screen output. Which works great, so long you do not place too many files on the disk that would make the dir scroll the screen.

Attached new build, will release soon after seeing feedback and suggestions in this thread first (if any). This disk image also contains my attempt at a PETSCII charset, the screen, standard and alternate charsets are on the disk (the PETSCII**.bin files) with a project file (PETSCIIPJ.bin to load all at once).

The images:
DSK:
OSE.dsk
(1.56 MiB) Downloaded 96 times
HFE:
OSE.hfe
(515.5 KiB) Downloaded 91 times
User avatar
coco.oric
Squad Leader
Posts: 720
Joined: Tue Aug 11, 2009 9:50 am
Location: North of France
Contact:

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

Post by coco.oric »

Hello,

@xahmol :
If you've a lot of files, may be it's an opportunity to install OSE with a sedoric 4 OS which allows directories, and for example let user using one for charsets, one for screens ...
coco.oric as DidierV, CEO Member
Historic owner of Oric, Apple II, Atari ST, Amiga
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/l

Post by xahmol »

Well, as long as the Tap2DSK tool is creating SEDORIC3 disks, using SEDORIC4 is not very practical as I then have no way of creating them autimatically in a build chain…. Or do you have a suggestion how to create SEDORIC4 discs automatically from the command prompt?

Next to that, the way now implemented of choosing files from having the BASIC dir command printing the dir on screen will certainly not work with subdirs, so that would actually get me farther from a solution than closer. Maybe that could be solved by forcing only a fixed dir structure indeed, so only supporting screens in a dir called screens and such, but that will come at the cost of being way more cumbersome on getting files to not standard OSE system disks.
Also, my issue is not that I have too many files already, more that I now have to warn users not to place too many .BIN files on disk as that will break the file picker.
(But curious for suggestions to create SEDORIC4 discs anyway)
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/lo

Post by xahmol »

Hmm, thinking of it, traversing subdirs down and up should be doable in the file picker: just do a new BASIC dir command if a dir is recognised on selection.
Would only still break if the subdir has too many files, with the downside of then needing to suppprt different versions of DIR output for different SEDORIC versions If I do not stick to just Tap2dsk created disks. Would make things much more complicated and still not completely take away the issue.

(But more important question is still how to include SEDORIC4 in an automated build chain, as copying the files to a SEDORIC4 disk manually on every build is extremely unpractical)
User avatar
Dbug
Site Admin
Posts: 4437
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: Sun Aug 14, 2022 4:37 pm Feel I was almost there as I saw things happening, but for some reason I caught most chars right but some not and for me in an unpredictable way. So that broke all my parser attempts.
I am sure it can be done because I feel I was so close, but also do not understand at all what went wrong, so decided to leave it for now.
Copying directly to memory was working fine, so think my routines became either too complex, took too long or I made some error somewhere.
Do you have the code of the parser somewhere so we can take a look at 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 »

Hesitant to post as very Work in progress, not yet complete and most certainly still very buggy:
See https://github.com/xahmol/OricScreenEdi ... dirparse.s

And then specifically these parts:
_ORIC_DIRParse_start_core:
DIRParse_nextX:
DIRParse_Stormem:
_ORIC_DIRParse_end:
ORIC_DIRParse_process:

It is not complete yet as I thought already I still miss a phase (skip from the right column to the left), but I think the first thing to understand is why solely capturting the dir to memory (did so for testing purposes in a memory area I actually can not miss, but wanted to see if the raw input was received correctly). This is the DIRParse_Stormem function that is called first in ORIC_DIRParse_process.
In memory I see this dump:
Schermafbeelding 2022-08-15 085609.png
Schermafbeelding 2022-08-15 085609.png (10.09 KiB) Viewed 2574 times
Compared to this actual dir just in BASIC on screen:
Schermafbeelding 2022-08-15 091030.png
Schermafbeelding 2022-08-15 091030.png (11.56 KiB) Viewed 2574 times
First thing I encounter is that the coloured part of the disk name gives output with escape codes ($1B) instead of just attribute values that can be plot directly. So have to figure that one out, as I assume that the number of escape codes will differ from dir to dir, so might be different on reading other disks. Parked that one for later if I can get the rest working.

But more worrying is that somehow the output of the filenames seems to be inconsistently weird sometimes in the extensions.
See:
- on the first file OSEHS1.BIN the extension suddenly misses a dot, but more worryingly, there is a weird sequence of 0D 08 2E 06 20 40 4F behind the BIN that I really can not place and do not see further on. $0D is an ENTER, weird, as it should keep printing on the same line, see output in plain BASIC. $08 is a backspace, why? And why does it do that here, but with further files sometimes (not always) that $0D but not the rest?
- On the second file OSEHS2.BIN there is suddenly a dot within the .BIN extension instead of before (so B.IN instead of .BIN)

The code to print things to screen is also far from functional still. It also is not complete and WIP yet as I know I still miss a phase (skipping chars going from right column to left column again). But solving the bugs that must be there is rather pointless if I can not understand what is happening with those irregularities in the raw stream in the first place, as my parser logic only works if distances between two file names are always exactly the same or at least follow a standard predictable pattern.
That is why I for now gave up on this rote, and reverted to the simple way of not interfering with the DIR output, Which works great with the caveat of breaking on too many files.
User avatar
Dbug
Site Admin
Posts: 4437
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 »

Will require some reading, but I can already say that there's a much easier way to handle your state machine, which would also end up being much faster code.

Instead of that:

Code: Select all

	lda DIRParse_Phase					; Check phase

	; Check for phase 0: skip first header and disk name
	cmp #$00							; Compare for phase 0
	bne DP_phase1						; Go to next check
	jmp DP_skipheader					; Branch to skip header if phase 0

DP_phase1:
	; Check for phase 2: print filename left column
	cmp #$01							; Compare for phase 2
	bne DP_phase2						; Go to next check
	jmp	DP_printleftcolumn				; Branch to read disk name if phase 2
	(...)
DP_phase4:
	; Check for phase 5: print filename right column
	cmp #$04							; Compare for phase 5
	bne DP_phase9						; Go to next check
	jmp DP_printleftcolumn				; Branch to read disk name if phase 5
You can instead use either a pointer in zero page or a self-modified jmp that points to the code to run in the next phase, and all you need to do is to have the previous phase change the pointer to point to the next code to run, so "header" changes it to "print left column" which itself changes it to print right column, etc...
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 DBug. Using zero page I want to avoid because I already had conflicts with the SEDORIC code when I tried that (and safeguarding ZP values every time will certainly make the code slower), but self modifying is certainly possible. Good suggestion.
However, if I do not first solve why the data stream coming in is irregular.. Maybe will revert back to just one phase with just a memdump first to see if too complex / slow code effects this data stream. If yes, your suggestion could indeed help. If not, there is some other issue to solve first.
User avatar
Dbug
Site Admin
Posts: 4437
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 »

To test the speed theory, one thing you could do is to keep the byte fetcher hook, but just have it call the original function directly (check that it still works fine), then add a delay loop, and increase the value until it stops working.

If it gets slow without even stopping to work, it means it's probably not a performance related issue.
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: Mon Aug 15, 2022 11:18 am To test the speed theory, one thing you could do is to keep the byte fetcher hook, but just have it call the original function directly (check that it still works fine), then add a delay loop, and increase the value until it stops working.

If it gets slow without even stopping to work, it means it's probably not a performance related issue.
Good suggestion. Will do.
Post Reply