|
module ar_gen; |
|
|
|
import std.bitmanip; |
|
import std.typecons; |
|
|
|
void instr(uint addr, uint data) |
|
{ |
|
import std.stdio; |
|
writefln("%08X %08X", addr, data); |
|
} |
|
|
|
void zeroCode(uint data) { instr(0, data); } |
|
|
|
enum ZeroCode : ubyte { end = 0x00, norm = 0x02, row = 0x03, area = 0x04 } |
|
|
|
void zeroCode(ZeroCode kind, uint data) |
|
{ |
|
assert((data & ~((1 << 29) - 1)) == 0, "Zero code data too large"); |
|
zeroCode((kind << 29) | data); |
|
} |
|
|
|
enum DataType : ubyte |
|
{ |
|
dt8bit = 0x00, |
|
dt16bit = 0x01, |
|
dt32bit = 0x02, |
|
dt32float = 0x03, |
|
} |
|
|
|
template dataTypeOf(T) |
|
{ |
|
static if (is(T == ubyte)) |
|
enum dataTypeOf = DataType.dt8bit; |
|
else |
|
static if (is(T == ushort)) |
|
enum dataTypeOf = DataType.dt16bit; |
|
else |
|
static if (is(T == uint)) |
|
enum dataTypeOf = DataType.dt32bit; |
|
else |
|
static if (is(T == float)) |
|
enum dataTypeOf = DataType.dt32float; |
|
else |
|
static assert(false, "Bad type: " ~ T.stringof); |
|
} |
|
|
|
enum ConditionalType : ubyte |
|
{ |
|
normal = 0x00, |
|
equal = 0x01, |
|
notEqual = 0x02, |
|
lessThanSigned = 0x03, |
|
greaterThanSigned = 0x04, |
|
lessThanUnsigned = 0x05, |
|
greaterThanUnsigned = 0x06, |
|
and = 0x07, // bitwise AND |
|
} |
|
|
|
enum NormalSubType : ubyte |
|
{ |
|
ramWrite = 0x00, |
|
writePointr = 0x01, |
|
addCode = 0x02, |
|
masterCode = 0x03, |
|
} |
|
|
|
enum ConditionSkip : ubyte |
|
{ |
|
oneLine = 0x00, |
|
twoLines = 0x01, |
|
allLinesUntil = 0x02, |
|
allLines = 0x03, |
|
} |
|
|
|
uint mkaddr(uint gcAddr, DataType size, ubyte type = 0, ubyte subtype = 0) |
|
{ |
|
static union Address |
|
{ |
|
uint address; |
|
struct |
|
{ |
|
mixin(bitfields!( |
|
uint, "gcAddr" , 25, |
|
uint, "size" , 2, |
|
uint, "type" , 3, |
|
uint, "subtype" , 2, |
|
)); |
|
} |
|
} |
|
|
|
Address address; |
|
address.gcAddr = gcAddr & 0x01FFFFFF; |
|
address.size = size; |
|
address.type = type; |
|
address.subtype = subtype; |
|
return address.address; |
|
} |
|
|
|
/// Write value to address. |
|
void put(DataType type, uint addr, uint value) { instr(mkaddr(addr, type, 0, 0), value); } |
|
void put(T)(uint addr, uint value) { put(dataTypeOf!T, addr, value); } |
|
|
|
/// Add to value in memory. |
|
void add(DataType type, uint addr, uint value) { instr(mkaddr(addr, type, ConditionalType.normal, NormalSubType.addCode), value); } |
|
void add(T)(uint addr, uint value) { add(dataTypeOf!T, addr, value); } |
|
|
|
/// Copy bytes from srcAddr to dstAddr. |
|
/// If dereference is true, the addresses are pointers which indicate |
|
/// the source and target. |
|
void copy(uint srcAddr, uint dstAddr, ushort numBytes, Flag!"dereference" dereference) |
|
{ |
|
zeroCode(ZeroCode.area, mkaddr(dstAddr, cast(DataType)3, 0, 0)); |
|
instr(srcAddr, numBytes | (dereference << 24)); |
|
} |
|
void copy(T)(uint srcAddr, uint dstAddr, Flag!"dereference" dereference) { copy(srcAddr, dstAddr, T.sizeof, dereference); } |
|
|
|
/// Ensure address points to real GC address space. |
|
uint gcAddr(uint addr) { return addr | 0x80000000; } |
|
|
|
void conditional(DataType type, uint address, ConditionalType cond, uint value, ConditionSkip action) { instr(mkaddr(address, type, cond, action), value); } |
|
void conditional(T)(uint address, ConditionalType cond, uint value, ConditionSkip action) { conditional(dataTypeOf!T, address, cond, value, action); } |