OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [branches/] [stable_0_2_x/] [or1ksim/] [peripheral/] [ps2kbd.c] - Blame information for rev 1359

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 805 markom
/* ps2kbd.c -- Very simple (and limited) PS/2 keyboard simulation
2
   Copyright (C) 2002 Marko Mlinar, markom@opencores.org
3 684 lampret
 
4 805 markom
This file is part of OpenRISC 1000 Architectural Simulator.
5
 
6
This program is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2 of the License, or
9
(at your option) any later version.
10
 
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
GNU General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with this program; if not, write to the Free Software
18
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
 
20
#include <stdlib.h>
21
#include <stdio.h>
22
#include <string.h>
23 1350 nogj
 
24
#include "config.h"
25
 
26
#ifdef HAVE_INTTYPES_H
27
#include <inttypes.h>
28
#endif
29
 
30
#include "port.h"
31
#include "arch.h"
32 805 markom
#include "ps2kbd.h"
33
#include "sim-config.h"
34
#include "abstract.h"
35
#include "sched.h"
36 1308 phoenix
#include "pic.h"
37 805 markom
 
38
/* ASCII to scan code conversion table */
39
const static struct {
40
  /* Whether shift must be pressed */
41
  unsigned char shift;
42
  /* Scan code to be generated */
43
  unsigned char code;
44
} scan_table [128] = {
45
/* 0 - 15 */
46
{0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00},
47
{0, 0x0E}, {0, 0x0F}, {0, 0x1C}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00},
48
/* 16 - 31 */
49
{0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00},
50
{0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x01}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00},
51
/* 32 - 47 */
52
{0, 0x39}, {1, 0x02}, {1, 0x28}, {1, 0x04}, {1, 0x05}, {1, 0x06}, {1, 0x08}, {0, 0x28},
53
{1, 0x0A}, {1, 0x0B}, {1, 0x09}, {1, 0x0D}, {0, 0x33}, {0, 0x0C}, {0, 0x34}, {0, 0x35},
54
/* 48 - 63 */
55
{0, 0x0B}, {0, 0x02}, {0, 0x03}, {0, 0x04}, {0, 0x05}, {0, 0x06}, {0, 0x07}, {0, 0x08},
56
{0, 0x09}, {0, 0x0A}, {1, 0x27}, {0, 0x27}, {1, 0x33}, {0, 0x0D}, {1, 0x34}, {1, 0x35},
57
/* 64 - 79 */
58
{1, 0x03}, {1, 0x1E}, {1, 0x30}, {1, 0x2E}, {1, 0x20}, {1, 0x12}, {1, 0x21}, {1, 0x22},
59
{1, 0x23}, {1, 0x17}, {1, 0x24}, {1, 0x25}, {1, 0x26}, {1, 0x32}, {1, 0x31}, {1, 0x18},
60
/* 80 - 95 */
61
{1, 0x19}, {1, 0x10}, {1, 0x13}, {1, 0x1F}, {1, 0x14}, {1, 0x16}, {1, 0x2F}, {1, 0x11},
62
{1, 0x2D}, {1, 0x15}, {1, 0x2C}, {0, 0x1A}, {0, 0x2B}, {0, 0x1B}, {1, 0x07}, {1, 0x0C},
63
/* 96 - 111 */
64
{0, 0x29}, {0, 0x1E}, {0, 0x30}, {0, 0x2E}, {0, 0x20}, {0, 0x12}, {0, 0x21}, {0, 0x22},
65
{0, 0x23}, {0, 0x17}, {0, 0x24}, {0, 0x25}, {0, 0x26}, {0, 0x32}, {0, 0x31}, {0, 0x18},
66
/* 112 - 127 */
67
{0, 0x19}, {0, 0x10}, {0, 0x13}, {0, 0x1F}, {0, 0x14}, {0, 0x16}, {0, 0x2F}, {0, 0x11},
68
{0, 0x2D}, {0, 0x15}, {0, 0x2C}, {1, 0x1A}, {1, 0x2B}, {1, 0x1B}, {1, 0x29}, {0, 0x00}
69
};
70
 
71
/* Temporary buffer to store incoming scan codes */
72
static unsigned char kbd_buf[KBD_MAX_BUF] = {0};
73
 
74
/* Number of scan codes in buffer */
75
static unsigned long kbd_buf_count = 0;
76
static unsigned long kbd_buf_head = 0;
77
static unsigned long kbd_buf_tail = 0;
78
 
79
/* Input stream */
80
static FILE *kbd_rxfs = NULL;
81
 
82 684 lampret
/* Controller Command (write into 0x64) */
83
static int kbd_ccmd;
84
 
85
/* Keyboard Command (write into 0x60) */
86
static unsigned char kbd_kcmd;
87
 
88
/* Controller Command Byte */
89
static unsigned char kbd_ccmdbyte;
90
 
91
/* Keyboard response pending */
92
static unsigned long kbd_kresp;
93
 
94 805 markom
/* Keyboard slowdown factor */
95
static long kbd_slowdown;
96
 
97
static void kbd_put (unsigned char c)
98
{
99
  if (kbd_buf_count >= KBD_MAX_BUF) {
100
    fprintf (stderr, "WARNING: Keyboard buffer overflow.\n");
101
  } else {
102
    kbd_buf[kbd_buf_head] = c;
103
    kbd_buf_head = (kbd_buf_head + 1) % KBD_MAX_BUF;
104
    kbd_buf_count++;
105
  }
106
}
107
 
108
/* Decodes ascii code c into multiple scan codes, placed into buf, length is returned */
109
static void scan_decode (unsigned char c)
110
{
111
  /* Do not handle special characters and extended ascii */
112
  if (c >= 128 || !scan_table[c].code)
113
    return;
114
 
115
  /* Make shift? */
116
  if (scan_table[c].shift) kbd_put (0x2a);
117
  /* Make char */
118
  kbd_put (scan_table[c].code);
119
  /* Break char */
120
  kbd_put (scan_table[c].code | 0x80);
121
  /* Break shift? */
122
  if (scan_table[c].shift) kbd_put (0xaa);
123
}
124
 
125
/* Write a register */
126 1359 nogj
void kbd_write8 (oraddr_t addr, uint32_t value, void *dat)
127 805 markom
{
128
  int a = (addr - config.kbd.baseaddr);
129
  switch (a) {
130 684 lampret
    case KBD_CTRL:
131
      kbd_ccmd = value & 0xff;
132
      if (kbd_ccmd == KBD_CCMD_RCB)
133
          kbd_kresp = 0x1;
134
      if (kbd_ccmd == KBD_CCMD_ST1)
135
          kbd_kresp = 0x1;
136
      if (kbd_ccmd == KBD_CCMD_ST2)
137
          kbd_kresp = 0x1;
138
      if (kbd_ccmd == KBD_CCMD_DKI)
139
        kbd_ccmdbyte |= KBD_CCMDBYTE_EN;
140
      if (kbd_ccmd == KBD_CCMD_EKI)
141
        kbd_ccmdbyte &= ~KBD_CCMDBYTE_EN;
142
      if (config.sim.verbose)
143 1350 nogj
        PRINTF("kbd_write8(%"PRIxADDR") %"PRIx32"\n", addr, value);
144 805 markom
      break;
145 684 lampret
    case KBD_DATA:
146
      if (kbd_ccmd == KBD_CCMD_WCB) {
147
        kbd_ccmdbyte = value & 0xff;
148
        kbd_ccmd = 0x00;
149
      } else
150
        kbd_kcmd = value & 0xff;
151
      if (kbd_kcmd == KBD_KCMD_DK)
152
        kbd_ccmdbyte |= KBD_CCMDBYTE_EN;
153
      if (kbd_kcmd == KBD_KCMD_EK)
154
        kbd_ccmdbyte &= ~KBD_CCMDBYTE_EN;
155
      kbd_kresp = 0x1;
156
      kbd_ccmd = 0x00;
157
      if (config.sim.verbose)
158 1350 nogj
        PRINTF("kbd_write8(%"PRIxADDR") %"PRIx32"\n", addr, value);
159 805 markom
      break;
160
    default:
161 1350 nogj
      fprintf (stderr, "Write out of keyboard space (0x%"PRIxADDR")!\n", addr);
162 884 markom
      runtime.sim.cont_run = 0;
163 805 markom
      break;
164
  }
165
}
166
 
167
/* Read a register */
168 1359 nogj
uint32_t kbd_read8 (oraddr_t addr, void *dat)
169 805 markom
{
170
  int a = (addr - config.kbd.baseaddr);
171
  switch (a) {
172 684 lampret
    case KBD_CTRL: {
173
      unsigned long c = 0x0;
174
      if (kbd_kresp || kbd_buf_count)
175
        c |= KBD_STATUS_OBF;
176
      c |= kbd_ccmdbyte & KBD_CCMDBYTE_SYS;
177
      c |= KBD_STATUS_INH;
178
      if (config.sim.verbose)
179 1350 nogj
        PRINTF("kbd_read8(%"PRIxADDR") %lx\n", addr, c);
180 684 lampret
      return c;
181
    }
182
    case KBD_DATA:
183
      if (kbd_ccmd) {
184
        unsigned long rc;
185
        if (kbd_ccmd == KBD_CCMD_RCB)
186
          rc = kbd_ccmdbyte;
187
        if (kbd_ccmd == KBD_CCMD_ST1)
188
          rc = 0x55;
189
        if (kbd_ccmd == KBD_CCMD_ST2)
190
          rc = 0x00;
191
        kbd_ccmd = 0x00;
192
        kbd_kresp = 0x0;
193
        if (config.sim.verbose)
194 1350 nogj
          PRINTF("kbd_read8(%"PRIxADDR") %lx\n", addr, rc);
195 684 lampret
        return rc;
196
      }
197
      else if (kbd_kresp) {
198
        unsigned long rc;
199
        if (kbd_kresp == 0x2) {
200
          kbd_kresp = 0x0;
201
          rc = KBD_KRESP_RSTOK;
202
        } else if (kbd_kcmd == KBD_KCMD_RST) {
203
          kbd_kresp = 0x2;
204
          rc = KBD_KRESP_ACK;
205
        } else if (kbd_kcmd == KBD_KCMD_ECHO) {
206
          kbd_kresp = 0x0;
207
          rc = KBD_KRESP_ECHO;
208
        } else {
209
          kbd_kresp = 0x0;
210
          rc = KBD_KRESP_ACK;
211
        }
212
        kbd_kcmd = 0x00;
213
        if (config.sim.verbose)
214 1350 nogj
          PRINTF("kbd_read8(%"PRIxADDR") %lx\n", addr, rc);
215 684 lampret
        return rc;
216 805 markom
      } else if (kbd_buf_count) {
217
        unsigned long c = kbd_buf[kbd_buf_tail];
218
        kbd_buf_tail = (kbd_buf_tail + 1) % KBD_MAX_BUF;
219
        kbd_buf_count--;
220 684 lampret
        kbd_kresp = 0x0;
221
        if (config.sim.verbose)
222 1350 nogj
          PRINTF("kbd_read8(%"PRIxADDR") %lx\n", addr, c);
223 805 markom
        return c;
224
      }
225 684 lampret
      kbd_kresp = 0x0;
226
      if (config.sim.verbose)
227 1350 nogj
        PRINTF("kbd_read8(%"PRIxADDR") fifo empty\n", addr);
228 805 markom
      return 0;
229
    default:
230 1350 nogj
      fprintf (stderr, "Read out of keyboard space (0x%"PRIxADDR")!\n", addr);
231 884 markom
      runtime.sim.cont_run = 0;
232 805 markom
      return 0;
233
  }
234
}
235
 
236
 
237
/* Simulation hook. Must be called every couple of clock cycles to simulate incomming data. */
238
void kbd_job(int param)
239
{
240
  int c;
241
  int kbd_int = 0;
242
  /* Check if there is something waiting, and decode it into kdb_buf */
243
  if((c = fgetc(kbd_rxfs)) != EOF) {
244
    scan_decode (c);
245
  }
246
  kbd_int = kbd_kresp || kbd_buf_count;
247
  kbd_int = kbd_kresp || kbd_buf_count ? kbd_ccmdbyte & KBD_CCMDBYTE_INT : 0;
248
  if (config.sim.verbose && kbd_int)
249 1308 phoenix
    PRINTF("Keyboard Interrupt.... kbd_kresp %lx  kbd_buf_count %lx \n",
250
           kbd_kresp, kbd_buf_count);
251 805 markom
  if (kbd_int) report_interrupt(config.kbd.irq);
252 884 markom
  SCHED_ADD(kbd_job, 0, runtime.sim.cycles + kbd_slowdown);
253 805 markom
}
254
 
255 1350 nogj
/* Reset all (simulated) ps2 controlers/keyboards */
256 805 markom
void kbd_reset ()
257
{
258
  if (config.kbd.enabled) {
259
    kbd_buf_count = 0;
260
    kbd_buf_head = 0;
261
    kbd_buf_tail = 0;
262 684 lampret
    kbd_kresp = 0x0;
263
    kbd_ccmdbyte = 0x65; /* We reset into default normal operation. */
264 1359 nogj
    register_memoryarea(config.kbd.baseaddr, KBD_SPACE, 1, 0, kbd_read8, kbd_write8, NULL);
265 805 markom
 
266
    if (!(kbd_rxfs = fopen(config.kbd.rxfile, "r"))
267
     && !(kbd_rxfs = fopen(config.kbd.rxfile, "r+"))) {
268
      fprintf (stderr, "WARNING: Keyboard has problems with RX file stream.\n");
269
      config.kbd.enabled = 0;
270
    }
271
    kbd_slowdown = (long) ((config.sim.system_kfreq * 1000.) / KBD_BAUD_RATE);
272
    if (kbd_slowdown <= 0) kbd_slowdown = 1;
273 884 markom
    if (config.kbd.enabled) SCHED_ADD(kbd_job, 0, runtime.sim.cycles + kbd_slowdown);
274 805 markom
  }
275
}
276 684 lampret
 
277 805 markom
 
278 684 lampret
void kbd_info()
279
{
280 997 markom
        PRINTF("kbd_kcmd: %x\n", kbd_kcmd);
281
        PRINTF("kbd_ccmd: %x\n", kbd_ccmd);
282
        PRINTF("kbd_ccmdbyte: %x\n", kbd_ccmdbyte);
283 1308 phoenix
        PRINTF("kbd_kresp: %lx\n", kbd_kresp);
284
        PRINTF("kbd_buf_count: %lx\n", kbd_buf_count);
285 684 lampret
}
286 1358 nogj
 
287
/*----------------------------------------------------[ KBD Configuration ]---*/
288
void kbd_enabled(union param_val val, void *dat)
289
{
290
  config.kbd.enabled = val.int_val;
291
}
292
 
293
void kbd_baseaddr(union param_val val, void *dat)
294
{
295
  config.kbd.baseaddr = val.addr_val;
296
}
297
 
298
void kbd_irq(union param_val val, void *dat)
299
{
300
  config.kbd.irq = val.int_val;
301
}
302
 
303
void kbd_rxfile(union param_val val, void *dat)
304
{
305
  strcpy(config.kbd.rxfile, val.str_val);
306
}
307
 
308
void reg_kbd_sec(void)
309
{
310
  struct config_section *sec = reg_config_sec("kbd", NULL, NULL);
311
 
312
  reg_config_param(sec, "enabled", paramt_int, kbd_enabled);
313
  reg_config_param(sec, "baseaddr", paramt_int, kbd_baseaddr);
314
  reg_config_param(sec, "irq", paramt_int, kbd_irq);
315
  reg_config_param(sec, "rxfile", paramt_str, kbd_rxfile);
316
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.