C & Assembler conundrum

Everything about programming, including VDP and Sound programming.
Post Reply
User avatar
JonB
Posts: 101
Joined: 08 Nov 2013 11:16

C & Assembler conundrum

Post by JonB » 01 Jan 2016 16:44

Here's a straightforward bit of programming for you!

Consider the following C code:

Code: Select all

        char *p;
        for ( p=Fileend; p>Curschar; p-- )
        {
                *p = *(p-1);
        }
What it does is move a block of memory from Curschar to Fileend one byte up (to open a place in a buffer for a character that's about to be inserted).

I rewrote the loop in assembler:

Code: Select all

psect text
global  _Curschar
global  _Fileend

                                ;Init
        ld bc,(_Fileend)        ;p=Fileend
        inc bc                  ;p=Fileend+1
loop1:  dec bc                  ;p--
        dec bc                  ;p--

        ld a,(bc)               ;get char to be moved (swap=*p)
        inc bc                  ;copy it (p++)
        ld (bc),a               ;..to p (*p=swap)

        ld h,b
        ld l,c
        ld de,(_Curschar)       ;have we reached the insert point?

        ld a,h
        cp d
        jp nz, loop1

        ld a,l
        cp e
        jp nz,loop1
Only problem is, it fails. What appears to be happening is the character to insert is overwriting the insert point and the memory is not being shuffled down. I must have done something really stupid but I can't spot it. Any ideas?

Cheers
JonB

PS, the assembler algorithm looks like this is C, and it works.

Code: Select all

        char* p=Fileend;
        char swap;
        for(;;)
        {
                p--;
                swap=*p;
                p++;
                *p=swap;
                if(p-Curschar == 0) break;
                p--;
        }

Bill B
Posts: 159
Joined: 26 Jan 2014 16:31

Re: C & Assembler conundrum

Post by Bill B » 01 Jan 2016 17:08

I think that the way I would do this is something like:

Code: Select all

	ld	hl, _fileend	; High address
	ld	de, _Curschar	; Low address
	and	a			; Ensure carry is clear
	sbc	hl, de		; Number of bytes to move
	ld	b, h			; Copy HL to BC
	ld	c, l
	ld	de, _fileend
	ld	h, d			; Copy DE to HL
	ld	l, e
	dec	hl			HL points one byte lower
	lddr				; Copy (HL) to (DE), Decrement HL and DE, repeat BC times
Either way, single step the code in PANEL, either in MEMU or a real MTX.

User avatar
JonB
Posts: 101
Joined: 08 Nov 2013 11:16

Re: C & Assembler conundrum

Post by JonB » 01 Jan 2016 17:21

Or this:

Code: Select all

#asm

psect text
global  _Curschar
global  _Fileend

                                ;Init
        ld bc,(_Fileend)        ;p=Fileend
loop1:  dec bc                  ;p--
        ld a,(bc)               ;get char to be moved (swap=*p)
        inc bc                  ;copy it (p++)
        ld (bc),a               ;..to p (*p=swap)

        ld h,b
        ld l,c
        ld de,(_Curschar)       ;have we reached the insert point?

        dec bc

        ld a,h
        cp d
        jp nz, loop1

        ld a,l
        cp e
        jp nz,loop1

#endasm
(which seems to work...)

Bill B
Posts: 159
Joined: 26 Jan 2014 16:31

Re: C & Assembler conundrum

Post by Bill B » 01 Jan 2016 17:37

The only difference between your two versions that I can see is that the original version will stop after copying

*(_Curschar-1) -> *(_Curschar)

Whereas your second version will stop after copying

(*_Curschar) -> *(_Curschar+1)

If, as I understand, you are then going to replace *(_Curschar) by a new value, it should not make any difference (except the extra work).

Bill.

Bill B
Posts: 159
Joined: 26 Jan 2014 16:31

Re: C & Assembler conundrum

Post by Bill B » 01 Jan 2016 17:54

And why use BC at all? How about:

Code: Select all

#asm

psect text
global  _Curschar
global  _Fileend

                                ;Init
        ld hl,(_Fileend)        ;p=Fileend
        ld de,(_Curschar)       ; Remember the insert point
loop1:  dec hl                  ;p--
        ld a,(hl)               ;get char to be moved (swap=*p)
        inc hl                  ;copy it (p++)
        ld (hl),a               ;..to p (*p=swap)
        dec hl

        ld a,h		;have we reached the insert point?
        cp d
        jr nz, loop1

        ld a,l
        cp e
        jr nz,loop1

#endasm
Indirect addressing on Z80 is most efficient using HL.

User avatar
JonB
Posts: 101
Joined: 08 Nov 2013 11:16

Re: C & Assembler conundrum

Post by JonB » 01 Jan 2016 18:06

This is the problem.

I am developing it on CP/M with Hi-Tech C 3.09 and there is some corruption going on. Unfortunately the manual, while detailed, doesn't give much guidance on embedding assembler inline in a C program (which this is - and I'm trying to optimise it).

It seems to be stable with the psect macro and enclosed in braces... until the next crash!

It's not on the MTX (although it could be) so I have no Panel. I am using an emulated CP/M machine running in a Linux VM so speed isn't an issue, but the 4Mhz target machine (a Philips P2000C) is way too slow to run this...

User avatar
JonB
Posts: 101
Joined: 08 Nov 2013 11:16

Re: C & Assembler conundrum

Post by JonB » 01 Jan 2016 18:08

Bill B wrote:Indirect addressing on Z80 is most efficient using HL.
I did wonder. I suppose I wanted it working first! Yes, 3 t-states with HL vs BC..

(edit:seems to be broken again. I think it is psect areas conflicting)

Post Reply