6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sun Sep 22, 2024 6:34 pm

All times are UTC




Post new topic Reply to topic  [ 81 posts ]  Go to page Previous  1, 2, 3, 4, 5, 6  Next
Author Message
 Post subject: Re: Multiple interrupts?
PostPosted: Tue Aug 25, 2015 12:01 pm 
Offline
User avatar

Joined: Tue Mar 05, 2013 4:31 am
Posts: 1382
As most here don't use the BRK instruction, I do support it in my mini C02Bios. I also use a JMP table for the BIOS routines which make it easier to keep some consistency in your coding. Here's a link to the thread which also has code attached:

viewtopic.php?f=12&t=3045

I've included clock cycle timings on many of the comments and have detailed the IRQ service routine which has a 65C51 at 38.4K baud and a 65C22 with a 4ms jiffy clock timer running:

viewtopic.php?f=2&t=2849

My BIOS is also soft-vectored and has soft I/O parameters so it's easily extended and/or modified. Good luck with your BIOS project.

_________________
Regards, KM
https://github.com/floobydust


Top
 Profile  
Reply with quote  
 Post subject: Re: Multiple interrupts?
PostPosted: Tue Aug 25, 2015 12:03 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10938
Location: England
(Just to note: the Beeb does use BRK, at least in BASIC where it's used to signal an error and print a message. A few emulators trip up on that. But it uses JSR for syscalls.)


Top
 Profile  
Reply with quote  
 Post subject: Re: Multiple interrupts?
PostPosted: Tue Aug 25, 2015 1:31 pm 
Offline
User avatar

Joined: Tue Mar 02, 2004 8:55 am
Posts: 996
Location: Berkshire, UK
My take on all this is that BRK makes a better API when your operating system is multi-tasking and JSR is better when it is not. Using a software interrupt to invoke core kernel functions makes saving the callers state easier (just push all the key registers on the stack) and simplifies task switching (essentially switching one tasks stack pointer for anothers) but is more time consuming that a s.

UNIX traditionally uses system calls/traps/software interrupts for the core functions like unbuffered I/O (e.g. read,write) and the implements buffering in subroutine libraries (e.g. fread, fwrite). This way a process minimises relatively expensive systems calls and makes better use of its allocated CPU execution time.

Cycle counting and minimising branches makes sense at 1MHz but is not so worthwhile at 10 or 20MHz. Calling a subroutine in an interrupt makes sense if reuses code to save memory space. As the 65C816 has different vectors for native and emulation modes its quite probable that at least part of the interrupt handler will be in a subroutine.

The most important feature of an API is stability. As part of my 6502 emulation work I have written a clone of bits of the BBC MOS, enough to fool BASIC and other languages to work but my code it is completely different to the original. Doing the same with the 6800 emulation is much harder as the original boot ROMs like MIKBUG didn't contain a clean API and you need to keep key routines at thier original memory addresses to support old code.

_________________
Andrew Jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs


Top
 Profile  
Reply with quote  
 Post subject: Re: Multiple interrupts?
PostPosted: Tue Aug 25, 2015 2:41 pm 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
BigEd wrote:
(Just to note: the Beeb does use BRK, at least in BASIC where it's used to signal an error and print a message. A few emulators trip up on that. But it uses JSR for syscalls.)


Acorn Atom did the same thing. And most of the time, they didn't use real BRK instructions, but rather did a branch to some zero byte in the neighbourhood. So, if there was a LDA #0, then the 0 operand could be reused as a branch target. The error message itself was a number derived from least significant byte of return address, so that's why they are so chaotic.


Top
 Profile  
Reply with quote  
 Post subject: Re: Multiple interrupts?
PostPosted: Wed Aug 26, 2015 12:09 am 
Offline
User avatar

Joined: Sat Aug 22, 2015 8:54 pm
Posts: 31
Quote:
My take on all this is that BRK makes a better API when your operating system is multi-tasking and JSR is better when it is not. Using a software interrupt to invoke core kernel functions makes saving the callers state easier (just push all the key registers on the stack) and simplifies task switching (essentially switching one tasks stack pointer for anothers) but is more time consuming that a s.


BitWise- Would it be overhaul to try using BRK if I wanted to make the BIOS only and have users write their own OS (which may or may not be multitasking?)

_________________
It may look hard, but it won't take long if you take it one byte at a time.


Top
 Profile  
Reply with quote  
 Post subject: Re: Multiple interrupts?
PostPosted: Wed Aug 26, 2015 2:12 am 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
BitWise wrote:
My take on all this is that BRK makes a better API when your operating system is multi-tasking and JSR is better when it is not. Using a software interrupt to invoke core kernel functions makes saving the callers state easier (just push all the key registers on the stack) and simplifies task switching (essentially switching one tasks stack pointer for anothers) but is more time consuming that a s.
Can you clarify, please, Andrew? I have a feeling I'm missing something. It seems to me that "just push all the key registers on the stack" will work whether you call the system with a BRK or with a JSR. (Maybe it's a little handier if the desired function is specified by contents of a register rather than by the signature byte of a BRK, but that remark applies whether the operating system is multi-tasking or not.) I'd say JSR and BRK are merely the mechanism that gets you from point A to point B. After you arrive, does it matter how you got there?

_________________
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  
 Post subject: Re: Multiple interrupts?
PostPosted: Wed Aug 26, 2015 3:35 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8511
Location: Southern California
I took it to mean that it's assumed your ISR will stack all the registers, and he's taking advantage of that. However, I would think that you can put the BRK at points where it is not necessary to save the registers at all. I also don't automatically stack all the registers, only the ones I'll modify, and that will depend on which device caused the interrupt, so there may not be any point in wasting the time to stack anything until you find out. The ISRs I see in all the books are extremely inefficient.

_________________
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: Multiple interrupts?
PostPosted: Wed Aug 26, 2015 5:03 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8390
Location: Midwestern USA
BigEd wrote:
It is notable that serial processing takes quite an effort. That's why having a FIFO in the UART can be a big advantage...

Indeed! Modern UARTs, such as the 16550 found in PC hardware and the NXP 26xx and 28xx "automotive/industrial" series have FIFOs to reduce interrupt overhead (the NXP 28L92 in POC has 16-deep FIFOs). Taking advantage of those FIFOs can noticeably improve overall system throughput, especially during sustained input or output. I saw a remarkable reduction in interrupt frequency when I switched to the 28L92 and modified the BIOS to enable the 16-deep FIFOs on both transmit and receive.

The availability of FIFOs in modern UARTs (among other things) is one of my principle arguments against the use of ancient designs like the 6551 or the MC6850. Neither of those devices can buffer bytes in either direction, which becomes a critical drawback during reception at high data rates. Unless the system can get a deserialized byte out of the UART before the next one is processed a receiver overrun will occur and data will be lost.

Quote:
...likewise arranging for the interrupt servicing to place characters into a buffer, rather than forcing the application to deal with each character in real time.

Also a good point. Using buffered I/O "black boxes" things, relieving the foreground of having to deal with the hardware—the ISR deals with it. Plus foreground blocking will be less frequent with buffered I/O.

A while back, I extracted the UART drivers from POC's BIOS and coagulated them into a standalone package for the benefit of one of our members who is using the 28L92 in his 65C816 homebrew unit. These drivers fully utilize the UART FIFOs and are interrupt-driven in both directions. If anyone wants a copy please advise via PM.

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


Top
 Profile  
Reply with quote  
 Post subject: Re: Multiple interrupts?
PostPosted: Wed Aug 26, 2015 5:17 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8390
Location: Midwestern USA
Dr Jefyll wrote:
Can you clarify, please, Andrew? I have a feeling I'm missing something. It seems to me that "just push all the key registers on the stack" will work whether you call the system with a BRK or with a JSR. (Maybe it's a little handier if the desired function is specified by contents of a register rather than by the signature byte of a BRK, but that remark applies whether the operating system is multi-tasking or not.) I'd say JSR and BRK are merely the mechanism that gets you from point A to point B. After you arrive, does it matter how you got there?

I'm guessing that Andrew meant that the software interrupt front end would do the register saving, eliminating the need for the caller to handle that chore. On the other hand, if the function is called as a subroutine then the code immediately before the call has to handle saving state, which compounds if multiple calls are made to the same routine.

In my 65C816 interrupts article, I highlight several of the advantages of using software interrupts to call system services. Here is the relevant prose:

    Over the years, various methods that implement API calls have been devised, the two most common being that of treating a kernel function as a conventional subroutine or treating a kernel function as a specialized form of an interrupt service routine.

    In the former case, a static jump table provides access to the internal kernel functions. Perhaps the best known example of a kernel jump table is the one present in the Commodore 64's "kernal" ROM, with which any Commodore eight bit assembly language programmer will be familiar. User programs access kernel functions by treating them as subroutines and pass parameters via the microprocessor registers. Each kernel function has a unique entry point in the jump table, which as the "static" adjective implies, appears at a fixed address, with entries in an immutable order. The result is that assembly language programs that use only the jump table to access the kernel are portable to any eight bit Commodore computer in which the required kernel functions are present.

    In the interrupt service routine method, APIs are called via a kernel trap, which is a machine-dependent code sequence that transfers execution from the user program to the kernel. Each API call is assigned an immutable index number that tells the kernel what code must be executed to complete the desired function. Along with the API index number, any parameters to be passed to the kernel are loaded into the microprocessor's registers and/or pushed to the hardware stack before the call. Any parameters returned by the API are likewise loaded in the registers and/or placed on the stack. Implied is that the microprocessor has a large number of general purpose registers, has instructions to address the stack by means other than just pushes and pulls, or both capabilities.

    Naturally, both API calling methods have their strong and weak points. Use of a jump table makes for simple user application programming and a generally less complicated kernel. Applications merely JSR to access the API and the kernel exits with RTS. The required kernel code can be very small and fast-executing, which was an important consideration in early home computers. However, once a system has been developed with a specific jump table layout, the design is essentially cast in concrete, even if future hardware and/or operating system revisions would be better served with a relocated kernel and/or rearranged jump table. The fact that applications must know where in memory the kernel is loaded and must be able to access that memory makes the kernel non-portable and if running in RAM instead of ROM, vulnerable to corrupting wild writes caused by program errors and/or malicious coding.

    Calling APIs via a kernel trap offers the advantages of portability and isolation. User programs don't need to know specific addresses to access the kernel API—applications only need to know API index numbers. If a new kernel is released with a new API-accessible function, the lowest unused API index number is assigned to the new function, which will not affect any applications that were written prior to the kernel update. As a user-accessible jump table is not used for calling APIs, the kernel can be loaded anywhere in memory that is convenient.

    Isolation offers the kernel some protection from misbehaving user applications, reducing the likelihood of random instructions or wild address pointers accidentally accessing and/or overwriting kernel space and causing system fatality. In most systems, a kernel trap causes a hardware context switch that may be used to modify the memory map, alter memory protection rules, and/or change instruction execution privileges, all of which can be used to tightly control what user programs can and cannot do.

    The principal downsides to a kernel trap API calling method are greater code complexity, heavy stack usage and slower execution. As will be seen, a kernel trap API ultimately involves a software interrupt to switch execution from user mode to kernel mode. Therefore, code in both the API "front end" and "back end" is essentially a specialized form of an interrupt service routine, which adds complexity to the kernel. Also, since the API entry point is the same for all APIs, dispatch code is required to select the specific function that must be executed for a particular API, as well as determine how many parameters are expected by the API. That an API call culminates in an interrupt means that slower execution will occur due to hardware and software-induced latency.

The software interrupt method has a clear advantage over a jump table, but places more burden on the kernel and the microprocessor. With the 65C816, at least, the required code isn't difficult and one can use COP instead of BRK as a "trap" instruction. The 65C02 doesn't lend itself as well to this style of programming due to limited stack addressing capabilities. Also, the only software interrupt is BRK, which could give rise to some interesting debugging problems.

As always, everything has pros and cons.

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


Top
 Profile  
Reply with quote  
 Post subject: Re: Multiple interrupts?
PostPosted: Wed Aug 26, 2015 5:26 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8511
Location: Southern California
Quote:
I'm guessing that Andrew meant that the software interrupt front end would do the register saving, eliminating the need for the caller to handle that chore. On the other hand, if the function is called as a subroutine then the code immediately before the call has to handle saving state, which compounds if multiple calls are made to the same routine.

Why not just have the subroutine do the register-saving? Or is it that BRK's operand byte can be had without affecting any register until after the register-saving? To preserve interrupt performance, I would be in favor of using the JSR and using a macro to hide whatever needs to be done in the process of calling.

_________________
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: Multiple interrupts?
PostPosted: Wed Aug 26, 2015 5:54 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8390
Location: Midwestern USA
GARTHWILSON wrote:
To preserve interrupt performance, I would be in favor of using the JSR and using a macro to hide whatever needs to be done in the process of calling.

As I said in my previous post, there are tradeoffs in both cases. Whether the MPU state is preserved by the caller or within the API doesn't affect performance, only code size. Calling a kernel API as a subroutine is indeed somewhat faster (by 3 cycles total per call in the case of the 65C816) than calling it via a software interrupt, as no "forced" saving of state occurs as it would with an interrupt. However, in a general purpose operating system, it's desirable to erect a "Chinese wall" between the kernel and user applications to maintain system integrity. That isn't possible if kernel APIs are treated as subroutines, as user code has to be able to access kernel space. On the other hand, if an API is through a software interrupt it is possible to prohibit user mode access to kernel space, since the software interrupt can also be made trigger changes to the execution environment.

Something else to consider in the case of the 65C816 is that JSR can only reach subroutines in the bank from which they are called. If the application is in bank $02 and the kernel is in bank $01 an API call has to be via JSL/RTL, adding a cycle (JSR uses 6, JSL uses 7). On the other hand, if the kernel call is made with COP, it will work no matter in which bank the caller is located, as well as in which bank the kernel is located. The difference in performance is 13 cycles for JSL/RTL and 15 cycles for COP/RTI. Not much of a difference, I say.

Pick yer poison! :D

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


Top
 Profile  
Reply with quote  
 Post subject: Re: Multiple interrupts?
PostPosted: Wed Aug 26, 2015 6:29 am 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
A disadvantage of using BRK for kernel calls is that it will disable interrupts even when it's not necessary, increasing latency for real interrupts.

The disadvantage of having direct JSR to absolute addresses is not very limiting for the (single user) hobby systems we're talking about here. It's easy enough to rebuild the whole project when something changes.


Top
 Profile  
Reply with quote  
 Post subject: Re: Multiple interrupts?
PostPosted: Wed Aug 26, 2015 6:46 am 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
Thanks, all, for the replies. Unfortunately I did a poor job phrasing my question, which is: why might BRK make a better API specifically when the operating system is multi-tasking. But Arlet managed to shed some light anyway -- the interrupt latency point, I mean. (I'm not convinced that's what Andrew was driving at, though. In fact the latency issue might argue against his stance.)

Quote:
The disadvantage of having direct JSR to absolute addresses is not very limiting for the (single user) hobby systems we're talking about here. It's easy enough to rebuild the whole project when something changes.
I agree a JSR is not very limiting. And, if protection against future revisions is desired, it's still possible for the OP's system to stick to a single, "cast in stone" entry address. It costs 3 cycles, but just have a JMP located there.

_________________
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  
 Post subject: Re: Multiple interrupts?
PostPosted: Wed Aug 26, 2015 7:03 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8511
Location: Southern California
And again, LDX#<function_number>, JSR <BIOS> does not change any addresses as the BIOS changes. It's only one address, and it can be cast in stone. The addresses in the table used there can change at any time without any need to inform the user.

_________________
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: Multiple interrupts?
PostPosted: Wed Aug 26, 2015 2:37 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10938
Location: England
This might be a point making explicitly, since some people will have come across machine code habits which JSR into the middle of ROMs to pick up useful routines - all of us here talking about using JSR are, I think, speaking of a smallish number of entry points all packed right up at the top of memory below the vectors, and not moving around between ROM revisions. In most cases, that means you'll see a collection of JMP instructions which redirect to the real routines, which may well move around. Another possibility is that you'll see some indirect JMP instructions, which go through a RAM pointer, allowing an OS routine to be prefixed or replaced by RAM code.

So, using JSR does not necessarily mean jumping into the middle of ROM, and having entry points subject to change!


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

All times are UTC


Who is online

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