Making real 256kb ROMs in SDCC

Page 3/4
1 | 2 | | 4

By geijoenr

Master (140)

geijoenr's picture

24-05-2020, 21:47

salutte, samsaga2,
I made huge progress today, I managed patch both sdcc and the included linker to translate banked calls into the sequences indicated above resolving the bank numbers.

https://github.com/retrodeluxe/sdcc-msx

It works by using "--model-large" when compiling. Then specifying for each module to which bank it belongs by either using the -bo [bank] option, or "#pragma bank [bank]" in the code.
Bank addresses need to be passed to the linker, e.g. "-b _CODE_[bank]=0x[bank]A000"

Then __sdcc_banked_call needs to be implemented in a non-banked area. I am not sure how this function should look like yet, it needs to read an address and a parameter, then setup the stack properly on return.

   call __sdcc_banked_call
   dw address
   db bank

Banked calls are default when using model large, but are selectable by using the __nonbaked attribute. Note that this only works if the functions are in a separate module that doesn't contain any #pragma banks, and is not compiled using the -bo option.

void unbanked_function() __nonbanked
{
}

By salutte

Resident (58)

salutte's picture

25-05-2020, 07:19

Wow! This is awesome! I read the commit and it's very clean Smile

I just read your post, and thus I'm not sure about how the __sdcc_banked_call should look like, but by placing it into the "_HOME" area it should be always in a non bankable place.

To extend this, do you think it is feasible to add a 3 byte sized pointer too? (e.g.. attribute __far) MMM.. or it's better to leave the data manage to manual, to minimize problems.

Also, it is possible to split and place the const data in a module, and the actual code in another (i.e. ($NAME)_CODE and ($NAME)_DATA)? Or even... if each function had it's module name.... that'd be nice for libraries...

ahhh so many options! so many ideas! That was an enlighting progress! Thanks!!!

By geijoenr

Master (140)

geijoenr's picture

25-05-2020, 15:16

Quote:

To extend this, do you think it is feasible to add a 3 byte sized pointer too? (e.g.. attribute __far) MMM.. or it's better to leave the data manage to manual, to minimize problems.

Also, it is possible to split and place the const data in a module, and the actual code in another (i.e. ($NAME)_CODE and ($NAME)_DATA)? Or even... if each function had it's module name.... that'd be nice for libraries...

far pointers are indeed supported in sdcc using "model-huge", but I don't think there is code generation for z80. It could be done, but I think the overhead would be quite big. Note that banked calls will already mean there is a considerable performance hit, imagine using a far pointer for switching banks before each data load. The problem is nested references, you need to keep track in a separate stack of every banked call and store the 24bit pointers.

I see the benefit of doing this be to be able to easily port a big application of up to 2MB (or 4MB) binary and put it in an ascii rom or run it on a memory mapper (something like an open source pc game?). It could be a good exercise to see how it turns out, but I have the feeling it only would work reasonably fast on a TurboR.

Regarding the separation of code and data, there is a -ba X option to generate _DATA_X segments, but there is no pragma at the moment. The separation of functions into modules would be indeed nice, because when included in a library only the modules that are actually linked go into the binary. I think this could be implemented in the linker itself probably.

By geijoenr

Master (140)

geijoenr's picture

27-05-2020, 08:30

I have made some additional improvements and I am testing it, it works quite well. Added a pragma for data and switch 2 pages in an ascii8 rom, one for code and the second for data.

https://github.com/retrodeluxe/rlengine-msx1/tree/linker_exp

the banked call handler looks like this, using a secondary stack to store the 24bit pointers.

__sdcc_banked_call:
		; save caller and current bank
		pop 	ix
		ld	a,(cur_page)
		ld	iy,#0
		add	iy,sp
		ld 	sp,(banked_sp)
		push 	ix
		push 	af
		ld 	(banked_sp), sp
		ld 	sp,iy

		; push return adrress
		ld	hl, #__sdcc_banked_ret
		push 	hl

		; read jump address and target page
		ld	l,(ix)
		ld 	h,1(ix)
		ld	a,2(ix)
		ld 	(cur_page),a

		; switch bank and perform call
		ld 	(ASCII8_PAGE2),a
		jp	(hl)
__sdcc_banked_ret:
		ld	iy,#0
		add	iy,sp
		ld 	sp, (banked_sp)
		pop 	af
		pop 	hl
		ld 	(banked_sp), sp
		ld 	sp,iy

		; restore bank
		ld 	(ASCII8_PAGE2),a
		ld 	(cur_page),a
		inc 	hl
		inc	hl
		inc	hl
		push	hl
		ret

By salutte

Resident (58)

salutte's picture

27-05-2020, 22:44

This is awesome! I need to explore more. I don't see exactly how the model works when dealing with data.

Thanks for your efforts!

By geijoenr

Master (140)

geijoenr's picture

28-05-2020, 00:21

I am trying to use it with the port of Abbaye des morts that I am doing as part of the test of my engine (same repo as above). I think is a good example because it contains 7 pages of data and several pages of code. If it works well is a perfect proof of concept, but as I mentioned before I am worried about performance. Let's see how it turns out. You can check it out as a full example on how to deal with data once is done (in a few days).

By geijoenr

Master (140)

geijoenr's picture

31-05-2020, 14:10

Salutte, it doesn't look very good so far. SDCC has some bugs in code generation when using the large model: the indexing of parameters from the stack sometimes is correct and sometimes makes no sense. It appears to be related to the handling of byte sized parameters but I am still investigating.

By salutte

Resident (58)

salutte's picture

02-06-2020, 10:27

Hi gejoenr,

that is sad news... I was always very afraid of going towards the way of modifying sdcc because of its complexity :S Let's see if you can find a way! I am continuing with the linker only avenue... I'm really motivated now to find a bank intercall routine that the linker can interpose. However, I am still worried about the const data areas, I'd love to have them distingushable. Maybe using the "non-intrinsic" named spaces is an option. I don't like it entirely, because it does not fulill one of my goals, to have a call with this prototype:
music_play(far const uint8_t *sound) ;

Maybe I can wrap a function and send a pointer to a function there... It sounds to me as very inefficient though.

By geijoenr

Master (140)

geijoenr's picture

02-06-2020, 11:18

I sorted it out partially. There is still some problem with the preambles when using __nonbaked, but as long as you are aware you can work around it. I have put some notes on the README of the sdcc-msx repo.

The game prototype I am working on is now using banked calls and I can extend the code beyond 32Kb without switching pages manually. Performance is also pretty good as long as critical calls use __nonbanked calls.

so I am quite happy with the result so far.

By samsaga2

Resident (57)

samsaga2's picture

05-06-2020, 19:35

My point of view it is that a sdcc fork is hard to maintain (too many work if you want to have your fork updated). I prefer an external utility like k5link.

I don't know if I understand well the problem about the trampoline. But I can see four type of calls:
1) From any page to page A. Direct call, you don't have to change the page. The page A never changes.
2) From a page to a different page. Save the current page on the stack, change the page, make the call, restore the page. You can have a method in the page A to do this.
3) Call in the same page, same rom segment. Direct call.
4) Call in the same page, different rom segment. You can use the same page A method used in the point 2. It's a very easy function to do.

I don't like very much solutions like Hitech-C far call. They use a function that pushes all the registers in the stack and then make the call, it's very slow.

About the constant segment... It's useful but it's easy to avoid. If the linker don't have support it, it is not the end of the world. If you have a const array it will be compiled in the code segment.

Page 3/4
1 | 2 | | 4