Glass Z80 assembler

Page 14/16
7 | 8 | 9 | 10 | 11 | 12 | 13 | | 15 | 16

By friguron

Master (162)

friguron's picture

02-06-2020, 04:09

Hi...

I've been messing around with Glass for some months. I've started to get the gist of it, being it the very first Z80 assembler I've used somewhat seriously.I'm liking it a lot, its cross compiling capabilities are fantastic, etc, etc... I'm using the latest "development version" .jar file. So far, all good.

My doubt will be explained after giving some context:

Lately my MSX needs have started to move into a recognizable pattern. I'm using some memory managment routines/libraries I'm starting to create, that live and are defined inside ROM (page 1) and that need to live in RAM (page 2 or 3, doesn't matter) to really be useful for my needs.
What does it mean? I don't really know how/where to write them inside my .asm file for them to be deployed onto RAM (automatically or manually).

Well I know how to do it manually, I'm somewhat managing to do it, but I'm somewhat lost among the different compiling dierctives of GLASS, as I'd like to know how to do it if I want my routines to be somewhat relocatable.

Typical thing I do: declare my routine in rom (page 1).

org 4000

RAM_ADDRESS: equ 0F000H

ld hl,routine
ld de, RAM_ADDRESS
ld bc, end_routine - routine

ldir

jp RAM_ADDRESS

routine:
ld
ld
ld
ld
ld
end_routine:

With this approach I deploy my rom defined routine onto RAM F000, which is what I want, but I'd like to know how to do it in the case my routine needs to have labels and conditional jumps inside (something that will happen whenever it becomes a bit more complex)... As far as I understand, relocating my routine onto RAM, would break all jumps, as they're defined onto .rom space inside my .asm file? Am I right?

Or even better I'd like to deploy my routines onto a RUNTIME calculated RAM address, instead of a compilation time defined one. Can Glass be of any help for this kind of dynamic deployment (I think) I need?

I've read the SECTION part of Glass manual but it's still unclear if it can serve my needs.

I've also come accross defining different org directives around my code, for the compiler to decide the deployment/compiling address... But then, does Glass "deploy" my rom defined routines onto ram automatically? Can't see how...

So here I am, asking what's the typical approach when dealing with a situation like this:

how to define a relocatable routine in rom (or at least in my asm file), that will live onto some defined|dynamic ram address on runtime, after I copy its code onto RAM?

I hope I've somewhat explained myself. Thanks in advance and kudos to Grauw for this fantastic small and compact assembler.

Greetings.

By Manuel

Ascended (16632)

Manuel's picture

02-06-2020, 07:53

Isn't it a matter of using jr instead of jp inside the relocatable routine?

By thegeps

Champion (439)

thegeps's picture

02-06-2020, 10:31

You can use jr if it fits your routine lenght. Else, if you already know the address you want to copy your routine, you can hardcode the jump addresses. Simply assemble your routine in a .bin file accordignly ORGed and copy labels' addresses from the symbol file...

By friguron

Master (162)

friguron's picture

02-06-2020, 10:59

I'm dealing with 2 or 3 routines as of now, but sadly there's one of them which is big enough to start needing JP's instead of JR's... That's my point...

I'd like not to depend on hardcoded approaches (as I manually do now with EQU's and so), as the ideas I have in mind would like to allocate dinamically these routines.

Something like this:

ld hl, 0xf100 ; dest address for my routine (decision made at runtime, not at compilation time)
call deploy_routine_onto_hl_address
"call hl"  ; I have some tricky routine to do this.

I'll study thegeps approach to see if it fits my automatic Makefile process to build my programs... Unsure about that... It will be later today anyway.

Thanks!

By thegeps

Champion (439)

thegeps's picture

02-06-2020, 11:56

Well, then you can set a lookup table, based of a pre assembled routine, containing the labels' offsets, that you can add to your start address and "fix" jump addresses after allocation...

By Grauw

Ascended (9054)

Grauw's picture

02-06-2020, 11:57

Call HL:

    call JumpHL
    ; ....

JumpHL:
    jp hl
JumpDE:
    push de
    ret
JumpBC:
    push bc
    ret
JumpIX:
    jp ix
JumpIY:
    jp iy

By Grauw

Ascended (9054)

Grauw's picture

02-06-2020, 12:15

Relocatable to a static address is easy, use org to set the address of the RAM section to the destination address, like:

    ld hl,RAM_sourceAddress
    ld de,RAM_startAddress
    ld bc,RAM_endAddress - RAM_startAddress
    ldir

; ...

RAM_sourceAddress:
    org 0C000H
RAM_startAddress:

; ... RAM stuff here

RAM_endAddress:
    org RAM_sourceAddress + (RAM_endAddress - RAM_startAddress)

This code is not specific to Glass by the way, it works like that in any assembler. And yes you need to take care of copying it yourself, there is no “runtime” which does it for you.

With Glass you can use the SECTION directive to simplify your life a bit, because stuff that needs to be in RAM does not need to be defined in a single place:

    ld hl,RAM_sourceAddress
    ld de,RAM_startAddress
    ld bc,RAM_endAddress - RAM_startAddress
    ldir

; ...

RAM_sourceAddress:
    org 0C000H
RAM_startAddress:
RAM: ds 2000H
RAM_endAddress:
    org RAM_sourceAddress + (RAM_endAddress - RAM_startAddress)

; ... and elsewhere have several

    SECTION RAM

    ; any code in a RAM section ends up in the DS above.

    ENDS

As for relocation to a dynamic location, that is more difficult unless you use jr only. You need to track all address pointers and rewrite them dynamically. One way to do so is to store two copies of the RAM routines at different addresses (so e.g. INCLUDE it twice), and then as you copy it to upper memory compare the bytes from the two copies. If they are different, then it is a relocated address pointer which you need to adjust appropriately.

By friguron

Master (162)

friguron's picture

02-06-2020, 12:14

How many hints and proofs of concept!

As I can confirm reading you replies, many assumptions I already made were true (mainly: a big routine is not being easily realocatable if it needs JP's inside)...

Otherwise I'm sure I'll manage to do something with that info. Thanks!

By Grauw

Ascended (9054)

Grauw's picture

02-06-2020, 12:36

So from an assembler perspective what could improve here is that it could support generating relocatable object files and linking. Then you could have a script generate a relocation table and link it and the object file against a runtime. That’s not what the assembler is set up for at the moment though. Also it places restrictions on the mathematical operations you can do on addresses in the assembly code.

What you can do to simulate that approach though, is to define labels with a particular prefix at every place where you have a reference to an address that is relocated. Like call Xxx, REL_callingXxx: equ $ - 2. Then use a script to generate a table of those from the symbol file generated by the assembler, and use that in your source as a list of addresses to rewrite.

But I think the two-copies-at-different-addresses approach is easier. And of course relocating to a static address rather than a dynamic one is the easiest.

By pgimeno

Master (170)

pgimeno's picture

02-06-2020, 14:33

Here's an example of relocatable code using a fixup (relocation) table. It needs a known address which has RAM and two bytes free. I've used 0FB36h (SAVSP, used only for the PLAY instruction) for this purpose.

TwoBytesFree	equ	0FB36h

		ld	hl,0E9E1h	; opcodes for POP HL / JP (HL)
		ld	(TwoBytesFree),hl
		call	TwoBytesFree
Ofs:
		ld	bc,-Ofs		; subtract real address
		add	hl,bc
		ld	b,h
		ld	c,l
		ld	hl,FixupTable	; get address of fixup table rel. to 0
		add	hl,bc		; fix up this address itself
		ex	de,hl
NextFixup:	ld	a,(de)
		inc	de
		ld	l,a		; Grab next entry into HL
		ld	a,(de)
		ld	h,a
		or	l		; A zero indicates end of fixup table
		jr	z,FixupEnd
		inc	de
		add	hl,bc		; Add correct offset
		ld	a,(hl)		; Fixup by adding BC to (HL)
		add	a,c
		ld	(hl),a
		inc	hl
		ld	a,(hl)
		adc	a,b
		ld	(hl),a
		jr	NextFixup

FixupEnd:	; Let's test it!

		ld	hl,TextOfs
Fixup1		equ	$-2
LoopPrint:	ld	a,(hl)
		inc	hl
		or	a
		ret	z
		rst	18h
		jp	LoopPrint
Fixup2		equ	$-2


TextOfs:	db	"It worked!"
		db	0

FixupTable:	dw	Fixup1, Fixup2
		dw	0		; End marker
Page 14/16
7 | 8 | 9 | 10 | 11 | 12 | 13 | | 15 | 16