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 1446

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 1371 nogj
struct kbd_state {
72
  /* Temporary buffer to store incoming scan codes */
73
  uint8_t buf[KBD_MAX_BUF];
74 805 markom
 
75 1371 nogj
  /* Number of scan codes in buffer */
76
  unsigned long buf_count;
77
  unsigned long buf_head;
78
  unsigned long buf_tail;
79 805 markom
 
80 1371 nogj
  /* Input stream */
81
  FILE *rxfs;
82 805 markom
 
83 1371 nogj
  /* Controller Command (write into 0x64) */
84
  int ccmd;
85 684 lampret
 
86 1371 nogj
  /* Keyboard Command (write into 0x60) */
87
  uint8_t kcmd;
88 684 lampret
 
89 1371 nogj
  /* Controller Command Byte */
90
  uint8_t ccmdbyte;
91 684 lampret
 
92 1371 nogj
  /* Keyboard response pending */
93
  unsigned long kresp;
94 684 lampret
 
95 1371 nogj
  /* Keyboard slowdown factor */
96
  long slowdown;
97 805 markom
 
98 1371 nogj
  /* Cofiguration */
99
  int irq;
100
  oraddr_t baseaddr;
101
  char *rxfile;
102
};
103
 
104
static void kbd_put (struct kbd_state *kbd, unsigned char c)
105 805 markom
{
106 1371 nogj
  if (kbd->buf_count >= KBD_MAX_BUF) {
107 805 markom
    fprintf (stderr, "WARNING: Keyboard buffer overflow.\n");
108
  } else {
109 1371 nogj
    kbd->buf[kbd->buf_head] = c;
110
    kbd->buf_head = (kbd->buf_head + 1) % KBD_MAX_BUF;
111
    kbd->buf_count++;
112 805 markom
  }
113
}
114
 
115
/* Decodes ascii code c into multiple scan codes, placed into buf, length is returned */
116 1371 nogj
static void scan_decode (struct kbd_state *kbd, unsigned char c)
117 805 markom
{
118
  /* Do not handle special characters and extended ascii */
119
  if (c >= 128 || !scan_table[c].code)
120
    return;
121
 
122
  /* Make shift? */
123 1371 nogj
  if (scan_table[c].shift) kbd_put (kbd, 0x2a);
124 805 markom
  /* Make char */
125 1371 nogj
  kbd_put (kbd, scan_table[c].code);
126 805 markom
  /* Break char */
127 1371 nogj
  kbd_put (kbd, scan_table[c].code | 0x80);
128 805 markom
  /* Break shift? */
129 1371 nogj
  if (scan_table[c].shift) kbd_put (kbd, 0xaa);
130 805 markom
}
131
 
132
/* Write a register */
133 1359 nogj
void kbd_write8 (oraddr_t addr, uint32_t value, void *dat)
134 805 markom
{
135 1371 nogj
  struct kbd_state *kbd = dat;
136
  int a = (addr - kbd->baseaddr);
137 805 markom
  switch (a) {
138 684 lampret
    case KBD_CTRL:
139 1371 nogj
      kbd->ccmd = value & 0xff;
140
      if (kbd->ccmd == KBD_CCMD_RCB)
141
          kbd->kresp = 0x1;
142
      if (kbd->ccmd == KBD_CCMD_ST1)
143
          kbd->kresp = 0x1;
144
      if (kbd->ccmd == KBD_CCMD_ST2)
145
          kbd->kresp = 0x1;
146
      if (kbd->ccmd == KBD_CCMD_DKI)
147
        kbd->ccmdbyte |= KBD_CCMDBYTE_EN;
148
      if (kbd->ccmd == KBD_CCMD_EKI)
149
        kbd->ccmdbyte &= ~KBD_CCMDBYTE_EN;
150 684 lampret
      if (config.sim.verbose)
151 1350 nogj
        PRINTF("kbd_write8(%"PRIxADDR") %"PRIx32"\n", addr, value);
152 805 markom
      break;
153 684 lampret
    case KBD_DATA:
154 1371 nogj
      if (kbd->ccmd == KBD_CCMD_WCB) {
155
        kbd->ccmdbyte = value & 0xff;
156
        kbd->ccmd = 0x00;
157 684 lampret
      } else
158 1371 nogj
        kbd->kcmd = value & 0xff;
159
      if (kbd->kcmd == KBD_KCMD_DK)
160
        kbd->ccmdbyte |= KBD_CCMDBYTE_EN;
161
      if (kbd->kcmd == KBD_KCMD_EK)
162
        kbd->ccmdbyte &= ~KBD_CCMDBYTE_EN;
163
      kbd->kresp = 0x1;
164
      kbd->ccmd = 0x00;
165 684 lampret
      if (config.sim.verbose)
166 1350 nogj
        PRINTF("kbd_write8(%"PRIxADDR") %"PRIx32"\n", addr, value);
167 805 markom
      break;
168
    default:
169 1350 nogj
      fprintf (stderr, "Write out of keyboard space (0x%"PRIxADDR")!\n", addr);
170 884 markom
      runtime.sim.cont_run = 0;
171 805 markom
      break;
172
  }
173
}
174
 
175
/* Read a register */
176 1359 nogj
uint32_t kbd_read8 (oraddr_t addr, void *dat)
177 805 markom
{
178 1371 nogj
  struct kbd_state *kbd = dat;
179
  int a = (addr - kbd->baseaddr);
180 805 markom
  switch (a) {
181 684 lampret
    case KBD_CTRL: {
182
      unsigned long c = 0x0;
183 1371 nogj
      if (kbd->kresp || kbd->buf_count)
184 684 lampret
        c |= KBD_STATUS_OBF;
185 1371 nogj
      c |= kbd->ccmdbyte & KBD_CCMDBYTE_SYS;
186 684 lampret
      c |= KBD_STATUS_INH;
187
      if (config.sim.verbose)
188 1350 nogj
        PRINTF("kbd_read8(%"PRIxADDR") %lx\n", addr, c);
189 684 lampret
      return c;
190
    }
191
    case KBD_DATA:
192 1371 nogj
      if (kbd->ccmd) {
193 684 lampret
        unsigned long rc;
194 1371 nogj
        if (kbd->ccmd == KBD_CCMD_RCB)
195
          rc = kbd->ccmdbyte;
196
        if (kbd->ccmd == KBD_CCMD_ST1)
197 684 lampret
          rc = 0x55;
198 1371 nogj
        if (kbd->ccmd == KBD_CCMD_ST2)
199 684 lampret
          rc = 0x00;
200 1371 nogj
        kbd->ccmd = 0x00;
201
        kbd->kresp = 0x0;
202 684 lampret
        if (config.sim.verbose)
203 1350 nogj
          PRINTF("kbd_read8(%"PRIxADDR") %lx\n", addr, rc);
204 684 lampret
        return rc;
205
      }
206 1371 nogj
      else if (kbd->kresp) {
207 684 lampret
        unsigned long rc;
208 1371 nogj
        if (kbd->kresp == 0x2) {
209
          kbd->kresp = 0x0;
210 684 lampret
          rc = KBD_KRESP_RSTOK;
211 1371 nogj
        } else if (kbd->kcmd == KBD_KCMD_RST) {
212
          kbd->kresp = 0x2;
213 684 lampret
          rc = KBD_KRESP_ACK;
214 1371 nogj
        } else if (kbd->kcmd == KBD_KCMD_ECHO) {
215
          kbd->kresp = 0x0;
216 684 lampret
          rc = KBD_KRESP_ECHO;
217
        } else {
218 1371 nogj
          kbd->kresp = 0x0;
219 684 lampret
          rc = KBD_KRESP_ACK;
220
        }
221 1371 nogj
        kbd->kcmd = 0x00;
222 684 lampret
        if (config.sim.verbose)
223 1350 nogj
          PRINTF("kbd_read8(%"PRIxADDR") %lx\n", addr, rc);
224 684 lampret
        return rc;
225 1371 nogj
      } else if (kbd->buf_count) {
226
        unsigned long c = kbd->buf[kbd->buf_tail];
227
        kbd->buf_tail = (kbd->buf_tail + 1) % KBD_MAX_BUF;
228
        kbd->buf_count--;
229
        kbd->kresp = 0x0;
230 684 lampret
        if (config.sim.verbose)
231 1350 nogj
          PRINTF("kbd_read8(%"PRIxADDR") %lx\n", addr, c);
232 805 markom
        return c;
233
      }
234 1371 nogj
      kbd->kresp = 0x0;
235 684 lampret
      if (config.sim.verbose)
236 1350 nogj
        PRINTF("kbd_read8(%"PRIxADDR") fifo empty\n", addr);
237 805 markom
      return 0;
238
    default:
239 1350 nogj
      fprintf (stderr, "Read out of keyboard space (0x%"PRIxADDR")!\n", addr);
240 884 markom
      runtime.sim.cont_run = 0;
241 805 markom
      return 0;
242
  }
243
}
244
 
245
 
246
/* Simulation hook. Must be called every couple of clock cycles to simulate incomming data. */
247 1371 nogj
void kbd_job(void *dat)
248 805 markom
{
249 1371 nogj
  struct kbd_state *kbd = dat;
250 805 markom
  int c;
251
  int kbd_int = 0;
252 1371 nogj
 
253 805 markom
  /* Check if there is something waiting, and decode it into kdb_buf */
254 1371 nogj
  if((c = fgetc(kbd->rxfs)) != EOF) {
255
    scan_decode (kbd, c);
256 805 markom
  }
257 1371 nogj
  kbd_int = kbd->kresp || kbd->buf_count ? kbd->ccmdbyte & KBD_CCMDBYTE_INT : 0;
258 805 markom
  if (config.sim.verbose && kbd_int)
259 1308 phoenix
    PRINTF("Keyboard Interrupt.... kbd_kresp %lx  kbd_buf_count %lx \n",
260 1371 nogj
           kbd->kresp, kbd->buf_count);
261
  if (kbd_int) report_interrupt(kbd->irq);
262 1390 nogj
  SCHED_ADD(kbd_job, dat, kbd->slowdown);
263 805 markom
}
264
 
265 1350 nogj
/* Reset all (simulated) ps2 controlers/keyboards */
266 1371 nogj
void kbd_reset (void *dat)
267 805 markom
{
268 1371 nogj
  struct kbd_state *kbd = dat;
269
 
270
  kbd->buf_count = 0;
271
  kbd->buf_head = 0;
272
  kbd->buf_tail = 0;
273
  kbd->kresp = 0x0;
274
  kbd->ccmdbyte = 0x65; /* We reset into default normal operation. */
275 805 markom
 
276 1371 nogj
  if (!(kbd->rxfs = fopen(kbd->rxfile, "r"))
277
      && !(kbd->rxfs = fopen(kbd->rxfile, "r+"))) {
278 1446 nogj
    fprintf (stderr, "WARNING: Unable to open RX file stream.\n");
279 1371 nogj
    return;
280 805 markom
  }
281 1371 nogj
  kbd->slowdown = (long) ((config.sim.system_kfreq * 1000.) / KBD_BAUD_RATE);
282
  if (kbd->slowdown <= 0) kbd->slowdown = 1;
283 1390 nogj
  SCHED_ADD(kbd_job, dat, kbd->slowdown);
284 805 markom
}
285 684 lampret
 
286 805 markom
 
287 1371 nogj
void kbd_info(void *dat)
288 684 lampret
{
289 1371 nogj
  struct kbd_state *kbd = dat;
290
  PRINTF("kbd_kcmd: %x\n", kbd->kcmd);
291
  PRINTF("kbd_ccmd: %x\n", kbd->ccmd);
292
  PRINTF("kbd_ccmdbyte: %x\n", kbd->ccmdbyte);
293
  PRINTF("kbd_kresp: %lx\n", kbd->kresp);
294
  PRINTF("kbd_buf_count: %lx\n", kbd->buf_count);
295 684 lampret
}
296 1358 nogj
 
297
/*----------------------------------------------------[ KBD Configuration ]---*/
298
void kbd_baseaddr(union param_val val, void *dat)
299
{
300 1371 nogj
  struct kbd_state *kbd = dat;
301
  kbd->baseaddr = val.addr_val;
302 1358 nogj
}
303
 
304
void kbd_irq(union param_val val, void *dat)
305
{
306 1371 nogj
  struct kbd_state *kbd = dat;
307
  kbd->irq = val.int_val;
308 1358 nogj
}
309
 
310
void kbd_rxfile(union param_val val, void *dat)
311
{
312 1371 nogj
  struct kbd_state *kbd = dat;
313
  if(!(kbd->rxfile = strdup(val.str_val))) {
314
    fprintf(stderr, "Peripheral KBD: Run out of memory\n");
315
    exit(-1);
316
  }
317 1358 nogj
}
318
 
319 1371 nogj
void *kbd_sec_start(void)
320
{
321
  struct kbd_state *new = malloc(sizeof(struct kbd_state));
322
 
323
  if(!new) {
324
    fprintf(stderr, "Peripheral KBD: Run out of memory\n");
325
    exit(-1);
326
  }
327
 
328
  new->buf_count = 0;
329
  new->buf_head = 0;
330
  new->buf_tail = 0;
331
  new->rxfs = NULL;
332
 
333
  return new;
334
}
335
 
336
void kbd_sec_end(void *dat)
337
{
338
  struct kbd_state *kbd = dat;
339
 
340
  register_memoryarea(kbd->baseaddr, KBD_SPACE, 1, 0, kbd_read8, kbd_write8, dat);
341
  reg_sim_reset(kbd_reset, dat);
342
  reg_sim_stat(kbd_info, dat);
343
}
344
 
345 1358 nogj
void reg_kbd_sec(void)
346
{
347 1371 nogj
  struct config_section *sec = reg_config_sec("kbd", kbd_sec_start, kbd_sec_end);
348 1358 nogj
 
349
  reg_config_param(sec, "baseaddr", paramt_int, kbd_baseaddr);
350
  reg_config_param(sec, "irq", paramt_int, kbd_irq);
351
  reg_config_param(sec, "rxfile", paramt_str, kbd_rxfile);
352
}

powered by: WebSVN 2.1.0

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