mirror of
https://github.com/google0101-ryan/Emotional.git
synced 2024-05-11 17:15:30 -04:00
Lots of changes
This commit is contained in:
parent
32c7787c86
commit
72ba66a000
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,4 +1,5 @@
|
|||
build
|
||||
compile_commands.json
|
||||
.clangd
|
||||
.vscode
|
||||
.vscode
|
||||
boost
|
|
@ -5,7 +5,8 @@ set(CMAKE_MINIMUM_REQUIRED_VERSION 3.16.3)
|
|||
set(SOURCES src/main.cpp
|
||||
src/app/Application.cpp
|
||||
src/emu/Bus.cpp
|
||||
src/emu/cpu/EmotionEngine.cpp)
|
||||
src/emu/cpu/EmotionEngine.cpp
|
||||
src/emu/cpu/instructions.cpp)
|
||||
|
||||
set(CMAKE_BUILD_TYPE DEBUG)
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ class Bus
|
|||
private:
|
||||
uint8_t ram[0x2000000];
|
||||
uint8_t bios[0x400000];
|
||||
uint8_t scratchpad[0x4000];
|
||||
|
||||
uint32_t Translate(uint32_t addr)
|
||||
{
|
||||
|
@ -40,9 +41,40 @@ public:
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
void write(uint32_t addr, T)
|
||||
void write(uint32_t addr, T data)
|
||||
{
|
||||
addr = Translate(addr);
|
||||
|
||||
if (addr >= 0x70000000 && addr < 0x70004000)
|
||||
{
|
||||
*(T*)&scratchpad[addr - 0x70000000] = data;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0x1000f500:
|
||||
return;
|
||||
}
|
||||
|
||||
printf("[emu/Bus]: %s: Write to unknown addr 0x%08x\n", __FUNCTION__, addr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Returns whether a region of memory is cacheable by the bus
|
||||
bool IsCacheable(uint32_t addr)
|
||||
{
|
||||
if (addr <= 0x7FFFFFFF)
|
||||
return true;
|
||||
else if (addr >= 0x80000000 && addr <= 0x9FFFFFFF)
|
||||
return true;
|
||||
else if (addr >= 0xA0000000 && addr <= 0xBFFFFFFF)
|
||||
return false;
|
||||
else if (addr >= 0xC0000000 && addr <= 0xDFFFFFFF)
|
||||
return true;
|
||||
else if (addr >= 0xE0000000 && addr <= 0xFFFFFFF)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
};
|
|
@ -11,6 +11,8 @@ EmotionEngine::EmotionEngine(Bus* bus)
|
|||
memset(regs, 0, sizeof(regs));
|
||||
pc = 0xBFC00000;
|
||||
next_pc = pc + 4;
|
||||
|
||||
cop0_regs[15] = 0x2E20;
|
||||
}
|
||||
|
||||
void EmotionEngine::Clock()
|
||||
|
@ -18,16 +20,99 @@ void EmotionEngine::Clock()
|
|||
Opcode instr;
|
||||
instr.full = Read32Instr(pc);
|
||||
|
||||
AdvancePC();
|
||||
|
||||
if (instr.full == 0)
|
||||
{
|
||||
printf("nop\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (instr.r_type.opcode)
|
||||
{
|
||||
case 0x00:
|
||||
{
|
||||
switch (instr.r_type.func)
|
||||
{
|
||||
case 0x00:
|
||||
sll(instr);
|
||||
break;
|
||||
case 0x08:
|
||||
jr(instr);
|
||||
break;
|
||||
case 0x09:
|
||||
jalr(instr);
|
||||
break;
|
||||
case 0x0F:
|
||||
printf("sync\n");
|
||||
break;
|
||||
case 0x2d:
|
||||
daddu(instr);
|
||||
break;
|
||||
default:
|
||||
printf("[emu/CPU]: %s: Unknown special instruction 0x%08x (0x%02x)\n", __FUNCTION__, instr.full, instr.r_type.func);
|
||||
Application::Exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x03:
|
||||
j(instr);
|
||||
break;
|
||||
case 0x05:
|
||||
bne(instr);
|
||||
break;
|
||||
case 0x09:
|
||||
addiu(instr);
|
||||
break;
|
||||
case 0x0A:
|
||||
slti(instr);
|
||||
break;
|
||||
case 0x0C:
|
||||
andi(instr);
|
||||
break;
|
||||
case 0x0D:
|
||||
ori(instr);
|
||||
break;
|
||||
case 0x0F:
|
||||
lui(instr);
|
||||
break;
|
||||
case 0x10:
|
||||
{
|
||||
switch (instr.r_type.rs)
|
||||
{
|
||||
case 0:
|
||||
mfc0(instr);
|
||||
break;
|
||||
case 4:
|
||||
mtc0(instr);
|
||||
break;
|
||||
case 0x10:
|
||||
printf("TODO: tlbwi\n");
|
||||
break;
|
||||
default:
|
||||
printf("[emu/CPU]: %s: Unknown cop0 instruction 0x%08x (0x%02x)\n", __FUNCTION__, instr.full, instr.r_type.rs);
|
||||
Application::Exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x2B:
|
||||
sw(instr);
|
||||
break;
|
||||
case 0x3f:
|
||||
sd(instr);
|
||||
break;
|
||||
default:
|
||||
printf("[emu/CPU]: %s: Unknown instruction 0x%08x (0x%02x)\n", __FUNCTION__, instr.full, instr.r_type.opcode);
|
||||
Application::Exit(1);
|
||||
}
|
||||
|
||||
regs[0].u64[0] = regs[0].u64[1] = 0;
|
||||
}
|
||||
|
||||
void EmotionEngine::Dump()
|
||||
{
|
||||
for (int i = 0; i < 32; i++)
|
||||
printf("[emu/CPU]: %s: r%d\t->\t%s\n", __FUNCTION__, i, print_128(regs[i]));
|
||||
printf("[emu/CPU]: %s: %s\t->\t%s\n", __FUNCTION__, Reg(i), print_128(regs[i]));
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "emu/Bus.h"
|
||||
#include "emu/cpu/opcode.h"
|
||||
#include "util/uint128.h"
|
||||
#include <bits/stdint-uintn.h>
|
||||
|
||||
|
@ -10,6 +11,7 @@ class EmotionEngine
|
|||
private:
|
||||
Bus* bus;
|
||||
uint128_t regs[32];
|
||||
uint32_t cop0_regs[32];
|
||||
uint32_t pc, next_pc;
|
||||
uint64_t hi, lo;
|
||||
|
||||
|
@ -17,53 +19,242 @@ private:
|
|||
{
|
||||
bool valid = false;
|
||||
bool dirty = false;
|
||||
bool lrf = false;
|
||||
uint32_t page = 0;
|
||||
};
|
||||
|
||||
struct Cache
|
||||
{
|
||||
CacheTag tag;
|
||||
uint8_t data[64] = {0};
|
||||
CacheTag tag[2];
|
||||
uint8_t data[2][64] = {0};
|
||||
} icache[128], dcache[64];
|
||||
|
||||
bool isCacheEnabled = false;
|
||||
|
||||
uint32_t Read32Instr(uint32_t addr)
|
||||
{
|
||||
if (!bus->IsCacheable(addr) || !isCacheEnabled)
|
||||
return bus->read<uint32_t>(addr);
|
||||
|
||||
uint32_t page = (addr >> 14);
|
||||
uint32_t index = (addr >> 5) & 8;
|
||||
uint32_t offset = addr & 0x3F;
|
||||
|
||||
Cache& line = icache[index];
|
||||
|
||||
if (line.tag.page != page || !line.tag.valid)
|
||||
for (int way = 0; way < 2; way++)
|
||||
{
|
||||
printf("[emu/CPU]: Cache miss at 0x%08x\n", addr);
|
||||
if (line.tag.dirty)
|
||||
if (line.tag[way].page == page && line.tag[way].valid)
|
||||
{
|
||||
uint32_t p = (line.tag.page << 14);
|
||||
for (int i = 0; i < 64; i++)
|
||||
bus->write(p+i, line.data[i]);
|
||||
return *((uint32_t*)&line.data[way][offset]);
|
||||
}
|
||||
line.tag.page = page;
|
||||
line.tag.valid = true;
|
||||
line.tag.dirty = false;
|
||||
for (int i = 0; i < 64; i++)
|
||||
{
|
||||
line.data[i] = bus->read<uint8_t>((page << 14) + i);
|
||||
}
|
||||
return *(uint32_t*)&line.data[offset];
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Cache hit at 0x%08x\n", addr);
|
||||
return *(uint32_t*)&line.data[offset];
|
||||
}
|
||||
|
||||
// Welp, cache miss
|
||||
printf("[emu/CPU]: Cache miss for address 0x%08x\n", addr);
|
||||
|
||||
int replace = 0;
|
||||
if (!line.tag[0].valid && line.tag[1].valid)
|
||||
replace = 0;
|
||||
else if (line.tag[0].valid && !line.tag[1].valid)
|
||||
replace = 1;
|
||||
else
|
||||
replace = line.tag[0].lrf ^ line.tag[1].lrf;
|
||||
|
||||
for (int i = 0; i < 64; i++)
|
||||
line.data[replace][i] = bus->read<uint8_t>((page << 14) + i);
|
||||
return *(uint32_t*)&line.data[replace][offset];
|
||||
}
|
||||
|
||||
void Write32(uint32_t addr, uint32_t data)
|
||||
{
|
||||
if (!bus->IsCacheable(addr) || !isCacheEnabled)
|
||||
{
|
||||
bus->write(addr, data);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t page = (addr >> 13);
|
||||
uint32_t index = (addr >> 5) & 0b1111111;
|
||||
uint32_t offset = addr & 0x3F;
|
||||
|
||||
Cache& line = dcache[index];
|
||||
|
||||
for (int way = 0; way < 2; way++)
|
||||
{
|
||||
if (line.tag[way].page == page && line.tag[way].valid)
|
||||
{
|
||||
*((uint32_t*)&line.data[way][offset]) = data;
|
||||
line.tag[way].dirty = true; // We mark as dirty to flush back to main memory on eviction
|
||||
}
|
||||
}
|
||||
|
||||
printf("[emu/CPU]: Cache miss for address 0x%08x\n", addr);
|
||||
|
||||
int replace = 0;
|
||||
if (!line.tag[0].valid && line.tag[1].valid)
|
||||
replace = 0;
|
||||
else if (line.tag[0].valid && !line.tag[1].valid)
|
||||
replace = 1;
|
||||
else
|
||||
replace = line.tag[0].lrf ^ line.tag[1].lrf;
|
||||
|
||||
if (line.tag[replace].dirty)
|
||||
{
|
||||
for (int i = 0; i < 64; i++)
|
||||
bus->write((page << 13) + i, line.data[replace][i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 64; i++)
|
||||
{
|
||||
line.data[replace][i] = bus->read<uint8_t>((page << 13) + i);
|
||||
}
|
||||
*(uint32_t*)&line.data[replace][offset] = data;
|
||||
line.tag[replace].dirty = true;
|
||||
}
|
||||
|
||||
void Write64(uint32_t addr, uint64_t data)
|
||||
{
|
||||
if (!bus->IsCacheable(addr) || !isCacheEnabled)
|
||||
{
|
||||
bus->write(addr, data);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t page = (addr >> 13);
|
||||
uint32_t index = (addr >> 5) & 0b1111111;
|
||||
uint32_t offset = addr & 0x3F;
|
||||
|
||||
Cache& line = dcache[index];
|
||||
|
||||
for (int way = 0; way < 2; way++)
|
||||
{
|
||||
if (line.tag[way].page == page && line.tag[way].valid)
|
||||
{
|
||||
*((uint64_t*)&line.data[way][offset]) = data;
|
||||
line.tag[way].dirty = true; // We mark as dirty to flush back to main memory on eviction
|
||||
}
|
||||
}
|
||||
|
||||
printf("[emu/CPU]: Cache miss for address 0x%08x\n", addr);
|
||||
|
||||
int replace = 0;
|
||||
if (!line.tag[0].valid && line.tag[1].valid)
|
||||
replace = 0;
|
||||
else if (line.tag[0].valid && !line.tag[1].valid)
|
||||
replace = 1;
|
||||
else
|
||||
replace = line.tag[0].lrf ^ line.tag[1].lrf;
|
||||
|
||||
if (line.tag[replace].dirty)
|
||||
{
|
||||
for (int i = 0; i < 64; i++)
|
||||
bus->write((page << 13) + i, line.data[replace][i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 64; i++)
|
||||
{
|
||||
line.data[replace][i] = bus->read<uint8_t>((page << 13) + i);
|
||||
}
|
||||
*(uint64_t*)&line.data[replace][offset] = data;
|
||||
line.tag[replace].dirty = true;
|
||||
}
|
||||
|
||||
void j(Opcode i); // 0x03
|
||||
void bne(Opcode i); // 0x05
|
||||
void addiu(Opcode i); // 0x09
|
||||
void slti(Opcode i); // 0x0A
|
||||
void andi(Opcode i); // 0x0C
|
||||
void ori(Opcode i); // 0x0D
|
||||
void lui(Opcode i); // 0x0F
|
||||
void mfc0(Opcode i); // 0x10 0x00
|
||||
void mtc0(Opcode i); // 0x10 0x04
|
||||
void sw(Opcode i); // 0x2B
|
||||
void sd(Opcode i); // 0x3f
|
||||
|
||||
void sll(Opcode i); // 0x00
|
||||
void jr(Opcode i); // 0x08
|
||||
void jalr(Opcode i); // 0x09
|
||||
void daddu(Opcode i); // 0x2d
|
||||
|
||||
void AdvancePC()
|
||||
{
|
||||
pc = next_pc;
|
||||
next_pc += 4;
|
||||
}
|
||||
|
||||
const char* Reg(int index)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
return "$zero";
|
||||
case 1:
|
||||
return "$at";
|
||||
case 2:
|
||||
return "$v0";
|
||||
case 3:
|
||||
return "$v1";
|
||||
case 4:
|
||||
return "$a0";
|
||||
case 5:
|
||||
return "$a1";
|
||||
case 6:
|
||||
return "$a2";
|
||||
case 7:
|
||||
return "$a3";
|
||||
case 8:
|
||||
return "$t0";
|
||||
case 9:
|
||||
return "$t1";
|
||||
case 10:
|
||||
return "$t2";
|
||||
case 11:
|
||||
return "$t3";
|
||||
case 12:
|
||||
return "$t4";
|
||||
case 13:
|
||||
return "$t5";
|
||||
case 14:
|
||||
return "$t6";
|
||||
case 15:
|
||||
return "$t7";
|
||||
case 16:
|
||||
return "$s0";
|
||||
case 17:
|
||||
return "$s1";
|
||||
case 18:
|
||||
return "$s2";
|
||||
case 19:
|
||||
return "$s3";
|
||||
case 20:
|
||||
return "$s4";
|
||||
case 21:
|
||||
return "$s5";
|
||||
case 22:
|
||||
return "$s6";
|
||||
case 23:
|
||||
return "$s7";
|
||||
case 24:
|
||||
return "$t8";
|
||||
case 25:
|
||||
return "$t9";
|
||||
case 26:
|
||||
return "$k0";
|
||||
case 27:
|
||||
return "$k1";
|
||||
case 28:
|
||||
return "$gp";
|
||||
case 29:
|
||||
return "$sp";
|
||||
case 30:
|
||||
return "$fp";
|
||||
case 31:
|
||||
return "$ra";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
public:
|
||||
EmotionEngine(Bus* bus);
|
||||
|
||||
|
|
141
src/emu/cpu/instructions.cpp
Normal file
141
src/emu/cpu/instructions.cpp
Normal file
|
@ -0,0 +1,141 @@
|
|||
#include "emu/cpu/opcode.h"
|
||||
#include <bits/stdint-intn.h>
|
||||
#include <bits/stdint-uintn.h>
|
||||
#include <cstdio>
|
||||
#include <emu/cpu/EmotionEngine.h>
|
||||
|
||||
void EmotionEngine::j(Opcode i)
|
||||
{
|
||||
uint32_t target = (i.j_type.target << 2);
|
||||
next_pc = (pc & 0xF0000000) | target;
|
||||
printf("j 0x%08x\n", next_pc);
|
||||
}
|
||||
|
||||
void EmotionEngine::bne(Opcode i)
|
||||
{
|
||||
int32_t imm = (int32_t)((uint32_t)i.i_type.imm << 2);
|
||||
|
||||
printf("bne %s, %s, 0x%08x\n", Reg(i.i_type.rs), Reg(i.i_type.rt), next_pc + imm);
|
||||
|
||||
if ((int32_t)regs[i.i_type.rs].u32[0] != (int32_t)regs[i.i_type.rt].u32[0])
|
||||
{
|
||||
next_pc = pc + imm;
|
||||
}
|
||||
}
|
||||
|
||||
void EmotionEngine::addiu(Opcode i)
|
||||
{
|
||||
int rt = i.i_type.rt;
|
||||
int rs = i.i_type.rs;
|
||||
int32_t imm = (int16_t)(uint32_t)i.i_type.imm;
|
||||
|
||||
regs[rt].u32[0] = (uint32_t)((int32_t)regs[rt].u32[0] + imm);
|
||||
|
||||
printf("addiu %s, %s, %d\n", Reg(rt), Reg(rs), imm);
|
||||
}
|
||||
|
||||
void EmotionEngine::slti(Opcode i)
|
||||
{
|
||||
regs[i.i_type.rt].u32[0] = (int32_t)regs[i.i_type.rs].u32[0] < (int32_t)(uint32_t)i.i_type.imm;
|
||||
printf("slti %s, %s, 0x%04x\n", Reg(i.i_type.rt), Reg(i.i_type.rs), i.i_type.imm);
|
||||
}
|
||||
|
||||
void EmotionEngine::andi(Opcode i)
|
||||
{
|
||||
regs[i.i_type.rt].u32[0] = regs[i.i_type.rs].u32[0] & (uint32_t)(int32_t)i.i_type.imm;
|
||||
printf("andi %s, %s, 0x%08x\n", Reg(i.i_type.rt), Reg(i.i_type.rs), i.i_type.imm);
|
||||
}
|
||||
|
||||
void EmotionEngine::ori(Opcode i)
|
||||
{
|
||||
regs[i.i_type.rt].u32[0] = regs[i.i_type.rs].u32[0] | (uint32_t)(int32_t)i.i_type.imm;
|
||||
printf("ori %s, %s, 0x%08x\n", Reg(i.i_type.rt), Reg(i.i_type.rs), i.i_type.imm);
|
||||
}
|
||||
|
||||
void EmotionEngine::lui(Opcode i)
|
||||
{
|
||||
regs[i.i_type.rt].u32[0] = (int32_t)((uint32_t)i.i_type.imm << 16);
|
||||
printf("lui %s, 0x%08x\n", Reg(i.i_type.rt), regs[i.i_type.rt].u32[0]);
|
||||
}
|
||||
|
||||
void EmotionEngine::mfc0(Opcode i)
|
||||
{
|
||||
regs[i.r_type.rt].u32[0] = cop0_regs[i.r_type.rd];
|
||||
printf("mfc0 %s, r%d\n", Reg(i.r_type.rt), i.r_type.rd);
|
||||
}
|
||||
|
||||
void EmotionEngine::mtc0(Opcode i)
|
||||
{
|
||||
cop0_regs[i.r_type.rd] = regs[i.r_type.rt].u32[0];
|
||||
printf("mtc0 %s, r%d\n", Reg(i.r_type.rt), i.r_type.rd);
|
||||
}
|
||||
|
||||
void EmotionEngine::sw(Opcode i)
|
||||
{
|
||||
int base = i.i_type.rs;
|
||||
int rt = i.i_type.rt;
|
||||
int16_t off = (int16_t)i.i_type.imm;
|
||||
|
||||
uint32_t addr = regs[base].u32[0] + off;
|
||||
|
||||
Write32(addr, regs[rt].u32[0]);
|
||||
|
||||
printf("sw %s, %d(%s)\n", Reg(rt), off, Reg(base));
|
||||
}
|
||||
|
||||
void EmotionEngine::sd(Opcode i)
|
||||
{
|
||||
int base = i.i_type.rs;
|
||||
int rt = i.i_type.rt;
|
||||
int16_t off = (int16_t)i.i_type.imm;
|
||||
|
||||
uint32_t addr = regs[base].u32[0] + off;
|
||||
|
||||
Write64(addr, regs[rt].u32[0]);
|
||||
|
||||
printf("sd %s, %d(%s)\n", Reg(rt), off, Reg(base));
|
||||
}
|
||||
|
||||
|
||||
void EmotionEngine::jr(Opcode i)
|
||||
{
|
||||
next_pc = regs[i.r_type.rs].u32[0];
|
||||
printf("jr %s\n", Reg(i.r_type.rs));
|
||||
}
|
||||
|
||||
|
||||
void EmotionEngine::sll(Opcode i)
|
||||
{
|
||||
int rd = i.r_type.rd;
|
||||
int rt = i.r_type.rt;
|
||||
int sa = i.r_type.sa;
|
||||
|
||||
regs[rd].u32[0] = regs[rt].u32[0] << sa;
|
||||
|
||||
printf("sll %s, %s, %d\n", Reg(rd), Reg(rt), sa);
|
||||
}
|
||||
|
||||
void EmotionEngine::jalr(Opcode i)
|
||||
{
|
||||
int rs = i.r_type.rs;
|
||||
int rd = i.r_type.rd;
|
||||
|
||||
regs[rd].u32[0] = next_pc;
|
||||
next_pc = regs[rs].u32[0];
|
||||
|
||||
printf("jalr %s, %s\n", Reg(rs), Reg(rd));
|
||||
}
|
||||
|
||||
void EmotionEngine::daddu(Opcode i)
|
||||
{
|
||||
int rd = i.r_type.rd;
|
||||
int rs = i.r_type.rs;
|
||||
int rt = i.r_type.rt;
|
||||
|
||||
int64_t reg1 = regs[rs].u64[0];
|
||||
int64_t reg2 = regs[rt].u64[0];
|
||||
|
||||
regs[rd].u64[0] = reg1 + reg2;
|
||||
|
||||
printf("daddu %s, %s, %s\n", Reg(rd), Reg(rs), Reg(rt));
|
||||
}
|
|
@ -6,12 +6,6 @@ typedef union
|
|||
uint32_t full;
|
||||
struct
|
||||
{
|
||||
// uint32_t opcode : 6;
|
||||
// uint32_t rs : 5;
|
||||
// uint32_t rt : 5;
|
||||
// uint32_t rd : 5;
|
||||
// uint32_t sa : 5;
|
||||
// uint32_t func : 6;
|
||||
uint32_t func : 6;
|
||||
uint32_t sa : 5;
|
||||
uint32_t rd : 5;
|
||||
|
@ -19,4 +13,16 @@ typedef union
|
|||
uint32_t rs : 5;
|
||||
uint32_t opcode : 6;
|
||||
} r_type;
|
||||
struct
|
||||
{
|
||||
uint32_t imm : 16;
|
||||
uint32_t rt : 5;
|
||||
uint32_t rs : 5;
|
||||
uint32_t opcode : 6;
|
||||
} i_type;
|
||||
struct
|
||||
{
|
||||
uint32_t target : 26;
|
||||
uint32_t opcode : 6;
|
||||
} j_type;
|
||||
} Opcode;
|
|
@ -21,7 +21,7 @@ inline char* print_128(uint128_t s)
|
|||
|
||||
memset(ret, 0, 33);
|
||||
|
||||
sprintf(ret, "%lx%016lx", s.u64[0], s.u64[1]);
|
||||
sprintf(ret, "%lx%016lx", s.u64[1], s.u64[0]);
|
||||
|
||||
return ret;
|
||||
}
|
Loading…
Reference in a new issue