Jump to content

Photo

Creating bank switched cartridges with gcc

gcc cartridge bankswitching

101 replies to this topic

#26 JamesD OFFLINE  

JamesD

    Quadrunner

  • 8,461 posts
  • Location:Flyover State

Posted Sat Aug 8, 2015 6:42 PM

Let me ask you this... are you trying to do it all in C because you want to avoid assembly?



#27 RXB OFFLINE  

RXB

    River Patroller

  • 3,583 posts
  • Location:Vancouver, Washington, USA

Posted Sat Aug 8, 2015 7:23 PM

C is a good language but a huge waste of memory to use.

 

Unix when converted from Assembly to C took up so much more space that it took a cut down version call Linux to fit on a standard PC.

 

Later with the marked increase in memory on Desktop PC Unix would fit, but with a huge cut down of Libraries.

 

Assembly takes more time and effort to get it right.



#28 JamesD OFFLINE  

JamesD

    Quadrunner

  • 8,461 posts
  • Location:Flyover State

Posted Sat Aug 8, 2015 7:41 PM

To clarify, I was just referring to the bank switched function calls.
But yeah, C takes less time to develop but wastes more memory and assembly takes longer to get right.


  • RXB likes this

#29 RXB OFFLINE  

RXB

    River Patroller

  • 3,583 posts
  • Location:Vancouver, Washington, USA

Posted Sat Aug 8, 2015 8:42 PM

You know bank switching SAMS or ROMs is much more easy from GPL then any other way as you can switch the entire RAM without using any RAM?



#30 JamesD OFFLINE  

JamesD

    Quadrunner

  • 8,461 posts
  • Location:Flyover State

Posted Sat Aug 8, 2015 8:43 PM

;Function stub routines
...
;Trampoline return code
TrampolineExit:
	;pop previous memory page from stack
	MOV		R11,@R11Temp				;save R11
	MOV		@STACK,R11				;get the stack pointer
	DECT	        R11					;since stack points to next stack location
	MOV		*R11-,@MEMPAGE				;get the previous memory page info
...
There is no auto decrement in indirect addressing?
Ok, so a minor code change.
 
;Trampoline return code
...
TrampolineExit:
        ;pop previous memory page from stack
        MOV             R11,@R11Temp                            ;save R11
        MOV             @STACK,R11                              ;get the stack pointer
        DECT            R11                                     ;since stack points to next stack location
 
	MOV		*R11,@MEMPAGE				;get the previous memory page info
        DECT            R11                                     ;decrement stack pointer
...


#31 Tursi OFFLINE  

Tursi

    Quadrunner

  • 5,641 posts
  • HarmlessLion
  • Location:BUR

Posted Sat Aug 8, 2015 11:05 PM

(Never mind, already covered, and no underscore on the 9900 GCC like I thought ;) )

 

If you aren't familiar with 9900 assembly, and you aren't familiar with the 9900 port of GCC, I'd recommend building the switching in C first. You can always look at the generated assembly code and optimize that. The 9900 GCC usually produces pretty good code.

 

 

 

 


Edited by Tursi, Sat Aug 8, 2015 11:27 PM.


#32 Tursi OFFLINE  

Tursi

    Quadrunner

  • 5,641 posts
  • HarmlessLion
  • Location:BUR

Posted Sat Aug 8, 2015 11:51 PM

As a test, I wrote a simple trampoline function and verified the assembly -- you'll have a hard time doing much better, I think.

 

void trampoline(void (*target)(), volatile char *targetBank) {
  volatile char *old = CurrentBank; // save the current bank
  CurrentBank = targetBank;   // update the cache variable
  *targetBank;  // force a memory read to switch, but we don't need the result. The volatile makes it work.
  target();  // call the target function
  CurrentBank = old; // update the cache variable
  *old; // force a memory read to switch back
}

 

This function takes the address of a function to call, and a pointer to the bank switch address (ie: 0x6000 for bank 0, 0x6002 for 1, etc). It expects that somewhere you have a global to cache the 'current' bank, defined as "volatile char *CurrentBank". Volatile is important to prevent optimizing out or re-ordering accesses to it.

 

The generated assembly code for this function looks like this (using -O2, no optimizations produced broken code).

 

 def trampoline
trampoline
 ai   r10, >FFFC        * update the stack pointer
 mov  r11, *r10         * save return address on stack
 mov  r9, @>2(r10)      * save frame pointer on stack
 mov  @CurrentBank, r9  * save current value of CurrentBank ('old')
 mov  r2, @CurrentBank  * save 'targetBank' into CurrentBank
 movb *r2, r2           * read targetBank, which performs the bank switch
 bl   *r1               * call target function
 mov  r9, @CurrentBank  * restore saved value from 'old' (note: saved in register!)
 movb *r9, r1           * perform the memory read, which switches the bank back
 mov  *r10+, r11        * restore return address from stack
 mov  *r10+, r9         * restore frame pointer from stack
 b    *r11              * return to caller

 

A nice thing about this function is it's completely position independent. You could build it without any special consideration, and manually copy it from ROM to RAM or scratchpad (it's only 32 bytes) for actual execution. It'd be hard to do too much better - even without the GCC considerations, as a generic trampoline function I don't know if I'd change anything there.



#33 Lee Stewart OFFLINE  

Lee Stewart

    River Patroller

  • 3,967 posts
  • Location:Silver Run, Maryland

Posted Sat Aug 8, 2015 11:56 PM

 

I make no promises on syntax but this is the general idea using a stack to track mem pages and return addresses.... and it's bigger than it probably needs to be.

I'm sure an experienced 9900 programmer can improve on it

Spoiler

 

 

I haven't tested this; but, something like the following should work:

Spoiler

 

Tursi's advice re C over Assembly is probably better, however.

 

...lee


Edited by Lee Stewart, Sun Aug 9, 2015 5:09 PM.


#34 JamesD OFFLINE  

JamesD

    Quadrunner

  • 8,461 posts
  • Location:Flyover State

Posted Sun Aug 9, 2015 2:16 AM

Nice to see that assembly.  

The 9900 does  allow a couple things I thought it didn't because I couldn't find them in the book.

I either missed the info in the book I was looking at or it just wasn't there.

I initially had the stack building down and can't remember why I changed it.

The C code definitely looks the best.



#35 TheMole OFFLINE  

TheMole

    Dragonstomper

  • Topic Starter
  • 819 posts
  • Location:Belgium

Posted Sun Aug 9, 2015 4:22 AM

Unix when converted from Assembly to C took up so much more space that it took a cut down version call Linux to fit on a standard PC.

Later with the marked increase in memory on Desktop PC Unix would fit, but with a huge cut down of Libraries.

 

This is not true. AT&T put out UNIX for PCs in 1985, MINIX was release in 1987. Linux was first released on October 5th, 1991 because Linus wanted to have a free Unix-like OS for day-to-day use and MINIX's licensing conditions limited it to educational use. Nothing to do with memory consumption.



#36 TheMole OFFLINE  

TheMole

    Dragonstomper

  • Topic Starter
  • 819 posts
  • Location:Belgium

Posted Sun Aug 9, 2015 4:30 AM

Ok but where is the bank switch and switch back so you can call between banks?  
If you bank switch there, you'll be in a different bank before your call.

Just to clarify, I was working from your example code. That macro doesn't do the bank switching itself, that happens in the trampoline function. The macro only replace the stub functions in your example, not the actual trampoline code.
 

If you are calling the trampoline code directly, it has to know what to set and call.


That's what the "FunctionJump+2 = &_far_somefunction;" does, it overwrites the >0000 part in the JMP instruction in your code around line 26 with the address of _far_somefunction. The page can still be looked up in a lookup table, or you can simply follow the same approach as for the function pointer, with the exception that the page address needs to be hardcoded.



#37 TheMole OFFLINE  

TheMole

    Dragonstomper

  • Topic Starter
  • 819 posts
  • Location:Belgium

Posted Sun Aug 9, 2015 4:37 AM

As a test, I wrote a simple trampoline function and verified the assembly -- you'll have a hard time doing much better, I think.

void trampoline(void (*target)(), volatile char *targetBank) {
  volatile char *old = CurrentBank; // save the current bank
  CurrentBank = targetBank;   // update the cache variable
  *targetBank;  // force a memory read to switch, but we don't need the result. The volatile makes it work.
  target();  // call the target function
  CurrentBank = old; // update the cache variable
  *old; // force a memory read to switch back
}

This function takes the address of a function to call, and a pointer to the bank switch address (ie: 0x6000 for bank 0, 0x6002 for 1, etc). It expects that somewhere you have a global to cache the 'current' bank, defined as "volatile char *CurrentBank". Volatile is important to prevent optimizing out or re-ordering accesses to it.

 

The generated assembly code for this function looks like this (using -O2, no optimizations produced broken code).

 def trampoline
trampoline
 ai   r10, >FFFC        * update the stack pointer
 mov  r11, *r10         * save return address on stack
 mov  r9, @>2(r10)      * save frame pointer on stack
 mov  @CurrentBank, r9  * save current value of CurrentBank ('old')
 mov  r2, @CurrentBank  * save 'targetBank' into CurrentBank
 movb *r2, r2           * read targetBank, which performs the bank switch
 bl   *r1               * call target function
 mov  r9, @CurrentBank  * restore saved value from 'old' (note: saved in register!)
 movb *r9, r1           * perform the memory read, which switches the bank back
 mov  *r10+, r11        * restore return address from stack
 mov  *r10+, r9         * restore frame pointer from stack
 b    *r11              * return to caller

A nice thing about this function is it's completely position independent. You could build it without any special consideration, and manually copy it from ROM to RAM or scratchpad (it's only 32 bytes) for actual execution. It'd be hard to do too much better - even without the GCC considerations, as a generic trampoline function I don't know if I'd change anything there.

 

That's what I did for my first test, but I don't see an obvious way to make this work with functions that take arguments (except writing a specific trampoline function for each)?



#38 Tursi OFFLINE  

Tursi

    Quadrunner

  • 5,641 posts
  • HarmlessLion
  • Location:BUR

Posted Sun Aug 9, 2015 5:12 AM

 

That's what I did for my first test, but I don't see an obvious way to make this work with functions that take arguments (except writing a specific trampoline function for each)?

 

Yes. :) At 40 bytes each, I think you'll have to work pretty hard to break the bank.

 

Remember that calling convention is part of the compilation, if you try to abstract that all away, even if you manage to build something that works, it will reduce the compiler's ability to create optimized code. Since neither the compiler nor the linker are aware of banking right now, we don't get any specific optimizations tied to that, so not everything is going to be beautiful.

 

For my own use I write a trampoline for every function that needs one, just to save the function call and parameter passing overhead. They're cheap. ;)



#39 JamesD OFFLINE  

JamesD

    Quadrunner

  • 8,461 posts
  • Location:Flyover State

Posted Sun Aug 9, 2015 10:44 AM

So, what we have here is a rewrite with stack that builds down and instructions I think I learned from you guys.
Insert it could be completely crap disclaimer here.  I removed so much code that I'm worried.

Spoiler

*edit*
Technically, there doesn't need to be a function table. The data could be located with each stub routine itself.  (updated code with this)

I feel like I'm wandering around in the dark.


Edited by JamesD, Sun Aug 9, 2015 12:58 PM.


#40 Lee Stewart OFFLINE  

Lee Stewart

    River Patroller

  • 3,967 posts
  • Location:Silver Run, Maryland

Posted Sun Aug 9, 2015 1:50 PM

So, what we have here is a rewrite with stack that builds down and instructions I think I learned from you guys.
Insert it could be completely crap disclaimer here.  I removed so much code that I'm worried.

Spoiler

*edit*
Technically, there doesn't need to be a function table. The data could be located with each stub routine itself.  (updated code with this)

I feel like I'm wandering around in the dark.

 

I learned something new:  I was going to tell you not to use the trailing ‘:’ in your labels, but Asm994a allows it and ignores it.  I am pretty sure you cannot use it with the TI Editor/Assembler, however; but, there, you would be limited to 6 characters!

 

In your branches to TrampolineMain, you need to use BL @TrampolineMain to have a return address put in R11.  B is an unconditional branch, much like JMP, but unrestricted by distance—also, it is slower.  Also, if a function stub is called by BL, you will need to preserve R11 before calling the trampoline code.

 

With the BL change and your inclusion of the table information in the function stub, you no longer need the opening MOV because R11 is pointing at the DATA statement.

 

I think that the stack pointer for a downward-growing stack should point to the top of the stack, not beyond it, which means that you must reserve that space with the DECT before copying a value to it.  Also, STACK must be a register to use indirection.  If you use R10, you will need to EQUate STACK to R10:  STACK EQU R10.  If you label the base of the stack as STACK0, say, you will need to load that value into the STACK pointer register before its first use or when you wish to clear the stack:  LI STACK,STACK0.  DECT @STACK should be DECT STACK and before the MOV.  Popping the stack, then, is only one statement:  MOV *STACK+,@MEMPAGE, for example.

 

Another note:  You do not want to return to the function stub at the DATA statement, which is where R11 is pointing upon entry into the trampoline code; so, I would decrement the stack pointer by 4 and store the current MEMPAGE value as the top of the two reserved spaces on the stack:  

 

   AI   STACK,-4

   MOV  @MEMPAGE,*STACK

 

and wait until after the function table values are saved and R11 is incremented to the proper return address to store it under the old MEMPAGE value on the stack:

 

;load and set memory page of function from table based on value saved from R11
   MOV  *R11,@PageRegister        ;set memory page register to table entry
   MOV  *R11+,@MEMPAGE            ;copy for the return
   MOV  *R11+,R9                  ;save function address; R11 now pointing to proper return address
   MOV  R11,@2(STACK)             ;store function stub return address under top stack item
   BL   *R9                       ;call the function

 

One last note:  In order to switch ROM banks, you need to write to the index location for a particular bank, which means that all of the memory page locations should be one of these indices.  For a ROM using a 378 latch (non-inverted), the index location for switching to bank 0 is >6000; for bank 1, >6002, etc.  I think you will need to use a register to do this.  You should be able to do this by changing the page register code above to

 

   MOV  *R11,R9             ;move ROM address index to R9

   CLR  *R9                 ;switch to ROM bank address index in R9

 

and the trampoline return code to

 

;Trampoline return code
 
   ;set memory page, which should be a ROM bank index address
   MOV  *STACK,R9           ;move ROM address index location to R9

   CLR  *R9                 ;switch to ROM bank address index in R9

 
   ;pop previous memory page from stack
   MOV  *STACK+,@MEMPAGE    ;get the previous memory page info
 
   ;pop return address from stack
   MOV  *STACK+,R9
   
   B    *R9                 ;return to caller
 

 

...lee


Edited by Lee Stewart, Tue Aug 2, 2016 2:59 PM.


#41 Lee Stewart OFFLINE  

Lee Stewart

    River Patroller

  • 3,967 posts
  • Location:Silver Run, Maryland

Posted Sun Aug 9, 2015 2:12 PM

My bank-changing code in the last and a previous post won't work :dunce: without another level of indirection, which I will correct in those posts, shortly.

 

...lee



#42 JamesD OFFLINE  

JamesD

    Quadrunner

  • 8,461 posts
  • Location:Flyover State

Posted Sun Aug 9, 2015 2:54 PM

I learned something new:  I was going to tell you not to use the trailing : in your labels, but Asm994a allows it and ignores it.  I am pretty sure you cannot use it with the TI Editor/Assembler, however; but, there, you would be limited to 6 characters!

I think every other assembler I've used supports it. I'm not sure they require it though so I'm not sure why I adopted the practice.
 

In your branches to TrampolineMain, you need to use BL @TrampolineMain to have a return address put in R11.  B is an unconditional branch, much like JMP, but unrestricted by distancealso, it is slower.  Also, if a function stub is called by BL, you will need to preserve R11 before calling the trampoline code.

Doesn't the compiler BL to the code stubs? R11 should already have the return address of the caller so just save it and restore it on exit.
If you use a BL from the code stubs you need to return from the bottom of the stub instead of the trampoline exit which is why I used B rather than BL.
Or maybe I'm missing something.
 

With the BL change and your inclusion of the table information in the function stub, you no longer need the opening MOV because R11 is pointing at the DATA statement.

You need to save the return address of the caller in it's place but yeah, this would work.
See my response on the stack below.

 

I think that the stack pointer for a downward-growing stack should point to the top of the stack, not beyond it, which means that you must reserve that space with the DECT before copying a value to it.  Also, STACK must be a register to use indirection.  If you use R10, you will need to EQUate STACK to R10:  STACK EQU R10.  If you label the base of the stack as STACK0, say, you will need to load that value into the STACK pointer register before its first use or when you wish to clear the stack:  LI STACK,STACK0.  DECT @STACK should be DECT STACK and before the MOV.  Popping the stack, then, is only one statement:  MOV *STACK+,@MEMPAGE, for example.

If you take the approach you suggest by using BL (which looks like an excellent idea the more I think about it), you do.
You can push directly to the stack to save R11 in the stubs.
 

Another note:  You do not want to return to the function stub at the DATA statement, which is where R11 is pointing upon entry into the trampoline code; so, I would decrement the stack pointer by 4 and store the current MEMPAGE value as the top of the two reserved spaces on the stack:  


That's why I used B rather than BL in the stubs.

 

   AI   STACK,-4

   MOV  @MEMPAGE,*STACK

 
and wait until after the function table values are saved and R11 is incremented to the proper return address to store it under the old MEMPAGE value on the stack:
 

;load and set memory page of function from table based on value saved from R11

   MOV  *R11,@PageRegister        ;set memory page register to table entry

   MOV  *R11+,@MEMPAGE            ;copy for the return

   MOV  *R11+,R9                  ;save function address; R11 now pointing to proper return address

   MOV  R11,@2(STACK)             ;store function stub return address under top stack item

   BL   *R9                       ;call the function

 
One last note:  In order to switch ROM banks, you need to write to the index location for a particular bank, which means that all of the memory page locations should be one of these indices.  For a ROM using a 378 latch (non-inverted), the index location for switching to bank 0 is >6000; for bank 1, >6002, etc.  I think you will need to use a register to do this.  You should be able to do this by changing the page register code above to
 

   MOV  *R11,*R11                 ;set memory page register to table entry

I don't see how this is setting the memory page. You are moving from/to the same location.
You should be moving the page number to the page register of the hardware.
If *R11 points to the same number it sure doesn't point the the paging hardware unless you expand the data and use MOV *R11+,*R11 .
Or am I wrong about what that does?
 

and the trampoline return code to
 

;Trampoline return code


   ;set memory page

   MOV  *STACK,*STACK


   ;pop previous memory page from stack

   MOV  *STACK+,@MEMPAGE   ;get the previous memory page info


   ;pop return address from stack, while returning to caller

   B    *STACK+            ;return to caller

 
 
...lee

*STACK *STACK? I still don't see a memory page register being set if there is a bank register and parameters.
So, I guess I don't understand what is going on there.

The *STACK+ does work if you point to the current location so that's a good argument for that approach but you still need to save the return address in R11 to get back to the caller.

B *STACK will save code even on what I have.

#43 JamesD OFFLINE  

JamesD

    Quadrunner

  • 8,461 posts
  • Location:Flyover State

Posted Sun Aug 9, 2015 3:02 PM

Ok, without pointing to the current stack address, I have this and it would get shorter with the changes *R11,*R11 for setting the memory page but I don't see how that works yet.
Spoiler

Edited by JamesD, Sun Aug 9, 2015 3:13 PM.


#44 Lee Stewart OFFLINE  

Lee Stewart

    River Patroller

  • 3,967 posts
  • Location:Silver Run, Maryland

Posted Sun Aug 9, 2015 3:16 PM

...

Doesn't the compiler BL to the code stubs? R11 should already have the return address of the caller so just save it and restore it on exit.
If you use a BL from the code stubs you need to return from the bottom of the stub instead of the trampoline exit which is why I used B rather than BL.
Or maybe I'm missing something.

 

I am looking at this as strictly ALC.  Whether or not this is the result of compiled code, if BL is used to execute the function stub, you would need to save R11 in the stub before moving on, just as you indicate.

 

 

If you take the approach you suggest by using BL (which looks like an excellent idea the more I think about it), you do.

You can push directly to the stack to save R11 in the stubs.

 

Yup.

 

 That's why I used B rather than BL in the stubs.

 

I thought as much, but did not want to presume anything.

 

 

 I don't see how this is setting the memory page. You are moving from/to the same location.

You should be moving the page number to the page register of the hardware.
If *R11 points to the same number it sure doesn't point the the paging hardware unless you expand the data and use MOV *R11+,*R11 .
Or am I wrong about what that does?
 
*STACK *STACK? I still don't see a memory page register being set if there is a bank register and parameters.
So, I guess I don't understand what is going on there.
 
The *STACK+ does work if you point to the current location so that's a good argument for that approach but you still need to save the return address in R11 to get back to the caller.
 
B *STACK will save code even on what I have.

 

This stuff is wrong because I needed another level of indirection with some of it—sorry about that.  I corrected that post and will also correct the previous one soon.

 

Regarding switching banks, there is no register to do that for ROM banks.  You must write (MOV, CLR, etc.) to an index address, even though nothing changes because it is ROM.  The index addresses are (for 378-latched ROM memory banks) >6000 for bank 0, >6002 for bank 1, etc.

 

...lee



#45 JamesD OFFLINE  

JamesD

    Quadrunner

  • 8,461 posts
  • Location:Flyover State

Posted Sun Aug 9, 2015 4:25 PM

Is this a legal instruction? 

MOV *STACK(4),R11

It's not in the book, it only shows something like @LABEL(5)

*edit*
Here is the corrected memory paging. (?)

Spoiler

Edited by JamesD, Sun Aug 9, 2015 4:44 PM.


#46 mizapf OFFLINE  

mizapf

    River Patroller

  • 3,633 posts
  • Location:Germany

Posted Sun Aug 9, 2015 4:57 PM

No, it's not legal. After * there must be a number from 0 to 15, possibly followed by a plus sign. The number may also come from some explicit EQU lines (or implicit lines like R0 EQU 0, R1 EQU 1 ...). Even when STACK is a EQU constant, the parentheses are not allowed.



#47 Lee Stewart OFFLINE  

Lee Stewart

    River Patroller

  • 3,967 posts
  • Location:Silver Run, Maryland

Posted Sun Aug 9, 2015 5:24 PM

What you want is

 

MOV @4(STACK),R11

 

This, of course, assumes STACK is a synonym for a register number and not a memory address.

 

Also, your DECT and INCT statements are decrementing/incrementing memory address contents, but the statements with *STACK are attempting to reference a register, which must evaluate to a number from 0 to 15.

 

...lee



#48 JamesD OFFLINE  

JamesD

    Quadrunner

  • 8,461 posts
  • Location:Flyover State

Posted Sun Aug 9, 2015 5:41 PM

And back to the drawing board.  
If *STACK is a register the code is totally wrong.
Using another register is possible but you have to use one the compiler doesn't care about or preserve it.


Edited by JamesD, Sun Aug 9, 2015 5:45 PM.


#49 Lee Stewart OFFLINE  

Lee Stewart

    River Patroller

  • 3,967 posts
  • Location:Silver Run, Maryland

Posted Sun Aug 9, 2015 8:33 PM

And back to the drawing board.  
If *STACK is a register the code is totally wrong.
Using another register is possible but you have to use one the compiler doesn't care about or preserve it.

 

Ah-h-h...I am flying blind when it comes to what registers the compiler may be using.  Like I said, I was treating it as pure ALC...sorry.

 

I suppose we could figure out a way to use our own registers for our own parameter stack and, if necessary, our own return stack, with LWPI or BLWP/RTWP for functions needing bank switching.  Since we would likely need to use our stack for passing parameters to the function stub, we might need to switch to our workspace registers with LWPI to manage our stack(s), switch back to the system workspace and execute BLWP to get to the function stub with our own workspace with system workspace stuff in our R13 – R15 until we return to the caller with RTWP from the trampoline function.  There's probably a less convoluted way to do this than my rambling here; but, this maybe will generate some ideas that actually might work..

 

...lee



#50 Tursi OFFLINE  

Tursi

    Quadrunner

  • 5,641 posts
  • HarmlessLion
  • Location:BUR

Posted Sun Aug 9, 2015 10:22 PM

Not sound petty, but I posted working code. What are you guys trying to build?

 

The compiler already maintains a stack.... it's overkill to create your own off to the side. If you must push your data to a stack (and you don't always have to, which was why the code GCC produced was nice, it would only store the bank and return address on the stack if it was necessary), if you must, just use the compiler's stack. it's pointed to by R10, counts down, and you have to pre-decrement it. Fix it back up before returning to compiled code, and you're golden.

 

The compiler will store the function arguments in registers whenever possible -- in the case of the code I posted, R1 and R2 already have the arguments. This is faster and easier than trying to store the information in DATA statements after the call, especially if most of your code is already in C. The 9900 is not a stack-based processor, and Insomnia did a fantastic job adapting GCC to produce good code for it by not using the stack whenever it was possible - this is counter-intuitive if you are used to stack-based systems like the 6502 or Z80. It's not necessary to try to outsmart it - with twenty years experience there are still instances where it surprises me with brilliant assembly. ;)

 

I'm happy to go away and let you guys play with it if you're just trying to think it through, I don't mean to belittle that effort. I'd just like to help and I don't understand the end goal. 







Also tagged with one or more of these keywords: gcc, cartridge, bankswitching

0 user(s) are browsing this forum

0 members, 0 guests, 0 anonymous users