// (C) 2024 by Folkert van Heusden // Released under MIT license #include #include #include #include #include "bus.h" #include "cpu.h" #include "dc11.h" #include "log.h" #include "utils.h" dc11::dc11(const int base_port, bus *const b): base_port(base_port), b(b) { // TODO move to begin() th = new std::thread(std::ref(*this)); } dc11::~dc11() { stop_flag = true; if (th) { th->join(); delete th; } } void dc11::trigger_interrupt(const int line_nr) { printf("Interrupt %d\r\n", line_nr); b->getCpu()->queue_interrupt(5, 0300 + line_nr * 4); } void dc11::operator()() { set_thread_name("kek:DC11"); DOLOG(info, true, "DC11 thread started"); for(int i=0; i(&listen_addr), sizeof(listen_addr)) == -1) { close(pfds[i].fd); pfds[i].fd = -1; DOLOG(warning, true, "Cannot bind to port %d (DC11)", port); continue; } if (listen(pfds[i].fd, SOMAXCONN) == -1) { close(pfds[i].fd); pfds[i].fd = -1; DOLOG(warning, true, "Cannot listen on port %d (DC11)", port); continue; } pfds[i].events = POLLIN; } while(!stop_flag) { int rc = poll(pfds, dc11_n_lines * 2, 100); if (rc == 0) continue; // accept any new session for(int i=0; i lck(input_lock[line_nr]); for(int k=0; k> 8; return v; } uint16_t dc11::read_word(const uint16_t addr) { int reg = (addr - DC11_BASE) / 2; int line_nr = reg / 4; // emulate DTR, CTS & READY registers[line_nr * 4 + 0] &= ~1; // DTR: bit 0 [RCSR] registers[line_nr * 4 + 0] &= ~4; // CD : bit 2 registers[line_nr * 4 + 2] &= ~2; // CTS: bit 1 [TSCR] registers[line_nr * 4 + 2] &= ~128; // READY: bit 7 if (pfds[line_nr + dc11_n_lines].fd != -1) { registers[line_nr * 4 + 0] |= 1; registers[line_nr * 4 + 0] |= 4; registers[line_nr * 4 + 2] |= 2; registers[line_nr * 4 + 2] |= 128; } uint16_t vtemp = registers[reg]; if ((reg & 3) == 1) { // read data register std::unique_lock lck(input_lock[line_nr]); // get oldest byte in buffer if (recv_buffers[line_nr].empty() == false) { vtemp = *recv_buffers[line_nr].begin(); printf("return: %d\n", vtemp); recv_buffers[line_nr].erase(recv_buffers[line_nr].begin()); // still data in buffer? generate interrupt if (recv_buffers[line_nr].empty() == false) { registers[line_nr * 4 + 0] |= 128; // DONE: bit 7 if (is_rx_interrupt_enabled(line_nr)) trigger_interrupt(line_nr); } } } DOLOG(debug, true, "DC11: read register %06o (line %d): %06o", addr, line_nr, vtemp); printf("DC11: read register %06o (line %d): %06o\r\n", addr, line_nr, vtemp); return vtemp; } void dc11::write_byte(const uint16_t addr, const uint8_t v) { uint16_t vtemp = registers[(addr - DC11_BASE) / 2]; if (addr & 1) { vtemp &= ~0xff00; vtemp |= v << 8; } else { vtemp &= ~0x00ff; vtemp |= v; } write_word(addr, vtemp); } void dc11::write_word(const uint16_t addr, uint16_t v) { int reg = (addr - DC11_BASE) / 2; int line_nr = reg / 4; DOLOG(debug, true, "DC11: write register %06o (%d line_nr %d) to %06o", addr, reg, line_nr, v); printf("DC11: write register %06o (%d line_nr %d) to %06o\r\n", addr, reg, line_nr, v); if ((reg & 3) == 3) { // transmit buffer char c = v & 127; // TODO handle failed transmit printf("%ld\r\n", write(pfds[dc11_n_lines + line_nr].fd, &c, 1)); if (is_tx_interrupt_enabled(line_nr)) trigger_interrupt(line_nr); } registers[reg] = v; }