English Amiga Board


Go Back   English Amiga Board > Coders > Coders. Asm / Hardware

 
 
Thread Tools
Old 14 August 2021, 12:41   #1
hjalfi
Registered User
 
Join Date: Feb 2019
Location: Zurich
Posts: 38
Can anyone make this code shorter?

I'm working with a Dragonball VZ CPU. It's got a built-in bootloader which allows you to operate the CPU remotely (with no RAM or ROM needed); this has a 32-byte buffer which you can use to upload code fragments which can then be executed.

I'm trying to write a code fragment which will read addresses and values from the serial port and write them to the internal registers. So far I've got this:

Code:
loop:
	movq #4, %d7
	lea insn+2, %a2
wait:
	movew RX, %d1
	btstl #13, %d1    ; check for data being ready
	beqb wait
	moveb %d1, (%a2)+ ; received data is in the low byte
	dbf %d7, wait

	movew insn+4, %d1
	beqb exit
insn:
	movew #0x1234, 0x5678 ; overwritten with value and 16-bit target address
	brab loop
exit:
	; no return instruction needed
However, this is both too long (by four bytes) and uses self-modifying code, which I gather is a bad idea on the 68000.

Are there any clever tricks for making this fit within the 32-byte buffer?
hjalfi is offline  
Old 14 August 2021, 12:49   #2
grond
Registered User
 
Join Date: Jun 2015
Location: Germany
Posts: 1,918
Perhaps do the lea to a3 and then use a copy in the loop and later on 2(a3) instead of the insn+4.
grond is offline  
Old 14 August 2021, 13:02   #3
hjalfi
Registered User
 
Join Date: Feb 2019
Location: Zurich
Posts: 38
Oops, I completely forgot to say --- this code loads at 0xffffffc0, so all addresses can be represented with a negative 16-bit value rather than needing a 32-bit address...
hjalfi is offline  
Old 14 August 2021, 13:17   #4
a/b
Registered User
 
Join Date: Jun 2016
Location: europe
Posts: 1,039
Is the loop actually executed 5 times (d7=4 -> dbf loops 5 times), or is that a typo? 5 times means you rewrite the first byte of brab loop.

If it's executed 4 times, you can replace "movew insn+4,%d1" with "tstw -(a2)" (or move to d1 if you need the value for later).
Next... What are the replacement values for $5678? If they are within -$8000-$7fff you can try something like this (32 bytes):
Code:
loop	moveq	#4-1,d7
wait	move.w	RX(pc),d1	; or RX.w, no info on RX but since you said 36 bytes I guess it's either of these two
	btst	#13,d1
	beq.b	wait
	lsl.l	#8,d0
	move.b	d1,d0
	dbf	d7,wait

	tst.w	d0
	beq.b	exit
	move.w	d0,a2
	swap	d0
	move.w	d0,(a2)		; this works if a2 is within [-$8000,$7fff]
	bra.b	loop
exit

Last edited by a/b; 14 August 2021 at 13:34.
a/b is offline  
Old 14 August 2021, 13:31   #5
meynaf
son of 68k
 
meynaf's Avatar
 
Join Date: Nov 2007
Location: Lyon / France
Age: 51
Posts: 5,323
What is the effect of a write to address zero ? If it's no-op, then you can perform the write in all cases and do the loop afterwards, sparing a branch.
meynaf is offline  
Old 14 August 2021, 13:32   #6
Kalms
Registered User
 
Join Date: Nov 2006
Location: Stockholm, Sweden
Posts: 237
Taking the above into account, and also moving the test to the end, results in a 32-byte version:

(edit: meynaf beat me to it )

Code:
loop:
	movq #4-1, %d7
	lea insn+2, %a2
wait:
	movew RX.w, %d1
	btstl #13, %d1    ; check for data being ready
	beqb wait
	moveb %d1, (%a2)+ ; received data is in the low byte
	dbf %d7, wait

insn:
	movew #0x1234, 0x5678 ; overwritten with value and 16-bit target address
	tstw -(%a2)
	bneb loop
exit:
	; no return instruction needed
Also, self modifying code is fine on 68000. You can run into problems if you modify the directly preceding instruction on the classic M68000, not sure about the FLX68000 core. It is with 68020+ that have instruction/data caches that you need to be careful.
Kalms is offline  
Old 14 August 2021, 14:19   #7
Exodous
Registered User
 
Join Date: Sep 2019
Location: Leicester / England
Posts: 201
If a write to 0x0000 isn't a no-op, I can get it down to 32 bytes, but you do need to write 6 bytes each time via the serial link... 0x31 0xfc (move instruction) followed by 2 bytes of immediate value and 2 bytes of data...

Devpac 68000 format (org and RX equ just so it assembles for testing):

Code:
	org $ffffffc0

RX	equ	$1234	; Set this accordingly

loop:
	moveq	#6-1,d7
	lea	next(pc),a2
next:
	nop		; Overwritten with 0x31fc
	nop		; Overwritten with immediate value
	nop		; Overwritten with address
wait:
	move.w	RX.w,d1
	btst.l	#13,d1
	beq.s	wait
	move.b	d1,(a2)+
	dbf	d7,wait

	tst.w	-(a2)	; Test address
	bne.s	loop

exit:
and hopefully code that matches your assembler:

Code:
; Assumes RX is already defined

loop:
	movq	#6-1,%d7
	lea	next(%pc),%a2
next:
	nop		; Overwritten with 0x31fc
	nop		; Overwritten with immediate value
	nop		; Overwritten with address
wait:
	movew	RX.w,%d1
	btstl	#13,%d1
	beqb	wait
	moveb	%d1,(%a2)+
	dbf	%d7,wait

	tstw	-(%a2)	; Test address
	bneb	loop

exit:
Exodous is offline  
Old 14 August 2021, 14:34   #8
meynaf
son of 68k
 
meynaf's Avatar
 
Join Date: Nov 2007
Location: Lyon / France
Age: 51
Posts: 5,323
If write to 0 isn't acceptable, then it's still doable this way :
Code:
insn:
	move.w #$31fc,insn.w ; neutral - overwritten with value and 16-bit target address
	moveq #3,d7
	lea insn+2(pc),a2
wait:
	move.w RX.w,d1
	btst #13,d1    ; check for data being ready
	beq.b wait
	move.b d1,(a2)+ ; received data is in the low byte
	dbf d7,wait
	tst.w -(a2)
	bne.b insn
meynaf is offline  
Old 14 August 2021, 14:54   #9
Exodous
Registered User
 
Join Date: Sep 2019
Location: Leicester / England
Posts: 201
Whilst having lunch, I realised you can still do it sending 4 bytes with the following minor adjustment which basically sets the move instruction to be the ocode of the move instruction on the first pass.


Code:
 ; Assumes RX is already defined

loop:
    movq    #3-1,%d7
    lea    next+2(%pc),%a2
next:
    movew    #0x31fc,next.w   ; Sets this instruction to what it currently is 
wait:
    movew    RX.w,%d1
    btstl    #13,%d1
    beqb    wait
    moveb    %d1,(%a2)+
    dbf    %d7,wait

    tstw    -(%a2)    ; Test address
    bneb    loop

exit:
Exodous is offline  
Old 14 August 2021, 14:56   #10
Exodous
Registered User
 
Join Date: Sep 2019
Location: Leicester / England
Posts: 201
Which is what @meynaf has effectively posted
Exodous is offline  
Old 14 August 2021, 15:06   #11
meynaf
son of 68k
 
meynaf's Avatar
 
Join Date: Nov 2007
Location: Lyon / France
Age: 51
Posts: 5,323
Is the code allowed to destroy itself ?
Because then we can do :
Code:
insn:
	lea insn(pc),a2
loop:
	moveq #3,d7
wait:
	move.w RX.w,d1
	btst #13,d1    ; check for data being ready
	beq.b wait
	move.b d1,(a2)+ ; received data is in the low byte
	dbf d7,wait
	movea.w -(a2),a1  ; address
	move.l a1,d1    ; tst.l a1
	beq.b exit
	move.w -(a2),(a1)   ; data
	bra.b loop
exit:
No SMC this time. We just write data over an already executed instruction (that won't be executed again).
Of course, if writes to zero are allowed too, then extra branch is removed and it's done in 30 bytes
meynaf is offline  
Old 14 August 2021, 15:47   #12
a/b
Registered User
 
Join Date: Jun 2016
Location: europe
Posts: 1,039
Lunch break is over for me as well... Came up with another 2 or 4 bytes save in my code (=30 or 28 bytes):
1. -2: if you can use 4 bytes as a terminator, no need to tst.w d0 because swap will do that for free
2. -2: if you can have an arbitrary entry point (first instruction doesn't have to be the entry point)
Code:
loop	move.w	d0,(a2)
start_here
	moveq	#4-1,d7		; <= ENTRY POINT
wait	move.w	RX.w,d1		; this seems to be a general consensus
	btst	#13,d1
	beq.b	wait
	lsl.l	#8,d0
	move.b	d1,d0
	dbf	d7,wait
	move.w	d0,a2
	swap	d0		; d0.l = 0?
	bne.b	loop
a/b is offline  
Old 14 August 2021, 23:45   #13
hjalfi
Registered User
 
Join Date: Feb 2019
Location: Zurich
Posts: 38
Thanks very much --- that works fine!

Now I just need to work out why my much simpler memory fill routine always appears to hang the board after writing 205 bytes. It's not related as to where it's writing, as if I tell it to write to ROM it behaves exactly the same way, so it's not hitting an address trap of some kind...

Code:
_start:
	lea 0x12345678, %a2   | address; placeholder value, replaced
	movl #0x12345678, %d7 | length; placeholder value, replaced
loop:
	movb #0x88, (%a2)+    | value; placeholder value, replaced
	subql #1, %d7
	bneb loop
exit:
hjalfi is offline  
Old 16 August 2021, 08:10   #14
meynaf
son of 68k
 
meynaf's Avatar
 
Join Date: Nov 2007
Location: Lyon / France
Age: 51
Posts: 5,323
Quote:
Originally Posted by hjalfi View Post
Now I just need to work out why my much simpler memory fill routine always appears to hang the board after writing 205 bytes. It's not related as to where it's writing, as if I tell it to write to ROM it behaves exactly the same way, so it's not hitting an address trap of some kind...
Try this :
Code:
_start:
    lea 0x12345678, %a2   | address; placeholder value, replaced
    movl #0x12345678, %d7 | length; placeholder value, replaced
    movb #0x88, %d1    | value; placeholder value, replaced
loop:
    movb %d1, (%a2)+
    subql #1, %d7
    bneb loop
exit:
This one is just slightly faster. I suspect the problem is timing related and if it is so, you'll get a little more than 205 bytes.
meynaf is offline  
Old 17 August 2021, 23:39   #15
hjalfi
Registered User
 
Join Date: Feb 2019
Location: Zurich
Posts: 38
That does indeed help --- but only very slightly. But I've managed to do some more debugging; it seems that when it crashes, my machine resets. (I laboriously wrote some code which intercepts the exception vectors and I can see it hit exception #0.)

The more I look into this the more confused I get.

- it doesn't matter whether I'm writing to RAM or ROM.
- if I write to the same address (i.e. by removing the + postincrement), it's fine.
- adding a trivial delay loop (wait: movql #1, %d1; dbf %d1, wait) between writes causes it to die immediately. A wait value of 0 lets it succeed, but the magic number is still 205 bytes.
- if I do 'movb %d1, (%a2); addql #1, %a2' then it behaves precisely as before (205 bytes).
- if I do 'movb #0x88, %d1; ... movb %d1, (%a2); addql #1, %a2' I get 209 bytes.
- if I do 'movb #0x88, %d1; ... movb %d1, (%a2)+' I get 209 bytes.
- when the bootloader itself does a write, everything works fine! And I've disassembled that, and it's not touching any mysterious registers between writes --- the only thing it's doing is polling the uart for more data...

This is increasingly less and less Amiga related, but... do 68000 machines tend to reset when a double fault occurs? (I can see in the data sheet that normally the CPU halts and waits for external input, which is normally no use to anyone.)
hjalfi is offline  
Old 18 August 2021, 00:15   #16
Don_Adan
Registered User
 
Join Date: Jan 2008
Location: Warsaw/Poland
Age: 55
Posts: 1,959
Are you sure that your code dont overwrite/trash important data/code?
Maybe try move.l #205,D7 and later move.l #206,D7 and check output.
Don_Adan is offline  
Old 18 August 2021, 05:16   #17
a/b
Registered User
 
Join Date: Jun 2016
Location: europe
Posts: 1,039
Quote:
Originally Posted by hjalfi View Post
- adding a trivial delay loop (wait: movql #1, %d1; dbf %d1, wait) between writes causes it to die immediately. A wait value of 0 lets it succeed, but the magic number is still 205 bytes.
That's an infinite loop if d1 > 0. Label wait should be between movql and dbf.

Also, exception #0 doesn't sound right. First two vectors are reset sp and pc.
I don't know how limited is debugging in your case, can you display any info and/or have access to specific data like stack or register values...? I would start with setting the exception vectors 2-15 ($0008-$003c) to something like:
Code:
vecX:	move.w	#$4000,$dff09a
loopX:	move.w	#<COLOR>,$dff180
	bra.b	looopX
X=2..15, and use a different color for each exception. That would tell you which one is happening based on the color of the screen, and then if you can display data perhaps dump or save (if you can somehow access them elsewhere or maybe after the reset if the memory is not being wiped out) stack frame (exception specific) and/or register values.
a/b is offline  
Old 18 August 2021, 08:31   #18
grond
Registered User
 
Join Date: Jun 2015
Location: Germany
Posts: 1,918
From what privilege level are you running that code?
grond is offline  
Old 18 August 2021, 11:25   #19
meynaf
son of 68k
 
meynaf's Avatar
 
Join Date: Nov 2007
Location: Lyon / France
Age: 51
Posts: 5,323
My impression is that an interrupt comes for whatever reason and there is nothing to handle it -> crash.
If running in supervisor mode (i suppose it does, it's embedded thingy), then move.w #$2700,sr should clear that up.
meynaf is offline  
Old 18 August 2021, 18:39   #20
WayneK
Registered User
 
Join Date: May 2004
Location: Somewhere secret
Age: 50
Posts: 364
Are you sure there is no kind of watchdog timer that you need to acknowledge? This behaviour seems odd...
WayneK is offline  
 


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools

Similar Threads
Thread Thread Starter Forum Replies Last Post
how to make this code 68000 compliant? jotd Coders. Asm / Hardware 2 30 January 2021 18:25
Do I have to change anything in the code to make BB2 work as AB3? peceha Coders. Blitz Basic 4 22 June 2020 09:24
I am trying to make my first GFX assembler code litwr Coders. Tutorials 111 14 December 2018 21:10
Make IDE cable shorter Photon support.Hardware 10 21 August 2011 11:48
Another World - Amiga's version is shorter?? Anubis Retrogaming General Discussion 13 06 May 2007 15:39

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 00:38.

Top

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.
Page generated in 0.09644 seconds with 13 queries