6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Thu May 16, 2024 12:23 am

All times are UTC




Post new topic Reply to topic  [ 72 posts ]  Go to page Previous  1, 2, 3, 4, 5
Author Message
PostPosted: Tue May 30, 2017 12:52 pm 
Offline
User avatar

Joined: Wed Mar 01, 2017 8:54 pm
Posts: 660
Location: North-Germany
Rob Finch wrote:
The following EhBASIC program shows interrupts happening by displaying an “I” on screen when an interrupt occurs.
Code:
10 ON IRQ GOTO 1000
20 GOTO 10
1000 PRINT “I”;
1010 RETIRQ

This piece of code is a typical example to me why I have problems to understand the concept of IRQ handling in EhBasic.
If line 10 "enables" a sort of IRQ handler (that causes a GOTO 1000 if an IRQ is present) then the example should have a second line like
20 GOTO 20
But if the ON IRQ has to be executed frequently - well this is no IRQ service, it is a special sort of polling (and useless).

The same confusion with line 1000, 1010. OK, 1000 does something because of a present IRQ, so far so fine. Then 1010 RETIRQ. ??? How does RETIRQ know where and how to clear the interrupt? It makes no sense to return from IRQ without clearing the cause of the IRQ somehow. The IRQ - as I see it - is still present, so this would result in an infinite loop.

It only would make a (very limited) sense, if IRQ "processing" is done by polling (ON IRQ GOTO...).

Sorry for this outbreak Rob :oops: - the reason you gave this example is more serious and its challenging to detect the cause. If it were a new hardware I would estimate an open circuit (at least temporarily) somewhere. Could this in this virtual case be possible? An undefined state of one signal between two clocks or so? Another candidate would be a timing violation.

As you say task#0 is working fine, the others not so fine, what if you would generate a copy of your BIOS-monitor and have it running on a different task number. Perhaps you change only the prompt of this clone to distinguish which monitor is running. If you switch to this clone - whats then about the IRQs?


Top
 Profile  
Reply with quote  
PostPosted: Tue May 30, 2017 3:22 pm 
Offline
User avatar

Joined: Sun Dec 29, 2002 8:56 pm
Posts: 449
Location: Canada
I had the code as 20 GOTO 20, but then only 3 IRQ's (three 'i's) showed up on the screen before IRQ's were disabled. It's a mystery to me why it worked three times then interrupts became disabled. You are correct it is really polling the way I have it setup with 20 GOTO 10, but it does allow IRQ's to appear as the ON IRQ statement has a CLI in it. It was setup this way just for test purposes.
Note that if the IRQ system were working properly there would be no need to poll. It's not EhBASIC's problem. Omitting the line 20 GOTO 10 and just letting the remainder of the program run would be the normal way of doing things.
Quote:
How does RETIRQ know where and how to clear the interrupt? It ma

The IRQ code would have to clear the interrupt possibly by poking a register before the RETIRQ command. The way I have my system setup it's the ISR service written in assembler that takes care of acknowledging the interrupt. The ISR service sets a flag that the BASIC interpreter reads while it's getting characters. The BASIC IRQ isn't really a genuine IRQ, instead BASCI polls for the IRQ flag being set in it's "get" loop. It sort of a co-operative IRQ detection.
Quote:
It makes no sense to return from IRQ without clearing the cause of the IRQ somehow. The IRQ - as I see it - is still present, so this would result in an infinite loop.
The ISR service routine has already cleared the cause of the IRQ so BASIC doesn't have to. It's not impossible to clear in the source in a BASIC program but I wouldn't recommend it. Note that the BASIC IRQ flag still has to be set by an external IRQ handler. The flag is a bit in the $DF zeropage variable.
Processing IRQ's in BASIC seems somewhat dubious to me and one would want as little IRQ code in BASIC as possible. But it is occasionally useful to have it available, especially with low speed interrupts. It could be connected to a watchdog timer for instance. Or it could be connected to another timer for a game loop.

_________________
http://www.finitron.ca


Top
 Profile  
Reply with quote  
PostPosted: Tue May 30, 2017 5:51 pm 
Offline
User avatar

Joined: Wed Mar 01, 2017 8:54 pm
Posts: 660
Location: North-Germany
Rob Finch wrote:
It's a mystery to me why it worked three times then interrupts became disabled.
and
Rob Finch wrote:
One thing which may be causing a problem is that there is a three cycle delay before a CLI instruction becomes active. This is to prevent the core from hanging on a single instruction if interrupt overrun occurs.

Might there be a relation? Can you change only the delay cycle count (e.g. 5 instead of 3) and check whether there are still three 'i' or perhaps 5 then?

The other '3' I found is the number of tasks beside the monitor. If you bring up a second Basic - does that influence anything?

Rob Finch wrote:
The way I have my system setup it's the ISR service written in assembler that takes care of acknowledging the interrupt. The ISR service sets a flag that the BASIC interpreter reads while it's getting characters. The BASIC IRQ isn't really a genuine IRQ, instead BASCI polls for the IRQ flag being set in it's "get" loop. It sort of a co-operative IRQ detection. ... The flag is a bit in the $DF zeropage variable.

OK, that is rational. Polling a flag (say a known mem.loc.) and then do some "higher stuff"...
In your case: the IRQ service routine runs in the same context, having the same zeropage than BASIC? Since the "invention" of a DP register (or similar ways to shuffle memory locations :wink: ) I always mistrust referencing such "local" locations from "outside" - it is too easy to fail.


Top
 Profile  
Reply with quote  
 Post subject: Re: FT816 Core
PostPosted: Tue May 30, 2017 7:15 pm 
Offline
User avatar

Joined: Sun Dec 29, 2002 8:56 pm
Posts: 449
Location: Canada
Here is the current IRQ routine:
Code:
; IRQ routine for all modes. The interrupted task must of had interrupts
; enabled and this status should be saved on the stack with the value of
; the status register. The RTI instruction will pop the status register off
; the stack and restore the interrupt enable.
; Note that all this routine does is switch to a task which has a different
; register set, so there's no need to stack and restore registers. The
; task switch also allows the routine to be located anywhere in the memory
; system, so we don't have to worry about using up bank 0 memory.

IRQRout832:
IRQRout816:
IRQRout02:
   TSK      #1         ; switch to the interrupt handling task
   RTI

; This task has interrupts masked in it's startup record and therefore runs
; with interrupts masked as the task never enables interrupts. Note that it's
; important that interrupts are masked while this is running, otherwise the
; uncleared interrupt status would cause another interrupt resulting in an
; infinite interrupt loop.
   MEM      16
Task1:
   LDA.B   MPU_IRQ_STATUS   ; check if counter expired
   BIT      #2            ; counter #1 IRQ active bit
   BEQ      .0001         ; no IRQ ?
   LDA      TickCount      ; increment the tick count
   INA                  ; lower 16 bits
   STA      TickCount
   STA.B   $FFF:$D00A4      ; update on-screen IRQ live indicator
   BNE      .0002
   INC      TickCount+2      ; increment upper 16 bits of tick count
.0002:
   LDA      #$05         ; count down, on mpu clock, irq enabled (clears irq)
   STA.B   CTR1_CTRL      ; set control register clearing interrupt
   LDA.B   $0:$100DF      ; Set flag for EhBASIC Irq
   ORA      #$20
   STA.B   $0:$100DF
.0001:
   RTT               ; go back to interrupted task (back to the RTI above)
   BRA      Task1      ; the next time task1 is run it will start here

Quote:
In your case: the IRQ service routine runs in the same context, having the same zeropage than BASIC?

The IRQ routine in BASIC runs in the same context as BASIC yes. However, the assembler IRQ service routine runs in it's own context and doesn't use the same area of memory for zeropage.

The system spits out about 8 to 10 'i's now before interrupts become disabled. I found a software problem. The '02 mode irq routine was just an 'RTI'. So while running in '02 mode interrupts were effectively ignored.

There can't be pre-emptive tasking until interrupts are working correctly !

_________________
http://www.finitron.ca


Top
 Profile  
Reply with quote  
 Post subject: Re: FT816 Core
PostPosted: Wed May 31, 2017 12:27 am 
Offline
User avatar

Joined: Wed Mar 01, 2017 8:54 pm
Posts: 660
Location: North-Germany
Hmm, I try to put things together:

Before you corrected the 02 Assembler_ISR you got 3 'i's and then IRQs are disabled. With correction (that is updating TickCount and setting Basics IRF) you get 8..10 'i's.
Basic is running as an 02 mode task and is issuing an 'i' only if there is its IRF set, that wasn't set by the 02 Asm_ISR. So the IRF was set by a 816 or 832 Asm_ISR. This could happen when BASIC is looking for a key (probably checking for CTL-C), as BASIC calls a BIOS routine that runs in 816 or 832 mode.

After changing the 02 Asm_ISR to act like the others, Basics IRF is set immediately after a tick, so perhaps before Basic is calling the BIOS it recognizes the IFR and skips the BIOS call but processing the Basic ISR (where it needs to print an 'i' what in turn means a call to the BIOS).

If Basic is checking its IRF before calling the BIOS and then aborts this BIOS call but start processing the BASIC_ISR where it performs an CLI and then the PRINT - it could happen that a next IRQ occurs (and is processed by the Asm_ISR) before the BIOS call to print a char is issued. This call would be aborted and the same procedure (executing the Basic_ISR...) happens again.

This should work. The consequence of aborting the BIOS calls would only a few 'i's not get printed. But if the BIOS calls would not be aborted but rather suspended? If the interrupt frequency would be too high it is only a question of time until a stack overflow would occur.

Hmm, I would try to slow down the IRQ frequency, say issuing the Basic_IRF only every 10 or 100 ticks. Just to see how many 'i's Basic can print :)


Top
 Profile  
Reply with quote  
 Post subject: Re: FT816 Core
PostPosted: Wed May 31, 2017 7:26 am 
Offline
User avatar

Joined: Sun Dec 29, 2002 8:56 pm
Posts: 449
Location: Canada
I tried running the interrupts at a 2Hz rate (as slow as possible) with the same effect. So it’s not an irq rate thing. BTW the register values have been dumped after exiting basic and it’s visible that the IRQ mask is actually set. This should be virtually impossible because the BASIC code never does a SEI.

I “fixed” the interrupt problem by having the interrupt enable status set to fixed values during a context update rather than reading the actual interrupt mask setting. For contexts 1,2, and 3 interrupts are always forced disabled. For the other contexts 4 to 511, interrupts are always enabled. This setting is only when a context is saved. It can still be temporarily overridden using the ‘SEI’ and ‘CLI’ instructions in a task. The reasoning behind this is that for most tasks one would want the interrupt system enabled anyways. For only a couple of really high priority (realtime) tasks one would want interrupts disabled. It’s a bit of a kludge but it works.

Two more levels of interrupts have been added to the core, so it has three IRQ inputs now (irq1, irq2, irq3). irq3 is the highest priority and can interrupt an ISR running below level 3.
The CLI instruction now only enables higher level interrupts to occur.

The core can now automatically switch to task when an interrupt occurs. This is accomplished by placing the task number in the vector instead of an ISR address. The core can tell the difference because the upper seven bits of the task number are zero, and the upper seven bits of an ISR routine address would never be zero.

I decided to try ramping up the clock speed of system even though there are timing errors reported by the tools. The system runs at 66MHz now but the display is fuzzy because the video timing isn’t quite met.
Now to get more working software for the system.

_________________
http://www.finitron.ca


Top
 Profile  
Reply with quote  
 Post subject: Re: FT816 Core
PostPosted: Wed May 31, 2017 4:27 pm 
Offline
User avatar

Joined: Wed Mar 01, 2017 8:54 pm
Posts: 660
Location: North-Germany
Well :) hardcoding irqs in or out is definitely a "bit of kludge" :lol: -- I hope you have placed a very well visible comment there :wink: .

On the other hand, there are currently a few threads dealing with EhBasic and it seems to be a bit bitchy as it matters where and how buffers and working area are placed. So it might not a general but a Basic specific problem.

If you have some other non primitive program to check it might run fine w/o any issues related to interrupts.


Top
 Profile  
Reply with quote  
 Post subject: Re: FT816 Core
PostPosted: Sun Jun 04, 2017 3:56 am 
Offline
User avatar

Joined: Sun Dec 29, 2002 8:56 pm
Posts: 449
Location: Canada
Eliminated the RIT instruction and instead made RTI more adaptable. The mnemonics would be too confusing. RIT was added to handle a return from an interrupt task as opposed to an interrupt subroutine. RTI now detects if a task switch occurred rather than a jump vector. This is accomplished by maintaining a hidden task switch bit in the core. When an interrupt occurs the task switch bit is set if the vector contains a task instead of a jump vector.

There are two more return instructions that may be merged into a single instruction. RTT and RTC are almost the same. By specifying more options with the instruction, they could be turned into a single instruction. The wrong return instruction has been used a couple of times now causing grief.

The number of tasks the core can handle may be reduced to 256 from 512. The benefit of doing this is that it only takes a single byte to represent the task number. That means only a single byte needs to be pushed for a task switching interrupt, or another task switch. 512 tasks was chosen because it uses the same hardware resources (block ram) as 256 tasks would. Part of the original reason for using two byte task numbers was the possible expansion of the context memory. However, if more tasks are required in a system then more cores can be used. One would likely want the tasks to be running in parallel on multiple cores as opposed to using just a single core in a larger system.

Loading and saving BASIC programs to an SD Card is just about working. For now the code just saves the entire block of BASIC memory from $0000 to $8000 to sector 136+ on the card.

Code to support (UI) I/O focus switching is being added. Only one task at a time can have the I/O focus. If a task attempts to do an I/O operation and it doesn’t have the focus, then the task is switched to another ready to run task. However in the case of a non-blocking keyboard character fetch the task is not switched, instead a status of no-character-available is returned to the task. In case the task does other work. The code controlling the I/O focus doesn’t work yet, but it’s getting there.

_________________
http://www.finitron.ca


Top
 Profile  
Reply with quote  
 Post subject: Re: FT816 Core
PostPosted: Sun Jun 04, 2017 11:32 am 
Offline
User avatar

Joined: Wed Mar 01, 2017 8:54 pm
Posts: 660
Location: North-Germany
Rob Finch wrote:
... This is accomplished by maintaining a hidden task switch bit in the core. When an interrupt occurs the task switch bit is set if the vector contains a task instead of a jump vector.

Does one bit be sufficient - I'm thinking whether there are nested (different priorities) interrupts?


Top
 Profile  
Reply with quote  
 Post subject: Re: FT816 Core
PostPosted: Sun Jun 04, 2017 7:03 pm 
Offline
User avatar

Joined: Sun Dec 29, 2002 8:56 pm
Posts: 449
Location: Canada
Quote:
Does one bit be sufficient - I'm thinking whether there are nested (different priorities) interrupts?

Yes, it is more complex than I mentioned before. There is an internal interrupt bits stack. The stack keeps track of the priority level and task switched status.
The stack is four entries deep. But interrupts are not allowed to nest at the same level. But a higher interrupt can interrupt a lower level one, so there is nesting that way. It can only occur up to three levels deep. One problem with the system is that interrupt routines must always exit with an RTI because RTI pops the internal stack. That means one can't create a fake interrupt return by manipulating the stack. The SEI instruction can now optionally set the interrupt level (0 to 3). A CLI sets it to zero.

Strangely, the system is more stable running at 33MHz than it is at 25MHz. It does crash differently based on the operating frequency. So there are timing problems that are probably not logic problems. (The tools do complain about timing errors).

_________________
http://www.finitron.ca


Top
 Profile  
Reply with quote  
 Post subject: Re: FT816 Core
PostPosted: Sun Jun 04, 2017 10:12 pm 
Offline
User avatar

Joined: Wed Mar 01, 2017 8:54 pm
Posts: 660
Location: North-Germany
Rob Finch wrote:
Quote:
Strangely, the system is more stable running at 33MHz than it is at 25MHz. It does crash differently based on the operating frequency. So there are timing problems that are probably not logic problems. (The tools do complain about timing errors).

That reminds me to a problem I once had with an amplifier. A few asymmetries in first stages were responsible for failing EMC tests but only during low to medium radiation. High field strengths doesn't matter :shock:
Perhaps running at higher frequencies masks out errors in a similar way: a second (or nth) timing problem cures previous ones.
To be honest: I don't think I would run a simulation with a slow clock if it seems to work with a high one :roll:


Top
 Profile  
Reply with quote  
PostPosted: Tue Jun 06, 2017 3:44 am 
Offline
User avatar

Joined: Sun Dec 29, 2002 8:56 pm
Posts: 449
Location: Canada
Added context stacks to support the JCR instructions. Previously JCR switched contexts to the specified context and began running code from the target. However this has a problem. The problem is the target context is not re-entrant. It’s not possible for two different tasks to use the same target context at the same time. Suppose a BIOS context was setup and task A is trying to do a character input via the BIOS. That means that task B can’t do a character output at the same time, because the single BIOS context is busy. It was also not possible for a context to do another JCR into the same context.
To “fix” this problem contexts are now stored in an internal stack when the JCR instruction is executed. There is no context switch, the context remains the same. The current context is saved on stack, then loaded from the target context. Program execution continues in the same context, however the register set has been loaded from the target, meaning it effectively uses the target context. At the end of the context subroutine the context’s register set is popped off the internal context stack.
There is a separate eight entry stack for each context. This means that when the context is switched there is no requirement to copy the stacks. There is such a limited stack because context routines are not used that often. There is a limited requirement for re-entrancy. For instance and app may call the OS which may then call the BIOS. That’s only requires a two level stack. Having several more stack entries allows for instance the BIOS to call another BIOS routine. Once the context is set, regular subroutine calls can be used.

The BSR, BSL instructions (relative branch to subroutine) may not survive to the finish. I added them thinking it might help make code relocatable, but I’ve yet to use the instructions. Instead regular JSR instructions are used. I like to be able to read the address in the machine code. Given the presence of a code segment which allows relocating programs, the BSR and BSL instructions are of limited use. 6502’ers have got by without BSR and BSL.

A bit of ugliness in the works. The RTIC instruction. This instruction is for circumstances where an interrupt return is required and at the same time popping the context stack is also required.

_________________
http://www.finitron.ca


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 72 posts ]  Go to page Previous  1, 2, 3, 4, 5

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: