6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sun Nov 24, 2024 6:45 am

All times are UTC




Post new topic Reply to topic  [ 8 posts ] 
Author Message
PostPosted: Tue May 09, 2017 9:03 pm 
Offline

Joined: Thu Sep 15, 2016 1:52 pm
Posts: 60
Location: UK
I have an ISR that is working but the vector to the routine is hard coded and I would like to be able to change it so I would like to have the IRQ vector in RAM instead. I thought that wouldn't be that hard to code but I'm stuck because the code simply doesn't work.
So the reset code looks like this:
Code:
1383    .8849                   COLDSTART
1384    .8849   d8                      CLD           ;Disable decimal mode
1385    .884a   a2 ff                   LDX  #$FF     ;Initialize STACK POINTER
1386    .884c   9a                      TXS
1388    .884d   a5 ab                   LDA  <DOINTERRUPT
1389    .884f   8d 02 03                STA  INTERRUPTVECTOR
1390    .8852   a5 89                   LDA  >DOINTERRUPT
1391    .8854   8d 03 03                STA  INTERRUPTVECTOR+1
....

COLDSTART is the reset vector which initialise the IRQ vector.
The ISR looks like this.
Code:
1601    .89a8                   INTERRUPT
1602    .89a8   6c 02 03                JMP  (INTERRUPTVECTOR)
1604    .89ab                   DOINTERRUPT
1605    .89ab   85 ed                   STA  AINTSAV  ;Save ACCUMULATOR
1606    .89ad   86 ee                   STX  XINTSAV  ;Save X-REGISTER
1607    .89af   84 ef                   STY  YINTSAV  ;Save Y-REGISTER
1608    .89b1   ad e1 7f                LDA  SIOSTAT  ;Read 6551 ACIA status register
1609    .89b4   29 88                   AND  #$88     ;Isolate bits. bit 7: Interrupt has occured and bit 3: receive data register full
1610    .89b6   49 88                   EOR  #$88     ;Invert state of both bits
.....

and so on. The ISR just receives bytes from the ACIA and puts them in a buffer.
The initialisation of the vectors looks like this
Code:
3232    >fffa   00 03                    .word $0300        ;NMI
3233    >fffc   49 88                    .word COLDSTART    ;RESET
3234    >fffe   a8 89                    .word INTERRUPT    ;IRQ

So why is it that if I change the IRQ vector to DOINTERRUPT everything works but if it is INTERRUPT nothing works?
I know I'm missing something trivial but I can't find figure out why it is not working.
Any ideas anyone?

/Jgroth


Top
 Profile  
Reply with quote  
PostPosted: Tue May 09, 2017 9:56 pm 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
Code:
1388    .884d   a5 ab                   LDA  <DOINTERRUPT          <------- opcode should be $A9 not $A5
1389    .884f   8d 02 03                STA  INTERRUPTVECTOR
1390    .8852   a5 89                   LDA  >DOINTERRUPT          <------- opcode should be $A9 not $A5
1391    .8854   8d 03 03                STA  INTERRUPTVECTOR+1


I think you intended these two LDA instructions to use immediate address mode. But you've omitted the # symbol and consequently the assembler gave you z-pg mode instead.

Darn assembler! Insists on giving you what you asked for (instead of what you wanted)!! :evil: :evil: :evil: :wink: :D

_________________
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html


Top
 Profile  
Reply with quote  
PostPosted: Tue May 09, 2017 10:59 pm 
Offline

Joined: Thu Sep 15, 2016 1:52 pm
Posts: 60
Location: UK
Dr Jefyll wrote:
Code:
1388    .884d   a5 ab                   LDA  <DOINTERRUPT          <------- opcode should be $A9 not $A5
1389    .884f   8d 02 03                STA  INTERRUPTVECTOR
1390    .8852   a5 89                   LDA  >DOINTERRUPT          <------- opcode should be $A9 not $A5
1391    .8854   8d 03 03                STA  INTERRUPTVECTOR+1


I think you intended these two LDA instructions to use immediate address mode. But you've omitted the # symbol and consequently the assembler gave you z-pg mode instead.

Darn assembler! Insists on giving you what you asked for (instead of what you wanted)!! :evil: :evil: :evil: :wink: :D

Slapping palm against forehead! That was it. I knew it was something simple. Thank you so much!


Top
 Profile  
Reply with quote  
PostPosted: Tue May 09, 2017 11:55 pm 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
You're welcome -- glad to help! I admit I had to stare at this for a while. :roll:

[ramble]

When I first learned to code it was a pencil and paper affair. This meant manually looking up every opcode that was required. (No assembler, eh?) To slightly reduce the drudgery I memorized a dozen or so of the most common opcodes.

This was a cloud that didn't seem to have any silver lining. But today it was the a5 ab in the object code of your program that eventually jumped out at me, not the missing # in the corresponding source. Maybe the LDA <DOINTERRUPT ought to have been conspicuous (ie: no #), but frankly I got entirely distracted wondering about the < operator (not the #). :oops:

I don't know if there's any moral to all this... :) [/ramble]

-- Jeff

_________________
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html


Top
 Profile  
Reply with quote  
PostPosted: Wed May 10, 2017 4:28 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8514
Location: Midwestern USA
Dr Jefyll wrote:
Code:
1388    .884d   a5 ab                   LDA  <DOINTERRUPT          <------- opcode should be $A9 not $A5
1389    .884f   8d 02 03                STA  INTERRUPTVECTOR
1390    .8852   a5 89                   LDA  >DOINTERRUPT          <------- opcode should be $A9 not $A5
1391    .8854   8d 03 03                STA  INTERRUPTVECTOR+1


I think you intended these two LDA instructions to use immediate address mode. But you've omitted the # symbol and consequently the assembler gave you z-pg mode instead.

Darn assembler! Insists on giving you what you asked for (instead of what you wanted)!! :evil: :evil: :evil: :wink: :D

Good catch! :D

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Wed May 10, 2017 5:06 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8514
Location: Midwestern USA
jgroth wrote:
Code:
1383    .8849                   COLDSTART
1384    .8849   d8                      CLD           ;Disable decimal mode
1385    .884a   a2 ff                   LDX  #$FF     ;Initialize STACK POINTER
1386    .884c   9a                      TXS
1388    .884d   a5 ab                   LDA  #<DOINTERRUPT
1389    .884f   8d 02 03                STA  INTERRUPTVECTOR
1390    .8852   a5 89                   LDA  #>DOINTERRUPT
1391    .8854   8d 03 03                STA  INTERRUPTVECTOR+1
....

I suggest you insert SEI as the first instruction in the above and then follow STA INTERRUPTVECTOR+1 with CLI. Once interrupt processing is in effect, re-executing the above code could result in an IRQ occurring between an LDA and an STA. If subsequent code pointed INTERRUPTVECTOR to a new location, the temporary inconsistency of the vector as it is being initialized will likely cause a crash.

Quote:
Code:
1601    .89a8                   INTERRUPT
1602    .89a8   6c 02 03                JMP  (INTERRUPTVECTOR)
1604    .89ab                   DOINTERRUPT
1605    .89ab   85 ed                   STA  AINTSAV  ;Save ACCUMULATOR
1606    .89ad   86 ee                   STX  XINTSAV  ;Save X-REGISTER
1607    .89af   84 ef                   STY  YINTSAV  ;Save Y-REGISTER
1608    .89b1   ad e1 7f                LDA  SIOSTAT  ;Read 6551 ACIA status register
1609    .89b4   29 88                   AND  #$88     ;Isolate bits. bit 7: Interrupt has occured and bit 3: receive data register full
1610    .89b6   49 88                   EOR  #$88     ;Invert state of both bits
.....

Using RAM as temporary register storage within an ISR as you are doing is not particularly good practice, as it precludes the possibility of processing nested IRQs. I recommend you push them to the stack and then pull them (in reverse order) at the termination of your ISR. Also, don't save registers that your ISR will not use, as all you'll be doing is wasting clock cycles.

Your code will be slightly faster and more efficient with the following change:

Code:
INTERRUPT   JMP  (INTERRUPTVECTOR)
DOINTERRUPT PHA                       ;save MPU state
            PHX                       ;save if necessary
            PHY                       ;save if necessary
            LDA SIOSTAT               ;Read 6551 ACIA status register
            BPL NOT_ACIA              ;skip ahead if ACIA is not interrupting
;
;...no reason to execute the following instructions if the ACIA wasn't the IRQ source...
;
            AND  #$88                 ;Isolate bits. bit 7: Interrupt has occured and bit 3: receive data register full
            EOR  #$88                 ;Invert state of both bits
...

Something else: values such as the two masks used in the final two instructions should not be hard-coded into your source. They should be symbolically defined and since they are masks, should be expressed in bit-wise notation so it is clear which bits are being manipulated. Although I and some others here can mentally translated hex values to binary equivalents (and in reverse), others may not. A year or two or three from now when you revisit the code you yourself may be pondering what you meant with the above code.

Documentation means not only commenting the intended effect of each instruction, it also means defining "magic numbers" referred to within your code. This is where INCLUDE files are put to use. A professional would put something like the following into an INCLUDE file somewhere and refer to it during assembly:

Code:
ACIAMASK  = %10001000        ;mask used to analyze ACIA status

and later on:

Code:
          AND #ACIAMASK               
          EOR #ACIAMASK

Of course, there is a more efficient way to analyze the 6551's status—you don't need to know about bit 7 once you fall through the BPL NOT_ACIA instruction. However, that's for you to work out. :)

BTW, have you studied Garth Wilson's interrupt primer?

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Wed May 10, 2017 7:35 am 
Offline

Joined: Thu Sep 15, 2016 1:52 pm
Posts: 60
Location: UK
BigDumbDinosaur wrote:
jgroth wrote:
Code:
1383    .8849                   COLDSTART
1384    .8849   d8                      CLD           ;Disable decimal mode
1385    .884a   a2 ff                   LDX  #$FF     ;Initialize STACK POINTER
1386    .884c   9a                      TXS
1388    .884d   a5 ab                   LDA  #<DOINTERRUPT
1389    .884f   8d 02 03                STA  INTERRUPTVECTOR
1390    .8852   a5 89                   LDA  #>DOINTERRUPT
1391    .8854   8d 03 03                STA  INTERRUPTVECTOR+1
....

I suggest you insert SEI as the first instruction in the above and then follow STA INTERRUPTVECTOR+1 with CLI. Once interrupt processing is in effect, re-executing the above code could result in an IRQ occurring between an LDA and an STA. If subsequent code pointed INTERRUPTVECTOR to a new location, the temporary inconsistency of the vector as it is being initialized will likely cause a crash.

Good point. SEI and CLI added.

Quote:
Code:
1601    .89a8                   INTERRUPT
1602    .89a8   6c 02 03                JMP  (INTERRUPTVECTOR)
1604    .89ab                   DOINTERRUPT
1605    .89ab   85 ed                   STA  AINTSAV  ;Save ACCUMULATOR
1606    .89ad   86 ee                   STX  XINTSAV  ;Save X-REGISTER
1607    .89af   84 ef                   STY  YINTSAV  ;Save Y-REGISTER
1608    .89b1   ad e1 7f                LDA  SIOSTAT  ;Read 6551 ACIA status register
1609    .89b4   29 88                   AND  #$88     ;Isolate bits. bit 7: Interrupt has occured and bit 3: receive data register full
1610    .89b6   49 88                   EOR  #$88     ;Invert state of both bits
.....
BigDumbDinosaur wrote:
Using RAM as temporary register storage within an ISR as you are doing is not particularly good practice, as it precludes the possibility of processing nested IRQs. I recommend you push them to the stack and then pull them (in reverse order) at the termination of your ISR. Also, don't save registers that your ISR will not use, as all you'll be doing is wasting clock cycles.

Will take that into consideration
BigDumbDinosaur wrote:
Your code will be slightly faster and more efficient with the following change:

Code:
INTERRUPT   JMP  (INTERRUPTVECTOR)
DOINTERRUPT PHA                       ;save MPU state
            PHX                       ;save if necessary
            PHY                       ;save if necessary
            LDA SIOSTAT               ;Read 6551 ACIA status register
            BPL NOT_ACIA              ;skip ahead if ACIA is not interrupting
;
;...no reason to execute the following instructions if the ACIA wasn't the IRQ source...
;
            AND  #$88                 ;Isolate bits. bit 7: Interrupt has occured and bit 3: receive data register full
            EOR  #$88                 ;Invert state of both bits
...

Something else: values such as the two masks used in the final two instructions should not be hard-coded into your source. They should be symbolically defined and since they are masks, should be expressed in bit-wise notation so it is clear which bits are being manipulated. Although I and some others here can mentally translated hex values to binary equivalents (and in reverse), others may not. A year or two or three from now when you revisit the code you yourself may be pondering what you meant with the above code.

Yeah, should be constant with a meaningful name (haven't gotten that far yet).
BigDumbDinosaur wrote:
Documentation means not only commenting the intended effect of each instruction, it also means defining "magic numbers" referred to within your code. This is where INCLUDE files are put to use. A professional would put something like the following into an INCLUDE file somewhere and refer to it during assembly:

Code:
ACIAMASK  = %10001000        ;mask used to analyze ACIA status

and later on:

Code:
          AND #ACIAMASK               
          EOR #ACIAMASK

Of course, there is a more efficient way to analyze the 6551's status—you don't need to know about bit 7 once you fall through the BPL NOT_ACIA instruction. However, that's for you to work out. :)

BTW, have you studied Garth Wilson's interrupt primer?

No, where can I find it?


Top
 Profile  
Reply with quote  
PostPosted: Wed May 10, 2017 7:39 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8546
Location: Southern California
jgroth wrote:
BigDumbDinosaur wrote:
BTW, have you studied Garth Wilson's interrupt primer?

No, where can I find it?

Here. (Enjoy the outdated cartoons! Actually, that's where Mike Naberezny pulled my avatar from.)

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 8 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 5 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: