diff options
author | AJR <ajrhacker@users.noreply.github.com> | 2022-11-19 08:37:37 -0500 |
---|---|---|
committer | AJR <ajrhacker@users.noreply.github.com> | 2022-11-19 08:38:19 -0500 |
commit | 70deb801709efaffee2cc799e2a62c5beeec377a (patch) | |
tree | 78b07013273968d2514cdf3534e29604b88d7650 /src/devices | |
parent | 04ac8329dca93d226be099937bc32f3cf03ac508 (diff) |
nios2: Preliminary execution core and gdb support
Diffstat (limited to 'src/devices')
-rw-r--r-- | src/devices/cpu/nios2/nios2.cpp | 506 | ||||
-rw-r--r-- | src/devices/cpu/nios2/nios2.h | 15 | ||||
-rw-r--r-- | src/devices/cpu/nios2/nios2dasm.cpp | 2 |
3 files changed, 515 insertions, 8 deletions
diff --git a/src/devices/cpu/nios2/nios2.cpp b/src/devices/cpu/nios2/nios2.cpp index 39dd0fc6209..b2f1868deed 100644 --- a/src/devices/cpu/nios2/nios2.cpp +++ b/src/devices/cpu/nios2/nios2.cpp @@ -4,7 +4,9 @@ Altera Nios II soft processor - Currently this device is just a stub with no actual execution core. + Currently only a rudimentary execution core is provided. No attempt + has been made yet to emulate correct timings, pipelining, cache + control, interrupts, trap instructions, etc. ***************************************************************************/ @@ -20,6 +22,7 @@ nios2_device::nios2_device(const machine_config &mconfig, const char *tag, devic , m_program_config("program", ENDIANNESS_LITTLE, 32, 32, 0) { std::fill(std::begin(m_gpr), std::end(m_gpr), 0); + std::fill(std::begin(m_ctl), std::end(m_ctl), 0); } std::unique_ptr<util::disasm_interface> nios2_device::create_disassembler() @@ -34,8 +37,19 @@ device_memory_interface::space_config_vector nios2_device::memory_space_config() }; } +namespace { + +static const char *const s_ctl_names[16] = +{ + "status", "estatus", "bstatus", "ienable", "ipending", "cpuid", "ctl6", "exception", + "pteaddr", "tlbacc", "tlbmisc", "eccinj", "badaddr", "config", "mpubase", "mpuacc" +}; + +} // anonymous namespace + void nios2_device::device_start() { + space(AS_PROGRAM).specific(m_space); space(AS_PROGRAM).cache(m_cache); set_icountptr(m_icount); @@ -43,20 +57,502 @@ void nios2_device::device_start() state_add(NIOS2_PC, "PC", m_pc); state_add(STATE_GENPC, "GENPC", m_pc).noshow(); state_add(STATE_GENPCBASE, "CURPC", m_pc).noshow(); - for (int i = 1; i < 32; i++) - state_add(NIOS2_R1 + i - 1, util::string_format("r%d", i).c_str(), m_gpr[i]); + state_add<u32>(NIOS2_ZERO, "zero", []() { return 0; }).noshow(); + state_add(NIOS2_AT, "at", m_gpr[1]); + for (int i = 2; i < 24; i++) + state_add(NIOS2_R2 + i - 2, util::string_format("r%d", i).c_str(), m_gpr[i]); + state_add(NIOS2_ET, "et", m_gpr[24]); + state_add(NIOS2_BT, "bt", m_gpr[25]); + state_add(NIOS2_GP, "gp", m_gpr[26]); + state_add(NIOS2_SP, "sp", m_gpr[27]); + state_add(NIOS2_FP, "fp", m_gpr[28]); + state_add(NIOS2_EA, "ea", m_gpr[29]); + state_add(NIOS2_BA, "ba", m_gpr[30]); + state_add(NIOS2_RA, "ra", m_gpr[31]); + for (int n = 0; n < 16; n++) + state_add(NIOS2_STATUS + n, s_ctl_names[n], m_ctl[n]); save_item(NAME(m_gpr)); + save_item(NAME(m_ctl)); save_item(NAME(m_pc)); } void nios2_device::device_reset() { m_pc = 0; + m_ctl[0] = 0; // clear status +} + +u32 nios2_device::read_ctl(unsigned r) const +{ + if (r < std::size(m_ctl)) + return m_ctl[r]; + else + return 0; +} + +void nios2_device::write_ctl(unsigned r, u32 val) +{ + if (r < std::size(m_ctl)) + m_ctl[r] = val; } void nios2_device::execute_run() { - debugger_instruction_hook(m_pc); - m_icount = 0; + do + { + debugger_instruction_hook(m_pc); + u32 inst = m_cache.read_dword(m_pc); + + switch (BIT(inst, 0, 6)) + { + case 0x00: // call + m_gpr[31] = m_pc + 4; + m_pc = (m_pc & 0xf0000000) | (inst >> 4); + m_icount--; + break; + + case 0x01: // jmpi + m_pc = (m_pc & 0xf0000000) | (inst >> 4); + m_icount--; + break; + + case 0x03: case 0x23: // ldbu(io) + m_gpr[BIT(inst, 22, 5)] = m_space.read_byte(get_reg(BIT(inst, 27, 5)) + s16(BIT(inst, 6, 16))); + m_pc += 4; + m_icount--; + break; + + case 0x04: // addi + m_gpr[BIT(inst, 22, 5)] = get_reg(BIT(inst, 27, 5)) + s16(BIT(inst, 6, 16)); + m_pc += 4; + m_icount--; + break; + + case 0x05: case 0x25: // stbio + m_space.write_byte(get_reg(BIT(inst, 27, 5)) + s16(BIT(inst, 6, 16)), get_reg(BIT(inst, 22, 5)) & 0xff); + m_pc += 4; + m_icount--; + break; + + case 0x06: // br + m_pc += 4 + s32(s16(BIT(inst, 6, 16))); + m_icount--; + break; + + case 0x07: case 0x27: // ldb(io) + m_gpr[BIT(inst, 22, 5)] = s32(s8(m_space.read_byte(get_reg(BIT(inst, 27, 5)) + s16(BIT(inst, 6, 16))))); + m_pc += 4; + m_icount--; + break; + + case 0x08: // cmpgei + m_gpr[BIT(inst, 22, 5)] = s32(get_reg(BIT(inst, 27, 5))) >= s16(BIT(inst, 6, 16)) ? 1 : 0; + m_pc += 4; + m_icount--; + break; + + case 0x0b: case 0x2b: // ldhu(io) + m_gpr[BIT(inst, 22, 5)] = m_space.read_word(get_reg(BIT(inst, 27, 5)) + s16(BIT(inst, 6, 16))); + m_pc += 4; + m_icount--; + break; + + case 0x0c: // andi + m_gpr[BIT(inst, 22, 5)] = get_reg(BIT(inst, 27, 5)) & BIT(inst, 6, 16); + m_pc += 4; + m_icount--; + break; + + case 0x0d: case 0x2d: // sth(io) + m_space.write_word(get_reg(BIT(inst, 27, 5)) + s16(BIT(inst, 6, 16)), get_reg(BIT(inst, 22, 5)) & 0xffff); + m_pc += 4; + m_icount--; + break; + + case 0x0e: // bge + if (s32(get_reg(BIT(inst, 27, 5))) >= s32(get_reg(BIT(inst, 22, 5)))) + m_pc += 4 + s32(s16(BIT(inst, 6, 16))); + else + m_pc += 4; + m_icount--; + break; + + case 0x0f: case 0x2f: // ldh(io) + m_gpr[BIT(inst, 22, 5)] = s32(s16(m_space.read_word(get_reg(BIT(inst, 27, 5)) + s16(BIT(inst, 6, 16))))); + m_pc += 4; + m_icount--; + break; + + case 0x10: // cmplti + m_gpr[BIT(inst, 22, 5)] = s32(get_reg(BIT(inst, 27, 5))) < s16(BIT(inst, 6, 16)) ? 1 : 0; + m_pc += 4; + m_icount--; + break; + + case 0x14: // ori + m_gpr[BIT(inst, 22, 5)] = get_reg(BIT(inst, 27, 5)) | BIT(inst, 6, 16); + m_pc += 4; + m_icount--; + break; + + case 0x15: case 0x35: // stw(io) + m_space.write_dword(get_reg(BIT(inst, 27, 5)) + s16(BIT(inst, 6, 16)), get_reg(BIT(inst, 22, 5))); + m_pc += 4; + m_icount--; + break; + + case 0x16: // blt + if (s32(get_reg(BIT(inst, 27, 5))) < s32(get_reg(BIT(inst, 22, 5)))) + m_pc += 4 + s32(s16(BIT(inst, 6, 16))); + else + m_pc += 4; + m_icount--; + break; + + case 0x17: case 0x37: // ldw(io) + m_gpr[BIT(inst, 22, 5)] = m_space.read_dword(get_reg(BIT(inst, 27, 5)) + s16(BIT(inst, 6, 16))); + m_pc += 4; + m_icount--; + break; + + case 0x18: // cmpnei + m_gpr[BIT(inst, 22, 5)] = get_reg(BIT(inst, 27, 5)) != s32(s16(BIT(inst, 6, 16))) ? 1 : 0; + m_pc += 4; + m_icount--; + break; + + case 0x1c: // xori + m_gpr[BIT(inst, 22, 5)] = get_reg(BIT(inst, 27, 5)) ^ BIT(inst, 6, 16); + m_pc += 4; + m_icount--; + break; + + case 0x1e: // bne + if (get_reg(BIT(inst, 27, 5)) != get_reg(BIT(inst, 22, 5))) + m_pc += 4 + s32(s16(BIT(inst, 6, 16))); + else + m_pc += 4; + m_icount--; + break; + + case 0x20: // cmpeqi + m_gpr[BIT(inst, 22, 5)] = get_reg(BIT(inst, 27, 5)) == s32(s16(BIT(inst, 6, 16))) ? 1 : 0; + m_pc += 4; + m_icount--; + break; + + case 0x24: // muli + m_gpr[BIT(inst, 22, 5)] = s32(get_reg(BIT(inst, 27, 5))) * s16(BIT(inst, 6, 16)); + m_pc += 4; + m_icount--; + break; + + case 0x26: // beq + if (get_reg(BIT(inst, 27, 5)) == get_reg(BIT(inst, 22, 5))) + m_pc += 4 + s32(s16(BIT(inst, 6, 16))); + else + m_pc += 4; + m_icount--; + break; + + case 0x28: // cmpgeui + m_gpr[BIT(inst, 22, 5)] = get_reg(BIT(inst, 27, 5)) >= BIT(inst, 6, 16) ? 1 : 0; + m_pc += 4; + m_icount--; + break; + + case 0x2c: // andhi + m_gpr[BIT(inst, 22, 5)] = get_reg(BIT(inst, 27, 5)) & (BIT(inst, 6, 16) << 16); + m_pc += 4; + m_icount--; + break; + + case 0x2e: // bgeu + if (get_reg(BIT(inst, 27, 5)) >= get_reg(BIT(inst, 22, 5))) + m_pc += 4 + s32(s16(BIT(inst, 6, 16))); + else + m_pc += 4; + m_icount--; + break; + + case 0x30: // cmpltui + m_gpr[BIT(inst, 22, 5)] = get_reg(BIT(inst, 27, 5)) < BIT(inst, 6, 16) ? 1 : 0; + m_pc += 4; + m_icount--; + break; + + case 0x33: // initd + logerror("initd 0x%08X\n", get_reg(BIT(inst, 27, 5) + s16(BIT(inst, 6, 16)))); + m_pc += 4; + m_icount--; + break; + + case 0x34: // orhi + m_gpr[BIT(inst, 22, 5)] = get_reg(BIT(inst, 27, 5)) | (BIT(inst, 6, 16) << 16); + m_pc += 4; + m_icount--; + break; + + case 0x36: // bltu + if (get_reg(BIT(inst, 27, 5)) < get_reg(BIT(inst, 22, 5))) + m_pc += 4 + s32(s16(BIT(inst, 6, 16))); + else + m_pc += 4; + m_icount--; + break; + + case 0x3a: + switch (BIT(inst, 11, 6)) + { + case 0x01: // eret + case 0x05: // ret + case 0x09: // bret + case 0x0d: // jmp + m_pc = get_reg(BIT(inst, 27, 5)); + m_icount--; + break; + + case 0x02: // roli + m_gpr[BIT(inst, 17, 5)] = rotl_32(get_reg(BIT(inst, 27, 5)), BIT(inst, 6, 5)); + m_pc += 4; + m_icount--; + break; + + case 0x03: // rol + m_gpr[BIT(inst, 17, 5)] = rotl_32(get_reg(BIT(inst, 27, 5)), get_reg(BIT(inst, 22, 5))); + m_pc += 4; + m_icount--; + break; + + case 0x04: // flushp + logerror("flushp instruction encountered (PC = 0x%08X)\n", m_pc); + m_pc += 4; + m_icount--; + break; + + case 0x06: // nor + m_gpr[BIT(inst, 17, 5)] = ~(get_reg(BIT(inst, 27, 5)) | get_reg(BIT(inst, 22, 5))); + m_pc += 4; + m_icount--; + break; + + case 0x07: // mulxuu + m_gpr[BIT(inst, 17, 5)] = mulu_32x32_hi(get_reg(BIT(inst, 27, 5)), get_reg(BIT(inst, 22, 5))); + m_pc += 4; + m_icount--; + break; + + case 0x08: // cmpge + m_gpr[BIT(inst, 17, 5)] = s32(get_reg(BIT(inst, 27, 5))) >= s32(get_reg(BIT(inst, 22, 5))) ? 1 : 0; + m_pc += 4; + m_icount--; + break; + + case 0x0b: // ror + m_gpr[BIT(inst, 17, 5)] = rotr_32(get_reg(BIT(inst, 27, 5)), get_reg(BIT(inst, 22, 5))); + m_pc += 4; + m_icount--; + break; + + case 0x0c: // flushi + logerror("flushi 0x%08X (PC = 0x%08X)\n", get_reg(BIT(inst, 27, 5)), m_pc); + m_pc += 4; + m_icount--; + break; + + case 0x0e: // and + m_gpr[BIT(inst, 17, 5)] = get_reg(BIT(inst, 27, 5)) & get_reg(BIT(inst, 22, 5)); + m_pc += 4; + m_icount--; + break; + + case 0x10: // cmplt + m_gpr[BIT(inst, 17, 5)] = s32(get_reg(BIT(inst, 27, 5))) < s32(get_reg(BIT(inst, 22, 5))) ? 1 : 0; + m_pc += 4; + m_icount--; + break; + + case 0x12: // slli + m_gpr[BIT(inst, 17, 5)] = get_reg(BIT(inst, 27, 5)) << BIT(inst, 6, 5); + m_pc += 4; + m_icount--; + break; + + case 0x13: // sll + m_gpr[BIT(inst, 17, 5)] = get_reg(BIT(inst, 27, 5)) << (get_reg(BIT(inst, 22, 5)) & 0x1f); + m_pc += 4; + m_icount--; + break; + + case 0x17: // mulxsu + m_gpr[BIT(inst, 17, 5)] = (s64(s32(get_reg(BIT(inst, 27, 5)))) * u64(get_reg(BIT(inst, 22, 5)))) >> 32; + m_pc += 4; + m_icount--; + break; + + case 0x18: // cmpne + m_gpr[BIT(inst, 17, 5)] = get_reg(BIT(inst, 27, 5)) != get_reg(BIT(inst, 22, 5)) ? 1 : 0; + m_pc += 4; + m_icount--; + break; + + case 0x16: // or + m_gpr[BIT(inst, 17, 5)] = get_reg(BIT(inst, 27, 5)) & get_reg(BIT(inst, 22, 5)); + m_pc += 4; + m_icount--; + break; + + case 0x1a: // srli + m_gpr[BIT(inst, 17, 5)] = get_reg(BIT(inst, 27, 5)) >> BIT(inst, 6, 5); + m_pc += 4; + m_icount--; + break; + + case 0x1b: // srl + m_gpr[BIT(inst, 17, 5)] = get_reg(BIT(inst, 27, 5)) >> (get_reg(BIT(inst, 22, 5)) & 0x1f); + m_pc += 4; + m_icount--; + break; + + case 0x1c: // nextpc + m_gpr[BIT(inst, 17, 5)] = m_pc += 4; + m_icount--; + break; + + case 0x1d: // callr + m_gpr[BIT(inst, 17, 5)] = m_pc + 4; + m_pc = get_reg(BIT(inst, 27, 5)); + m_icount--; + break; + + case 0x1e: // xor + m_gpr[BIT(inst, 17, 5)] = get_reg(BIT(inst, 27, 5)) ^ get_reg(BIT(inst, 22, 5)); + m_pc += 4; + m_icount--; + break; + + case 0x1f: // mulxss + m_gpr[BIT(inst, 17, 5)] = mul_32x32_hi(get_reg(BIT(inst, 27, 5)), get_reg(BIT(inst, 22, 5))); + m_pc += 4; + m_icount--; + break; + + case 0x20: // cmpeq + m_gpr[BIT(inst, 17, 5)] = get_reg(BIT(inst, 27, 5)) == get_reg(BIT(inst, 22, 5)) ? 1 : 0; + m_pc += 4; + m_icount--; + break; + + case 0x24: // divu + if (u32 divisor = get_reg(BIT(inst, 22, 5)); divisor != 0) + m_gpr[BIT(inst, 17, 5)] = get_reg(BIT(inst, 27, 5)) / divisor; + else + { + logerror("Divide by 0 at PC = 0x%08X\n", m_pc); + m_gpr[BIT(inst, 17, 5)] = 0xffffffff; // result is undefined + } + m_pc += 4; + m_icount--; + break; + + case 0x25: // div + if (s32 divisor = get_reg(BIT(inst, 22, 5)); divisor != 0) + m_gpr[BIT(inst, 17, 5)] = s32(get_reg(BIT(inst, 27, 5)) / divisor); + else + { + logerror("Divide by 0 at PC = 0x%08X\n", m_pc); + m_gpr[BIT(inst, 17, 5)] = 0xffffffff; // result is undefined + } + m_pc += 4; + m_icount--; + break; + + case 0x26: // rdctl + m_gpr[BIT(inst, 17, 5)] = read_ctl(BIT(inst, 6, 5)); + m_pc += 4; + m_icount--; + break; + + case 0x27: // mul + m_gpr[BIT(inst, 17, 5)] = get_reg(BIT(inst, 27, 5)) * get_reg(BIT(inst, 22, 5)); + m_pc += 4; + m_icount--; + break; + + case 0x28: // cmpgeu + m_gpr[BIT(inst, 17, 5)] = get_reg(BIT(inst, 27, 5)) >= get_reg(BIT(inst, 22, 5)) ? 1 : 0; + m_pc += 4; + m_icount--; + break; + + case 0x29: // initi + logerror("initi 0x%08X (PC = 0x%08X)\n", get_reg(BIT(inst, 27, 5)), m_pc); + m_pc += 4; + m_icount--; + break; + + case 0x2e: // wrctl + write_ctl(BIT(inst, 6, 5), get_reg(BIT(inst, 27, 5))); + m_pc += 4; + m_icount--; + break; + + case 0x30: // cmpltu + m_gpr[BIT(inst, 17, 5)] = get_reg(BIT(inst, 27, 5)) < get_reg(BIT(inst, 22, 5)) ? 1 : 0; + m_pc += 4; + m_icount--; + break; + + case 0x31: // add + m_gpr[BIT(inst, 17, 5)] = get_reg(BIT(inst, 27, 5)) + get_reg(BIT(inst, 22, 5)); + m_pc += 4; + m_icount--; + break; + + case 0x36: // sync + logerror("sync instruction encountered (PC = 0x%08X)\n", m_pc); + m_pc += 4; + m_icount--; + break; + + case 0x39: // sub + m_gpr[BIT(inst, 17, 5)] = get_reg(BIT(inst, 27, 5)) - get_reg(BIT(inst, 22, 5)); + m_pc += 4; + m_icount--; + break; + + case 0x3a: // srai + m_gpr[BIT(inst, 17, 5)] = s32(get_reg(BIT(inst, 27, 5))) >> BIT(inst, 6, 5); + m_pc += 4; + m_icount--; + break; + + case 0x3b: // sra + m_gpr[BIT(inst, 17, 5)] = s32(get_reg(BIT(inst, 27, 5))) >> (get_reg(BIT(inst, 22, 5)) & 0x1f); + m_pc += 4; + m_icount--; + break; + + default: + logerror("Unknown/invalid R-type instruction word encountered (OPX = 0x%02X, PC = 0x%08X)\n", BIT(inst, 11, 6), m_pc); + m_pc += 4; + m_icount--; + break; + } + break; + + case 0x3c: // xorhi + m_gpr[BIT(inst, 22, 5)] = get_reg(BIT(inst, 27, 5)) ^ (BIT(inst, 6, 16) << 16); + m_pc += 4; + m_icount--; + break; + + default: + logerror("Unknown/invalid instruction word encountered (OP = 0x%02X, PC = 0x%08X)\n", BIT(inst, 0, 6), m_pc); + m_pc += 4; + m_icount--; + break; + } + } while (m_icount > 0); } diff --git a/src/devices/cpu/nios2/nios2.h b/src/devices/cpu/nios2/nios2.h index de2073e0e47..5ec25c8369d 100644 --- a/src/devices/cpu/nios2/nios2.h +++ b/src/devices/cpu/nios2/nios2.h @@ -10,11 +10,15 @@ class nios2_device : public cpu_device { public: enum { - NIOS2_R1 = 1, NIOS2_R2, NIOS2_R3, NIOS2_R4, NIOS2_R5, NIOS2_R6, NIOS2_R7, + NIOS2_ZERO = 0, NIOS2_AT, NIOS2_R2, NIOS2_R3, NIOS2_R4, NIOS2_R5, NIOS2_R6, NIOS2_R7, NIOS2_R8, NIOS2_R9, NIOS2_R10, NIOS2_R11, NIOS2_R12, NIOS2_R13, NIOS2_R14, NIOS2_R15, NIOS2_R16, NIOS2_R17, NIOS2_R18, NIOS2_R19, NIOS2_R20, NIOS2_R21, NIOS2_R22, NIOS2_R23, - NIOS2_R24, NIOS2_R25, NIOS2_R26, NIOS2_R27, NIOS2_R28, NIOS2_R29, NIOS2_R30, NIOS2_R31, + NIOS2_ET, NIOS2_BT, NIOS2_GP, NIOS2_SP, NIOS2_FP, NIOS2_EA, NIOS2_BA, NIOS2_RA, NIOS2_PC, + NIOS2_STATUS, NIOS2_BSTATUS, NIOS2_ESTATUS, NIOS2_IENABLE, + NIOS2_IPENDING, NIOS2_CPUID, NIOS2_CTLID, NIOS2_EXCEPTION, + NIOS2_PTEADDR, NIOS2_TLBACC, NIOS2_TLBMISC, NIOS2_ECCINJ, + NIOS2_BADADDR, NIOS2_CONFIG, NIOS2_MPUBASE, NIOS2_MPUACC }; // construction/destruction @@ -35,12 +39,19 @@ protected: virtual space_config_vector memory_space_config() const override; private: + u32 get_reg(unsigned r) const noexcept { return r == 0 ? 0 : m_gpr[r]; } + + u32 read_ctl(unsigned r) const; + void write_ctl(unsigned r, u32 val); + // address space address_space_config m_program_config; + memory_access<32, 2, 0, ENDIANNESS_LITTLE>::specific m_space; memory_access<32, 2, 0, ENDIANNESS_LITTLE>::cache m_cache; // internal registers u32 m_gpr[32]; + u32 m_ctl[16]; u32 m_pc; s32 m_icount; }; diff --git a/src/devices/cpu/nios2/nios2dasm.cpp b/src/devices/cpu/nios2/nios2dasm.cpp index ae58986c67a..6b8e18a62cb 100644 --- a/src/devices/cpu/nios2/nios2dasm.cpp +++ b/src/devices/cpu/nios2/nios2dasm.cpp @@ -52,7 +52,7 @@ const char *const s_reg_names[32] = const char *const s_ctlreg_names[16] = { "status", "estatus", "bstatus", "ienable", "ipending", "cpuid", "ctl6", "exception", - "pteaddr", "tlbacc", "tlbmisc", "ctl11", "badaddr", "config", "mpubase", "mpuacc" + "pteaddr", "tlbacc", "tlbmisc", "eccinj", "badaddr", "config", "mpubase", "mpuacc" }; } // anonymous namespace |