Jump to content
IGNORED

New GUI for the Atari 8-bit


flashjazzcat

Recommended Posts

My 6502 skills are still very limited, but this code looks really fast and compact!

 

I suppose messages intended for more than one recipient will have to be instanced multiple times, because messages without a specific addressee just don't fit this scheme at all. Still don't know what SymbOS does with those.

 

There is no support for broadcast messages in SymbOS. I wonder in which cases this would be helpful? As you ask I guess this is a feature of other multitasking operating systems, so I would like to know, why they need that. Wouldn't it also be necessary to introduce different process groups? E.g. there are system and application processes.

At the moment I can only think about a very few system events, where you could need broadcast messages ("system shuts down", "screensaver starts" [but even for the latter one it's not required in SymbOS]). I guess I would just send multiple copies of the messages for such cases.

Link to comment
Share on other sites

It was the SymbOS developer docs which seemed to indicate that broadcast messages are possible. I'm sure one can set the PID to 'any' when sending and receiving messages? Perhaps with $FF. In any case, if you don't handle it, my mind is put at ease. I also thought the receiver could specify that it only wanted to receive a message from a specific process; this would slightly complicate things, but perhaps that's not the case either, and the receiver must simply react to the sender ID of the incoming message.

Edited by flashjazzcat
Link to comment
Share on other sites

It was the SymbOS developer docs which seemed to indicate that broadcast messages are possible. I'm sure one can set the PID to 'any' when sending and receiving messages? Perhaps with $FF. In any case, if you don't handle it, my mind is put at ease. I also thought the receiver could specify that it only wanted to receive a message from a specific process; this would slightly complicate things, but perhaps that's not the case either, and the receiver must simply react to the sender ID of the incoming message.

Yeah, it was receiving messages from any process (ID = -1), not sending to any process! :)

So yes, you can send a message only to one process. But when you listen for new messages, you can specify the sender or just watch out for any message of any other process.

As an example that makes sense if you currently only want to communicate with one other process (e.g. the Desktop Manager), telling him to open a window, receiving the window ID etc. In this part of the code you don't want to take care about other messages, which could occur as well because we are in a multitasking environment.

In your "main loop" you want to check all messages, but in special situations, where you only want to communicate with one specific process you want to ignore all other ones. They stay untouched in the queue and can be received later.

Edited by Prodatron
  • Like 1
Link to comment
Share on other sites

In your "main loop" you want to check all messages, but in special situations, where you only want to communicate with one specific process you want to ignore all other ones. They stay untouched in the queue and can be received later.

Right: so if we're filtering the messages by sender, we can only update the 'first message' pointer if the message received is the first one in the 'sub-list'. A few extra lines of code will handle that. :)

Link to comment
Share on other sites

How about having a pool of, say, 16-32 page zero locations. A process gets assigned exactly as many locations as it requests after loading and during relocation. Only swap out zp locations if the pool runs dry.

+1. I think you were the first to suggest this and it turned out to be the best solution once I figured out how to perform the relocation. Coupled with stack segmentation and fall-back stack caching (when we run out of stack slots), this kind of page zero allocation (coupled also with fall-back caching if the pool is exhausted) means a context switch can potentially take place with no copying loops whatsoever, even if the application has a half-full stack and a number of ZP locations. Thus the two major drawbacks of the 6502 are overcome. :)

Edited by flashjazzcat
  • Like 2
Link to comment
Share on other sites

After many hours of pure slog, I've ironed out the banking bugs in the first cart build, and suddenly it gets as far as relocating the kernel into RAM and starting up the scheduler. The inter-bank JSR mechanism seems to work just great, although cartridge debugging (and this is my first real attempt at it) is a total nightmare. Anyway: thanks to Jac! and MrFish for keeping morale high. I'll try to get the UI manager and the desktop running concurrently and then I'll have to ease off for a while (I'm spending far too much time on this thing, much to my wife's consternation). ;)

  • Like 2
Link to comment
Share on other sites

After many hours of pure slog, I've ironed out the banking bugs in the first cart build, and suddenly it gets as far as relocating the kernel into RAM and starting up the scheduler. The inter-bank JSR mechanism seems to work just great, although cartridge debugging (and this is my first real attempt at it) is a total nightmare. Anyway: thanks to Jac! and MrFish for keeping morale high. I'll try to get the UI manager and the desktop running concurrently and then I'll have to ease off for a while (I'm spending far too much time on this thing, much to my wife's consternation). ;)

Sounds good! I still hold out hope to being able to use my 65XE with the AtariMax Flash cart. :)

Link to comment
Share on other sites

+1. I think you were the first to suggest this and it turned out to be the best solution once I figured out how to perform the relocation. Coupled with stack segmentation and fall-back stack caching (when we run out of stack slots), this kind of page zero allocation (coupled also with fall-back caching if the pool is exhausted) means a context switch can potentially take place with no copying loops whatsoever, even if the application has a half-full stack and a number of ZP locations. Thus the two major drawbacks of the 6502 are overcome. :)

 

Thanks. Glad you figured out a way to get it working in your setup. It was actually based on an idea I had years ago when I was thinking about multitasking on a 6502. Never got around to actually code something though. Looking forward to see your implementation running :)

Link to comment
Share on other sites

I can completely relate. When I told my wife that I was writing a BBS package for a 30 year old computer, she gave me a confused look, when I told her I am writing it to clear my head (mental cucumber), she just shook her head and walked away.

 

-Thom

This is off-topic, so I'll keep it short, but please be sure to keep us informed (in a separate thread) of your progress on the BBS program. I am very interested in it, and, I'm sure others are, as well.

 

-K

Link to comment
Share on other sites

Ouch: testing the kernel in Altirra, I discovered that on entering the IRQ handler via BRK, occasionally a Pokey timer interrupt request bit is already set, causing the ISR to acknowledge and service the timer interrupt and miss BRK entirely. I'm not sure why the Pokey interrupt request would fail to pre-empt the software interrupt, unless this is another 6502 quirk. I thought it was only NMIs which could cause BRK to be missed (by entering the NMI handler with the BRK flag set; this condition is already handled).

 

The slightly inconvenient fix is to test for BRK before testing bits in IRQST, although I'm still quite surprised by the apparent behaviour which necessitates this.

Edited by flashjazzcat
Link to comment
Share on other sites

I think this in the nature of the BRK instruction. As with any other IRQ interrupt can occur at the same cycle (SERIN, SEROU, KEY, ..) you have to check the correspond bit in the interrupt status registers (IRQST is just one of them, there could be any other part in the HW/PBI triggering an IRQ) to find out which IRQ sources are active and which if them has to be served first. The "quirk" is that the B-flag is just a status bit and does not actually trigger the interrupt, nor does it have an explicit clear instruction. It is automatically "cleared" by RTI. Hence checking for the B-flag in the main IRQ handler is correct and the only solution from my point of view.

Edited by JAC!
Link to comment
Share on other sites

Hasn't really spoiled the party. The interrupt handlers - being freed from the stock OS and thus not generic - are still pretty lean even with all the checks, although that Pokey timer 2 is taking quite a hit (it runs at 800Hz):

 

	.proc IRQHand
	pha
	txa
	pha
	cld
	tsx
	lda $103,x
	and #$10 ; check for brk flag first since it's critical we don't miss it
	bne SupervisorCall
	lda #2
	bit irqst ; Pokey Timer 2
	bne NotTimer2
	lda #4
	sta irqen
	lda #6
	sta irqen
	jmp Mouse
NotTimer2
	lda #4
	bit irqst ; Pokey Timer 4
	bne NotTimer4
	lda #2
	sta irqen
	lda #6
	sta irqen
	jmp Scheduler
NotTimer4
	pla
	tax
	pla
	rti
SupervisorCall

...

	.endp



	.proc NMIHand
	pha
	txa
	pha
	tya
	pha
	cld
	bit nmist
	bpl NotDLI
	jmp Draw_Mouse
NotDLI
	sta nmires
	jmp VBI
	.endp




	.proc ExitNMI
	tsx
	lda $0104,x ; get saved processor status register
	and #$10 ; check for BRK flag
	beq NotBRK
	lda $0105,x
	sec
	sbc #2 ; drop PC by 2 (back to missed BRK)
	sta $0105,x
	lda $0106,x
	sbc #0
	sta $0106,x ; RTI will immediately return to BRK instruction
NotBRK
	pla
	tay
	pla
	tax
	pla
	rti
	.endp
Edited by flashjazzcat
Link to comment
Share on other sites

I think there's still a gap. If the NMIHand occurs when IRQHand just starts, it'll assume that it can re-execute the BRK in ExitNMI. But BRK will not be the last instruction in the actual sequence. And the only way to prevent this I can think of would be prefixing every BRK with an explicit SEI to ensure the situation does not occur. And then a JSR <fixed_kernel_entry+3*command> looks not that bad again.

Edited by JAC!
Link to comment
Share on other sites

I cannot visualise this scenario. IRQ pushes B=0, so even if NMI fired simultaneously, how does the NMI exit see a BRK which isn't there? Sorry if I'm being dense... so tired. :)

 

Oh - assuming it's not in vain, this reduces latency somewhat:

	.proc IRQHand
	sta IRQSaveA
	pla ; get flags
	pha
	and #$10 ; check for brk flag first since it's critical we don't miss it
	bne SupervisorCall
	lda #2
	bit irqst ; Pokey Timer 2
	bne NotTimer2
	lda #4
	sta irqen
	lda #6
	sta irqen
	jmp Mouse
NotTimer2
	lda #4
	bit irqst ; Pokey Timer 4
	bne NotTimer4
	lda #2
	sta irqen
	lda #6
	sta irqen
	jmp Scheduler
NotTimer4
	lda IRQSaveA
	rti
SupervisorCall

...

	.endp

Timer 2 doesn't use the X register unless the mouse has moved, so getting rid of the indexed addressing at the top of the ISR saves pointlessly saving X when it's not necessarily needed. CLD can also be skipped when the mouse is idle.

Edited by flashjazzcat
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...