implement some more of the keyboard controller

Wed, 09 Feb 2011 15:03:31 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Wed, 09 Feb 2011 15:03:31 +0000
changeset 80
9581358e92b0
parent 79
674226015c8a
child 81
6484b646bc31

implement some more of the keyboard controller

src/keyboard.c file | annotate | diff | revisions
src/keyboard.h file | annotate | diff | revisions
src/main.c file | annotate | diff | revisions
src/state.c file | annotate | diff | revisions
src/state.h file | annotate | diff | revisions
     1.1 diff -r 674226015c8a -r 9581358e92b0 src/keyboard.c
     1.2 --- a/src/keyboard.c	Wed Dec 29 09:06:17 2010 +0000
     1.3 +++ b/src/keyboard.c	Wed Feb 09 15:03:31 2011 +0000
     1.4 @@ -1,4 +1,6 @@
     1.5 +#include <stdbool.h>
     1.6  #include "SDL.h"
     1.7 +#include "keyboard.h"
     1.8  
     1.9  /**
    1.10   * Key map -- a mapping from SDLK_xxx constants to scancodes and vice versa.
    1.11 @@ -126,19 +128,96 @@
    1.12  //	{ SDLK_,				1,	0x7f },	// Dlete
    1.13  };
    1.14  
    1.15 -/**
    1.16 - * List of key states
    1.17 - */
    1.18 -int keystate[0x80];
    1.19 -
    1.20 -void keyboard_init(void)
    1.21 +void keyboard_init(KEYBOARD_STATE *ks)
    1.22  {
    1.23  	// Set all key states to "not pressed"
    1.24 -	for (int i=0; i<(sizeof(keystate)/sizeof(keystate[0])); i++) {
    1.25 -		keystate[i] = 0;
    1.26 +	for (int i=0; i<(sizeof(ks->keystate)/sizeof(ks->keystate[0])); i++) {
    1.27 +		ks->keystate[i] = 0;
    1.28 +	}
    1.29 +
    1.30 +	// Reset the R/W pointers and length
    1.31 +	ks->readp = ks->writep = ks->buflen = 0;
    1.32 +}
    1.33 +
    1.34 +void keyboard_event(KEYBOARD_STATE *ks, SDL_Event *ev)
    1.35 +{
    1.36 +	// event handler -- handles SDL events
    1.37 +}
    1.38 +
    1.39 +void keyboard_scan(KEYBOARD_STATE *ks)
    1.40 +{
    1.41 +	// if buffer empty, do a keyboard scan
    1.42 +	if (ks->buflen == 0) {
    1.43 +		for (int i=0; i<(sizeof(ks->keystate)/sizeof(ks->keystate[0])); i++) {
    1.44 +			if (ks->keystate[i]) {
    1.45 +				ks->buffer[ks->writep] = i;
    1.46 +				ks->writep = (ks->writep + 1) % KEYBOARD_BUFFER_SIZE;
    1.47 +			}
    1.48 +		}
    1.49  	}
    1.50  }
    1.51  
    1.52 -void keyboard_event(SDL_Event *ev)
    1.53 +bool keyboard_get_irq(KEYBOARD_STATE *ks)
    1.54 +{
    1.55 +	bool irq_status = false;
    1.56 +
    1.57 +	// Conditions which may cause an IRQ :-
    1.58 +	//   Read Data Reg has data and RxIRQ enabled
    1.59 +	if (ks->rxie)
    1.60 +		if (ks->buflen > 0) irq_status = true;
    1.61 +
    1.62 +	//   Transmit Data Reg empty and TxIRQ enabled
    1.63 +//	if (ks->txie)
    1.64 +
    1.65 +	//   DCD set and RxIRQ enabled
    1.66 +//
    1.67 +
    1.68 +	// returns interrupt status -- i.e. is there data in the buffer?
    1.69 +	return irq_status;
    1.70 +}
    1.71 +
    1.72 +uint8_t keyboard_read(KEYBOARD_STATE *ks, uint8_t addr)
    1.73  {
    1.74 +	if ((addr & 1) == 0) {
    1.75 +		// Status register -- RS=0, read
    1.76 +		return
    1.77 +			(ks->buflen > 0) ? 1 : 0 +		// SR0: a new character has been received
    1.78 +			0 +								// SR1: Transmitter Data Register Empty
    1.79 +			0 +								// SR2: Data Carrier Detect
    1.80 +			0 +								// SR3: Clear To Send
    1.81 +			0 +								// SR4: Framing Error
    1.82 +			0 +								// SR5: Receiver Overrun
    1.83 +			0 +								// SR6: Parity Error
    1.84 +			(keyboard_get_irq(ks)) ? 0x80 : 0;	// SR7: IRQ status
    1.85 +	} else {
    1.86 +		// return data, pop off the fifo
    1.87 +		uint8_t x = ks->buffer[ks->readp];
    1.88 +		ks->readp = (ks->readp + 1) % KEYBOARD_BUFFER_SIZE;
    1.89 +		return x;
    1.90 +	}
    1.91  }
    1.92 +
    1.93 +void keyboard_write(KEYBOARD_STATE *ks, uint8_t addr, uint8_t val)
    1.94 +{
    1.95 +	if ((addr & 1) == 0) {
    1.96 +		// write to control register
    1.97 +		// transmit intr enabled when CR6,5 = 01
    1.98 +		// receive intr enabled when CR7 = 1
    1.99 +
   1.100 +		// CR0,1 = divider registers. When =11, do a software reset
   1.101 +		if ((val & 3) == 3) {
   1.102 +			ks->readp = ks->writep = ks->buflen = 0;
   1.103 +		}
   1.104 +
   1.105 +		// Ignore CR2,3,4 (word length)...
   1.106 +
   1.107 +		// CR5,6 = Transmit Mode
   1.108 +		ks->txie = (val & 0x60)==0x20;
   1.109 +
   1.110 +		// CR7 = Receive Interrupt Enable
   1.111 +		ks->rxie = (val & 0x80)==0x80;
   1.112 +	} else {
   1.113 +		// Write command to KBC -- TODO!
   1.114 +	}
   1.115 +}
   1.116 +
     2.1 diff -r 674226015c8a -r 9581358e92b0 src/keyboard.h
     2.2 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.3 +++ b/src/keyboard.h	Wed Feb 09 15:03:31 2011 +0000
     2.4 @@ -0,0 +1,56 @@
     2.5 +#ifndef _KEYBOARD_H
     2.6 +#define _KEYBOARD_H
     2.7 +
     2.8 +#include "SDL.h"
     2.9 +
    2.10 +/// Keyboard buffer size in bytes
    2.11 +#define KEYBOARD_BUFFER_SIZE 256
    2.12 +
    2.13 +typedef struct {
    2.14 +	/// Key states
    2.15 +	int keystate[0x80];
    2.16 +
    2.17 +	/// Keyboard buffer
    2.18 +	char buffer[KEYBOARD_BUFFER_SIZE];
    2.19 +
    2.20 +	/// Read pointer
    2.21 +	size_t readp;
    2.22 +
    2.23 +	/// Write pointer
    2.24 +	size_t writep;
    2.25 +
    2.26 +	/// Number of bytes in keyboard buffer
    2.27 +	size_t buflen;
    2.28 +
    2.29 +	/// Transmit Interrupt Enable
    2.30 +	bool txie;
    2.31 +	/// Receive Interrupt Enable
    2.32 +	bool rxie;
    2.33 +} KEYBOARD_STATE;
    2.34 +
    2.35 +/**
    2.36 + * Initialise a keyboard state block.
    2.37 + *
    2.38 + * Call this once when the keyboard is added to the emulation.
    2.39 + */
    2.40 +void keyboard_init(KEYBOARD_STATE *ks);
    2.41 +
    2.42 +/**
    2.43 + * SDL_Event delegation routine.
    2.44 + *
    2.45 + * Call this when an SDL keyup or keydown event is received.
    2.46 + */
    2.47 +void keyboard_event(KEYBOARD_STATE *ks, SDL_Event *ev);
    2.48 +
    2.49 +/**
    2.50 + * Keyboard scan routine.
    2.51 + *
    2.52 + * Call this periodically to scan the keyboard. 60 times/sec should be fine.
    2.53 + */
    2.54 +void keyboard_scan(KEYBOARD_STATE *ks);
    2.55 +
    2.56 +bool keyboard_get_irq(KEYBOARD_STATE *ks);
    2.57 +uint8_t keyboard_read(KEYBOARD_STATE *ks, uint8_t addr);
    2.58 +void keyboard_write(KEYBOARD_STATE *ks, uint8_t addr, uint8_t val);
    2.59 +
    2.60 +#endif
     3.1 diff -r 674226015c8a -r 9581358e92b0 src/main.c
     3.2 --- a/src/main.c	Wed Dec 29 09:06:17 2010 +0000
     3.3 +++ b/src/main.c	Wed Feb 09 15:03:31 2011 +0000
     3.4 @@ -123,6 +123,10 @@
     3.5  	SDL_Event event;
     3.6  	while (SDL_PollEvent(&event))
     3.7  	{
     3.8 +		if ((event.type == SDL_KEYDOWN) || (event.type == SDL_KEYUP)) {
     3.9 +			keyboard_event(&state.kbd, &event);
    3.10 +		}
    3.11 +
    3.12  		switch (event.type) {
    3.13  			case SDL_QUIT:
    3.14  				// Quit button tagged. Exit.
    3.15 @@ -341,6 +345,8 @@
    3.16  			// Refresh the screen
    3.17  			refreshScreen(screen);
    3.18  			// TODO: trigger periodic interrupt (if enabled)
    3.19 +			// scan the keyboard
    3.20 +			keyboard_scan(&state.kbd);
    3.21  			// decrement clock cycle counter, we've handled the intr.
    3.22  			clock_cycles -= CLOCKS_PER_60HZ;
    3.23  		}
     4.1 diff -r 674226015c8a -r 9581358e92b0 src/state.c
     4.2 --- a/src/state.c	Wed Dec 29 09:06:17 2010 +0000
     4.3 +++ b/src/state.c	Wed Feb 09 15:03:31 2011 +0000
     4.4 @@ -3,6 +3,7 @@
     4.5  #include <malloc.h>
     4.6  #include <stdio.h>
     4.7  #include "wd279x.h"
     4.8 +#include "keyboard.h"
     4.9  #include "state.h"
    4.10  
    4.11  int state_init(size_t base_ram_size, size_t exp_ram_size)
    4.12 @@ -92,6 +93,8 @@
    4.13  
    4.14  	// Initialise the disc controller
    4.15  	wd2797_init(&state.fdc_ctx);
    4.16 +	// Initialise the keyboard controller
    4.17 +	keyboard_init(&state.kbd);
    4.18  
    4.19  	return 0;
    4.20  }
     5.1 diff -r 674226015c8a -r 9581358e92b0 src/state.h
     5.2 --- a/src/state.h	Wed Dec 29 09:06:17 2010 +0000
     5.3 +++ b/src/state.h	Wed Feb 09 15:03:31 2011 +0000
     5.4 @@ -5,6 +5,7 @@
     5.5  #include <stdint.h>
     5.6  #include <stdbool.h>
     5.7  #include "wd279x.h"
     5.8 +#include "keyboard.h"
     5.9  
    5.10  // Maximum size of the Boot PROMs. Must be a binary power of two.
    5.11  #define ROM_SIZE 32768
    5.12 @@ -70,6 +71,9 @@
    5.13  
    5.14  	/// Floppy disc controller context
    5.15  	WD2797_CTX	fdc_ctx;
    5.16 +
    5.17 +	/// Keyboard controller context
    5.18 +	KEYBOARD_STATE	kbd;
    5.19  } S_state;
    5.20  
    5.21  // Global emulator state. Yes, I know global variables are evil, please don't