6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Fri Nov 22, 2024 9:50 pm

All times are UTC




Post new topic Reply to topic  [ 217 posts ]  Go to page Previous  1 ... 3, 4, 5, 6, 7, 8, 9 ... 15  Next
Author Message
 Post subject: Re: 65VM02
PostPosted: Thu May 18, 2017 5:19 pm 
Offline
User avatar

Joined: Sun Dec 29, 2002 8:56 pm
Posts: 460
Location: Canada
Let's see if I get this. It's suggested that the NEXT instruction have it's own dedicated hardware signal input associated with it (say NIRQ). And that whenever NEXT is executed the signal is tested which causes a jump to the interrupt subroutine if active, otherwise the regular NEXT operation is performed ?

_________________
http://www.finitron.ca


Top
 Profile  
Reply with quote  
 Post subject: Re: 65VM02
PostPosted: Thu May 18, 2017 5:52 pm 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
Quote:
And that whenever NEXT is executed the signal is tested which causes a jump to the interrupt subroutine if active, otherwise the regular NEXT operation is performed ?

Yes, something like that. I'm not a Forth expert, so I'm not sure exactly what would be the best way to implement this. But even without considering Forth, I can imagine a special 6502 instruction that enables a low priority interrupt for one cycle, and then disables it again, and then you could insert that instruction wherever it was convenient.


Top
 Profile  
Reply with quote  
 Post subject: Re: 65VM02
PostPosted: Thu May 18, 2017 6:28 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8544
Location: Southern California
It wouldn't even particularly enable and disable it; it's just that it only looks at it at the beginning of the NEXT instruction, not in any other instructions or times.

_________________
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  
 Post subject: Re: 65VM02
PostPosted: Fri May 19, 2017 2:12 pm 
Offline
User avatar

Joined: Sun Dec 29, 2002 8:56 pm
Posts: 460
Location: Canada
It could be a mask able interrupt too. A byte code fetch instruction could test the signal as well. But it would have to be a special first instruction byte fetch instruction.
That would place the test at the beginning of an operation rather than at the end.

_________________
http://www.finitron.ca


Top
 Profile  
Reply with quote  
 Post subject: Re: 65VM02
PostPosted: Sat May 20, 2017 8:15 am 
Offline

Joined: Fri Jun 03, 2016 3:42 am
Posts: 158
A lot of your post was quite confusing to me, but it is late at night --- I'll try to figure it out later.

GARTHWILSON wrote:
Perhaps you're thinking of something I'm forgetting; but C@ (whether I/O byte or otherwise) is not like @ which can get interrupted between the fetch of the two bytes if it's on an '02 and not the '816. C@ and C! shouldn't cause any problems even on the '02. OTOH, a primitive that does a R-M-W on a single byte but without the benefit of being able to do it in a single instruction like INC or TSB may require care. What I do (in assembly language too) when reading the RTC bytes in memory that get incremented by a timer interrupt is to read them multiple times until I get the same thing twice in a row, eliminating the possibility of invalid sets when the low byte's rollover carries into higher bytes in the middle of the reading process.

This part I will comment on now.

My EXA instruction is intended to support reading and writing a semaphore in a single non-interruptable instruction. You can't use C@ to read the current value and then use C! to set your own value, because there might be a task-switch between the C@ and the C!. Note that allowing a task-switch to only occur at NEXT (between primitives) doesn't help because C@ and C! are different primitives.


Top
 Profile  
Reply with quote  
 Post subject: Re: 65VM02
PostPosted: Sat May 20, 2017 8:22 am 
Offline

Joined: Fri Jun 03, 2016 3:42 am
Posts: 158
Rob Finch wrote:
Let's see if I get this. It's suggested that the NEXT instruction have it's own dedicated hardware signal input associated with it (say NIRQ). And that whenever NEXT is executed the signal is tested which causes a jump to the interrupt subroutine if active, otherwise the regular NEXT operation is performed ?

That was the idea with the T-flag. The heartbeat timer would set the T-flag (either in hardware, or in a very short ISR). Later on, NEXT would check if the T-flag was set and, if so, would do a task-switch.

I got rid of the T-flag though --- I'm still considering it --- at this time however I don't like the idea.


Top
 Profile  
Reply with quote  
 Post subject: Re: 65VM02
PostPosted: Sat May 20, 2017 8:35 am 
Offline

Joined: Fri Jun 03, 2016 3:42 am
Posts: 158
Arlet wrote:
You could make different interrupt priorities, where the highest priority would be handled in assembly language, and can happen at any time, and a lower priority one that works on Forth level, and can only happen during NEXT.

Yes, ISRs can be written in either assembly-language or in Forth.

It is not necessary however, for an interrupt to only occur in NEXT if the ISR is written in Forth. Each task has its own D-register value, so when an interrupt occurs D gets a new value. This means a new direct-page, a new data-stack and a new return-stack. There is no context that needs to be saved and restored (such as on the return-stack) because the entire context (including the return-stack) changes when D changes.

The only advantage of doing this at NEXT is that A, Y and P don't need to be saved and restored because it is guaranteed that none of these are valid at NEXT (the X register and S register are valid though, and have to be saved in the direct-page somewhere). This isn't much of an advantage because saving A Y and P doesn't take much time (that has always been the good thing about the 65c02; there aren't many registers, and they are 8-bit, so saving and restoring them doesn't take much time).

I think it is okay to do a task-switch anywhere, including in the middle of a primitive, and it is okay for ISRs to be written in Forth rather than assembly-language.

It may not be practical to write ISRs in Forth though, because Forth is maybe an order of magnitude slower than assembly-language, and ISRs need to be fast --- it may be necessary to write ISRs in assembly-language because of the speed issue --- ISRs tend to be short and simple though, so this isn't a lot of extra work for the programmer.


Top
 Profile  
Reply with quote  
 Post subject: Re: 65VM02
PostPosted: Sat May 20, 2017 8:39 am 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
Quote:
It may not be practical to write ISRs in Forth though, because Forth is maybe an order of magnitude slower than assembly-language, and ISRs need to be fast --- it may be necessary to write ISRs in assembly-language because of the speed issue --- ISRs tend to be short and simple though, so this isn't a lot of extra work for the programmer.

The idea was that you would have a choice between a fast interrupt that can happen at any time, and a slow one that you could write in Forth. Not all ISRs need to be fast, and as long as the fast ones can interrupt the slow one (by using more than one priority), there's no problem with missing important events while processing a slow IRQ.


Top
 Profile  
Reply with quote  
 Post subject: Re: 65VM02
PostPosted: Sat May 20, 2017 9:08 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8544
Location: Southern California
Arlet wrote:
Quote:
It may not be practical to write ISRs in Forth though, because Forth is maybe an order of magnitude slower than assembly-language, and ISRs need to be fast --- it may be necessary to write ISRs in assembly-language because of the speed issue --- ISRs tend to be short and simple though, so this isn't a lot of extra work for the programmer.

The idea was that you would have a choice between a fast interrupt that can happen at any time, and a slow one that you could write in Forth. Not all ISRs need to be fast, and as long as the fast ones can interrupt the slow one (by using more than one priority), there's no problem with missing important events while processing a slow IRQ.

Yes, and my Forths allow for both. My RS-232 receive at 9600bps is serviced in Forth. Especially for ones that might occasionally have error conditions to fix or report, it may be much easier to handle them in Forth if they don't need machine-language speed. However, a machine-language ISR can also trigger a Forth one if necessary. Interrupts that are to be serviced in machine language get immediate attention, while the others wait for NEXT. Within each group, sources are polled in order of priority (but only the activated sources are polled while all the others get ignored).

Quote:
My EXA instruction is intended to support reading and writing a semaphore in a single non-interruptible instruction. You can't use C@ to read the current value and then use C! to set your own value, because there might be a task-switch between the C@ and the C!. Note that allowing a task-switch to only occur at NEXT (between primitives) doesn't help because C@ and C! are different primitives.

So since C@ doesn't alter the port, it sounds like the concern is that another task could alter the port you already read with C@, so when the task runs again and does a C! to the same port, it may think it's not altering bits it didn't intend to. It's probably a valid concern; although I wouldn't generally recommend putting different tasks on the same port like that. However, I've only done cooperative multitasking (where that problem won't happen), so I might need to give it some more though, or see how this develops.

_________________
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  
 Post subject: Re: 65VM02
PostPosted: Sat May 20, 2017 9:13 am 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
Quote:
However, a machine-language ISR can also trigger a Forth one if necessary. Interrupts that are to be serviced in machine language get immediate attention, while the others wait for NEXT.

But that would slow down the NEXT processing when nothing is pending. My idea was to implement some mechanism that would enable low priority interrupts briefly during NEXT processing. If there was no interrupt pending, it would continue as normal without any overhead.


Top
 Profile  
Reply with quote  
 Post subject: Re: 65VM02
PostPosted: Sat May 20, 2017 6:48 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8544
Location: Southern California
The interrupt capability in NEXT slows everything down less than 4% which is not noticeable. But if there is an interrupt, NEXT is much faster than the normal NEXT, and the ISR works like any other word, not having to save anything or set up or move to new stacks or anything. That's with of-the-shelf parts. It will be nice, Hugh, to see your improvements, since you're working the design with Forth ISRs (among other things) in mind.

Quote:
My idea was to implement some mechanism that would enable low priority interrupts briefly during NEXT processing.

I'd enjoy hearing more.

Edit: Jeff Laughton reminded me there's a way to use additional self-modifying code to eliminate all the extra cycles from the normal '816 NEXT to carry out the interrupt method I mentioned earlier; so I edited my post on the last page, at viewtopic.php?p=53082#p53082 .

_________________
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  
 Post subject: Re: 65VM02
PostPosted: Sun May 21, 2017 1:08 am 
Offline

Joined: Fri Jun 03, 2016 3:42 am
Posts: 158
Arlet wrote:
Quote:
It may not be practical to write ISRs in Forth though, because Forth is maybe an order of magnitude slower than assembly-language, and ISRs need to be fast --- it may be necessary to write ISRs in assembly-language because of the speed issue --- ISRs tend to be short and simple though, so this isn't a lot of extra work for the programmer.

The idea was that you would have a choice between a fast interrupt that can happen at any time, and a slow one that you could write in Forth. Not all ISRs need to be fast, and as long as the fast ones can interrupt the slow one (by using more than one priority), there's no problem with missing important events while processing a slow IRQ.

I wasn't planning on allowing ISRs to be interrupted. I was expecting ISRs to be pretty short and quick. The AIRQ interrupts do have priorities, but that only affects which one is serviced if more than one are pending. The I-flag is set during an ISR, so when the ISR ends and the I-flag gets cleared, there may be more than one pending interrupt that was triggered while the I-flag was set and hasn't been serviced yet.

Note that an ISR can force a task-switch to a particular task. So, if you have some lengthy code that you want written in Forth, this would not be an ISR, but would be a task. You would have a short ISR that does some time-critical access of I/O and then it forces a task-switch to the task that is waiting on this data.

Anyway, I have a new document with the EXA instruction added. It is attached. I also have a section discussing the multi-tasking OS:
Code:
Section 5.) the multi-tasking OS

The OS does preemptive task switches. A task-switch may occur at any time, including in the middle of a primitive.
There is a heartbeat timer that does a task-switch periodically (typically every 10 milliseconds).
It is also possible for a task to pause, waiting to obtain a semaphore, in which case it does a task-switch.

Tasks aren't guaranteed to execute on an exact schedule.
The time between executions of a particular task will vary a lot depending upon these factors:
1.) The number of tasks is the major factor.
2.) If any tasks are pausing, they don't get their full allotment of time.
3.) An ISR may change the order of the tasks being executed, to move a particular task to the front.

If you need code to execute on an exact schedule, this should be an ISR tied to a timer interrupt.
An ISR is different from a task because it can't be interrupted by anything (the I-flag is set).
An ISR should be pretty short and quick so it doesn't prevent other ISRs from losing data.

An ISR can be written in either assembly-language or Forth.
Forth is about an order of magnitude slower than assembly-language though, so assembly-language is generally preferred.
Each ISR is quite short though, so the application programmer won't be writing a lot of assembly-language.
Most of the work will be in tasks, and these are written in Forth. Tasks are not time-critical.
The ISRs and tasks communicate through circular buffers. The task only has to be fast enough that the buffer doesn't overflow.
The buffer will typically be 256 elements because this is easy to implement on the 65VM02 using Y as the index.

The buffers don't have associated semaphores.
A task can be reading or writing to a buffer and get interrupted by an ISR that is also reading or writing to that buffer.
Semaphores are primarily needed when a task accesses I/O directly, and more than one task may access the same I/O.
A typical example would be an LCD display. A task has to hold this for itself until it is done, or the messages will get jumbled.

The EXA instruction was provided to support obtaining a semaphore without the test and set being interrupted by a task switch.
This is the code for obtaining and releasing a semaphore (1 means held and 0 means free):

OBTAIN: ( semadr -- )
    LDY toslo,X
    LDA toshi,X
    STA ptr+1
obtain_begin
    LDA #1
    EXA (ptr),Y             ; hold the semaphore (by setting it to 1)
    BEQ obtain_done         ; the semaphore was free, so we have obtained it for our task
    JSR task-switch         ; let the other tasks execute --- maybe whichever task is holding the semaphore will free it
    BRA obain_begin
obtain_done:
    INX
    NEXT

RELEASE: ( semadr -- )      ; assumes that OBTAIN has already been done and we are holding the semaphore
    LDY toslo,X
    LDA toshi,X
    STA ptr+1
    LDA #0
    STA (ptr),Y             ; release the semaphore (by setting it to 0)
    NEXT

In OBTAIN we have an EXA that sets the semaphore to 1 and tests the old value for 0. EXA can't be interrupted.
If we didn't have EXA and used LDA and STA instead, a task-switch could occur between loading the semaphore and storing the 1.
If the semaphore was 0, then our OBTAIN is going to assume that it can obtain the semaphore.
Another task may call OBTAIN for the same semaphore while it is still 0 and will assume that it can also obtain the semaphore.
The result is that both tasks think that they have obtained the semaphore.

We also have a READ-BUFFER primitive that a task uses to read data from a buffer that is being filled by an ISR (such as a UART).
If there is no data in the buffer, then READ-BUFFER will do a task-switch to allow other tasks to execute.
READ-BUFFER will also set a flag to indicate that the task is waiting on a buffer, and should not be executed by the heartbeat timer.
The ISR for the heartbeat timer will do a task-switch, but will not execute any task that is waiting on a buffer.
If all the tasks are waiting on buffers, heartbeat timer ISR will shut down the system.
This means that the heartbeat timer is shut down so it doesn't cause any more interrupts, and a WAI is done.
The system will restart when an interrupt occurs. That ISR will execute, and the heartbeat timer will be restarted.
It is possible that this ISR puts some data in a buffer when it executes (data that was input from an external source).
When the heartbeat timer does a task-switch it will find the task that is waiting on a buffer that now has data (from the ISR earlier).
If all the tasks are waiting on buffers that are still empty though, the heartbeat timer ISR will shut down the system again.

The heartbeat timer is typically 10 milliseconds (100 times per second).
If the heartbeat is too slow, a fast interrupt may cause a buffer to overflow before the task comes around to empty the buffer.
If the heartbeat is too fast, the processor spends too much time doing task-switches and not enough time in the tasks.
The tasks are stored in a circular linked-list.
If an ISR is filling a buffer, and notices that the buffer is over half full, it can adjust the task-list so that its task will be next.
It would also force an task-switch so its task will execute immediately.
This allows the heartbeat timer to be slow (100 hz.) and yet have a task execute at a high frequency while inputting data quickly.
It is important to be able to handle a burst of data that comes in fast, while still having a slow heartbeat.


Attachments:
File comment: added the EXA instruction and also provided a discussion of the multi-tasking OS
65VM02.txt [29.76 KiB]
Downloaded 57 times
Top
 Profile  
Reply with quote  
 Post subject: Re: 65VM02
PostPosted: Sun May 21, 2017 4:30 pm 
Offline

Joined: Fri Jun 03, 2016 3:42 am
Posts: 158
Hugh Aguilar wrote:
Arlet wrote:
Quote:
It may not be practical to write ISRs in Forth though, because Forth is maybe an order of magnitude slower than assembly-language, and ISRs need to be fast --- it may be necessary to write ISRs in assembly-language because of the speed issue --- ISRs tend to be short and simple though, so this isn't a lot of extra work for the programmer.

The idea was that you would have a choice between a fast interrupt that can happen at any time, and a slow one that you could write in Forth. Not all ISRs need to be fast, and as long as the fast ones can interrupt the slow one (by using more than one priority), there's no problem with missing important events while processing a slow IRQ.

I wasn't planning on allowing ISRs to be interrupted. I was expecting ISRs to be pretty short and quick. The AIRQ interrupts do have priorities, but that only affects which one is serviced if more than one are pending. The I-flag is set during an ISR, so when the ISR ends and the I-flag gets cleared, there may be more than one pending interrupt that was triggered while the I-flag was set and hasn't been serviced yet.

I will give some thought to the subject of ISRs being interrupted. This might be possible. I'm concerned that this might be dangerous, and make the system prone to bugs, but maybe it is okay.

If I did allow this, then I would need another interrupt-mask. The 65c02 already has the I-flag and the SEI and CLI instructions. There is an extra bit available in the P register (what I was using previously for the T-flag that I no longer have). Maybe I could dedicate this to being another interrupt mask --- lets call it the L-flag (for low-priority interrupt mask), and provide two new instructions SEL and CLL for setting and clearing it.
IRQ AIRQ0 AIRQ1 --- These would be masked by the I-flag. When they begin, I-flag and L-flag are both set.
AIRQ2 AIRQ3 --- These would be masked by the L-flag. When they begin, I-flag is clear and L-flag is set.

Note that IRQ and NMI are left in the 65VM02 primarily to support legacy programs. They aren't very useful in regard to the multi-tasking OS because they don't change D to zero, so your ISR ends up with whichever direct-page that the current task was using, which is not the direct-page that you want (because all the I/O ports are in page zero).

ISRs getting interrupted(?)! Something to think about! :idea:


Top
 Profile  
Reply with quote  
 Post subject: Re: 65VM02
PostPosted: Sun May 21, 2017 4:36 pm 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
Quote:
ISRs getting interrupted(?)! Something to think about! 

It's pretty standard on ARM Cortex, typically with 16 or more priorities. Once you get used to it, it works great because you can spend a long time in a low-priority interrupt, without having to worry about blocking higher priority ones.


Top
 Profile  
Reply with quote  
 Post subject: Re: 65VM02
PostPosted: Sun May 21, 2017 5:08 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
Acorn's BBC Micro uses IRQ for housekeeping (for timer ticks, serial, VIA) and NMI for floppy disk data transfer. It must be that NMI can happen during an IRQ service.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 217 posts ]  Go to page Previous  1 ... 3, 4, 5, 6, 7, 8, 9 ... 15  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 9 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: