Author Topic: Interrupt Routine not RETurning  (Read 11096 times)

0 Members and 1 Guest are viewing this topic.

Offline Excelseo

  • LV2 Member (Next: 40)
  • **
  • Posts: 21
  • Rating: +0/-0
    • View Profile
Interrupt Routine not RETurning
« on: August 26, 2016, 09:08:25 am »
So, I've been trying to learn assembly as of late, and a few days ago I started messing around with interrupts. However, I could never get the programs to work as intended, and corrupted the calculator's system routines accidentally whilst trying to do so. (I'm on vacation without my link cable and writing the code on-calc with Mimas)  Forced to use direct output rather than putS to figure out what was going on, I wrote this program.
Code: [Select]
  di
  ld a,$99
;setting up interrupt
  ld i,a
  ld hl,Interrupt
  ld ($993F),hl
  ld ($997F),hl
  ld ($99BF),hl
  ld ($99FF),hl
  im 2
  ld e,$FF
  ei
Loop:
;Infinite loop o' ram clears
  jr Loop
Interrupt:
  ld a,26
;setting column
  out ($10),a
  call WasteTime
;my equivalent of _LCD_BUSY_QUICK
  ld a,$96
;setting row
  out ($10),a
  call WasteTime
  ld a,e
;displaying e as row of pixels
  out ($11),a
  dec e
  reti
WasteTime:
  ld l,10
WasteLoop:
  nop
;344 T-states, just to be safe
  nop
  nop
  nop
  dec l
  jr nz,WasteLoop
  ret
The expectation here is that every 140th of a second, the row of pixels specified would update to reflect e. I understand that the LCD has a refresh rate of 60 fps, but the row of pixels should update on some interval. However, instead, only a solid row of pixels (reflecting e's original $FF) is displayed, which never changes. Since the pixels were displayed at the correct coordinates as intended, I'm reasonably certain that the interrupt setup is working, and that WasteTime is functional as well. That narrows it down to these two lines:
Code: [Select]
dec e
reti
And I'm pretty sure I know how dec works :). Is there something I don't understand about reti? Or is there something entirely different wrong with my understanding of assembly? Sorry for the long post, I wanted to give as much information as possible.

Thanks in advance!


Edit Sorunome: added code tags

 
 
« Last Edit: August 26, 2016, 10:46:45 am by Sorunome »

Offline Geekboy1011

  • The Oneironaut
  • Donator
  • LV11 Super Veteran (Next: 3000)
  • ***********
  • Posts: 2031
  • Rating: +119/-2
  • Dream that Awakening dream
    • View Profile
Re: Interrupt Routine not RETurning
« Reply #1 on: August 26, 2016, 09:25:42 am »
I am afraid I have no code to help you right now but I have some suggestions.

It looks like you are not servicing the interrupt call so it can run again. SO in essence your never re-enabling it.
I would recommend following this page on how to setup your interrupt as well http://wikiti.brandonw.net/index.php?title=83Plus:Ports:03
Your initialization is not 100% guaranteed to work on all calculator models!

also reti is rather useless on the 8X series we work with. Due to how it does interrupts a simple ret will usually suffice (we have no user properly nestable interrupts so it is more tricky then abusing reti)

Offline Excelseo

  • LV2 Member (Next: 40)
  • **
  • Posts: 21
  • Rating: +0/-0
    • View Profile
Re: Interrupt Routine not RETurning
« Reply #2 on: August 26, 2016, 09:31:09 am »
You are a speed demon, my good sir.

Offline Geekboy1011

  • The Oneironaut
  • Donator
  • LV11 Super Veteran (Next: 3000)
  • ***********
  • Posts: 2031
  • Rating: +119/-2
  • Dream that Awakening dream
    • View Profile
Re: Interrupt Routine not RETurning
« Reply #3 on: August 26, 2016, 09:34:35 am »
no problems ask questions as needed please :D i'll help with what I can. (I am at work right now so I don't have all my code to help me. Else I would have just handed you a re-written set of code already lol) :D

Offline Sorunome

  • Fox Fox Fox Fox Fox Fox Fox!
  • Support Staff
  • LV13 Extreme Addict (Next: 9001)
  • *************
  • Posts: 7920
  • Rating: +374/-13
  • Derpy Hooves
    • View Profile
    • My website! (You might lose the game)
Re: Interrupt Routine not RETurning
« Reply #4 on: August 26, 2016, 10:45:17 am »
On the calculator interrupts are unfortunately a bit more complex than that.

The reason being is that TI didn't care about im2 mode, and thus the hardware is returning a random address to jump to.

What does this mean? You will need to place your interrupt handler at an address where the high and the low bytes are the same and your interrupt vector needs to be 257 bytes large.

Here's an example with the instruction tale at $8000 (note that with this way you will have to disable interrupts before archiving stuff and re-create your jump table as it uses up the first byte of ramCode)
The interrupt handler is located at $8585, we will jump to some other location straight away
Code: [Select]
; disable interrupts and set interrupt mode 2
di
im 2

; set the upper byte of the jumptable to $80
ld a,$80
ld i,a

; create the vector table (do this every time before you enable interrupts, be sure to disable interrupts before archiving / unarchiving stuff)
ld hl, $8000
ld de, $8001
ld (hl), $85
ld bc,256
ldir

; setting up the jump handler at $8585
ld hl,$8585
ld (hl),$c3 ; this is the jp instruction
ld de,InterruptHandler ; replace this with whatever label you are jumping to, where you have your interrupt handler
inc hl
ld (hl),e
inc hl
ld (hl),d

; time to enable interrupts
ei
Keep in mind that interrupts keep on disable themself, you will have to call "ei" at the end of your interrupt routine so that it'll trigger again.

You could also set up your interrupt table at $9900, just adjust setting the riger i and the vector table accordingly, that would allow you to do whatever flash operations while running the interrupt, however that means you can't use appBakUpScrn


If you are creating an app your interrupt handler will need to be in a ram location and you need to make sure you swap in the correct flash pages (or, alternatively, you may not use any bcalls at all, custom ones or system ones).


Here's the code for an app:
Note that it also uses $8584 and keyToStr
Code: [Select]
#define basepage $8584
Run:
; disable interrupts and set interrupt mode 2
di
im 2

; save whichever page we are on so that we know where to go
in a,(6)
ld (basepage),a

; set the upper byte of the jumptable to $80
ld a,$80
ld i,a

; now we copy our interrupt loader to ram, we only have to do this once
ld hl,LoadInterrupt
ld de,keyToStr
ld bc,LoadInterruptSize
ldir

; create the vector table (do this every time before you enable interrupts, be sure to disable interrupts before archiving / unarchiving stuff)
ld hl, $8000
ld de, $8001
ld (hl), $85
ld bc,256
ldir

; setting up the jump handler at $8585
ld hl,$8585
ld (hl),$c3 ; this is the jp instruction
ld de,InterruptHandler ; replace this with whatever label you are jumping to, where you have your interrupt handler
inc hl
ld (hl),e
inc hl
ld (hl),d

; time to enable interrupts
ei

; we will copy this to ram, it'll swap us the correct page in and swap back whichever page we had before
LoadInterrupt:
push af
in a,(6)
push af
ld a,(basepage)
out (6),a
call Interrupt
pop af
out (6),a
pop af
ei
ret
LoadInterruptSize = $ - LoadInterrupt

; now we have our actual interrupt handler
Interrupt:
; we can do whatever here, since LoadInterrupt already does ei we don't have to do it in here
ret

Why does the Interrupt address has to be at a place where high and low bytes match?
Well, let's say you set i to $80 so that the interrupt jump-tabe starts at $8000. Now, let's say you want to have the handler at, like $9876
For that you'd want to set these bytes starting at $8000:
Code: [Select]
.db $76,$98 ; reverse order due to little endian-ness
.db $76,$98
.db $76,$98
.db $76,$98
.db $76,$98

etc.
Now, let's say the interrupt fires and the hardware reports as lower byte 0, so we take the address at $8000, which is $9876.
If the hardware reports 2 we take the address at $8002, which is $9876

That all seems fine. However, the addresses the hardware reports are seemingly random, so let's say the hardware reports 1
Now we take the address at $8001 which is $7698. Woops, that shouldn't happen.
You overgo this by only using addresses where the high and the low bytes match

EDIT: As Runer112 pointed out, you don't actually need the upper and lower bytes to match, you'd need to have two handlers then, though, in this example one at $9876 and one at $7698 (while the later is actually not possible as that isn't ram, which just shows how much easier it is if you have the upper and lower bytes matched)
Why must the interrupt vector be 257 bytes large?
Especially, why not 256 bytes?
Well, 256 bytes would be sufficiant if the hardware could only reply 0 - $FE
However, if the hardware replies $FF, then we are looking for the address at $80FF which consists of one byte at $80FF and one byte at $8100, thus we need a 257-bytes large vector table
« Last Edit: August 26, 2016, 12:08:36 pm by Sorunome »

THE GAME
Also, check out my website
If OmnomIRC is screwed up, blame me!
Click here to give me an internet!

Offline Excelseo

  • LV2 Member (Next: 40)
  • **
  • Posts: 21
  • Rating: +0/-0
    • View Profile
Re: Interrupt Routine not RETurning
« Reply #5 on: August 26, 2016, 12:43:49 pm »
Thank you Sorunome, but I'm afraid that's not the problem. I got the interrupt setup method I used from http://tutorials.eeems.ca/ASMin28Days/lesson/day23.html, which explains that the lowest 6 bits of the data bus are always set when calling a mode 2 interrupt. There may be a catch to this, but the fact that the pixels were displayed as intended in my original program shows that the interrupt was called correctly.

Offline Sorunome

  • Fox Fox Fox Fox Fox Fox Fox!
  • Support Staff
  • LV13 Extreme Addict (Next: 9001)
  • *************
  • Posts: 7920
  • Rating: +374/-13
  • Derpy Hooves
    • View Profile
    • My website! (You might lose the game)
Re: Interrupt Routine not RETurning
« Reply #6 on: August 26, 2016, 12:47:30 pm »
Thank you Sorunome, but I'm afraid that's not the problem. I got the interrupt setup method I used from http://tutorials.eeems.ca/ASMin28Days/lesson/day23.html, which explains that the lowest 6 bits of the data bus are always set when calling a mode 2 interrupt. There may be a catch to this, but the fact that the pixels were displayed as intended in my original program shows that the interrupt was called correctly.
Unfortunately the 28 days tutorial is wrong in some aspects, including how interrupts are working. What the tutorial states may be true for some calculatores with certain revision numbers, but definitally not for all calculators. I'd strongly recommend setting up a full jump-table like i stated above.

THE GAME
Also, check out my website
If OmnomIRC is screwed up, blame me!
Click here to give me an internet!

Offline Excelseo

  • LV2 Member (Next: 40)
  • **
  • Posts: 21
  • Rating: +0/-0
    • View Profile
Re: Interrupt Routine not RETurning
« Reply #7 on: August 26, 2016, 12:58:49 pm »
Spent a little while tinkering with the program this morning, and I have two things that are definitely not solutions.

1. I output %00001011 to port 3 during setup, output %00000000 at the beginning of the interrupt routine, and reverted it to %00001011 at the end, which I think is what Geekboy was suggesting. I changed reti to ret as well, but I wouldn't really call that a proposed solution, just an optimization.

2. I added two "srl a"s before "out ($11),a". This way, the pixels to be displayed only change every 4 interrupts i.e. 35 times a second, which is well within the LCD's refresh rate. The problem persisted, and I didn't expect it to, as I don't think the interrupt routine is running a second time.

I might try some more solutions later but I'm out of ideas at the moment.

EDIT: changing the interrupt setup to a full table now



Ok, I replaced the interrupt setup with the following code, similar to Sorunome's, but with a slight optimization using ix instead of hl, and moving the table to $9900 since I was more familiar with that area of RAM.

ld a,$99
ld i,a
ld hl,$9900
ld de, $9901
ld (hl),$9A
ld bc,256
ldir
ld ix,$9A9A
ld (ix+0),$C3
ld hl,Interrupt
ld (ix+1),l
ld (ix+2),h
im 2

Unfortunately, it had the same result. The specified 8 pixels set, and no updates.


Edit (Eeems): Merged double post
« Last Edit: August 26, 2016, 02:13:38 pm by Eeems »

Offline Sorunome

  • Fox Fox Fox Fox Fox Fox Fox!
  • Support Staff
  • LV13 Extreme Addict (Next: 9001)
  • *************
  • Posts: 7920
  • Rating: +374/-13
  • Derpy Hooves
    • View Profile
    • My website! (You might lose the game)
Re: Interrupt Routine not RETurning
« Reply #8 on: August 26, 2016, 01:27:13 pm »
Do you run "ei" before returning from your interrupt? I did mention it in my huge post but you might have simpely over-read it ^.^

THE GAME
Also, check out my website
If OmnomIRC is screwed up, blame me!
Click here to give me an internet!

Offline Excelseo

  • LV2 Member (Next: 40)
  • **
  • Posts: 21
  • Rating: +0/-0
    • View Profile
Re: Interrupt Routine not RETurning
« Reply #9 on: August 26, 2016, 01:27:47 pm »
Yes.

Offline Sorunome

  • Fox Fox Fox Fox Fox Fox Fox!
  • Support Staff
  • LV13 Extreme Addict (Next: 9001)
  • *************
  • Posts: 7920
  • Rating: +374/-13
  • Derpy Hooves
    • View Profile
    • My website! (You might lose the game)
Re: Interrupt Routine not RETurning
« Reply #10 on: August 26, 2016, 01:28:07 pm »
What about re-outputting your interrupt mask to port 03?

THE GAME
Also, check out my website
If OmnomIRC is screwed up, blame me!
Click here to give me an internet!

Offline Excelseo

  • LV2 Member (Next: 40)
  • **
  • Posts: 21
  • Rating: +0/-0
    • View Profile
Re: Interrupt Routine not RETurning
« Reply #11 on: August 26, 2016, 01:40:30 pm »
Tried that as well.

Offline Sorunome

  • Fox Fox Fox Fox Fox Fox Fox!
  • Support Staff
  • LV13 Extreme Addict (Next: 9001)
  • *************
  • Posts: 7920
  • Rating: +374/-13
  • Derpy Hooves
    • View Profile
    • My website! (You might lose the game)
Re: Interrupt Routine not RETurning
« Reply #12 on: August 26, 2016, 01:42:07 pm »
Mind posting the whole code you currently have? The thing is, I can't see any port 03 access in your top post.

THE GAME
Also, check out my website
If OmnomIRC is screwed up, blame me!
Click here to give me an internet!

Offline Excelseo

  • LV2 Member (Next: 40)
  • **
  • Posts: 21
  • Rating: +0/-0
    • View Profile
Re: Interrupt Routine not RETurning
« Reply #13 on: August 26, 2016, 01:45:39 pm »
Yeah I didn't mention adding it until my 2nd reply. I'll post the whole code as it is currently in half an hour or so, so stay tuned. :)

Offline Eeems

  • Mr. Dictator
  • Administrator
  • LV13 Extreme Addict (Next: 9001)
  • *************
  • Posts: 6266
  • Rating: +318/-36
  • little oof
    • View Profile
    • Eeems
Re: Interrupt Routine not RETurning
« Reply #14 on: August 26, 2016, 02:12:18 pm »
FYI about 28 days. If you want to use an updated version of the guide I would highly recommend looking here: https://bitbucket.org/tari/83pa28d
Here is a direct link to day 23
/e