English Amiga Board


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

 
 
Thread Tools
Old 05 November 2018, 23:13   #1
ross
Defendit numerus
 
ross's Avatar
 
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,474
Floppy disk Spurious PORTS irq

While I was writing some code using CIA registers I came across a strange behaviour that I can not understand.
All tests done in WinUAE, latest version, bare Quickstart A500 configuration or A1200 configuration.
I was undecided whether to write in support.WinUAE thread or in the Coders.Asm/Hardware section.

I have finally decided to post here because maybe something obvious escapes me.

I have written only the minimum parts that reproduce the problem, in the simplest way: a bare keyboard handler.

This code generates spurious PORTS irq and I can not quite understand why:
Code:
progstart
	lea	$dff000,a6
	lea	$bfed01,a5
	move.w	#$7fff,($9a,a6)
	move.b	#$7f,(a5)
	move.b	#$89,(a5)	;SP+TA
;	move.b	#$8f,(a5)
	lea	(.i2,pc),a0
	move.l	a0,($68).w
	move.w	#$c008,($9a,a6)	;PORTS

.la	cmpi.w	#$9007,($6,a6)	;keyboard raw code 
	blo.b	.la		;as colors on screen
	move.b	(key,pc),d0
	move.w	d0,$180(a6)
.lb	cmpi.w	#$0101,($6,a6)
	bhs.b	.lb
	bra.b	.la

;PORTS irq handler
.i2	movem.l	d0/a0/a1,-(SP)
	lea	($bfe001),a0
	lea	($dff09c),a1

	move.b	($d00,a0),d0	;read IRQ source and clear
	btst	#3,D0		;serial (keyboard)
	bne.b	.ik
	tst.b	d0		;is there really a CIA IRQ?
	bne.b	.ix		;if==0 spurious PORTS irq
.ic	move.w	($6-$9c,a1),($180-$9c,a1)	;rainbow
	bra.b	.ic

.ik	move.b	($c00,a0),d0	;read raw key
	move.b	#$48,($e00,a0)	;SPMODE=output, RUNMODE=one-shot
	move.b	#$8E,($400,a0)	;setup ~200us delay
	clr.b	($500,a0)	;start timer A
	not.b	d0
	ror.b	#1,d0

.il	btst	#0,($d00,a0)	;check if time passed
	beq.b	.il		;and cleans IRQ
;	tst.b	($d00,a0)	;* 1)
;	tst.b	($d00,a0)	;* 2)
	clr.b	($e00,a0)	;SPMODE=input, ACK keyboard
;	tst.b	($d00,a0)	;* 3)

	lea	(key,pc),a0
	move.b	d0,(a0)	        ;store raw key

.ix	moveq	#8,D0
	move.w	d0,(a1)	        ;cleans PORTS irq
	move.w	d0,(a1)
	movem.l	(sp)+,d0/a0/a1
	rte

key	ds.b	1
pad	ds.b	1
If the spurious IRQ is not generated you can notice a simple colour change in the middle of the screen with a keypress, else system stuck and a multicolor rainbow screen.

To have a working code on A500 you've to add the commented out line [* 1)], otherwise the code generates unwanted IRQs.
For machines from the A1200 and up you must also add line [* 2)] or alternatively a solo line [* 3)] (with cache deactivated it's sufficient [* 1)], like A500).

Attached two binary versions: the pure one (without added lines) [kbs.0] and the one with additional line [* 1)] [kbs.1].

I would be grateful to those who could try on real machines or who could help me to understand the reason for this behavior.

In fact are not a problem the strange IRQs generated, it's just enough ignore them by cleaning up INTREQ(PORTS), but I would like to understand..

EDIT: removed attached files

Last edited by ross; 07 November 2018 at 13:04.
ross is offline  
Old 06 November 2018, 11:04   #2
roondar
Registered User
 
Join Date: Jul 2015
Location: The Netherlands
Posts: 3,411
A silly question perhaps, but could it be that timer A is already running (through the OS for instance) when you start the program and enable it as a source for interrupts?

If I'm reading the code correctly, I don't see you disable the timer prior to setting/checking it later in the interrupt handler.
roondar is offline  
Old 06 November 2018, 12:25   #3
ross
Defendit numerus
 
ross's Avatar
 
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,474
Your question is relevant and you're right, at first I don't touch Timer A counter.
But there is a simple reason: seems that it's not used by the system, at least not at boot and I assumed that the program was launched at boot.
Sorry if I did not add that to the description.

At program start, if you wait, no interrupts are triggered, a confirmation that TA is unused (in code I've left active only SP and TA).
When a key is pressed IRQ2 is triggered (SP source), then inside the handler I make a delay of 200us (using timer A) for the ACK.
This delay triggers an IRQ but is cleared by the very same check.
I could have avoided from the beginning a TA IRQ generation (not enabling it), but the point is precisely this peculiarity, which makes the spurious IRQ happens.

When I release the key, an IRQ is triggered again, again due to SP: it's after this that most of the time the spurious IRQ is generated.
Despite ICR being cleaned up, for some reason an IRQ2 immediately retrigger and this time the source is apparently not the CIA!

You can see it because ICR on handler entrance is zeroed..
It's a possible situation if you have external devices (HDD controller, USB controller, also CD32 generates it) but I can not understand how an A500 generate it.
Furthermore, the fact that adding a fictitious ICR cleanup to not incur in this situation seems strange to me, as if there were delays in the propagation of the signals.

It may be that a real machine behaves like that, but it's odd, I do not know why and it's not documented.
I would like to have a confirmation

Thanks for your time!

Last edited by ross; 06 November 2018 at 13:19. Reason: maybe a better english.. maybe..
ross is offline  
Old 06 November 2018, 14:51   #4
roondar
Registered User
 
Join Date: Jul 2015
Location: The Netherlands
Posts: 3,411
Well, I can't really see any other issues - apart from one that seems far fetched to me. The code looks like it should work and resembles other keyboard handling code I've seen.

The only thing that might (emphasis on might) cause some issues on the A500 version is your use of the clr command. On a plain 68000 that does both a read and a write instead of just writing a zero, which might cause issues because the CIA register you clr.b is write-only AFAIK and thus should not be read from.

However, the 68020 should've fixed that issue so the A1200 version ought to be OK then.
roondar is offline  
Old 06 November 2018, 14:54   #5
dissident
Registered User
 
Join Date: Sep 2015
Location: Germany
Posts: 260
Hi ross, I saw your code and there are two things that I noticed and I got a little hint:

Code:
    move.b    #$48,($e00,a0)    ;SPMODE=output, RUNMODE=one-shot
    move.b    #$8E,($400,a0)    ;setup ~200us delay
    clr.b    ($500,a0)    ;start timer A
Why not doing it this way, so you have the guarantee that your code is executed serial in the right order especially on a 68060:

Code:
    moveq     #$48,d1
    move.b    d1,($e00,a0)    ;SPMODE=output, RUNMODE=one-shot
    moveq     #$-$72,d1       ;Same as $8e, but compatible to moveq command
    move.b    d1,($400,a0)    ;setup ~200us delay
    moveq     #0,d1
    move.b    d1,($500,a0)    ;start timer A
And for:

Code:
.ix    moveq    #8,D0
    move.w    d0,(a1)            ;cleans PORTS irq
    move.w    d0,(a1)
    movem.l    (sp)+,d0/a0/a1
    rte
Code:
.ix    moveq    #8,D0
    move.w    d0,(a1)            ;cleans PORTS irq
    movem.l    (sp)+,d0/a0/a1
    nop                                
    rte
Which does the same as above, but using a nop is shorter/faster and also prevents parallel execution on the 68060 and your code will be excuted in the right order (No execution of the rte command before the interrupt is cleared).
dissident is offline  
Old 06 November 2018, 15:00   #6
roondar
Registered User
 
Join Date: Jul 2015
Location: The Netherlands
Posts: 3,411
Quote:
Originally Posted by dissident View Post
so you have the guarantee that your code is executed serial in the right order especially on a 68060
Serial execution is guaranteed on all but 68060

So while still an interesting point, a better phrase would've been "so you have the guarantee your code is executed serial in order on a 68060". No other 68k chip has a superscalar/out of order design (perhaps the Vampire does though, I don't really know anything about that chip).

Quote:
Code:
.ix    moveq    #8,D0
    move.w    d0,(a1)            ;cleans PORTS irq
    move.w    d0,(a1)
    movem.l    (sp)+,d0/a0/a1
    rte
Code:
.ix    moveq    #8,D0
    move.w    d0,(a1)            ;cleans PORTS irq
    movem.l    (sp)+,d0/a0/a1
    nop                                
    rte
Which does the same as above, but using a nop is shorter/faster and also prevents parallel execution on the 68060 and your code will be excuted in the right order (No execution of the rte command before the interrupt is cleared).
AFAIK the double move.w d0,(a1) should guarantee this already as A1 points to a custom chip register and thus the write can't be cached. Accessing any custom chip register after interrupt clear but prior to rte should delay execution enough to prevent multiple interrupts firing.

Edit: or is your point purely only about a performance gain?

Last edited by roondar; 06 November 2018 at 15:17.
roondar is offline  
Old 06 November 2018, 16:28   #7
ross
Defendit numerus
 
ross's Avatar
 
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,474
Quote:
Originally Posted by roondar View Post
The only thing that might (emphasis on might) cause some issues on the A500 version is your use of the clr command. On a plain 68000 that does both a read and a write instead of just writing a zero, which might cause issues because the CIA register you clr.b is write-only AFAIK and thus should not be read from.
Cannot be this. CIA's registers are read/write and anyway where clr is used is harmless.

Quote:
Originally Posted by dissident View Post
Hi ross, I saw your code and there are two things that I noticed and I got a little hint:
The code I wrote is not meant for 68060 and it is not the code I normally use.
It is only some quick code to bring out the problem

Quote:
Code:
    moveq     #$48,d1
    move.b    d1,($e00,a0)    ;SPMODE=output, RUNMODE=one-shot
    moveq     #$-$72,d1       ;Same as $8e, but compatible to moveq command
    move.b    d1,($400,a0)    ;setup ~200us delay
    moveq     #0,d1
    move.b    d1,($500,a0)    ;start timer A
Yes, sure the right thing to do on 060
[I'm too used to patch old code where I simply disable superscalar bit in PCR register ]

Quote:
Code:
.ix    moveq    #8,D0
    move.w    d0,(a1)            ;cleans PORTS irq
    movem.l    (sp)+,d0/a0/a1
    nop                                
    rte
I'm not so sure of this.
The problem in this case is that the code is executed too quickly and access to a custom register (any) slows down enough before the RTE.
Is there a guarantee that the nop will do it too? (mmh, it sync the pipelines, maybe suffice in evey case.. well, the double access certainly works )
ross is offline  
Old 06 November 2018, 16:30   #8
dissident
Registered User
 
Join Date: Sep 2015
Location: Germany
Posts: 260
Quote:
Originally Posted by roondar View Post
Serial execution is guaranteed on all but 68060

So while still an interesting point, a better phrase would've been "so you have the guarantee your code is executed serial in order on a 68060". No other 68k chip has a superscalar/out of order design (perhaps the Vampire does though, I don't really know anything about that chip).
Yes, that's what I meant. Of course there's no parallel execution on the 68000-040. Only in the 68060. Your defenition is more clearly.

Quote:
Originally Posted by roondar View Post
AFAIK the double move.w d0,(a1) should guarantee this already as A1 points to a custom chip register and thus the write can't be cached. Accessing any custom chip register after interrupt clear but prior to rte should delay execution enough to prevent multiple interrupts firing.

Edit: or is your point purely only about a performance gain?
A double write to a custom chip register is not necessary. My interrupt code works fine on a real 68060/50 Mhz, but fails, if I don't use a nop before the rte and only do a single write to the INTREQ register. You get both. A peformance gain and the prevention of multiple interrupts.

Maybe an explanation from Motorola's User Manual of what the nop command on the 68020 does makes it clearer: "The NOP instruction forces instruction and bus synchronisation by freezing instruction execution until all pending bus cycles have completed."
Or for the 68060: "The following instructions perform this pipeline synchronization: ... nop..." or "... NOPs between instructions to guarantee serialization of reads and writes to I/O devices."
dissident is offline  
Old 06 November 2018, 16:37   #9
roondar
Registered User
 
Join Date: Jul 2015
Location: The Netherlands
Posts: 3,411
Quote:
Originally Posted by dissident View Post
A double write to a custom chip register is not necessary. My interrupt code works fine on a real 68060/50 Mhz, but fails, if I don't use a nop before the rte and only do a single write to the INTREQ register. You get both. A peformance gain and the prevention of multiple interrupts.

Maybe an explanation from Motorola's User Manual of what the nop command on the 68020 does makes it clearer: "The NOP instruction forces instruction and bus synchronisation by freezing instruction execution until all pending bus cycles have completed."
Or for the 68060: "The following instructions perform this pipeline synchronization: ... nop..." or "... NOPs between instructions to guarantee serialization of reads and writes to I/O devices."
I didn't know NOP did that (then again this might not be so odd as I've really only coded 68000 asm so far, not touched 68020+ stuff). Cool, that allows for a bit faster interrupt handling on all systems while retaining 68060/A4000 compatibility
roondar is offline  
Old 06 November 2018, 16:45   #10
dissident
Registered User
 
Join Date: Sep 2015
Location: Germany
Posts: 260
Quote:
Originally Posted by ross View Post
Cannot be this. CIA's registers are read/write and anyway where clr is used is harmless.


The code I wrote is not meant for 68060 and it is not the code I normally use.
It is only some quick code to bring out the problem


Yes, sure the right thing to do on 060
[I'm too used to patch old code where I simply disable superscalar bit in PCR register ]


I'm not so sure of this.
The problem in this case is that the code is executed too quickly and access to a custom register (any) slows down enough before the RTE.
Is there a guarantee that the nop will do it too? (mmh, it sync the pipelines, maybe suffice in evey case.. well, the double access certainly works )
Quote:
Originally Posted by roondar View Post
I didn't know NOP did that (then again this might not be so odd as I've really only coded 68000 asm so far, not touched 68020+ stuff). Cool, that allows for a bit faster interrupt handling on all systems while retaining 68060/A4000 compatibility
Well, that's the difference. My approach is writing code, which is compatible for all machines. 68000-68060 or 68020-68060. I do not hide anything here.
dissident is offline  
Old 06 November 2018, 16:53   #11
Toni Wilen
WinUAE developer
 
Join Date: Aug 2001
Location: Hämeenlinna/Finland
Age: 49
Posts: 26,516
This is getting far too off topic but in my opinion NOP is wrong and only accidental fix. Problem is Paula being slow, it needs one more CCK after INTREQ/INTENA write before it changes IPL lines (if RTE finishes during that extra CCK, CPU still sees old interrupt active and it can happen if all the stacked data is in caches). There is no guarantee NOP is slow enough (it probably is but no guarantee), only extra chip bus access guarantees it.

(and next I'll debug the actual problem..)
Toni Wilen is offline  
Old 06 November 2018, 17:06   #12
roondar
Registered User
 
Join Date: Jul 2015
Location: The Netherlands
Posts: 3,411
Quote:
Originally Posted by ross View Post
Cannot be this. CIA's registers are read/write and anyway where clr is used is harmless.
Are you sure about this? The HRM seems to disagree (http://amigadev.elowar.com/read/ADCD...ode0142.html):
Quote:
Originally Posted by HRM
A single register provides masking and interrupt information. The interrupt control register consists of a write-only MASK register and a read-only DATA register.
Not saying it's not harmless, but then the HRM is, well, wrong - or I'm misunderstanding what is written there


Quote:
Originally Posted by dissident View Post
Well, that's the difference. My approach is writing code, which is compatible for all machines. 68000-68060 or 68020-68060. I do not hide anything here.
I also write code that is compatible on all machines.

Not knowing a specific bit of info about a single 68000 opcode that is only valid for 68020+ doesn't change this*. For instance, the double move.w to acknowledge interrupts prior to RTE accomplishes the exact same thing as what you're using the extra NOP for: it prevents double interrupts on 68060/A4000.

In fact, the double acknowledgement is only used to achieve just that - compatibility with the 68060/A4000.

*) note that there are indeed things you do need to know, such as the VBR register and how caches can affect your code.

Last edited by roondar; 06 November 2018 at 17:25.
roondar is offline  
Old 06 November 2018, 17:09   #13
dissident
Registered User
 
Join Date: Sep 2015
Location: Germany
Posts: 260
Quote:
Originally Posted by Toni Wilen View Post
This is getting far too off topic but in my opinion NOP is wrong and only accidental fix. Problem is Paula being slow, it needs one more CCK after INTREQ/INTENA write before it changes IPL lines (if RTE finishes during that extra CCK, CPU still sees old interrupt active and it can happen if all the stacked data is in caches). There is no guarantee NOP is slow enough (it probably is but no guarantee), only extra chip bus access guarantees it.

(and next I'll debug the actual problem..)
You excatly described the problem. Believe it or not, but the sequence:

Code:
move.w #xxxx,INTREQ(An)
nop
rte
prevents that RTE finishes during that extra CCK. Without the NOP the CPU still sees an old interrupt active. As a result you would get an infinite loop. This was my problem and I could fix it with the NOP.
dissident is offline  
Old 06 November 2018, 17:17   #14
Toni Wilen
WinUAE developer
 
Join Date: Aug 2001
Location: Hämeenlinna/Finland
Age: 49
Posts: 26,516
Reading CIA interrupt register without first waiting for Paula interrupt can get tricky because there is some internal delays in CIAs. I don't remember how it exactly goes but there was some buggy games that required this kind of behavior. (Not that it may not be 100% correct but close enough).

It is much more safe to poll timer start bit than interrupt. It will also surprise you later when you use other timer and wonder why interrupts sometimes get lost..

EDIT: It probably is something emulation related because it makes no sense to get interrupt when it was cleared in Paula.

Quote:
Originally Posted by dissident View Post
rte[/CODE]prevents that RTE finishes during that extra CCK. Without the NOP the CPU still sees an old interrupt active. As a result you would get an infinite loop. This was my problem and I could fix it with the NOP.
Yes, as I said, NOP probably is slow enough but it is only a side effect, NOP could have been faster and still do what it is documented to do. Of course it does not matter in practice. But in theory it is wrong

Last edited by Toni Wilen; 06 November 2018 at 17:29.
Toni Wilen is offline  
Old 06 November 2018, 17:26   #15
StingRay
move.l #$c0ff33,throat
 
StingRay's Avatar
 
Join Date: Dec 2005
Location: Berlin/Joymoney
Posts: 6,863
Quote:
Originally Posted by dissident View Post
Code:
move.w #xxxx,INTREQ(An)
nop
rte
prevents that RTE finishes during that extra CCK. Without the NOP the CPU still sees an old interrupt active. As a result you would get an infinite loop. This was my problem and I could fix it with the NOP.

Back then I made a lot of tests regarding reliable interrupt aknowledge on my A4000/60 and the NOP/RTE solution didn't work all the time, "randomly" interrupts wouldn't be acknowledged. Hence I always used the "write twice to INTREQ" approach which never failed even once.
StingRay is offline  
Old 06 November 2018, 17:29   #16
ross
Defendit numerus
 
ross's Avatar
 
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,474
Quote:
EDIT: It probably is something emulation related because it makes no sense to get interrupt when it was cleared in Paula.
EDIT: Ok, waiting the response


Quote:
It is much more safe to poll timer start bit than interrupt. It will also surprise you later when you use other timer and wonder why interrupts sometimes get lost..
Sure. But I needed a way to highlight the problem

Thanks.

Last edited by ross; 06 November 2018 at 17:44. Reason: edit
ross is offline  
Old 06 November 2018, 17:37   #17
ross
Defendit numerus
 
ross's Avatar
 
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,474
Quote:
Originally Posted by roondar View Post
Are you sure about this? The HRM seems to disagree (http://amigadev.elowar.com/read/ADCD.../node0142.html
Not saying it's not harmless, but then the HRM is, well, wrong - or I'm misunderstanding what is written there
Nothing wrong here. CIA registers are read/write.
But some are different from normal memory cells because they actually contain 2 different registers (one read-only and one write-only).
ICR is one of these, so 68000 clr.b is not to be used with it.
(you can actually use it but you have to be aware of the consequences)
ross is offline  
Old 06 November 2018, 17:42   #18
dissident
Registered User
 
Join Date: Sep 2015
Location: Germany
Posts: 260
Quote:
Originally Posted by Toni Wilen View Post
Reading CIA interrupt register without first waiting for Paula interrupt can get tricky because there is some internal delays in CIAs. I don't remember how it exactly goes but there was some buggy games that required this kind of behavior. (Not that it may not be 100% correct but close enough).

It is much more safe to poll timer start bit than interrupt. It will also surprise you later when you use other timer and wonder why interrupts sometimes get lost..

EDIT: It probably is something emulation related because it makes no sense to get interrupt when it was cleared in Paula.
This is interesting. Usually I wait for the timer to be finshed via the CIA-ICR register. Good to know this.
dissident is offline  
Old 06 November 2018, 17:47   #19
dissident
Registered User
 
Join Date: Sep 2015
Location: Germany
Posts: 260
Quote:
Originally Posted by StingRay View Post
Back then I made a lot of tests regarding reliable interrupt aknowledge on my A4000/60 and the NOP/RTE solution didn't work all the time, "randomly" interrupts wouldn't be acknowledged. Hence I always used the "write twice to INTREQ" approach which never failed even once.
I only tested my interrupt-routine on an A1200 with a Blizzard 1260, not on an A4000/060 yet. An important hint. Thanks.
dissident is offline  
Old 06 November 2018, 17:48   #20
ross
Defendit numerus
 
ross's Avatar
 
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,474
Quote:
Originally Posted by StingRay View Post
Back then I made a lot of tests regarding reliable interrupt aknowledge on my A4000/60 and the NOP/RTE solution didn't work all the time, "randomly" interrupts wouldn't be acknowledged. Hence I always used the "write twice to INTREQ" approach which never failed even once.
This is the definitive answer on the topic
ross 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
Emulated A500 with Kick 1.3 generates spurious Lev6 interrupt Kalms Coders. Asm / Hardware 2 20 March 2018 15:25
Irq Blitter LeCaravage Coders. Asm / Hardware 9 16 June 2017 10:21
IRQ Virus redblade request.Apps 8 01 September 2012 08:22
Spurious checksum errors MagerValp support.Hardware 6 28 August 2008 17:10
New Ports available DJBase News 1 26 January 2007 11:55

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 07:17.

Top

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