BRK detection

Programming the 6502 microprocessor and its relatives in assembly and other languages.
schidester
Posts: 57
Joined: 04 Sep 2002
Location: Iowa

Post by schidester »

Garth,
Quote:
> In defense of myself I must say that normally one does check the flags from an
> actual status register to determine the source of an interrupt...

BRK does not respect the interrupt-disable flag.
All I meant was that I expected (wrongly) to examine the B flag (not the I flag) to determine whether BRK was the cause of interrupt.
Quote:
If I'm understanding you right, this sounds like really bad programming!
That was precisely my point! Somewhere (I forgot where) I saw NMI handler code that attempted to get around the "skipped BRK on NMI" bug in the 6502 by examining the opcode at the saved PC minus 2. I was hoping that someone reading this might not make that mistake if they didn't think about it.

Quote:
..PC and Windoze are very unsuitable for real-time applications because the interrupt latency is so nondeterminate...
Agreed. I think the main problem is the lengthy swap times to harddisk. Windows is always messing around with the harddisk, making any application execution indeterminant. Nonetheless, I read somewhere that DOS is the most popular embedded operating system by volume. Scary.
Quote:
there are only certain places where it offers the system the option of switching to another task
An operating system can of course include a number of features which either complicate it or simplify it. It depends on your needs. If you write your own OS, naturally you have the most flexibility.
Quote:
But BRK can be entered endlessly without exiting
I forgot about that. I was thinking that a timer event might signal a task switch in the middle of an OS call, thus possibly reentering the same OS call. However, BRK doesn't just happen anywhere, so already we have control of it causing reentrancy problems. Also, if you're not using preemption, it's not an issue anyway.
Quote:
I can think of plenty of situations where you would want to re-enable
interrupts during an ISR
Me too. On my little SBC project I have a "panic" button attached to NMI, whose handler basically drops into a monitor prompt, enabling interrupts to do I/O. Until the monitor returns to the interrupted program, the NMI-triggered monitor prompt can be thought of as one long ISR. Thanks for the correction. I was trying to illustrate that in a multitasking OS, you probably likewise want to disable (hardware) interrupts because they cause a context switch, when your OS may already be in the middle of switching tasks.
Quote:
I hope none of this is taken to be combative and argumentative.
Nope. Again an interesting discussion.
kc5tja
Posts: 1706
Joined: 04 Jan 2003

Post by kc5tja »

GARTHWILSON wrote:
I guess I can see where you're coming from now. It's kind of a foreign idea to me because I have never had to work with someone else's OS on the 6502 since 1982 when we used the AIM-65's in school. I've always had full control of every speck of code, and my workbench computer quickly compiles applications on the fly every time I load them up to use them, so even the possibility of changing addresses in the kernel are no threat. I commented above about the problem of task-switching happening at the worst possible times.

Garth
Understood. :) As an avid Forth programmer myself, I fully desire having full control over everything. I'm currently hacking up a new native Forth implementation for my old, otherwise useless 486 laptop (not enough resources to run any OS of modern value, including Linux). I'm really enjoying the experience, but I fear that when it comes time to control the video, I won't have the degree of control that I desire. The chipset is Cirrus Logic, and that's all I know about it. It's really bizarre. I originally wanted to go into protected mode and utilize all available memory, but it's looking like I can't do that now, because going into protected mode eliminates any possibility of invoking BIOS services to set video mode. :( I'll just use "flat real mode" to fake a protected-mode environment in real-mode, I guess, and although program code will be limited to the first 640K (indeed, in my system, it'll probably be limited to a single 64K segment!), and set up extended RAM as a super-fast cache for block I/O. That should give me the next best thing in convenience and speed.

Just as a side project, I'm planning on building a wire-wrapped home computer around the 65816, probably running at 4MHz (since I have 7 CPUs of this type, I might as well do something with them). This is a long-term project for me, unfortunately, as I have many other things competing for my brain at the moment. It'll probably have 128K of RAM to start off with. And as much as I love preemptive multitasking, seeing as how the kernel will be Forth, I've decided to stick with cooperative multitasking instead. It's easier to implement in the kernel (indeed, for the Forth VM, it's utterly trivial), and as long as the applications are multitasking aware, it can be sufficiently responsive enough to rival preemptive systems. I have no real-time requirements, so preemption is a complexity not worth investing in. (Though I've done it in the past, and it's not that much harder to do once you've gotten cooperative multitasking implemented. So if I ever need it again, it would be rather easy to add.)

The nice thing about Forth is that switching from one application to another involves, literally, recompiling the source of the application from scratch. Suppose I have a calculator on-screen. I want to switch (back?) to a word processor. When I do that, the word processor invokes a word along the lines of "NEW" or something (it's usually Forth specific), which resets the Forth dictionary, and provides a clean slate for the WP code to load in. Since it's all source-based, fixups and OS entry points aren't a consideration. In fact, the coupling between the application and the Forth kernel is so tight that it's hard to tell where one starts and the other ends. :) Moreover, the persistence mechanism of Forth mimicks how a data cache operates; thus, even though your application is swapped out of memory, if your application's DATA space is kept purely in blocks, you still get excellent performance with the additional benefit of near-full persistence.

Another nice thing about Forth is that the language itself makes making multitasking-aware applications dead simple. In fact, they're as simple as non-multitasking-aware applications. Unless you're going to be doing heavy inner-loop calculations, you'll almost never call PAUSE yourself, which relinguishes the "time-slice" to another task, but otherwise appears as a NOP to the application. Forth's I/O words, including KEY(?), BLOCK/BUFFER, etc. all implicitly invoke PAUSE after initiating the I/O operation (hardware permitting), allowing some form of overlap to occur. It might sound primitive (and it is), but I've used systems like this, and considering the Forth kernel is kilobytes in size, the results are absolutely impressive. When developing code, I honestly thought it had preemptive multitasking at first.

But I'm digressing, and it's way off topic for this channel. :D I'll go back to my notebook and continue daydreaming about the '816 project.
User avatar
Rob Finch
Posts: 465
Joined: 29 Dec 2002
Location: Canada
Contact:

Post by Rob Finch »

Hey,

By reading this discussion, I've just uncovered a bug (well really a "feature") in my Verilog implementation of the 6502 processor. The "BC6502" actually does restore the previous state of the break flag from the stack. It seems that while reading docs on the 6502 I thought it must be a misprint where stated that the B flag is set to one by plp and rti, as this would mean the B flag is always set. :)

Regarding a multi-tasking OS, as far as interrupts go I've of the opinion that the only thing an ISR should do is send a message to the appropriate mailbox indicating that an ISR occurred and nothing else. This should be handled automatically within the scope of the operating system and not left up to device drivers. There is no real reason for device drivers to directly handle interrupts. Pre-emptive interrupts should only be used to avoid bogging the system down with polling loops and should only be used to send a simple "interrupt occurred" message. The only exception to this would be the OS time slicer that determines the time slice period (really a polling interval) at which point the OS can look at outstanding messages and prioritize what should be done next.

My two cents,
Rob
kc5tja
Posts: 1706
Joined: 04 Jan 2003

Post by kc5tja »

Rob Finch wrote:
Regarding a multi-tasking OS, as far as interrupts go I've of the opinion that the only thing an ISR should do is send a message to the appropriate mailbox indicating that an ISR occurred and nothing else.
Of course. However, in a memory protected environment, it could become a performance bottleneck if you're not careful, which is why so many MMU-based OSes do not do this.
Quote:
The only exception to this would be the OS time slicer that determines the time slice period (really a polling interval) at which point the OS can look at outstanding messages and prioritize what should be done next.
The time slice interrupt should be treated NO differently than any other interrupt. Moreover, messages should be handled as soon as they're delivered, task priority permitting. That is, if you deliver a message to a task that is higher in priority than your currently running task, a task switch should occur immediately. Waiting for the task quantum to expire before all messages are processed effectively makes your preemptive multitasker no more efficient than a poorly written cooperative multitasker.

Moreover, task switches can occur at any moment in time, but never when running kernel code. Thus, it makes perfect sense to switch tasks at the completion of ANY interrupt handling, not just timer interrupts. This is especially true if the OS entry point is handled as a system call interrupt of some kind.

I highly encourage people to study how VMS and AmigaOS implement its multitasking. They both have done things "The Right Way," to be sure. Even today, my 7MHz Amiga multitasks more reliably and predictably than my 1GHz Athlon running Linux. My multitasking kernels for the x86, which I've written years ago, also are incredibly more "regular" than Linux. All of my kernels are based on AmigaOS, which I later found out, was itself inspired by VMS.
User avatar
Rob Finch
Posts: 465
Joined: 29 Dec 2002
Location: Canada
Contact:

Post by Rob Finch »

Oh my gosh, I must have been asleep when I posted last time. Having written most of the kernel for my own OS you would think I would know how it was written. Although it has been quite a while since I worked on it last. :oops:
Quote:
The time slice interrupt should be treated NO differently than any other interrupt.
You're right on here. I confused a process based on a message from the time slice interrupt with the time slice interrupt itself.
Quote:
Moreover, messages should be handled as soon as they're delivered, task priority permitting.
Also the way to go. I even have a big comment about this in my code!
Quote:
Even today, my 7MHz Amiga multitasks more reliably and predictably than my 1GHz Athlon running Linux.
I've never been impressed with any OS that runs on the PC; one of the reasons why I started working on my own OS. I suspect there are two basic reasons why people like Linux 1) it's free 2) there is source code available.

Why is it that in Win2000 HE whenever a program crashes task manager is unable to shut it down ? I have had program crashes many times and not once has task manager been able to shut the program down. I have to reboot.
usotsuki
Posts: 70
Joined: 23 Dec 2002

Post by usotsuki »

I would die to see a real good, SIMPLE OS. Either on the 80386, or on the 65816.
kc5tja
Posts: 1706
Joined: 04 Jan 2003

Post by kc5tja »

usotsuki wrote:
I would die to see a real good, SIMPLE OS. Either on the 80386, or on the 65816.
Well, I had written an OS architecture called Dolphin years back that satisfied your requirements. The executive kernel was about 4K in size, and could perform about 1,000 task switches per second on a 386/33 without breaking a sweat. It was preemptively multitasking, with semaphores and message-passing as the sole IPC mechanisms. So, where were you back when I wrote this? :D

Though, it still needed a whole slew of device drivers and a shell implementation. But all other things combined, I still think the whole OS environment could easily have fit on a 360K floppy.

Now I'm planning an OS called Dolphin 0.5, which will probably never leave the ground due to my lack of time. But the kernel is memory protected, so it'll not switch tasks that fast. But it is still small and agile, and preserves the semaphore/message-passing IPC APIs from earlier Dolphin releases. Unlike previous Dolphin implementations, it's intended to be an exokernel, which would allow even more flexibility than a microkernel would. I was planning on implementing it in Forth.
orac
Posts: 64
Joined: 31 Aug 2002
Location: USA

Great OS

Post by orac »

Hi Everyone,

Someone said that they were looking for a great simple OS for x86....
Give QNX a try. I wrote a device driver for it once and it
is really good. I believe that you can download a demo copy.
It also has a GUI (if you are into that sort of thing). And to top-
it-all-off... it's actually a realtime OS (real realtime).

http://www.qnx.org/

Cheers,

Paul
usotsuki
Posts: 70
Joined: 23 Dec 2002

Post by usotsuki »

QNX?

(Of course, if I didn't have a problem with hard drive space, I'd try anything. Then again my OS is MS-DOS. I wonder how complex MSX-DOS 1 [=CP/M 2.2, roughly] is...)
blargg
Posts: 42
Joined: 30 Dec 2003
Contact:

Re: existence of the B flag

Post by blargg »

I recently ran some tests on the variant of the 6502 in the NES game console and came to the following conclusions regarding the $10 bit of the value:

IRQ, NMI: push status AND $EF

BRK: push status OR $10

PHP: push status OR $10

RTI, PLP: pop status

On this 6502 variant, there seems to be no way to get its value, since all push operations either set or clear this bit. What comes from this is that the existence of a B flag would be pointless, since its non-existence wouldn't affect operation in any way. In other words, there is no B flag; the value pushed on the stack during a status save has this bit set/cleared appropriately. Similar applies to the $20 bit position.
schidester
Posts: 57
Joined: 04 Sep 2002
Location: Iowa

Post by schidester »

Yeah, you're probably right about the B flag not actually being implemented in the hardware status register alongside N, Z, C, etc. That is probably the hardware optimization I was talking about. The B "flag" that gets pushed on the stack would then simply be derived from the IRQ/NMI lines. Any status push onto the stack would consist of the NVDIZC flags from the status register (only 6 memory cells), and a control line for the B flag that is derived from the control unit.

This makes the discussion in 6502 documentation about a B flag in the status register even more obtuse in my opinion, if it doesn't exist. It leads to the confusion that I had--where I thought you would check the status register for the BRK condition instead of what was pushed on the stack. Looking back over some documentation, it is clear now that checking the status as pushed on the stack is the proper way to do it, but even now the WDC document for the 65816 claims that the B flag is available only through the processor register. Isn't that what one would expect to do--to check the status of a flag by reading the actual register? Apparently this isn't the case with the B flag. Oh well.
User avatar
GARTHWILSON
Forum Moderator
Posts: 8773
Joined: 30 Aug 2002
Location: Southern California
Contact:

Post by GARTHWILSON »

> Looking back over some documentation, it is clear now that checking
> the status as pushed on the stack is the proper way to do it, but even
> now the WDC document for the 65816 claims that the B flag is available
> only through the processor register.

Did you find that in the data sheet? Their programming manual says on page 253, "notice that it is the stacked status byte which must be checked, not the current status byte."

The '816 does not require testing this flag though, because it has a separate vector for BRK in native mode, at FFE6-FFE7.

To say the B flag doesn't exist is an interesting way to look at it. Since I've never used BRK except in my days in that college class in 1982 with the AIM-65, I never gave it much thought; but it makes sense.
schidester
Posts: 57
Joined: 04 Sep 2002
Location: Iowa

Post by schidester »

Garth,

Page 9 of the Sept. 2003 WDC 65816 PDF states the following:

The Emulation (E) select and the Break (B) flags are accessible only through the Processor Status Register.
The Emulation mode select flag is selected by the Exchange Carry and Emulation Bits (XCE) instruction.
Table 8-1, W65C816S Compatibility Information, illustrates the features of the Native (E=0) and Emulation
(E=1) modes. The M and X flags are always equal to one in Emulation mode. When an interrupt occurs
during Emulation mode, the Break flag is written to stack memory as bit 4 of the Processor Status Register.

The latter half of that statement implies that you must check the B flag on the stack, but doesn't explicitly say to do so, and I think you'd only see it in that context if you read that part already knowing that that's the correct way to do it. However, the first part of the paragraph definitely gives the impression of checking the B flag "through the processor status register." If you don't already know which way to do it (like I didn't last year when I started this topic), then you'd naturally be inclined to think that you need to check the actual processor register.

Anyway, it sounds like I'm whining about the docs (and maybe I am a little), but my confusion was cleared up long ago when I was told explicitly by members of this forum that checking B in the processor register won't work, and that I need to check it on the stack.

Scott
User avatar
GARTHWILSON
Forum Moderator
Posts: 8773
Joined: 30 Aug 2002
Location: Southern California
Contact:

Post by GARTHWILSON »

Oh, I see what you're saying. I can't find that on my paper copies I have my notes in; but without downloading a long .pdf on a slow modem, I think the idea is that there's no instruction like BBC (Branch on Break bit Clear). Yes, it's confusing.
kc5tja
Posts: 1706
Joined: 04 Jan 2003

Post by kc5tja »

schidester wrote:
Quote:
The Emulation (E) select and the Break (B) flags are accessible only through the Processor Status Register.
The Emulation mode select flag is selected by the Exchange Carry and Emulation Bits (XCE) instruction.
Table 8-1, W65C816S Compatibility Information, illustrates the features of the Native (E=0) and Emulation
(E=1) modes. The M and X flags are always equal to one in Emulation mode. When an interrupt occurs
during Emulation mode, the Break flag is written to stack memory as bit 4 of the Processor Status Register.
The latter half of that statement implies that you must check the B flag on the stack
I interpret it distinctly as telling me to check the memory-stored copy of the flags. The words written to stack memory are the critical words. :)
Quote:
. . . but doesn't explicitly say to do so, and I think you'd only see it in that context if you read that part already knowing that that's the correct way to do it. However, the first part of the paragraph definitely gives the impression of checking the B flag "through the processor status register."
I agree that the beginning of the paragraph is ambiguous. Its verbiage should be changed or otherwise annotated with a footnote.
Post Reply