OPEL Software for the Oric

Want to talks about games you like, would like to see developed on the Oric, it's here.
User avatar
Dbug
Site Admin
Posts: 3572
Joined: Fri Jan 06, 2006 10:00 pm
Location: Oslo, Norway
Contact:

Re: OPEL Software for the Oric

Post by Dbug »

You are probably better than me at hacking this type of thing, as far as I understand they managed to embed the assembler before the BASIC because the file is saved as BASIC (00 instead of 80 in the tape header), and they cheat with the start address by doing the DOKE 154,#400/DOKE 154,1281 to change and restore the start address.

What I'm not sure about, is why do they keep copying the code from page 4 to 9C00, and why they seem to pretend all the key accesses are in page 3, but with an offset that actually write the data to page 4. Also they keep reusing the same addresses, sometimes in hex, sometimes in decimal, that's very hard to follow :)

Also the IRQ seem to push the content of the HIRES graphic command parameters, but it's actually offset by X so it's just saving the VIA registers in a convoluted way... because they just do normal restores with PLA/STA...

My VIA knowledge suck, so I'm not sure how that actually works, from what I see the activity detection is done in the top part of the routine:

Code: Select all

        LDA #$AF
        STA VIA_DDRB
        LDA #$FF
        STA VIA_DDRA
        LDA #$00
        STA VIA_PORTAH
        LDA #$10
        AND VIA_PORTB
        BEQ sub_routine
and the second routine would be the one that actually decodes the inputs, by having X actually be an offset in the table of values they can poke in the system variable containing the last keypress... except I'm not quite sure what the two other STA do:

Code: Select all

        LDA f9B93,X  ;300 DOKE #45E,AD-109
        STA SYS_ICHAR ;The AS’CII code for the last key pressed (with top bit set).
        LDA f9BB3,X  ;300 DOKE #464,AD-77
        STA VIA_PORTB
        LDA f9BD3,X  ;300 DOKE #46A,AD-45
        STA VIA_PORTAH

User avatar
Dbug
Site Admin
Posts: 3572
Joined: Fri Jan 06, 2006 10:00 pm
Location: Oslo, Norway
Contact:

Re: OPEL Software for the Oric

Post by Dbug »

As far as I can see, this routine works:

Code: Select all

_joystick_read_opel
.(
	; Save VIA Status
    LDA VIA_PORTB
    PHA
    LDA VIA_PORTAH
    PHA 
    LDA VIA_DDRB
    PHA 
    LDA VIA_DDRA
    PHA 

    LDA #$AF
    STA VIA_DDRB
    LDA #$FF
    STA VIA_DDRA
    LDA #$00
    STA VIA_PORTAH
    LDA #$10
    AND VIA_PORTB
    BNE end_opel

    .(

		LDA #$BF
        STA VIA_PORTB
        LDA #$7F
        STA VIA_PORTAH
        LDX #$05
loop_rotate 
		LSR 
        AND VIA_PORTB
        ORA #$E0
        ROR VIA_PORTAH
        DEX 
        BNE loop_rotate
		eor #%00011111        ; invert bits              
		sta _OsdkJoystick_0
    .)


end_opel
	; Restore VIA Status
    PLA 
    STA VIA_DDRA
    PLA 
    ;AND #$F7
    STA VIA_DDRB
    PLA 
    STA VIA_PORTAH
    PLA 
    STA VIA_PORTB
	rts
.)
I need to remap the bits to work with the rest, but I've a test routine that works with all ijk interfaces (egoist, higashijun, kenneth), pase, telestrat and now opel.

User avatar
Dbug
Site Admin
Posts: 3572
Joined: Fri Jan 06, 2006 10:00 pm
Location: Oslo, Norway
Contact:

Re: OPEL Software for the Oric

Post by Dbug »

I summarized what I found on Twitter:

User avatar
Xeron
Emulation expert
Posts: 395
Joined: Sat Mar 07, 2009 5:18 pm
Contact:

Re: OPEL Software for the Oric

Post by Xeron »

Nice! Good work.

User avatar
Dbug
Site Admin
Posts: 3572
Joined: Fri Jan 06, 2006 10:00 pm
Location: Oslo, Norway
Contact:

Re: OPEL Software for the Oric

Post by Dbug »

So, here is what the new sample code for the next version of the OSDK looks like:
ScreenShot.png
The idea is to totally abstract the interface (including if you are using the keyboard, in which case, key mapping will have to be provided), so basically in the game you just check for the joystick variables, like:

Code: Select all

joystick_type_select(JOYSTICK_INTERFACE_OPEL);
(...)
if (OsdkJoystick_0 & JOYSTICK_LEFT)  ... 
if (OsdkJoystick_0 & JOYSTICK_RIGHT)  ...
if (OsdkJoystick_0 & JOYSTICK_FIRE)  ...
there is a new "joystick_read" function to call every 50th of a second, which can be either in the main loop, or by calling "chain_irq_handler", which now "kind of work" even with a C callback, using some horrible horrible hack that exposed a bug in the C compiler.

Code: Select all

chain_irq_handler(NewHandler); 

char FlipFlop=1;

void NewHandler()
{
	IRQ_START;    // Horrible horrible thing (not needed in assembler)
	{	
		FlipFlop=-FlipFlop;  // The default system handler runs at 100hz, so we call it every two IRQ
		if (FlipFlop)
		{
			joystick_read();	
		}
	}
	IRQ_END;    // Horrible horrible thing (not needed in assembler)
}
As this point, all I need before I can release the new version is:
- The compiler bug needs to be fixed
- I need to implement the keyboard<->joystick mapping
and that's about it.

User avatar
Xeron
Emulation expert
Posts: 395
Joined: Sat Mar 07, 2009 5:18 pm
Contact:

Re: OPEL Software for the Oric

Post by Xeron »

Does flipflop work? Surely you're calling it at 100hz (1 and -1 both should evaluate to true).

Would expect something like FlipFlop ^= 1 (initialised to 0 or 1).

User avatar
iss
Wing Commander
Posts: 1199
Joined: Sat Apr 03, 2010 5:43 pm
Location: Bulgaria
Contact:

Re: OPEL Software for the Oric

Post by iss »

Great work @Dbug!
The joystick utility will be very helpful and even more as part of the OSDK. What is the bug related to the C compiler?

About the OPEL's code: you found all "secrets" which I discovered (are there more?).

To summarize what I found as interesting:
1. Merging machine code with BASIC - the trick for me was well known, but always the machine code is after the BASIC, then DOKE at 156,157 ($9C,$9D - End of Basic pointer.) new higher address and next CSAVE will store to tape the whole area including BASIC and ASM code. But OPEL does DOKE #400 at 154,155 ($9A,$9B Start of Basic pointer.) and next CSAVE stores again the whole area. What make this code "exceptional" is that the saved program has the flag of BASIC :!: program and no matter that the start address is not #501 (but #400) when loaded the execution starts at #501 as any other "normal" BASIC program. This makes me think: why the heck Tangerine left the page 4 free and made BASIC start at page 5 (i.e. #501)? Is it possible that this weird OPEL's code is actually a good and even "standard" feature? :)

2. Cross-page boundary indexing - using:

Code: Select all

9C03  A2 FC     LDX #$FC         
9C05  BD 04 02  LDA $0204,X      
9C08  48        PHA              
9C09  E8        INX              
9C0A  D0 F9     BNE $9C05        
instead of the "normal":

Code: Select all

              LDX #$00         
              LDA $0300,X      
              PHA              
              INX              
              CPX #$04
              BNE ...
has 2 advantages - it's 2 bytes shorter and at end of the cycle you have set Z-flag and ZERO value in X which can be handy for the next operations. The same trick is used to access the byte tables: :!:

Code: Select all

        LDA f9B93,X  ;300 DOKE #45E,AD-109
        STA SYS_ICHAR ;The AS’CII code for the last key pressed (with top bit set).
        LDA f9BB3,X  ;300 DOKE #464,AD-77
        STA VIA_PORTB
        LDA f9BD3,X  ;300 DOKE #46A,AD-45
        STA VIA_PORTAH

Notice here the base address used for indexing $9B93 but the table is actually placed at $9C73:

Code: Select all

9C73           .BYT    $55,$55,$55,$00,$55,$55,$00,$8B ; here $9C73 = $9B93,X (when $X >= E0)
               .BYT    $55,$00,$55,$88,$00,$8A,$89,$A0
               .BYT    $55,$55,$55,$00,$55,$55,$00,$8B
               .BYT    $55,$00,$55,$88,$00,$8A,$89,$AA
and to setup X register correctly we have:

Code: Select all

9748  09 E0     ORA    #$E0
.....
9750  AA        TAX
... crazy, right? :)

3. Easy relocatable code - at #4E0 we have:

Code: Select all

04E0  A2 00     LDX #$00         
04E2  BD 00 04  LDA $0400,X      
04E5  9D 00 9C  STA $9C00,X      
04E8  9D 00 B8  STA $B800,X      
04EB  E8        INX              
04EC  E0 E0     CPX #$E0         
04EE  D0 F2     BNE $04E2        
04F0  60        RTS              
this moves the driver code from $400..$4DF simultaneously to $9C00 and $B800 by default. But if you change the BASIC variable AD to (for instance) $5000 then the CALL#4E0 will move the driver code to $5000 and the (strange at first look) POKE's:

Code: Select all

300 DOKE #45E,AD-109:DOKE #464,AD-77:DOKE #46A,AD-45
will fix all absolute addressing to the new base.

4. Other tiny goodies - in the "JOYSTICK CONTROL" progy we have detection of the ROM version: IFPEEK(#FFF9)=1THEN Atmos ELSE Oric-1; and nice CSAVing as "JOY" tap file with modified key definition.

Well, sorry for the long post (I hope it's not boring) but I think it deserves this "waste" of time.
Be safe and Up the Orics!
Last edited by iss on Thu Dec 24, 2020 8:53 am, edited 1 time in total.

User avatar
Steve M
Squad Leader
Posts: 659
Joined: Fri Mar 24, 2006 3:33 am
Location: Cumbria, UK
Contact:

Re: OPEL Software for the Oric

Post by Steve M »

Not sure if you noticed but the tapes load with long titles displayed.
For example.
LOADING ... JOYSTICK CONTROLLER

I'm trying to remember what the trick was to get that shown?

User avatar
iss
Wing Commander
Posts: 1199
Joined: Sat Apr 03, 2010 5:43 pm
Location: Bulgaria
Contact:

Re: OPEL Software for the Oric

Post by iss »

Hm, I didn't noticed this. @Steve M: Are you sure? It would be interesting to know about such trick for long names...

In the above attached @Symoon's zip-file the longest name is "only" JOYSTICK CONTROL (i.e. without "LER").
This are 16 bytes and the ROM 1.1b routine (for 1.0 is slightly different) collects and stores at $0293-$02A3 exactly up to 16 bytes for tape name, every next byte is simply skipped until ZERO byte is found then the stored string is printed in the status line.

User avatar
Symoon
Archivist
Posts: 1934
Joined: Sat Jan 14, 2006 12:44 am
Location: Paris, France
Contact:

Re: OPEL Software for the Oric

Post by Symoon »

Off-topic tape names:
Yes, I'm transferring the actual tapes in the best possible way, which means keeping the original "loading name" (that's the way I call it). It can be essential as sometimes programs load a second part with instructions like CLOAD"JOYSTICK CONTROL", so if you don't keep that actual name, loading won't work.
It's displayd automatically in ROM 1.1, and only if you asked for CLOADing it in ROM 1.0
Also a bit of fun: CLOAD will only display 16 chars but the string length can be any size, so it's a nice place to store a hidden message in the TAP file if you want to ;) (edit: basically, just what ISS said just before me :D )
Last edited by Symoon on Thu Dec 24, 2020 11:04 am, edited 1 time in total.

User avatar
jbperin
Flying Officer
Posts: 209
Joined: Wed Nov 06, 2019 11:00 am
Location: Valence, France

Re: OPEL Software for the Oric

Post by jbperin »

Dbug wrote:
Wed Dec 23, 2020 9:10 pm

there is a new "joystick_read" function to call every 50th of a second, which can be either in the main loop, or by calling "chain_irq_handler", which now "kind of work" even with a C callback, using some horrible horrible hack that exposed a bug in the C compiler.

Code: Select all

chain_irq_handler(NewHandler); 

char FlipFlop=1;

void NewHandler()
{
	IRQ_START;    // Horrible horrible thing (not needed in assembler)
	... 
	IRQ_END;    // Horrible horrible thing (not needed in assembler)
}
Are you calling a C function from the IT handler ?

I've allways thought this kind of practice had to be prohibited. And I knew it from you ..

I had experienced some very weird behavior by calling C function from a IT handler.
I think it is very dangerous because:
- Code generated by C compiler for the NewHandler function can corrupt variables such as tmp0, tmp1.
- Calling C at 100Hz is risky because C code is slow and the risk is that the IT handler doesn't finish before the next IT happends.

How are you facing that ?
Xeron wrote:
Thu Dec 24, 2020 12:03 am
Does flipflop work? Surely you're calling it at 100hz (1 and -1 both should evaluate to true).

Would expect something like FlipFlop ^= 1 (initialised to 0 or 1).
I agree

User avatar
Dbug
Site Admin
Posts: 3572
Joined: Fri Jan 06, 2006 10:00 pm
Location: Oslo, Norway
Contact:

Re: OPEL Software for the Oric

Post by Dbug »

jbperin wrote:
Thu Dec 24, 2020 10:47 am
Are you calling a C function from the IT handler ?
I've allways thought this kind of practice had to be prohibited. And I knew it from you ..

I had experienced some very weird behavior by calling C function from a IT handler.
I think it is very dangerous because:
- Code generated by C compiler for the NewHandler function can corrupt variables such as tmp0, tmp1.
- Calling C at 100Hz is risky because C code is slow and the risk is that the IT handler doesn't finish before the next IT happends.

How are you facing that ?
Yes, and that's why there are these IRQ_START and IRQ_END things, I wanted to show an example of doing that 100% in C, which obviously is not recommended because of performance reason.

What these macros do is just that:

Code: Select all

#define IRQ_START asm(         \
" php;pha;txa;pha;tya;pha;\n"    \
" ldx #0\n" \
"copy_loop\n" \
" lda zp_compiler_save_start,x\n" \
" pha\n" \
" inx\n" \
" cpx #zp_compiler_save_end-zp_compiler_save_start\n" \
" bne copy_loop\n")

#define IRQ_END asm(         \
" ldx #zp_compiler_save_end-zp_compiler_save_start-1\n" \
"copy_loop2\n" \
" pla\n" \
" sta zp_compiler_save_start,x\n" \
" dex\n" \
" bpl copy_loop2\n" \
 "pla;tay;pla;tax;pla;plp")
and yes, it saves way too much things, but that was just a proof of concept, to show it was doable.
Xeron wrote:
Thu Dec 24, 2020 12:03 am
Does flipflop work? Surely you're calling it at 100hz (1 and -1 both should evaluate to true).

Would expect something like FlipFlop ^= 1 (initialised to 0 or 1).
Oops, was supposed to be FlipFlop=1-FlipFlop, and yes the xor is better :)

User avatar
coco.oric
Squad Leader
Posts: 616
Joined: Tue Aug 11, 2009 9:50 am
Location: North of France
Contact:

Re: OPEL Software for the Oric

Post by coco.oric »

Symoon wrote:
Wed Dec 23, 2020 10:43 am
If you have a FTP or whatever I can send them to you - I really have no time for updates these days :?
Hello Simon, je t'ai envoyé des mails avec des espaces alloués pour toi.
Si tu veux tu peux uploader ce que tu veux ou tu préfères.

Dropbox, il me reste 2,5 go de quota
Onedrive, pas de soucis de quota.

Je ferais un peu d'upload sur oric.org à l'occasion et le tri dans mon bazar (le hd en a partout)
Didier
coco.oric as DidierV, CEO Member
Historic owner of Oric, Apple II, Atari ST, Amiga

User avatar
jbperin
Flying Officer
Posts: 209
Joined: Wed Nov 06, 2019 11:00 am
Location: Valence, France

Re: OPEL Software for the Oric

Post by jbperin »

Dbug wrote:
Thu Dec 24, 2020 11:21 am

Yes, and that's why there are these IRQ_START and IRQ_END things, I wanted to show an example of doing that 100% in C, which obviously is not recommended because of performance reason.

What these macros do is just that:

Code: Select all

#define IRQ_START asm(         \
"..."
" bne copy_loop\n")

#define IRQ_END asm(         \
" ...")
and yes, it saves way too much things, but that was just a proof of concept, to show it was doable.
Nice trick .. that's smart .. thank you :-)
It's very convenient for prototyping .. before porting in assembly

User avatar
Dbug
Site Admin
Posts: 3572
Joined: Fri Jan 06, 2006 10:00 pm
Location: Oslo, Norway
Contact:

Re: OPEL Software for the Oric

Post by Dbug »

Except there's a bug in the C compiler that places the assembly code statement in the wrong place. I made a hack in the code to get that working, but I'm waiting for Fabrice to suggest a proper fix :)

Post Reply