6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sun Nov 24, 2024 5:38 am

All times are UTC




Post new topic Reply to topic  [ 8 posts ] 
Author Message
PostPosted: Wed Jun 08, 2022 7:19 pm 
Offline

Joined: Sat Oct 09, 2021 11:21 am
Posts: 718
Location: Texas
Hey everyone! I've been thinking about hypotheticals on an extreme minimal 6502 design that would still allow for keyboard input.

Attached is part of my schematic for PS/2 Keyboard input. Basically the CLK is connected directly to /IRQ and DATA is connected directly to /SO, with pull-up resistors.

My thoughts are that the keyboard clock would go low, triggering the interrupt. Inside the interrupt code, you read the Overflow (V) flag to see what is on the keyboard data line. Because the keyboard is pretty slow in comparison, I could even do some internal code to shift bits around and whatnot (something like what I do already).

I have always connected the /IRQ line to a VIA in the past, so I am unsure if this "direct connection" will work. I suppose I could use the /NMI line instead? And the /SO line is strange to use, but all I need is the one bit of data.

What do you think? Screwy? :)

Chad


Attachments:
MinimalKeyboard.png
MinimalKeyboard.png [ 5.21 KiB | Viewed 957 times ]
Top
 Profile  
Reply with quote  
PostPosted: Wed Jun 08, 2022 8:21 pm 
Offline

Joined: Tue Sep 03, 2002 12:58 pm
Posts: 336
All /SO can do is set the V flag. It can't clear it. And it's only the falling edge that sets V: you can't enter your interrupt handler, clear V, then check to see if /SO has set it again.

But it could still be made to work, if this was a truly minimal system with no other interrupt sources. The first bit sent by the keyboard is always 0, so it doesn't matter if you miss it. On receiving that first interrupt, clear V, switch to a special mode that does nothing(*) in non-interrupt code, then read the data bits during the next 8 interrupts. Then one more interrupt to check the stop bit. Make sure that V gets cleared again before the next bit gets sent.

(*) If there are any stray interrupts (due to noise or other causes), this will get out of sync and lock up the system. It would be best to have the non-interrupt code increment a counter while in keyboard mode, and return to normal if the next interrupt doesn't appear in a reasonable time. That can be done without disturbing V.

It'd be messy and not really practical in a real system where you have actual I/O. But it would be a fun challenge to get it working.


Top
 Profile  
Reply with quote  
PostPosted: Wed Jun 08, 2022 8:37 pm 
Offline
User avatar

Joined: Wed Feb 14, 2018 2:33 pm
Posts: 1488
Location: Scotland
sburrow wrote:
Hey everyone! I've been thinking about hypotheticals on an extreme minimal 6502 design that would still allow for keyboard input.


Have you seen the VCF 40th anniversary badge?

http://www.sunrise-ev.com/6502.htm

Although not PS/2, but serial, I wonder if it might be adapted...

-Gordon

_________________
--
Gordon Henderson.
See my Ruby 6502 and 65816 SBC projects here: https://projects.drogon.net/ruby/


Top
 Profile  
Reply with quote  
PostPosted: Wed Jun 08, 2022 8:40 pm 
Offline

Joined: Sat Oct 09, 2021 11:21 am
Posts: 718
Location: Texas
John West wrote:
But it could still be made to work, if this was a truly minimal system with no other interrupt sources. The first bit sent by the keyboard is always 0, so it doesn't matter if you miss it. On receiving that first interrupt, clear V, switch to a special mode that does nothing(*) in non-interrupt code, then read the data bits during the next 8 interrupts. Then one more interrupt to check the stop bit. Make sure that V gets cleared again before the next bit gets sent.


Excellent thoughts on how to do this! Yes, super extreme, no other interrupts, no other I/O, just the keyboard and the CPU (and graphics, but that's later!).

Thank you John West, good thoughts here. Sounds doable.

Chad


Top
 Profile  
Reply with quote  
PostPosted: Wed Jun 08, 2022 9:06 pm 
Offline

Joined: Sat Oct 09, 2021 11:21 am
Posts: 718
Location: Texas
drogon wrote:
Have you seen the VCF 40th anniversary badge?


That is neat! Yes, very minimal. I'll post a separate topic about the entire design later. Here I'm just wondering if the keyboard will work.

Thank you!

Chad


Top
 Profile  
Reply with quote  
PostPosted: Thu Jun 09, 2022 9:17 am 
Offline

Joined: Tue Sep 03, 2002 12:58 pm
Posts: 336
If you want a real challenge, we have /SO, /IRQ, and /NMI. Is there a way of getting a PS/2 keyboard and mouse working at the same time? I don't think I'm clever enough.


Top
 Profile  
Reply with quote  
PostPosted: Thu Dec 29, 2022 2:55 pm 
Offline

Joined: Sat Oct 09, 2021 11:21 am
Posts: 718
Location: Texas
Update to this topic I posted a long long time ago:

Using the SOB pin is fine and all, but I found a neat way to connect the PS/2 Keyboard directly to the /NMI and /IRQ lines without any extra gates. Attached is the picture, and below is the ISR code.

Code:

vector_nmi
   PHA
   LDA #$FF
   STA key_bit ; set key_bit to $FF
   CLI ; allow irq interrupts
   NOP ; irq should trigger by now if low
vector_nmi_continue
   LDA key_bit
   ROR A ; get 8th bit into carry
   ROR key_data ; put into key_data
   DEC key_counter
   BEQ vector_nmi_store ; if last data bit, store
   LDA key_counter
   CMP #$FE ; if last transmitted bit, reset
   BNE vector_nmi_exit
   LDA #$09
   STA key_counter ; reset counter
vector_nmi_exit
   PLA
   RTI ; exit
vector_nmi_store
   PHX
   LDA key_data ; get current data
   LDX key_write
   STA key_array,X ; write into key_array
   INC key_write ; increment write position
   PLX
   PLA
   RTI ; exit

vector_irq
   INC key_bit ; change key_bit to zero
   PLA
   PLA
   PLA ; trash the stack, interrupt flag is auto-set
   JMP vector_nmi_continue ; jump back to nmi



You must have a 256 byte page for the key buffer, and a few other spare bytes of memory for counters and stuff.

The idea behind the code is that you have the PS/2 Keyboard clock connected to /NMI. Thus, when something is incoming, the edge-sensitive /NMI triggers immediately. While inside of the NMI-ISR, you then clear the interrupt bit, allowing interrupts on /IRQ (previously it was set to not interrupt). The level-sensitive /IRQ then triggers if it's a 0, and doesn't trigger if it's a 1.

Inside the IRQ-ISR you can alter a bit in memory, but then instead of RTI just PLAx3 to remove everything put on the stack while IRQ was triggered. The interrupt flag then retains it's 'set' value, no longer allowing the IRQ-ISR to trigger. To exit the IRQ-ISR you JMP back to the NMI-ISR. From there you do housekeeping and what not.

This of course takes both the /NMI and /IRQ interrupts, not leaving them open for anything else. But hey, it works! I tested it myself just now on my latest board.

Just wanted to update this in case someone finds it later. I'm sure you could still use the SOB line somehow. Thanks everyone.

Chad

EDIT: So, the above all works, but only 99.9% of the time. Perhaps it is just my board, perhaps I'm just misunderstanding something small about interrupts. Every so often, /NMI is not triggered(?) and one bit is dropped from the PS/2 Keyboard, leaving it in a state that is garbled. This can be "fixed" in software, checking parity bits and all that, but I have never had to do that previously. Just a warning.


Attachments:
PS2KeyboardInterrupts.png
PS2KeyboardInterrupts.png [ 5.34 KiB | Viewed 772 times ]
Top
 Profile  
Reply with quote  
PostPosted: Mon Jan 02, 2023 1:45 pm 
Offline

Joined: Sat Oct 09, 2021 11:21 am
Posts: 718
Location: Texas
It seems that the above code is not... perfect. This setup wants to glitch very rarely, but when it does it is disastrous.

I've been doing a lot of research and work on this PS/2 Keyboard connection, and I found that my previous models using other logic methods were good, but only good for my specific keyboard speed. I would adjust the timing to fit what is needed, not too fast and not too slow. I have other keyboards, and they seem to work too, but the specs for PS/2 Keyboards have a wide range of speeds.

To accommodate for any keyboard speed I went back to this style. And so I did even more research and study while using this particular method. What I am finding is that (at least on my board) a clock signal goes missing sometimes. This might not happen in different setups, specifically using a VIA. But the idea is that IF there is a glitch in the system, the host computer sends a command to the keyboard to 'resend the last code'. With my setup here, I am incapable of doing that.

To work around it, I made this code:

Code:
; /NMI = Keyboard-Clock
; /IRQ = Keyboard-Data

vector_nmi
   PHA
   LDA #$FF
   CLI
   NOP ; for safety
   NOP
vector_nmi_read   
   DEC key_counter
   BEQ vector_nmi_code
   PHA
   LDA key_counter
   CMP #$FF
   BEQ vector_nmi_parity
   CMP #$FE
   BEQ vector_nmi_stop
   PLA
   PHA
   EOR key_parity
   STA key_parity
   PLA
   ROR A
   ROR key_data
   PLA
   RTI
vector_nmi_code   
   PHA
   EOR key_parity
   STA key_parity
   PLA
   ROR A
   ROR key_data
   LDA key_data
   STA key_code
   PLA
   RTI
vector_nmi_parity
   PLA
   CMP key_parity
   BEQ vector_nmi_parity_error
   PLA
   RTI
vector_nmi_parity_error
   PHX
   LDA #$00 ; null
   LDX key_write
   STA key_array,X
   INC key_write
   PLX
   LDA #$09
   STA key_counter
   STZ key_parity
   STZ key_data
   PLA
   RTI
vector_nmi_stop
   PLA
   BEQ vector_nmi_stop_error
   PHX
   LDA key_code
   LDX key_write
   STA key_array,X
   INC key_write
   PLX
   LDA #$09
   STA key_counter
   STZ key_parity
   STZ key_data
   PLA
   RTI
vector_nmi_stop_error
   PHX
   LDA #$00 ; null
   LDX key_write
   STA key_array,X
   INC key_write
   PLX
   LDA #$08
   STA key_counter
   STZ key_parity
   STZ key_data
   PLA
   RTI

vector_irq
   PLA
   PLA
   PLA
   LDA #$00
   JMP vector_nmi_read


The changes are that I am actually checking for parity and stop bits. I am not checking for start bits because that's too early in the byte sequence to do anything, and it will change the parity anyways since the normal start bit is always 0 and does not change parity. The folks who designed this 11 bit sequence were genius in that all instances of error would either fall on the parity bit or the stop bit. You must check both!

And I am happy to report that this seems to be working better. I don't know if I'd call it 'glitch free'. But I've been having it display when it does find a 'glitch' and I cannot tell when I was typing. I suppose I would miss a key, but heck, I do that all the time when typing anyways, so it goes nearly unnoticed.

There's the update. I know most of you won't be interested in implementing this radically "simple" hardware method, but I must say I learned a great deal about signal integrity and parity bits! If I decide to update the code in a significant way I will update y'all here. Thank you!

Chad

EDIT:

Had a talk with Bill (plasmo) and he said he had been having trouble with how slow the keyboard clock's falling edge was. Perhaps that is what was happening to me too? I think that if I had tried to buffer the signal through a 74HC14 schmitt-trigger vs the 74HC04 I had used, it might have worked.

Either way, I'm abandoning this particular setup for the keyboard in favor of some minimal logic changes that seem to work well. Just wanted to show a conclusion, thanks everyone.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 8 posts ] 

All times are UTC


Who is online

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