📄 main.cc
字号:
// Zilog Enhanced Serial Communication Controller// Matt Chapman <matthewc@cse.unsw.edu.au>//// NOTE: This is only a basic implementation, designed for usage as a console.#include <stdio.h>#include <string.h>#include <unistd.h>#include <assert.hh>#include <checkpoint.hh>#include <device.hh>#include <inttypes.hh>#include <module.hh>#include <serial.hh>#include <simarg.hh>#include <sulima.hh>#include <fcntl.h>#include "escc.hh"// Serialization information.SerialType<ZilogESCC> ZilogESCC::type( "ZilogESCC", "Zilog Enhanced Serial Communication Controller");// Runtime constructor.ZilogESCC::ZilogESCC(const SimArgs& args) : Module(args), Device(8){ if (args.length() > 2) throw Error("Too many arguments to \"sim::install ZilogESCC\"."); define("irq", conf.irq); define("debugirq", conf.debugirq);}// Serialized constructor.ZilogESCC::ZilogESCC(Checkpoint& cp) : Module(cp), Device(8){ reset(false);}// Module interface.voidZilogESCC::reset(bool warm){ intr_enable = false; intr_pending = intr_mask = intr_vector = intr_ius = 0; for (int i = 0; i < 2; i++) rx_lo[i] = rx_hi[i] = 0; reg = 0; status_poll = 0; setup_pty();}// Serialization interface.voidZilogESCC::checkpoint(Checkpoint& cp, bool parent) const{}// Reported Interrupt Under Service codes for each sourceconst UInt8 ZilogESCC::intr_ius_map[] = { 3 /* none */, 1, 0, 2, 5, 4, 6 };voidZilogESCC::check_interrupts(void){ if (intr_enable && (intr_pending & intr_mask)) { // select highest priority interrupt intr_ius = intr_ius_map[ffs(intr_pending & intr_mask)]; intctrl->deliver_interrupt(conf.irq); } else { intr_ius = intr_ius_map[0]; intctrl->clear_interrupt(conf.irq); }}ClockValueZilogESCC::read(UInt64 addr, UInt64* buf, int size){ UInt8 cmddata, channel; assert(size > 0 && size <= 8); assert(!is_power_of_two(size) || (addr & (size - 1)) == 0); cmddata = bit(addr, 0); channel = bit(addr, 1); if (cmddata == Data) { // collect next character *buf = rx_fifo[channel][rx_lo[channel]]; if (rx_lo[channel] != rx_hi[channel]) rx_lo[channel] = (rx_lo[channel]+1) & rx_fifo_mask; if (rx_lo[channel] == rx_hi[channel]){ intr_pending &= ~ ( (channel == ChannelA) ? RxIntrA : RxIntrB); check_interrupts(); } return 0; } switch (reg) { case 0: // Transmit/Receive Buffer Status and External Status */ *buf = (1 << 2); // Tx buffer empty if (rx_lo[channel] != rx_hi[channel]) *buf |= (1 << 0); // Rx char available // Upon polling the status register 10 times without an intervening write, // assume that we are waiting for input and flush output to user. if (++status_poll == 10) fflush(stdout); break; case 2: // Interrupt Vector if (channel == ChannelA) *buf = intr_vector; else *buf = intr_vector | (intr_ius << 1); break; case 3: // Interrupt Pending if (channel == ChannelA) *buf = intr_pending; else *buf = 0; break; default: //log("read unimplemented register %d", reg); *buf = 0; break; } reg = 0; return 0; // ignore latency}ClockValueZilogESCC::write(UInt64 addr, const UInt64* buf, int size){ UInt8 cmddata, channel, value; UInt8 command, mask, newreg = 0; assert(size > 0 && size <= 8); assert(!is_power_of_two(size) || (addr & (size - 1)) == 0); cmddata = bit(addr, 0); channel = bit(addr, 1); value = *buf & 0xff; if (cmddata == Data) { status_poll = 0; if (channel == ChannelA) putchar(value); else ::write(io_fd, &value, 1); // all sent, now the Tx buffer is empty... intr_pending |= (channel == ChannelA) ? TxIntrA : TxIntrB; check_interrupts(); return 0; } switch (reg) { case 0: /* Command Register */ newreg = bits(value, 2, 0); command = bits(value, 5, 3); switch (command) { case 0: /* null cmd */ break; case 1: /* point high */ newreg += 8; break; case 5: /* clear Tx int */ intr_pending &= ~((channel == ChannelA) ? TxIntrA : TxIntrB); check_interrupts(); break; case 7: /* reset highest IUS */ check_interrupts(); break; default: log("unsupported command %d", command); break; } command = bits(value, 7, 6); switch (command) { case 0: /* null cmd */ break; default: log("unsupported CRC command %d", command); break; } break; case 1: // Transmit/Receive Interrupt and Data Transfer Mode Definition mask = bits(value, 1, 0); // transmit, external/status if (bit(value, 3) ^ bit(value, 4)) // (01 or 10) mask |= 1 << 2; // receive if (channel == ChannelA) { intr_mask &= ~(RxIntrA | TxIntrA | ExtIntrA); intr_mask |= mask << 3; } else { intr_mask &= ~(RxIntrB | TxIntrB | ExtIntrB); intr_mask |= mask; } break; case 2: // Interrupt Vector intr_vector = value; break; case 9: // Master Interrupt Enable intr_enable = bit(value, 3); break; default: //log("write unimplemented register %d", reg); break; } reg = newreg; return 0; // ignore latency}voidZilogESCC::input(int c, int channel){ UInt8 new_rx_hi; static bool debug; if (debug) { intctrl->clear_interrupt(conf.debugirq); debug = false; } else { switch (c) { case 4: // Ctrl-D - DEBUG intctrl->deliver_interrupt(conf.debugirq); debug = true; return; case 18: // Ctrl-R - DUMP REGISTERS bus->clock->dump_state(); return; } } rx_fifo[channel][rx_hi[channel]] = (UInt8)c; new_rx_hi = (rx_hi[channel]+1) & rx_fifo_mask; if (new_rx_hi != rx_lo[channel]) rx_hi[channel] = new_rx_hi; intr_pending |= (channel == ChannelA) ? RxIntrA : RxIntrB; check_interrupts();}voidZilogESCC::input(int c){ input(c, ChannelA);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -