SandboXP

Форк
0
/
uart.js 
341 строка · 8.5 Кб
1
"use strict";
2

3
/*
4
 * Serial ports
5
 * http://wiki.osdev.org/UART
6
 * https://github.com/s-macke/jor1k/blob/master/js/worker/dev/uart.js
7
 * https://www.freebsd.org/doc/en/articles/serial-uart/
8
 */
9

10
/** @const */
11
var DLAB = 0x80;
12

13

14
/** @const */ var UART_IER_MSI  = 0x08; /* Modem Status Changed int. */
15
/** @const */ var UART_IER_THRI = 0x02; /* Enable Transmitter holding register int. */
16
/** @const */ var UART_IER_RDI = 0x01; /* Enable receiver data interrupt */
17

18
/** @const */var UART_IIR_MSI = 0x00; /* Modem status interrupt (Low priority) */
19
/** @const */var UART_IIR_NO_INT = 0x01;
20
/** @const */var UART_IIR_THRI = 0x02; /* Transmitter holding register empty */
21
/** @const */var UART_IIR_RDI = 0x04; /* Receiver data interrupt */
22
/** @const */var UART_IIR_RLSI = 0x06; /* Receiver line status interrupt (High p.) */
23
/** @const */var UART_IIR_CTI = 0x0c; /* Character timeout */
24

25
/** @const */ var UART_LSR_DATA_READY        = 0x1;  // data available
26
/** @const */ var UART_LSR_TX_EMPTY        = 0x20; // TX (THR) buffer is empty
27
/** @const */ var UART_LSR_TRANSMITTER_EMPTY = 0x40; // TX empty and line is idle
28

29

30
/**
31
 * @constructor
32
 * @param {CPU} cpu
33
 * @param {number} port
34
 * @param {BusConnector} bus
35
 */
36
function UART(cpu, port, bus)
37
{
38
    /** @const @type {BusConnector} */
39
    this.bus = bus;
40

41
    /** @const @type {CPU} */
42
    this.cpu = cpu;
43

44
    this.ints = 1 << UART_IIR_THRI;
45

46
    this.baud_rate = 0;
47

48
    this.line_control = 0;
49

50
    // line status register
51
    this.lsr = UART_LSR_TRANSMITTER_EMPTY | UART_LSR_TX_EMPTY;
52

53
    this.fifo_control = 0;
54

55
    // interrupts enable
56
    this.ier = 0;
57

58
    // interrupt identification register
59
    this.iir = UART_IIR_NO_INT;
60

61
    this.modem_control = 0;
62
    this.modem_status = 0;
63

64
    this.scratch_register = 0;
65

66
    this.irq = 0;
67

68
    this.input = new ByteQueue(4096);
69

70
    this.current_line = [];
71

72
    switch(port)
73
    {
74
        case 0x3F8:
75
            this.com = 0;
76
            this.irq = 4;
77
            break;
78
        case 0x2F8:
79
            this.com = 1;
80
            this.irq = 3;
81
            break;
82
        case 0x3E8:
83
            this.com = 2;
84
            this.irq = 4;
85
            break;
86
        case 0x2E8:
87
            this.com = 3;
88
            this.irq = 3;
89
            break;
90
        default:
91
            dbg_log("Invalid serial port: " + h(port), LOG_SERIAL);
92
            this.com = 0;
93
            this.irq = 4;
94
    }
95

96
    this.bus.register("serial" + this.com + "-input", function(data)
97
    {
98
        this.data_received(data);
99
    }, this);
100

101
    var io = cpu.io;
102

103
    io.register_write(port, this, function(out_byte)
104
    {
105
        this.write_data(out_byte);
106
    }, function(out_word)
107
    {
108
        this.write_data(out_word & 0xFF);
109
        this.write_data(out_word >> 8);
110
    });
111

112
    io.register_write(port | 1, this, function(out_byte)
113
    {
114
        if(this.line_control & DLAB)
115
        {
116
            this.baud_rate = this.baud_rate & 0xFF | out_byte << 8;
117
            dbg_log("baud rate: " + h(this.baud_rate), LOG_SERIAL);
118
        }
119
        else
120
        {
121
            this.ier = out_byte & 0xF;
122
            dbg_log("interrupt enable: " + h(out_byte), LOG_SERIAL);
123
            this.CheckInterrupt();
124
        }
125
    });
126

127
    io.register_read(port, this, function()
128
    {
129
        if(this.line_control & DLAB)
130
        {
131
            return this.baud_rate & 0xFF;
132
        }
133
        else
134
        {
135
            var data = this.input.shift();
136

137
            if(data === -1)
138
            {
139
                dbg_log("Read input empty", LOG_SERIAL);
140
            }
141
            else
142
            {
143
                dbg_log("Read input: " + h(data), LOG_SERIAL);
144
            }
145

146
            if(this.input.length === 0)
147
            {
148
                this.lsr &= ~UART_LSR_DATA_READY;
149
                this.ClearInterrupt(UART_IIR_CTI);
150
            }
151

152
            return data;
153
        }
154
    });
155

156
    io.register_read(port | 1, this, function()
157
    {
158
        if(this.line_control & DLAB)
159
        {
160
            return this.baud_rate >> 8;
161
        }
162
        else
163
        {
164
            return this.ier & 0xF;
165
        }
166
    });
167

168
    io.register_read(port | 2, this, function()
169
    {
170
        var ret = this.iir & 0xF | 0xC0;
171
        dbg_log("read interrupt identification: " + h(this.iir), LOG_SERIAL);
172

173
        if (this.iir == UART_IIR_THRI) {
174
            this.ClearInterrupt(UART_IIR_THRI);
175
        }
176

177
        return ret;
178
    });
179
    io.register_write(port | 2, this, function(out_byte)
180
    {
181
        dbg_log("fifo control: " + h(out_byte), LOG_SERIAL);
182
        this.fifo_control = out_byte;
183
    });
184

185
    io.register_read(port | 3, this, function()
186
    {
187
        dbg_log("read line control: " + h(this.line_control), LOG_SERIAL);
188
        return this.line_control;
189
    });
190
    io.register_write(port | 3, this, function(out_byte)
191
    {
192
        dbg_log("line control: " + h(out_byte), LOG_SERIAL);
193
        this.line_control = out_byte;
194
    });
195

196

197
    io.register_read(port | 4, this, function()
198
    {
199
        return this.modem_control;
200
    });
201
    io.register_write(port | 4, this, function(out_byte)
202
    {
203
        dbg_log("modem control: " + h(out_byte), LOG_SERIAL);
204
        this.modem_control = out_byte;
205
    });
206

207
    io.register_read(port | 5, this, function()
208
    {
209
        dbg_log("read line status: " + h(this.lsr), LOG_SERIAL);
210
        return this.lsr;
211
    });
212
    io.register_write(port | 5, this, function(out_byte)
213
    {
214
        dbg_log("Factory test write", LOG_SERIAL);
215
    });
216

217
    io.register_read(port | 6, this, function()
218
    {
219
        dbg_log("read modem status: " + h(this.modem_status), LOG_SERIAL);
220
        return this.modem_status;
221
    });
222
    io.register_write(port | 6, this, function(out_byte)
223
    {
224
        dbg_log("Unkown register write (base+6)", LOG_SERIAL);
225
    });
226

227
    io.register_read(port | 7, this, function()
228
    {
229
        return this.scratch_register;
230
    });
231
    io.register_write(port | 7, this, function(out_byte)
232
    {
233
        this.scratch_register = out_byte;
234
    });
235
}
236

237
UART.prototype.get_state = function()
238
{
239
    var state = [];
240

241
    state[0] = this.ints;
242
    state[1] = this.baud_rate;
243
    state[2] = this.line_control;
244
    state[3] = this.lsr;
245
    state[4] = this.fifo_control;
246
    state[5] = this.ier;
247
    state[6] = this.iir;
248
    state[7] = this.modem_control;
249
    state[8] = this.modem_status;
250
    state[9] = this.scratch_register;
251
    state[10] = this.irq;
252

253
    return state;
254
};
255

256
UART.prototype.set_state = function(state)
257
{
258
    this.ints = state[0];
259
    this.baud_rate = state[1];
260
    this.line_control = state[2];
261
    this.lsr = state[3];
262
    this.fifo_control = state[4];
263
    this.ier = state[5];
264
    this.iir = state[6];
265
    this.modem_control = state[7];
266
    this.modem_status = state[8];
267
    this.scratch_register = state[9];
268
    this.irq = state[10];
269
};
270

271
UART.prototype.CheckInterrupt = function() {
272
    if ((this.ints & (1 << UART_IIR_CTI))  && (this.ier & UART_IER_RDI)) {
273
        this.iir = UART_IIR_CTI;
274
        this.cpu.device_raise_irq(this.irq);
275
    } else
276
    if ((this.ints & (1 << UART_IIR_THRI)) && (this.ier & UART_IER_THRI)) {
277
        this.iir = UART_IIR_THRI;
278
        this.cpu.device_raise_irq(this.irq);
279
    } else
280
    if ((this.ints & (1 << UART_IIR_MSI))  && (this.ier & UART_IER_MSI)) {
281
        this.iir = UART_IIR_MSI;
282
        this.cpu.device_raise_irq(this.irq);
283
    } else {
284
        this.iir = UART_IIR_NO_INT;
285
        this.cpu.device_lower_irq(this.irq);
286
    }
287
};
288

289
UART.prototype.ThrowInterrupt = function(line) {
290
    this.ints |= (1 << line);
291
    this.CheckInterrupt();
292
};
293

294
UART.prototype.ClearInterrupt = function(line) {
295
    this.ints &= ~(1 << line);
296
    this.CheckInterrupt();
297
};
298

299
/**
300
 * @param {number} data
301
 */
302
UART.prototype.data_received = function(data)
303
{
304
    dbg_log("input: " + h(data), LOG_SERIAL);
305
    this.input.push(data);
306

307
    this.lsr |= UART_LSR_DATA_READY;
308
    this.ThrowInterrupt(UART_IIR_CTI);
309
};
310

311
UART.prototype.write_data = function(out_byte)
312
{
313
    if(this.line_control & DLAB)
314
    {
315
        this.baud_rate = this.baud_rate & ~0xFF | out_byte;
316
        return;
317
    }
318

319
    dbg_log("data: " + h(out_byte), LOG_SERIAL);
320

321
    this.ThrowInterrupt(UART_IIR_THRI);
322

323
    if(out_byte === 0xFF)
324
    {
325
        return;
326
    }
327

328
    var char = String.fromCharCode(out_byte);
329

330
    this.bus.send("serial" + this.com + "-output-char", char);
331

332
    this.current_line.push(out_byte);
333

334
    if(char === "\n")
335
    {
336
        const line = String.fromCharCode.apply("", this.current_line).trimRight().replace(/[\x00-\x08\x0b-\x1f\x7f\x80-\xff]/g, "");
337
        dbg_log("SERIAL: " + line);
338
        this.bus.send("serial" + this.com + "-output-line", String.fromCharCode.apply("", this.current_line));
339
        this.current_line = [];
340
    }
341
};
342

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.